From 3d0adfb109c2c5873e9a91849bc35e4ab1c1ea80 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=BCrg=20Billeter?= Date: Mon, 1 May 2006 08:07:14 +0000 Subject: [PATCH] support ENUM, FLAGS, STRUCT add structs, generic types, enums, flags, MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 2006-05-01 Jürg Billeter * valac/scanner.l: support ENUM, FLAGS, STRUCT * valac/parser.y: add structs, generic types, enums, flags, attributes, ref and out parameters * valac/context.h: add ValaFlags, ValaFlagsValue, and ValaAnnotation structs * valac/context.c: support bool, uint, pointer, generic types * valac/generator.h: save pointer to current struct * valac/generator.c: support structs, ReturnsModifiedPointer, include files svn path=/trunk/; revision=10 --- vala/ChangeLog | 12 ++ vala/valac/context.c | 75 ++++++-- vala/valac/context.h | 50 ++++++ vala/valac/generator.c | 248 ++++++++++++++++++++------ vala/valac/generator.h | 1 + vala/valac/parser.y | 460 ++++++++++++++++++++++++++++++++++++++++++++++--- vala/valac/scanner.l | 5 +- 7 files changed, 757 insertions(+), 94 deletions(-) diff --git a/vala/ChangeLog b/vala/ChangeLog index a5367a4..4eddb06 100644 --- a/vala/ChangeLog +++ b/vala/ChangeLog @@ -1,3 +1,15 @@ +2006-05-01 Jürg Billeter + + * valac/scanner.l: support ENUM, FLAGS, STRUCT + * valac/parser.y: add structs, generic types, enums, flags, attributes, + ref and out parameters + * valac/context.h: add ValaFlags, ValaFlagsValue, and ValaAnnotation + structs + * valac/context.c: support bool, uint, pointer, generic types + * valac/generator.h: save pointer to current struct + * valac/generator.c: support structs, ReturnsModifiedPointer, include + files + 2006-04-30 Jürg Billeter * valac/scanner.l: support AT, CONST, VALA_FALSE, VALA_NULL, OUT, REF, diff --git a/vala/valac/context.c b/vala/valac/context.c index 60c7e5c..2a133da 100644 --- a/vala/valac/context.c +++ b/vala/valac/context.c @@ -65,7 +65,9 @@ err (ValaLocation *location, const char *format, ...) { va_list args; va_start (args, format); - fprintf (stderr, "%s:%d:%d: ", location->source_file->filename, location->lineno, location->colno); + if (location != NULL) { + fprintf (stderr, "%s:%d:%d: ", location->source_file->filename, location->lineno, location->colno); + } vfprintf (stderr, format, args); fprintf (stderr, "\n"); va_end (args); @@ -288,6 +290,13 @@ vala_context_add_fundamental_symbols (ValaContext *context) symbol = vala_symbol_new (VALA_SYMBOL_TYPE_VOID); g_hash_table_insert (context->root->symbol_table, "void", symbol); + /* bool */ + struct_ = g_new0 (ValaStruct, 1); + struct_->name = "bool"; + struct_->namespace = namespace; + struct_->cname = "gboolean"; + namespace->structs = g_list_append (namespace->structs, struct_); + /* int */ struct_ = g_new0 (ValaStruct, 1); struct_->name = g_strdup ("int"); @@ -295,6 +304,20 @@ vala_context_add_fundamental_symbols (ValaContext *context) struct_->cname = g_strdup ("int"); namespace->structs = g_list_append (namespace->structs, struct_); + /* uint */ + struct_ = g_new0 (ValaStruct, 1); + struct_->name = "uint"; + struct_->namespace = namespace; + struct_->cname = "unsigned int"; + namespace->structs = g_list_append (namespace->structs, struct_); + + /* pointer */ + struct_ = g_new0 (ValaStruct, 1); + struct_->name = "pointer"; + struct_->namespace = namespace; + struct_->cname = "gpointer"; + namespace->structs = g_list_append (namespace->structs, struct_); + /* string */ struct_ = g_new0 (ValaStruct, 1); struct_->name = g_strdup ("string"); @@ -346,21 +369,38 @@ vala_context_add_symbols_from_source_files (ValaContext *context) } static void -vala_context_resolve_type_reference (ValaContext *context, ValaNamespace *namespace, ValaTypeReference *type_reference) +vala_context_resolve_type_reference (ValaContext *context, ValaNamespace *namespace, GList *type_parameter_list, ValaTypeReference *type_reference) { - ValaSymbol *type_symbol, *ns_symbol; + ValaSymbol *type_symbol = NULL, *ns_symbol; + GList *l; + type_reference->type_param_index = -1; + if (type_reference->type_name == NULL) { /* var type, resolve on initialization */ return; } else if (type_reference->namespace_name == NULL) { /* no namespace specified */ + + /* check for generic type parameter */ + int i; + for (i = 0, l = type_parameter_list; l != NULL; i++, l = l->next) { + if (strcmp (l->data, type_reference->type_name) == 0) { + type_reference->type_param_index = i; + type_symbol = g_hash_table_lookup (context->root->symbol_table, "pointer"); + break; + } + } - /* look in current namespace */ - type_symbol = g_hash_table_lookup (namespace->symbol->symbol_table, type_reference->type_name); - if (type_symbol != NULL) { - type_reference->namespace_name = namespace->name; - } else { + if (type_symbol == NULL) { + /* look in current namespace */ + type_symbol = g_hash_table_lookup (namespace->symbol->symbol_table, type_reference->type_name); + if (type_symbol != NULL) { + type_reference->namespace_name = namespace->name; + } + } + + if (type_symbol == NULL) { /* look in root namespace */ type_symbol = g_hash_table_lookup (context->root->symbol_table, type_reference->type_name); if (type_symbol != NULL) { @@ -370,7 +410,6 @@ vala_context_resolve_type_reference (ValaContext *context, ValaNamespace *namesp if (type_symbol == NULL) { /* look in namespaces specified by using directives */ - GList *l; for (l = namespace->source_file->using_directives; l != NULL; l = l->next) { char *ns = l->data; ns_symbol = g_hash_table_lookup (context->root->symbol_table, ns); @@ -408,6 +447,9 @@ vala_context_resolve_type_reference (ValaContext *context, ValaNamespace *namesp type_symbol->type == VALA_SYMBOL_TYPE_CLASS || type_symbol->type == VALA_SYMBOL_TYPE_STRUCT) { type_reference->symbol = type_symbol; + if (type_symbol->type != VALA_SYMBOL_TYPE_VOID) { + namespace->source_file->dep_types = g_list_prepend (namespace->source_file->dep_types, type_symbol); + } } else { err (type_reference->location, "error: specified symbol ´%s´ is not a type", type_reference->type_name); } @@ -420,7 +462,7 @@ vala_context_resolve_types_in_expression (ValaContext *context, ValaNamespace *n { switch (expr->type) { case VALA_EXPRESSION_TYPE_OBJECT_CREATION: - vala_context_resolve_type_reference (context, namespace, expr->object_creation.type); + vala_context_resolve_type_reference (context, namespace, NULL, expr->object_creation.type); break; } } @@ -430,7 +472,7 @@ vala_context_resolve_types_in_statement (ValaContext *context, ValaNamespace *na { switch (stmt->type) { case VALA_STATEMENT_TYPE_VARIABLE_DECLARATION: - vala_context_resolve_type_reference (context, namespace, stmt->variable_declaration->type); + vala_context_resolve_type_reference (context, namespace, NULL, stmt->variable_declaration->type); if (stmt->variable_declaration->declarator->initializer != NULL) { vala_context_resolve_types_in_expression (context, namespace, stmt->variable_declaration->declarator->initializer); } @@ -462,19 +504,22 @@ vala_context_resolve_types_in_method (ValaContext *context, ValaMethod *method) { GList *l; ValaNamespace *namespace; + GList *type_parameters; if (!method->is_struct_method) { namespace = method->class->namespace; + type_parameters = method->class->type_parameters; } else { namespace = method->struct_->namespace; + type_parameters = method->struct_->type_parameters; } - vala_context_resolve_type_reference (context, namespace, method->return_type); + vala_context_resolve_type_reference (context, namespace, type_parameters, method->return_type); for (l = method->formal_parameters; l != NULL; l = l->next) { ValaFormalParameter *formal_parameter = l->data; - vala_context_resolve_type_reference (context, namespace, formal_parameter->type); + vala_context_resolve_type_reference (context, namespace, type_parameters, formal_parameter->type); if (formal_parameter->type->symbol->type == VALA_SYMBOL_TYPE_VOID) { err (formal_parameter->location, "error: method parameters cannot be of type `void`"); } @@ -494,7 +539,7 @@ vala_context_resolve_types_in_field (ValaContext *context, ValaField *field) static void vala_context_resolve_types_in_property (ValaContext *context, ValaProperty *property) { - vala_context_resolve_type_reference (context, property->class->namespace, property->return_type); + vala_context_resolve_type_reference (context, property->class->namespace, property->class->type_parameters, property->return_type); vala_context_resolve_types_in_statement (context, property->class->namespace, property->get_statement); vala_context_resolve_types_in_statement (context, property->class->namespace, property->set_statement); } @@ -507,7 +552,7 @@ vala_context_resolve_types_in_class (ValaContext *context, ValaClass *class) for (l = class->base_types; l != NULL; l = l->next) { ValaTypeReference *type_reference = l->data; - vala_context_resolve_type_reference (context, class->namespace, type_reference); + vala_context_resolve_type_reference (context, class->namespace, NULL, type_reference); if (type_reference->symbol->type == VALA_SYMBOL_TYPE_CLASS) { if (class->base_class != NULL) { err (type_reference->location, "error: more than one base class specified in class ´%s.%s´", class->namespace->name, class->name); diff --git a/vala/valac/context.h b/vala/valac/context.h index 10ca16b..21d65c5 100644 --- a/vala/valac/context.h +++ b/vala/valac/context.h @@ -28,6 +28,7 @@ typedef enum _ValaConstantFlags ValaConstantFlags; typedef enum _ValaMethodFlags ValaMethodFlags; typedef enum _ValaFieldFlags ValaFieldFlags; typedef enum _ValaPropertyFlags ValaPropertyFlags; +typedef enum _ValaFormalParameterFlags ValaFormalParameterFlags; typedef enum _ValaStatementType ValaStatementType; typedef enum _ValaExpressionType ValaExpressionType; typedef enum _ValaOpType ValaOpType; @@ -40,11 +41,13 @@ typedef struct _ValaNamespace ValaNamespace; typedef struct _ValaClass ValaClass; typedef struct _ValaStruct ValaStruct; typedef struct _ValaEnum ValaEnum; +typedef struct _ValaFlags ValaFlags; typedef struct _ValaConstant ValaConstant; typedef struct _ValaMethod ValaMethod; typedef struct _ValaField ValaField; typedef struct _ValaProperty ValaProperty; typedef struct _ValaEnumValue ValaEnumValue; +typedef struct _ValaFlagsValue ValaFlagsValue; typedef struct _ValaStatement ValaStatement; typedef struct _ValaVariableDeclaration ValaVariableDeclaration; typedef struct _ValaVariableDeclarator ValaVariableDeclarator; @@ -52,6 +55,7 @@ typedef struct _ValaExpression ValaExpression; typedef struct _ValaTypeReference ValaTypeReference; typedef struct _ValaFormalParameter ValaFormalParameter; typedef struct _ValaNamedArgument ValaNamedArgument; +typedef struct _ValaAnnotation ValaAnnotation; enum _ValaSymbolType { VALA_SYMBOL_TYPE_ROOT, @@ -91,6 +95,11 @@ enum _ValaPropertyFlags { VALA_PROPERTY_PUBLIC = 1 << 0, }; +enum _ValaFormalParameterFlags { + VALA_FORMAL_PARAMETER_REF = 1 << 0, + VALA_FORMAL_PARAMETER_OUT = 1 << 1, +}; + enum _ValaStatementType { VALA_STATEMENT_TYPE_BLOCK, VALA_STATEMENT_TYPE_EXPRESSION, @@ -162,6 +171,7 @@ struct _ValaSourceFile { ValaNamespace *root_namespace; GList *namespaces; GList *using_directives; + GList *dep_types; }; struct _ValaLocation { @@ -177,9 +187,13 @@ struct _ValaNamespace { GList *classes; GList *structs; GList *enums; + GList *flags_list; GList *methods; + char *cprefix; char *lower_case_cname; char *upper_case_cname; + GList *annotations; + gboolean import; }; struct _ValaClass { @@ -193,11 +207,13 @@ struct _ValaClass { GList *fields; GList *constants; GList *properties; + GList *type_parameters; char *cname; char *lower_case_cname; char *upper_case_cname; ValaMethod *init_method; ValaMethod *class_init_method; + GList *annotations; }; struct _ValaStruct { @@ -208,7 +224,11 @@ struct _ValaStruct { gboolean reference_type; GList *methods; GList *fields; + GList *type_parameters; char *cname; + char *lower_case_cname; + char *upper_case_cname; + GList *annotations; }; struct _ValaEnum { @@ -218,6 +238,19 @@ struct _ValaEnum { ValaNamespace *namespace; GList *values; char *cname; + char *upper_case_cname; + GList *annotations; +}; + +struct _ValaFlags { + char *name; + ValaLocation *location; + ValaSymbol *symbol; + ValaNamespace *namespace; + GList *values; + char *cname; + char *upper_case_cname; + GList *annotations; }; struct _ValaMethod { @@ -237,6 +270,8 @@ struct _ValaMethod { char *cdecl1; char *cparameters; ValaStatement *body; + gboolean returns_modified_pointer; + GList *annotations; }; struct _ValaField { @@ -273,6 +308,13 @@ struct _ValaEnumValue { char *cname; }; +struct _ValaFlagsValue { + char *name; + char *value; + ValaSymbol *symbol; + char *cname; +}; + struct _ValaStatement { ValaStatementType type; ValaLocation *location; @@ -363,12 +405,15 @@ struct _ValaTypeReference { ValaSymbol *symbol; gboolean own; gboolean array_type; + int type_param_index; /* for type references within generic types */ + GList *type_params; /* for type references referring to generic types */ }; struct _ValaFormalParameter { char *name; ValaTypeReference *type; ValaLocation *location; + ValaFormalParameterFlags modifier; }; struct _ValaNamedArgument { @@ -378,6 +423,11 @@ struct _ValaNamedArgument { ValaSymbol *symbol; /* symbol corresponding to name */ }; +struct _ValaAnnotation { + ValaTypeReference *type; + GList *argument_list; +}; + ValaContext *vala_context_new (); void vala_context_free (ValaContext *context); void vala_context_parse (ValaContext *context); diff --git a/vala/valac/generator.c b/vala/valac/generator.c index acb3c75..e0a2203 100644 --- a/vala/valac/generator.c +++ b/vala/valac/generator.c @@ -151,6 +151,64 @@ vala_code_generator_process_methods1 (ValaCodeGenerator *generator, ValaClass *c fprintf (generator->c_file, "\n"); } +static void +vala_code_generator_process_struct_methods1 (ValaCodeGenerator *generator, ValaStruct *struct_) +{ + GList *l; + + char *camel_case; + char *ns_lower; + char *ns_upper; + + ValaNamespace *namespace = struct_->namespace; + + ns_lower = namespace->lower_case_cname; + ns_upper = namespace->upper_case_cname; + + char *lower_case = struct_->lower_case_cname; + char *upper_case = struct_->upper_case_cname; + + for (l = struct_->methods; l != NULL; l = l->next) { + ValaMethod *method = l->data; + + char *method_return_type_cname = get_cname_for_type_reference (method->return_type, FALSE, method->location); + method->cname = g_strdup_printf ("%s%s_%s", ns_lower, lower_case, method->name); + + char *parameters; + GList *parameter_list = NULL; + if ((method->modifiers & VALA_METHOD_STATIC) == 0) { + parameter_list = g_list_append (parameter_list, g_strdup_printf ("%s *self", struct_->cname)); + } + + GList *pl; + for (pl = method->formal_parameters; pl != NULL; pl = pl->next) { + ValaFormalParameter *param = pl->data; + char *param_string = g_strdup_printf ("%s%s", get_cname_for_type_reference (param->type, FALSE, param->location), param->name); + parameter_list = g_list_append (parameter_list, param_string); + } + + if (parameter_list == NULL) { + method->cparameters = g_strdup (""); + } else { + method->cparameters = parameter_list->data; + GList *sl; + for (sl = parameter_list->next; sl != NULL; sl = sl->next) { + method->cparameters = g_strdup_printf ("%s, %s", method->cparameters, sl->data); + g_free (sl->data); + } + g_list_free (parameter_list); + } + + if (method->modifiers & VALA_METHOD_PUBLIC) { + method->cdecl1 = g_strdup (method_return_type_cname); + } else { + method->cdecl1 = g_strdup_printf ("static %s", method_return_type_cname); + fprintf (generator->c_file, "%s %s (%s);\n", method->cdecl1, method->cname, method->cparameters); + } + } + fprintf (generator->c_file, "\n"); +} + static void vala_code_generator_process_expression (ValaCodeGenerator *generator, ValaExpression *expr); static void @@ -202,56 +260,6 @@ vala_code_generator_process_assignment (ValaCodeGenerator *generator, ValaExpres vala_code_generator_process_expression (generator, expr->assignment.right); } -static void -vala_code_generator_process_invocation (ValaCodeGenerator *generator, ValaExpression *expr) -{ - GList *l; - ValaMethod *method = NULL; - gboolean first = TRUE; - - vala_code_generator_process_expression (generator, expr->invocation.call); - method = expr->invocation.call->static_type_symbol->method; - switch (expr->invocation.call->type) { - case VALA_EXPRESSION_TYPE_MEMBER_ACCESS: - expr->invocation.instance = expr->invocation.call->member_access.left; - break; - } - fprintf (generator->c_file, " ("); - if ((method->modifiers & VALA_METHOD_STATIC) == 0) { - if (expr->invocation.instance != NULL) { - vala_code_generator_process_expression (generator, expr->invocation.instance); - } else { - fprintf (generator->c_file, "self"); - } - first = FALSE; - } - for (l = expr->invocation.argument_list; l != NULL; l = l->next) { - if (!first) { - fprintf (generator->c_file, ", "); - } else { - first = FALSE; - } - vala_code_generator_process_expression (generator, l->data); - } - fprintf (generator->c_file, ")"); -} - -static void -vala_code_generator_process_literal (ValaCodeGenerator *generator, ValaExpression *expr) -{ - switch (expr->type) { - case VALA_EXPRESSION_TYPE_LITERAL_BOOLEAN: - fprintf (generator->c_file, "%s", expr->num ? "TRUE" : "FALSE"); - break; - case VALA_EXPRESSION_TYPE_LITERAL_NULL: - fprintf (generator->c_file, "NULL"); - break; - default: - fprintf (generator->c_file, "%s", expr->str); - break; - } -} - static ValaSymbol * get_inherited_member (ValaSymbol *type, const char *name, ValaLocation *location, gboolean break_on_failure) { @@ -395,6 +403,71 @@ vala_code_generator_find_static_type_of_expression (ValaCodeGenerator *generator } static void +vala_code_generator_process_invocation (ValaCodeGenerator *generator, ValaExpression *expr) +{ + GList *l; + ValaMethod *method = NULL; + gboolean first = TRUE; + + vala_code_generator_find_static_type_of_expression (generator, expr->invocation.call); + method = expr->invocation.call->static_type_symbol->method; + switch (expr->invocation.call->type) { + case VALA_EXPRESSION_TYPE_MEMBER_ACCESS: + expr->invocation.instance = expr->invocation.call->member_access.left; + break; + } + + if (method->returns_modified_pointer) { + if (expr->static_type_symbol->type != VALA_SYMBOL_TYPE_VOID) { + err (method->location, "error: ReturnsModifiedPointer declared on a method with non-void return type"); + } + + if (expr->invocation.instance != NULL) { + vala_code_generator_process_expression (generator, expr->invocation.instance); + } else { + fprintf (generator->c_file, "self"); + } + fprintf (generator->c_file, " = "); + } + + vala_code_generator_process_expression (generator, expr->invocation.call); + fprintf (generator->c_file, " ("); + if ((method->modifiers & VALA_METHOD_STATIC) == 0) { + if (expr->invocation.instance != NULL) { + vala_code_generator_process_expression (generator, expr->invocation.instance); + } else { + fprintf (generator->c_file, "self"); + } + first = FALSE; + } + for (l = expr->invocation.argument_list; l != NULL; l = l->next) { + if (!first) { + fprintf (generator->c_file, ", "); + } else { + first = FALSE; + } + vala_code_generator_process_expression (generator, l->data); + } + fprintf (generator->c_file, ")"); +} + +static void +vala_code_generator_process_literal (ValaCodeGenerator *generator, ValaExpression *expr) +{ + switch (expr->type) { + case VALA_EXPRESSION_TYPE_LITERAL_BOOLEAN: + fprintf (generator->c_file, "%s", expr->num ? "TRUE" : "FALSE"); + break; + case VALA_EXPRESSION_TYPE_LITERAL_NULL: + fprintf (generator->c_file, "NULL"); + break; + default: + fprintf (generator->c_file, "%s", expr->str); + break; + } +} + +static void vala_code_generator_process_element_access (ValaCodeGenerator *generator, ValaExpression *expr) { vala_code_generator_process_expression (generator, expr->element_access.array); @@ -986,7 +1059,7 @@ vala_code_generator_process_class1 (ValaCodeGenerator *generator, ValaClass *cla char *ns_upper; GList *l; - camel_case = g_strdup_printf ("%s%s", namespace->name, class->name); + camel_case = class->cname; ns_lower = namespace->lower_case_cname; ns_upper = namespace->upper_case_cname; @@ -1035,6 +1108,32 @@ vala_code_generator_process_class1 (ValaCodeGenerator *generator, ValaClass *cla } static void +vala_code_generator_process_struct1 (ValaCodeGenerator *generator, ValaStruct *struct_) +{ + ValaNamespace *namespace = struct_->namespace; + + generator->struct_ = struct_; + + char *camel_case; + char *ns_lower; + char *ns_upper; + GList *l; + + camel_case = struct_->cname; + ns_lower = namespace->lower_case_cname; + ns_upper = namespace->upper_case_cname; + + char *lower_case = struct_->lower_case_cname; + char *upper_case = struct_->upper_case_cname; + + /* structs */ + fprintf (generator->h_file, "typedef struct _%s %s;\n", camel_case, camel_case); + fprintf (generator->h_file, "\n"); + + vala_code_generator_process_struct_methods1 (generator, struct_); +} + +static void vala_code_generator_process_class2 (ValaCodeGenerator *generator, ValaClass *class) { ValaNamespace *namespace = class->namespace; @@ -1125,6 +1224,9 @@ vala_code_generator_process_namespace1 (ValaCodeGenerator *generator, ValaNamesp for (l = namespace->classes; l != NULL; l = l->next) { vala_code_generator_process_class1 (generator, l->data); } + for (l = namespace->structs; l != NULL; l = l->next) { + vala_code_generator_process_struct1 (generator, l->data); + } } static void @@ -1189,6 +1291,50 @@ vala_code_generator_process_source_file (ValaCodeGenerator *generator, ValaSourc * same as in the source directory. compiler should accept parameter to * specify include root directory if something different than current * working directory is needed */ + + GList *dep_files = NULL; + + for (l = source_file->dep_types; l != NULL; l = l->next) { + ValaSymbol *dep_type = l->data; + ValaSourceFile *dep_file; + ValaNamespace *namespace; + if (dep_type->type == VALA_SYMBOL_TYPE_CLASS) { + namespace = dep_type->class->namespace; + } else if (dep_type->type == VALA_SYMBOL_TYPE_STRUCT) { + namespace = dep_type->struct_->namespace; + } else { + err (NULL, "internal error: dependant type is neither class nor struct"); + } + if (namespace->import) { + /* imported namespace, don't use stub header */ + /* FIXME: include real header instead */ + continue; + } + dep_file = namespace->source_file; + + if (dep_file == NULL) { + /* type without source file, ignore */ + continue; + } + + GList *fl; + for (fl = dep_files; fl != NULL; fl = fl->next) { + if (fl->data == dep_file) { + dep_file = NULL; + break; + } + } + if (dep_file == NULL) { + /* file already included, ignore */ + continue; + } + + char *dep_basename = g_strdup (dep_file->filename); + dep_basename[strlen (dep_basename) - strlen (".vala")] = '\0'; + + fprintf (generator->h_file, "#include <%s.h>\n", dep_basename); + } + fprintf (generator->h_file, "\n"); fprintf (generator->h_file, "G_BEGIN_DECLS\n"); fprintf (generator->h_file, "\n"); diff --git a/vala/valac/generator.h b/vala/valac/generator.h index 487a9fd..88008c7 100644 --- a/vala/valac/generator.h +++ b/vala/valac/generator.h @@ -31,6 +31,7 @@ struct _ValaCodeGenerator { FILE *h_file; ValaSymbol *sym; /* current block */ ValaClass *class; /* current class */ + ValaStruct *struct_; /* current struct */ }; ValaCodeGenerator *vala_code_generator_new (ValaContext *context); diff --git a/vala/valac/parser.y b/vala/valac/parser.y index 7c476fa..2cc2498 100644 --- a/vala/valac/parser.y +++ b/vala/valac/parser.y @@ -88,9 +88,18 @@ camel_case_to_upper_case (const char *camel_case) return str; } +static char * +eval_string (const char *cstring) +{ + char *ret = g_strdup (cstring + 1); + ret[strlen (ret) - 1] = '\0'; + return ret; +} + static ValaSourceFile *current_source_file; static ValaNamespace *current_namespace; static ValaClass *current_class; +static ValaStruct *current_struct; static ValaMethod *current_method; ValaLocation *get_location (int lineno, int colno) @@ -117,6 +126,10 @@ ValaLocation *get_location (int lineno, int colno) GList *list; ValaTypeReference *type_reference; ValaFormalParameter *formal_parameter; + ValaMethod *method; + ValaStruct *struct_; + ValaEnum *enum_; + ValaFlags *flags; ValaStatement *statement; ValaVariableDeclaration *variable_declaration; ValaVariableDeclarator *variable_declarator; @@ -125,6 +138,9 @@ ValaLocation *get_location (int lineno, int colno) ValaConstant *constant; ValaProperty *property; ValaNamedArgument *named_argument; + ValaEnumValue *enum_value; + ValaFlagsValue *flags_value; + ValaAnnotation *annotation; } %token OPEN_BRACE "{" @@ -157,7 +173,9 @@ ValaLocation *get_location (int lineno, int colno) %token CLASS "class" %token CONST "const" %token ELSE "else" +%token ENUM "enum" %token VALA_FALSE "false" +%token FLAGS "flags" %token FOR "for" %token GET "get" %token IF "if" @@ -168,8 +186,9 @@ ValaLocation *get_location (int lineno, int colno) %token PUBLIC "public" %token PRIVATE "private" %token REF "ref" -%token STATIC "static" %token SET "set" +%token STATIC "static" +%token STRUCT "struct" %token RETURN "return" %token THIS "this" %token VALA_TRUE "true" @@ -182,6 +201,12 @@ ValaLocation *get_location (int lineno, int colno) %token LITERAL_INTEGER "integer" %token LITERAL_STRING "string" +%type opt_type_parameter_list +%type type_parameter_list +%type type_parameters +%type opt_type_argument_list +%type type_argument_list +%type type_arguments %type opt_class_base %type class_base %type type_list @@ -204,6 +229,8 @@ ValaLocation *get_location (int lineno, int colno) %type opt_constant_modifiers %type constant_modifiers %type constant_modifier +%type opt_parameter_modifier +%type parameter_modifier %type opt_at %type opt_brackets %type boolean_literal @@ -258,6 +285,25 @@ ValaLocation *get_location (int lineno, int colno) %type set_accessor_declaration %type named_argument %type constant_declaration +%type struct_declaration +%type method_declaration +%type method_header +%type enum_declaration +%type flags_declaration +%type opt_enum_member_declarations +%type enum_member_declarations +%type enum_body +%type enum_member_declaration +%type opt_flags_member_declarations +%type flags_member_declarations +%type flags_body +%type flags_member_declaration +%type opt_attribute_sections +%type attribute_sections +%type attribute_section +%type attribute_list +%type attribute_arguments +%type attribute %% @@ -294,10 +340,11 @@ outer_declaration ; namespace_declaration - : NAMESPACE IDENTIFIER + : opt_attribute_sections NAMESPACE IDENTIFIER { current_namespace = g_new0 (ValaNamespace, 1); - current_namespace->name = $2; + current_namespace->name = $3; + current_namespace->cprefix = current_namespace->name; current_namespace->source_file = current_source_file; current_namespace->lower_case_cname = camel_case_to_lower_case (current_namespace->name); /* we know that this is safe */ @@ -307,6 +354,28 @@ namespace_declaration /* we know that this is safe */ current_namespace->upper_case_cname[strlen (current_namespace->upper_case_cname)] = '_'; + current_namespace->annotations = $1; + + GList *l, *al; + for (l = current_namespace->annotations; l != NULL; l = l->next) { + ValaAnnotation *anno = l->data; + + if (strcmp (anno->type->type_name, "CCode") == 0) { + for (al = anno->argument_list; al != NULL; al = al->next) { + ValaNamedArgument *arg = al->data; + + if (strcmp (arg->name, "cname") == 0) { + current_namespace->lower_case_cname = g_strdup_printf ("%s_", eval_string (arg->expression->str)); + current_namespace->upper_case_cname = g_ascii_strup (current_namespace->lower_case_cname, -1); + } else if (strcmp (arg->name, "cprefix") == 0) { + current_namespace->cprefix = eval_string (arg->expression->str); + } + } + } else if (strcmp (anno->type->type_name, "Import") == 0) { + current_namespace->import = TRUE; + } + } + current_source_file->namespaces = g_list_append (current_source_file->namespaces, current_namespace); } namespace_body @@ -335,17 +404,29 @@ namespace_member_declaration type_declaration : class_declaration + | struct_declaration + | enum_declaration + { + $1->namespace = current_namespace; + current_namespace->enums = g_list_append (current_namespace->enums, $1); + } + | flags_declaration + { + $1->namespace = current_namespace; + current_namespace->flags_list = g_list_append (current_namespace->flags_list, $1); + } ; class_declaration - : CLASS IDENTIFIER opt_class_base + : opt_attribute_sections CLASS IDENTIFIER opt_type_parameter_list opt_class_base { current_class = g_new0 (ValaClass, 1); - current_class->name = g_strdup ($2); - current_class->base_types = $3; + current_class->name = g_strdup ($3); + current_class->base_types = $5; + current_class->type_parameters = $4; current_class->location = current_location (@2); current_class->namespace = current_namespace; - current_class->cname = g_strdup_printf ("%s%s", current_namespace->name, current_class->name); + current_class->cname = g_strdup_printf ("%s%s", current_namespace->cprefix, current_class->name); current_class->lower_case_cname = camel_case_to_lower_case (current_class->name); current_class->upper_case_cname = camel_case_to_upper_case (current_class->name); current_namespace->classes = g_list_append (current_namespace->classes, current_class); @@ -353,6 +434,35 @@ class_declaration class_body ; +opt_type_parameter_list + : /* empty */ + { + $$ = NULL; + } + | type_parameter_list + { + $$ = $1; + } + ; + +type_parameter_list + : OP_LT type_parameters OP_GT + { + $$ = $2; + } + ; + +type_parameters + : IDENTIFIER + { + $$ = g_list_append (NULL, $1); + } + | type_parameters COMMA IDENTIFIER + { + $$ = g_list_append ($1, $3); + } + ; + opt_class_base : /* empty */ { @@ -383,27 +493,58 @@ type_list ; type_name - : IDENTIFIER opt_at opt_brackets + : IDENTIFIER opt_type_argument_list opt_at opt_brackets { ValaTypeReference *type_reference = g_new0 (ValaTypeReference, 1); type_reference->type_name = g_strdup ($1); type_reference->location = current_location (@1); - type_reference->own = $2; - type_reference->array_type = $3; + type_reference->own = $3; + type_reference->array_type = $4; + type_reference->type_params = $2; $$ = type_reference; } - | IDENTIFIER DOT IDENTIFIER opt_at opt_brackets + | IDENTIFIER DOT IDENTIFIER opt_type_argument_list opt_at opt_brackets { ValaTypeReference *type_reference = g_new0 (ValaTypeReference, 1); type_reference->namespace_name = g_strdup ($1); type_reference->type_name = g_strdup ($3); type_reference->location = current_location (@1); - type_reference->own = $4; - type_reference->array_type = $5; + type_reference->own = $5; + type_reference->array_type = $6; + type_reference->type_params = $4; $$ = type_reference; } ; +opt_type_argument_list + : /* empty */ + { + $$ = NULL; + } + | type_argument_list + { + $$ = $1; + } + ; + +type_argument_list + : OP_LT type_arguments OP_GT + { + $$ = $2; + } + ; + +type_arguments + : type_name + { + $$ = g_list_append (NULL, $1);; + } + | type_arguments COMMA type_name + { + $$ = g_list_append ($1, $3);; + } + ; + opt_at : /* empty */ { @@ -447,6 +588,10 @@ class_member_declaration current_class->constants = g_list_append (current_class->constants, $1); } | method_declaration + { + $1->class = current_class; + current_class->methods = g_list_append (current_class->methods, current_method); + } | field_declaration { $1->class = current_class; @@ -509,20 +654,33 @@ constant_modifier method_declaration : method_header method_body + { + $$ = $1; + } ; method_header - : opt_method_modifiers type_name IDENTIFIER OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS - { - current_method = g_new0 (ValaMethod, 1); - current_method->name = g_strdup ($3); - current_method->class = current_class; - current_method->return_type = $2; - current_method->formal_parameters = $5; - current_method->modifiers = $1; - current_method->location = current_location (@3); + : opt_attribute_sections opt_method_modifiers type_name IDENTIFIER OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS + { + $$ = g_new0 (ValaMethod, 1); + $$->name = g_strdup ($4); + $$->return_type = $3; + $$->formal_parameters = $6; + $$->modifiers = $2; + $$->location = current_location (@4); + + $$->annotations = $1; - current_class->methods = g_list_append (current_class->methods, current_method); + GList *l, *al; + for (l = $$->annotations; l != NULL; l = l->next) { + ValaAnnotation *anno = l->data; + + if (strcmp (anno->type->type_name, "ReturnsModifiedPointer") == 0) { + $$->returns_modified_pointer = TRUE; + } + } + + current_method = $$; } ; @@ -594,12 +752,35 @@ fixed_parameters ; fixed_parameter - : type_name IDENTIFIER + : opt_parameter_modifier type_name IDENTIFIER { $$ = g_new0 (ValaFormalParameter, 1); - $$->type = $1; - $$->name = $2; - $$->location = current_location (@2); + $$->type = $2; + $$->name = $3; + $$->modifier = $1; + $$->location = current_location (@1); + } + ; + +opt_parameter_modifier + : /* empty */ + { + $$ = 0; + } + | parameter_modifier + { + $$ = $1; + } + ; + +parameter_modifier + : REF + { + $$ = 1; + } + | OUT + { + $$ = 2; } ; @@ -1457,6 +1638,231 @@ struct_or_array_initializer } ; +struct_declaration + : opt_attribute_sections STRUCT IDENTIFIER opt_type_parameter_list + { + $$ = g_new0 (ValaStruct, 1); + $$->name = g_strdup ($3); + $$->location = current_location (@2); + $$->type_parameters = $4; + $$->namespace = current_namespace; + $$->cname = g_strdup_printf ("%s%s", current_namespace->cprefix, $$->name); + $$->lower_case_cname = camel_case_to_lower_case ($$->name); + $$->upper_case_cname = camel_case_to_upper_case ($$->name); + current_namespace->structs = g_list_append (current_namespace->structs, $$); + current_struct = $$; + + $$->annotations = $1; + + GList *l, *al; + for (l = $$->annotations; l != NULL; l = l->next) { + ValaAnnotation *anno = l->data; + + if (strcmp (anno->type->type_name, "ReferenceType") == 0) { + $$->reference_type = TRUE; + } + } + } + struct_body + { + current_struct = NULL; + } + ; + +struct_body + : OPEN_BRACE opt_struct_member_declarations CLOSE_BRACE + ; + +opt_struct_member_declarations + : /* empty */ + | struct_member_declarations + ; + +struct_member_declarations + : struct_member_declaration + | struct_member_declarations struct_member_declaration + ; + +struct_member_declaration + : field_declaration + | method_declaration + { + $1->is_struct_method = TRUE; + $1->struct_ = current_struct; + current_struct->methods = g_list_append (current_struct->methods, $1); + } + ; + +enum_declaration + : opt_attribute_sections ENUM IDENTIFIER enum_body + { + GList *l; + + $$ = g_new0 (ValaEnum, 1); + $$->name = $3; + $$->location = current_location (@2); + $$->cname = g_strdup_printf ("%s%s", current_namespace->cprefix, $$->name); + $$->upper_case_cname = camel_case_to_upper_case ($$->name); + $$->values = $4; + + for (l = $$->values; l != NULL; l = l->next) { + ValaEnumValue *value = l->data; + value->cname = g_strdup_printf ("%s%s_%s", current_namespace->upper_case_cname, $$->upper_case_cname, value->name); + } + } + ; + +enum_body + : OPEN_BRACE opt_enum_member_declarations CLOSE_BRACE + { + $$ = $2; + } + ; + +opt_enum_member_declarations + : /* empty */ + { + $$ = NULL; + } + | enum_member_declarations + { + $$ = $1; + } + ; + +enum_member_declarations + : enum_member_declaration + { + $$ = g_list_append (NULL, $1); + } + | enum_member_declarations COMMA enum_member_declaration + { + $$ = g_list_append ($1, $3); + } + ; + +enum_member_declaration + : IDENTIFIER + { + $$ = g_new0 (ValaEnumValue, 1); + $$->name = $1; + } + | IDENTIFIER ASSIGN expression + { + $$ = g_new0 (ValaEnumValue, 1); + $$->name = $1; + } + ; + +flags_declaration + : opt_attribute_sections FLAGS IDENTIFIER flags_body + { + $$ = g_new0 (ValaFlags, 1); + $$->name = $3; + $$->location = current_location (@2); + $$->cname = g_strdup_printf ("%s%s", current_namespace->cprefix, $$->name); + $$->values = $4; + } + ; + +flags_body + : OPEN_BRACE opt_flags_member_declarations CLOSE_BRACE + { + $$ = $2; + } + ; + +opt_flags_member_declarations + : /* empty */ + { + $$ = NULL; + } + | flags_member_declarations + { + $$ = $1; + } + ; + +flags_member_declarations + : flags_member_declaration + { + $$ = g_list_append (NULL, $1); + } + | flags_member_declarations COMMA flags_member_declaration + { + $$ = g_list_append ($1, $3); + } + ; + +flags_member_declaration + : IDENTIFIER + { + $$ = g_new0 (ValaFlagsValue, 1); + $$->name = $1; + } + | IDENTIFIER ASSIGN expression + { + $$ = g_new0 (ValaFlagsValue, 1); + $$->name = $1; + } + ; + +opt_attribute_sections + : /* empty */ + { + $$ = NULL; + } + | attribute_sections + { + $$ = $1; + } + ; + +attribute_sections + : attribute_section + { + $$ = $1; + } + | attribute_sections attribute_section + { + $$ = g_list_concat ($1, $2); + } + ; + +attribute_section + : OPEN_BRACKET attribute_list CLOSE_BRACKET + { + $$ = $2; + } + ; + +attribute_list + : attribute + { + $$ = g_list_append (NULL, $1); + } + | attribute_list COMMA attribute + { + $$ = g_list_append ($1, $3); + } + ; + +attribute + : type_name attribute_arguments + { + $$ = g_new0 (ValaAnnotation, 1); + $$->type = $1; + $$->argument_list = $2; + } + ; + +attribute_arguments + : OPEN_PARENS opt_named_argument_list CLOSE_PARENS + { + $$ = $2; + } + ; + %% extern FILE *yyin; diff --git a/vala/valac/scanner.l b/vala/valac/scanner.l index b71ead3..64919cf 100644 --- a/vala/valac/scanner.l +++ b/vala/valac/scanner.l @@ -67,7 +67,9 @@ "class" { uploc; return CLASS; } "const" { uploc; return CONST; } "else" { uploc; return ELSE; } +"enum" { uploc; return ENUM; } "false" { uploc; return VALA_FALSE; } +"flags" { uploc; return FLAGS; } "for" { uploc; return FOR; } "get" { uploc; return GET; } "if" { uploc; return IF; } @@ -78,8 +80,9 @@ "public" { uploc; return PUBLIC; } "private" { uploc; return PRIVATE; } "ref" { uploc; return REF; } -"static" { uploc; return STATIC; } "set" { uploc; return SET; } +"static" { uploc; return STATIC; } +"struct" { uploc; return STRUCT; } "return" { uploc; return RETURN; } "this" { uploc; return THIS; } "true" { uploc; return VALA_TRUE; } -- 2.7.4