From: Jürg Billeter Date: Wed, 31 May 2006 09:56:04 +0000 (+0000) Subject: support interfaces, adapt to Class/Struct/Type changes, improve error X-Git-Tag: VALA_0_0_1~41 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bb3a6298546a48bc535db1e4af21f812268a126f;p=platform%2Fupstream%2Fvala.git support interfaces, adapt to Class/Struct/Type changes, improve error 2006-05-31 Jürg Billeter * vala/parser.y: support interfaces, adapt to Class/Struct/Type changes, improve error handling * vala/valacodevisitor.vala: support interfaces * vala/valasymbolbuilder.vala: improve error handling * vala/valasymbolresolver.vala: use operators to compare strings * vala/valasemanticanalyzer.vala: improve error handling, convert method argument and type mismatch warnings to errors, add skeleton for expressoin type checks, support string comparison operators * vala/valacodegenerator.vala: fix warning, create structs for interfaces, adapt to Class/Struct/Type changes, refactor and fix code in visit_simple_name and visit_member_access, use operators to compare strings * vala/valainterfacewriter.vala: use operators to compare strings * vala/valasourcefile.vala: fix warnings * vala/valaclass.vala: don't inherit from Struct * vala/valacodenode.vala: add error flag * vala/valaconstant.vala: add get_cname method * vala/valaenum.vala: override get_upper_case_cname method * vala/valaenumvalue.vala: adapt to Class/Struct/Type changes * vala/valafield.vala: use operators to compare strings * vala/valainterface.vala * vala/valainvocationexpression.vala: add add_argument method * vala/valamethod.vala: adapt to Class/Struct/Type changes, use operators to compare strings * vala/valanamespace.vala: support interfaces, use operators to compare strings * vala/valastringliteral.vala: fix warning * vala/valastruct.vala: inline visit_children method, use operators to compare strings * vala/valatype.vala: add abstract get_lower_case_cname method * vala/valatypereference.vala: add to_string method * vala/vala.h: update * vala/Makefile.am: update * vapi/glib-2.0.vala: small fixes svn path=/trunk/; revision=38 --- diff --git a/vala/ChangeLog b/vala/ChangeLog index 08ed9c1..fd504e5 100644 --- a/vala/ChangeLog +++ b/vala/ChangeLog @@ -1,3 +1,40 @@ +2006-05-31 Jürg Billeter + + * vala/parser.y: support interfaces, adapt to Class/Struct/Type changes, + improve error handling + * vala/valacodevisitor.vala: support interfaces + * vala/valasymbolbuilder.vala: improve error handling + * vala/valasymbolresolver.vala: use operators to compare strings + * vala/valasemanticanalyzer.vala: improve error handling, convert method + argument and type mismatch warnings to errors, add skeleton for + expressoin type checks, support string comparison operators + * vala/valacodegenerator.vala: fix warning, create structs for + interfaces, adapt to Class/Struct/Type changes, refactor and fix code + in visit_simple_name and visit_member_access, use operators to compare + strings + * vala/valainterfacewriter.vala: use operators to compare strings + * vala/valasourcefile.vala: fix warnings + * vala/valaclass.vala: don't inherit from Struct + * vala/valacodenode.vala: add error flag + * vala/valaconstant.vala: add get_cname method + * vala/valaenum.vala: override get_upper_case_cname method + * vala/valaenumvalue.vala: adapt to Class/Struct/Type changes + * vala/valafield.vala: use operators to compare strings + * vala/valainterface.vala + * vala/valainvocationexpression.vala: add add_argument method + * vala/valamethod.vala: adapt to Class/Struct/Type changes, use + operators to compare strings + * vala/valanamespace.vala: support interfaces, use operators to compare + strings + * vala/valastringliteral.vala: fix warning + * vala/valastruct.vala: inline visit_children method, use operators to + compare strings + * vala/valatype.vala: add abstract get_lower_case_cname method + * vala/valatypereference.vala: add to_string method + * vala/vala.h: update + * vala/Makefile.am: update + * vapi/glib-2.0.vala: small fixes + 2006-05-26 Jürg Billeter * vala/valasemanticanalyzer.vala: fix member access to namespaces diff --git a/vala/vala/Makefile.am b/vala/vala/Makefile.am index 89d7904..26b833b 100644 --- a/vala/vala/Makefile.am +++ b/vala/vala/Makefile.am @@ -107,6 +107,9 @@ libvala_la_SOURCES = \ valaintegerliteral.c \ valaintegerliteral.h \ valaintegerliteral.vala \ + valainterface.c \ + valainterface.h \ + valainterface.vala \ valainterfacewriter.c \ valainterfacewriter.h \ valainterfacewriter.vala \ diff --git a/vala/vala/parser.y b/vala/vala/parser.y index 4b3d925..50ea90b 100644 --- a/vala/vala/parser.y +++ b/vala/vala/parser.y @@ -40,7 +40,9 @@ static ValaSourceFile *current_source_file; static ValaNamespace *current_namespace; +static ValaClass *current_class; static ValaStruct *current_struct; +static ValaInterface *current_interface; typedef enum { VALA_MODIFIER_NONE, @@ -71,6 +73,7 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg); ValaNamespace *namespace; ValaClass *class; ValaStruct *struct_; + ValaInterface *interface; ValaEnum *enum_; ValaEnumValue *enum_value; ValaConstant *constant; @@ -251,6 +254,12 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg); %type set_accessor_declaration %type struct_declaration %type struct_header +%type interface_declaration +%type interface_method_declaration +%type interface_property_declaration +%type interface_get_accessor_declaration +%type opt_interface_set_accessor_declaration +%type interface_set_accessor_declaration %type enum_declaration %type enum_body %type opt_enum_member_declarations @@ -670,6 +679,10 @@ opt_expression expression : conditional_expression | assignment + | error + { + $$ = NULL; + } ; statement @@ -929,25 +942,46 @@ namespace_member_declarations namespace_member_declaration : class_declaration { - vala_namespace_add_class (current_namespace, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_class (current_namespace, $1); + } } | struct_declaration { - vala_namespace_add_struct (current_namespace, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_struct (current_namespace, $1); + } } | interface_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_interface (current_namespace, $1); + } + } | enum_declaration { - vala_namespace_add_enum (current_namespace, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_enum (current_namespace, $1); + } } | flags_declaration | field_declaration { - vala_namespace_add_field (current_namespace, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_field (current_namespace, $1); + } } | method_declaration { - vala_namespace_add_method (current_namespace, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_namespace_add_method (current_namespace, $1); + } } ; @@ -955,22 +989,22 @@ class_declaration : comment opt_attributes opt_access_modifier opt_modifiers CLASS IDENTIFIER opt_type_parameter_list opt_class_base { GList *l; - current_struct = VALA_STRUCT (vala_class_new ($6, src_com (@6, $1))); - VALA_CODE_NODE(current_struct)->attributes = $2; + current_class = vala_class_new ($6, src_com (@6, $1)); + VALA_CODE_NODE(current_class)->attributes = $2; if ($3 != 0) { - VALA_TYPE_(current_struct)->access = $3; + VALA_TYPE_(current_class)->access = $3; } for (l = $7; l != NULL; l = l->next) { - vala_struct_add_type_parameter (current_struct, l->data); + vala_class_add_type_parameter (current_class, l->data); } for (l = $8; l != NULL; l = l->next) { - vala_class_add_base_type (VALA_CLASS (current_struct), l->data); + vala_class_add_base_type (current_class, l->data); } } class_body { - $$ = VALA_CLASS (current_struct); - current_struct = NULL; + $$ = current_class; + current_class = NULL; } ; @@ -1074,19 +1108,31 @@ class_member_declarations class_member_declaration : constant_declaration { - vala_struct_add_constant (current_struct, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_add_constant (current_class, $1); + } } | field_declaration { - vala_struct_add_field (current_struct, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_add_field (current_class, $1); + } } | method_declaration { - vala_struct_add_method (current_struct, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_add_method (current_class, $1); + } } | property_declaration { - vala_class_add_property (VALA_CLASS (current_struct), $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_class_add_property (current_class, $1); + } } ; @@ -1348,16 +1394,29 @@ struct_member_declarations struct_member_declaration : field_declaration { - vala_struct_add_field (current_struct, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_struct_add_field (current_struct, $1); + } } | method_declaration { - vala_struct_add_method (current_struct, $1); + /* skip declarations with errors */ + if ($1 != NULL) { + vala_struct_add_method (current_struct, $1); + } } ; interface_declaration - : comment opt_attributes opt_access_modifier INTERFACE IDENTIFIER interface_body + : comment opt_attributes opt_access_modifier INTERFACE IDENTIFIER + { + current_interface = vala_interface_new ($5, src_com (@5, $1)); + } + interface_body + { + $$ = current_interface; + } ; interface_body @@ -1375,7 +1434,77 @@ interface_member_declarations ; interface_member_declaration - : method_declaration + : interface_method_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_interface_add_method (current_interface, $1); + } + } + | interface_property_declaration + { + /* skip declarations with errors */ + if ($1 != NULL) { + vala_interface_add_property (current_interface, $1); + } + } + ; + +interface_method_declaration + : comment opt_attributes opt_ref type identifier_or_new OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON + { + GList *l; + + $$ = vala_method_new ($5, $4, src_com (@5, $1)); + $$->access = VALA_MEMBER_ACCESSIBILITY_PUBLIC; + $$->is_abstract = TRUE; + VALA_CODE_NODE($$)->attributes = $2; + + for (l = $7; l != NULL; l = l->next) { + vala_method_add_parameter ($$, l->data); + } + } + ; + +interface_property_declaration + : comment opt_attributes opt_ref type IDENTIFIER OPEN_BRACE interface_get_accessor_declaration opt_interface_set_accessor_declaration CLOSE_BRACE + { + $$ = vala_property_new ($5, $4, $7, $8, src_com (@4, $1)); + } + | comment opt_attributes opt_ref type IDENTIFIER OPEN_BRACE interface_set_accessor_declaration CLOSE_BRACE + { + $$ = vala_property_new ($5, $4, NULL, $7, src_com (@4, $1)); + } + ; + +interface_get_accessor_declaration + : opt_attributes GET SEMICOLON + { + $$ = vala_property_accessor_new (TRUE, FALSE, FALSE, NULL, src (@2)); + } + ; + +opt_interface_set_accessor_declaration + : /* empty */ + { + $$ = NULL; + } + | interface_set_accessor_declaration + ; + +interface_set_accessor_declaration + : opt_attributes SET SEMICOLON + { + $$ = vala_property_accessor_new (FALSE, TRUE, FALSE, NULL, src (@2)); + } + | opt_attributes SET CONSTRUCT SEMICOLON + { + $$ = vala_property_accessor_new (FALSE, TRUE, TRUE, NULL, src (@2)); + } + | opt_attributes CONSTRUCT SEMICOLON + { + $$ = vala_property_accessor_new (FALSE, FALSE, TRUE, NULL, src (@2)); + } ; enum_declaration @@ -1606,7 +1735,8 @@ extern int yylineno; static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg) { - printf ("%s:%d.%d-%d.%d: %s\n", vala_source_file_get_filename (current_source_file), locp->first_line, locp->first_column, locp->last_line, locp->last_column, msg); + ValaSourceReference *source_reference = vala_source_reference_new (current_source_file, locp->first_line, locp->first_column, locp->last_line, locp->last_column); + vala_report_error (source_reference, msg); } void diff --git a/vala/vala/vala.h b/vala/vala/vala.h index 83d3a5a..fdfdca9 100644 --- a/vala/vala/vala.h +++ b/vala/vala/vala.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/vala/vala/valaclass.vala b/vala/vala/valaclass.vala index 2e34029..e7128cb 100644 --- a/vala/vala/valaclass.vala +++ b/vala/vala/valaclass.vala @@ -23,19 +23,57 @@ using GLib; namespace Vala { - public class Class : Struct { + public class Class : Type_ { + List type_parameters; public List base_types; public Class base_class; public bool is_abstract; + List constants; + List fields; + List methods; List properties; + + public string cname; + public string lower_case_csuffix; + public bool has_private_fields; + + public static ref Class new (string name, SourceReference source) { + return (new Class (name = name, source_reference = source)); + } public void add_base_type (TypeReference type) { base_types.append (type); } + + public void add_type_parameter (TypeParameter p) { + type_parameters.append (p); + p.type = this; + } - public static ref Class new (string name, SourceReference source) { - return (new Class (name = name, source_reference = source)); + public void add_constant (Constant c) { + constants.append (c); + } + + public void add_field (Field f) { + fields.append (f); + if (f.access == MemberAccessibility.PRIVATE) { + has_private_fields = true; + } + } + + public ref List get_fields () { + return fields.copy (); + } + + public void add_method (Method m) { + return_if_fail (m != null); + + methods.append (m); + } + + public ref List get_methods () { + return methods.copy (); } public void add_property (Property prop) { @@ -60,7 +98,21 @@ namespace Vala { type.accept (visitor); } - visit_children (visitor); + foreach (TypeParameter p in type_parameters) { + p.accept (visitor); + } + + foreach (Field f in fields) { + f.accept (visitor); + } + + foreach (Constant c in constants) { + c.accept (visitor); + } + + foreach (Method m in methods) { + m.accept (visitor); + } foreach (Property prop in properties) { prop.accept (visitor); @@ -68,9 +120,75 @@ namespace Vala { visitor.visit_end_class (this); } + + public override string get_cname () { + if (cname == null) { + cname = "%s%s".printf (@namespace.get_cprefix (), name); + } + return cname; + } + + public void set_cname (string cname) { + this.cname = cname; + } + + public string get_lower_case_csuffix () { + if (lower_case_csuffix == null) { + lower_case_csuffix = Namespace.camel_case_to_lower_case (name); + } + return lower_case_csuffix; + } + + public void set_lower_case_csuffix (string csuffix) { + this.lower_case_csuffix = csuffix; + } + + public override ref string get_lower_case_cname (string infix) { + if (infix == null) { + infix = ""; + } + return "%s%s%s".printf (@namespace.get_lower_case_cprefix (), infix, get_lower_case_csuffix ()); + } + + public override ref string get_upper_case_cname (string infix) { + return get_lower_case_cname (infix).up (-1); + } public override bool is_reference_type () { return true; } + + void process_ccode_attribute (Attribute a) { + foreach (NamedArgument arg in a.args) { + if (arg.name == "cname") { + /* this will already be checked during semantic analysis */ + if (arg.argument is LiteralExpression) { + var lit = ((LiteralExpression) arg.argument).literal; + if (lit is StringLiteral) { + set_cname (((StringLiteral) lit).eval ()); + } + } + } else if (arg.name == "cheader_filename") { + /* this will already be checked during semantic analysis */ + if (arg.argument is LiteralExpression) { + var lit = ((LiteralExpression) arg.argument).literal; + if (lit is StringLiteral) { + var val = ((StringLiteral) lit).eval (); + foreach (string filename in val.split (",", 0)) { + cheader_filenames.append (filename); + } + } + } + } + } + } + + public void process_attributes () { + foreach (Attribute a in attributes) { + if (a.name == "CCode") { + process_ccode_attribute (a); + } + } + } } } diff --git a/vala/vala/valacodegenerator.vala b/vala/vala/valacodegenerator.vala index 2aca867..27410aa 100644 --- a/vala/vala/valacodegenerator.vala +++ b/vala/vala/valacodegenerator.vala @@ -36,7 +36,7 @@ namespace Vala { CCodeFragment source_type_member_definition; CCodeStruct instance_struct; - CCodeStruct class_struct; + CCodeStruct type_struct; CCodeStruct instance_priv_struct; CCodeEnum prop_enum; CCodeEnum cenum; @@ -110,7 +110,8 @@ namespace Vala { var i = filename; while (i.len (-1) > 0) { var c = i.get_char (); - if (c.isalnum () && c < 128) { + /* FIXME: remove explicit cast when implicit cast works */ + if (c.isalnum () && c < (unichar) 128) { define.append_unichar (c.toupper ()); } else { define.append_c ('_'); @@ -184,7 +185,7 @@ namespace Vala { current_symbol = cl.symbol; instance_struct = new CCodeStruct (name = "_%s".printf (cl.get_cname ())); - class_struct = new CCodeStruct (name = "_%sClass".printf (cl.get_cname ())); + type_struct = new CCodeStruct (name = "_%sClass".printf (cl.get_cname ())); instance_priv_struct = new CCodeStruct (name = "_%sPrivate".printf (cl.get_cname ())); prop_enum = new CCodeEnum (); prop_enum.add_value ("%s_DUMMY_PROPERTY".printf (cl.get_upper_case_cname (null)), null); @@ -213,19 +214,19 @@ namespace Vala { if (cl.source_reference.file.cycle == null) { header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (instance_struct.name), typedef_name = cl.get_cname ())); - header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (class_struct.name), typedef_name = "%sClass".printf (cl.get_cname ()))); + header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (type_struct.name), typedef_name = "%sClass".printf (cl.get_cname ()))); } header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (instance_priv_struct.name), typedef_name = "%sPrivate".printf (cl.get_cname ()))); instance_struct.add_field (cl.base_class.get_cname (), "parent"); instance_struct.add_field ("%sPrivate *".printf (cl.get_cname ()), "priv"); - class_struct.add_field ("%sClass".printf (cl.base_class.get_cname ()), "parent"); + type_struct.add_field ("%sClass".printf (cl.base_class.get_cname ()), "parent"); if (cl.source_reference.comment != null) { header_type_definition.append (new CCodeComment (text = cl.source_reference.comment)); } header_type_definition.append (instance_struct); - header_type_definition.append (class_struct); + header_type_definition.append (type_struct); source_type_member_declaration.append (instance_priv_struct); macro = "(G_TYPE_INSTANCE_GET_PRIVATE ((o), %s, %sPrivate))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ()); source_type_member_declaration.append (new CCodeMacroReplacement (name = "%s_GET_PRIVATE(o)".printf (cl.get_upper_case_cname (null)), replacement = macro)); @@ -312,15 +313,16 @@ namespace Vala { if (prop.type_reference.type is Class) { cspec.call = new CCodeIdentifier (name = "g_param_spec_object"); cspec.add_argument (new CCodeIdentifier (name = prop.type_reference.type.get_upper_case_cname ("TYPE_"))); - } else if (prop.type_reference.type_name.collate ("string") == 0) { + } else if (prop.type_reference.type_name == "string") { cspec.call = new CCodeIdentifier (name = "g_param_spec_string"); cspec.add_argument (new CCodeConstant (name = "NULL")); - } else if (prop.type_reference.type_name.collate ("int") == 0 || prop.type_reference.type is Enum) { + } else if (prop.type_reference.type_name == "int" + || prop.type_reference.type is Enum) { cspec.call = new CCodeIdentifier (name = "g_param_spec_int"); cspec.add_argument (new CCodeConstant (name = "G_MININT")); cspec.add_argument (new CCodeConstant (name = "G_MAXINT")); cspec.add_argument (new CCodeConstant (name = "0")); - } else if (prop.type_reference.type_name.collate ("bool") == 0) { + } else if (prop.type_reference.type_name == "bool") { cspec.call = new CCodeIdentifier (name = "g_param_spec_boolean"); cspec.add_argument (new CCodeConstant (name = "FALSE")); } else { @@ -399,11 +401,12 @@ namespace Vala { var csetcall = new CCodeFunctionCall (); if (prop.type_reference.type is Class) { csetcall.call = new CCodeIdentifier (name = "g_value_set_object"); - } else if (prop.type_reference.type_name.collate ("string") == 0) { + } else if (prop.type_reference.type_name == "string") { csetcall.call = new CCodeIdentifier (name = "g_value_set_string"); - } else if (prop.type_reference.type_name.collate ("int") == 0 || prop.type_reference.type is Enum) { + } else if (prop.type_reference.type_name == "int" + || prop.type_reference.type is Enum) { csetcall.call = new CCodeIdentifier (name = "g_value_set_int"); - } else if (prop.type_reference.type_name.collate ("bool") == 0) { + } else if (prop.type_reference.type_name == "bool") { csetcall.call = new CCodeIdentifier (name = "g_value_set_boolean"); } else { csetcall.call = new CCodeIdentifier (name = "g_value_set_pointer"); @@ -444,11 +447,12 @@ namespace Vala { var cgetcall = new CCodeFunctionCall (); if (prop.type_reference.type is Class) { cgetcall.call = new CCodeIdentifier (name = "g_value_get_object"); - } else if (prop.type_reference.type_name.collate ("string") == 0) { + } else if (prop.type_reference.type_name == "string") { cgetcall.call = new CCodeIdentifier (name = "g_value_dup_string"); - } else if (prop.type_reference.type_name.collate ("int") == 0 || prop.type_reference.type is Enum) { + } else if (prop.type_reference.type_name == "int" + || prop.type_reference.type is Enum) { cgetcall.call = new CCodeIdentifier (name = "g_value_get_int"); - } else if (prop.type_reference.type_name.collate ("bool") == 0) { + } else if (prop.type_reference.type_name == "bool") { cgetcall.call = new CCodeIdentifier (name = "g_value_get_boolean"); } else { cgetcall.call = new CCodeIdentifier (name = "g_value_get_pointer"); @@ -474,6 +478,42 @@ namespace Vala { } header_type_definition.append (instance_struct); } + + public override void visit_begin_interface (Interface iface) { + current_symbol = iface.symbol; + + type_struct = new CCodeStruct (name = "_%sInterface".printf (iface.get_cname ())); + + header_type_declaration.append (new CCodeNewline ()); + var macro = "(%s_get_type ())".printf (iface.get_lower_case_cname (null)); + header_type_declaration.append (new CCodeMacroReplacement (name = iface.get_upper_case_cname ("TYPE_"), replacement = macro)); + + macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (iface.get_upper_case_cname ("TYPE_"), iface.get_cname ()); + header_type_declaration.append (new CCodeMacroReplacement (name = "%s(obj)".printf (iface.get_upper_case_cname (null)), replacement = macro)); + + macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (iface.get_upper_case_cname ("TYPE_")); + header_type_declaration.append (new CCodeMacroReplacement (name = "%s(obj)".printf (iface.get_upper_case_cname ("IS_")), replacement = macro)); + + macro = "(G_TYPE_INSTANCE_GET_INTERFACE ((obj), %s, %sInterface))".printf (iface.get_upper_case_cname ("TYPE_"), iface.get_cname ()); + header_type_declaration.append (new CCodeMacroReplacement (name = "%s_GET_INTERFACE(obj)".printf (iface.get_upper_case_cname (null)), replacement = macro)); + header_type_declaration.append (new CCodeNewline ()); + + + if (iface.source_reference.file.cycle == null) { + header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (iface.get_cname ()), typedef_name = iface.get_cname ())); + header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (type_struct.name), typedef_name = "%sInterface".printf (iface.get_cname ()))); + } + + type_struct.add_field ("GTypeInterface", "parent"); + + if (iface.source_reference.comment != null) { + header_type_definition.append (new CCodeComment (text = iface.source_reference.comment)); + } + header_type_definition.append (type_struct); + } + + public override void visit_end_interface (Interface iface) { + } public override void visit_begin_enum (Enum en) { cenum = new CCodeEnum (name = en.get_cname ()); @@ -489,8 +529,8 @@ namespace Vala { } public override void visit_constant (Constant c) { - if (c.symbol.parent_symbol.node is Struct) { - var t = (Struct) c.symbol.parent_symbol.node; + if (c.symbol.parent_symbol.node is Type_) { + var t = (Type_) c.symbol.parent_symbol.node; var cdecl = new CCodeDeclaration (type_name = c.type_reference.get_const_cname ()); var arr = ""; if (c.type_reference.array) { @@ -509,8 +549,8 @@ namespace Vala { if (f.instance) { instance_priv_struct.add_field (f.type_reference.get_cname (), f.get_cname ()); } else { - if (f.symbol.parent_symbol.node is Struct) { - var t = (Struct) f.symbol.parent_symbol.node; + if (f.symbol.parent_symbol.node is Type_) { + var t = (Type_) f.symbol.parent_symbol.node; var cdecl = new CCodeDeclaration (type_name = f.type_reference.get_cname ()); cdecl.add_declarator (new CCodeVariableDeclarator (name = "%s_%s".printf (t.get_lower_case_cname (null), f.get_cname ()))); cdecl.modifiers = CCodeModifiers.STATIC; @@ -521,7 +561,7 @@ namespace Vala { } public override void visit_end_method (Method m) { - if (m.name.collate ("init") == 0) { + if (m.name == "init") { return; } @@ -530,9 +570,8 @@ namespace Vala { CCodeFunctionDeclarator vdeclarator = null; if (m.instance) { - var st = (Struct) m.symbol.parent_symbol.node; var this_type = new TypeReference (); - this_type.type = st; + this_type.type = (Type_) m.symbol.parent_symbol.node; if (!m.is_override) { var cparam = new CCodeFormalParameter (type_name = this_type.get_cname (), name = "self"); function.add_parameter (cparam); @@ -546,7 +585,7 @@ namespace Vala { var vdecl = new CCodeDeclaration (type_name = m.return_type.get_cname ()); vdeclarator = new CCodeFunctionDeclarator (name = m.name); vdecl.add_declarator (vdeclarator); - class_struct.add_declaration (vdecl); + type_struct.add_declaration (vdecl); var cparam = new CCodeFormalParameter (type_name = this_type.get_cname (), name = "self"); vdeclarator.add_parameter (cparam); @@ -601,9 +640,8 @@ namespace Vala { var vfunc = new CCodeFunction (name = m.get_cname (), return_type = m.return_type.get_cname ()); - var st = (Struct) m.symbol.parent_symbol.node; var this_type = new TypeReference (); - this_type.type = st; + this_type.type = (Type_) m.symbol.parent_symbol.node; var cparam = new CCodeFormalParameter (type_name = this_type.get_cname (), name = "self"); vfunc.add_parameter (cparam); @@ -630,7 +668,7 @@ namespace Vala { source_type_member_definition.append (vfunc); } - if (m.name.collate ("main") == 0) { + if (m.name == "main") { var cmain = new CCodeFunction (name = "main", return_type = "int"); cmain.add_parameter (new CCodeFormalParameter (type_name = "int", name = "argc")); cmain.add_parameter (new CCodeFormalParameter (type_name = "char **", name = "argv")); @@ -651,16 +689,10 @@ namespace Vala { } } - public override void visit_begin_property (Property prop) { - } - public override void visit_end_property (Property prop) { prop_enum.add_value (prop.get_upper_case_cname (), null); } - public override void visit_begin_property_accessor (PropertyAccessor acc) { - } - public override void visit_end_property_accessor (PropertyAccessor acc) { var prop = (Property) acc.symbol.parent_symbol.node; var cl = (Class) prop.symbol.parent_symbol.node; @@ -798,7 +830,7 @@ namespace Vala { cfor.add_initializer (new CCodeAssignment (left = new CCodeIdentifier (name = it_name), right = (CCodeExpression) stmt.collection.ccodenode)); cfor.add_iterator (new CCodeAssignment (left = new CCodeIdentifier (name = it_name), right = new CCodeBinaryExpression (operator = CCodeBinaryOperator.PLUS, left = new CCodeIdentifier (name = it_name), right = new CCodeConstant (name = "1")))); cblock.add_statement (cfor); - } else if (stmt.collection.static_type.type.name.collate ("List") == 0) { + } else if (stmt.collection.static_type.type.name == "List") { var it_name = "%s_it".printf (stmt.variable_name); var citdecl = new CCodeDeclaration (type_name = "GList *"); @@ -868,18 +900,19 @@ namespace Vala { expr.ccodenode = expr.literal.ccodenode; } - public override void visit_simple_name (SimpleName expr) { - if (expr.name.collate ("this") == 0) { - expr.ccodenode = new CCodeIdentifier (name = "self"); - } else if (expr.symbol_reference.node is Method) { + private void process_cmember (Expression expr, CCodeIdentifier pub_inst, Type_ base_type) { + if (expr.symbol_reference.node is Method) { var m = (Method) expr.symbol_reference.node; - expr.ccodenode = new CCodeIdentifier (name = m.get_cname ()); + if (!m.is_override) { + expr.ccodenode = new CCodeIdentifier (name = m.get_cname ()); + } else { + expr.ccodenode = new CCodeIdentifier (name = m.base_method.get_cname ()); + } } else if (expr.symbol_reference.node is Field) { var f = (Field) expr.symbol_reference.node; if (f.instance) { - var pub_inst = new CCodeIdentifier (name = "self"); ref CCodeExpression typed_inst; - if (f.symbol.parent_symbol != current_symbol) { + if (f.symbol.parent_symbol.node != base_type) { typed_inst = new CCodeFunctionCall (call = new CCodeIdentifier (name = ((Type_) f.symbol.parent_symbol.node).get_upper_case_cname (null))); ((CCodeFunctionCall) typed_inst).add_argument (pub_inst); } else { @@ -893,8 +926,8 @@ namespace Vala { } expr.ccodenode = new CCodeMemberAccess (inner = inst, member_name = f.get_cname (), is_pointer = true); } else { - if (f.symbol.parent_symbol.node is Struct) { - var t = (Struct) f.symbol.parent_symbol.node; + if (f.symbol.parent_symbol.node is Type_) { + var t = (Type_) f.symbol.parent_symbol.node; expr.ccodenode = new CCodeIdentifier (name = "%s_%s".printf (t.get_lower_case_cname (null), f.get_cname ())); } else { expr.ccodenode = new CCodeIdentifier (name = f.get_cname ()); @@ -902,64 +935,48 @@ namespace Vala { } } else if (expr.symbol_reference.node is Constant) { var c = (Constant) expr.symbol_reference.node; - if (c.symbol.parent_symbol.node is Struct) { - var t = (Struct) c.symbol.parent_symbol.node; - expr.ccodenode = new CCodeIdentifier (name = "%s_%s".printf (t.get_lower_case_cname (null), expr.name)); - } else { - expr.ccodenode = new CCodeIdentifier (name = expr.name); - } + expr.ccodenode = new CCodeIdentifier (name = c.get_cname ()); } else if (expr.symbol_reference.node is Property) { var prop = (Property) expr.symbol_reference.node; var cl = (Class) prop.symbol.parent_symbol.node; var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = "%s_get_%s".printf (cl.get_lower_case_cname (null), prop.name))); - ccall.add_argument (new CCodeIdentifier (name = "self")); + ccall.add_argument (pub_inst); expr.ccodenode = ccall; - } else { - expr.ccodenode = new CCodeIdentifier (name = expr.name); + } else if (expr.symbol_reference.node is EnumValue) { + var ev = (EnumValue) expr.symbol_reference.node; + expr.ccodenode = new CCodeConstant (name = ev.get_cname ()); + } else if (expr.symbol_reference.node is VariableDeclarator) { + var decl = (VariableDeclarator) expr.symbol_reference.node; + expr.ccodenode = new CCodeIdentifier (name = decl.name); + } else if (expr.symbol_reference.node is FormalParameter) { + var p = (FormalParameter) expr.symbol_reference.node; + if (p.name == "this") { + expr.ccodenode = pub_inst; + } else { + expr.ccodenode = new CCodeIdentifier (name = p.name); + } } } + + public override void visit_simple_name (SimpleName expr) { + var pub_inst = new CCodeIdentifier (name = "self"); + var base_type = (Type_) current_symbol.node; + + process_cmember (expr, pub_inst, base_type); + } public override void visit_parenthesized_expression (ParenthesizedExpression expr) { expr.ccodenode = new CCodeParenthesizedExpression (inner = (CCodeExpression) expr.inner.ccodenode); } public override void visit_member_access (MemberAccess expr) { - if (expr.symbol_reference.node is Method) { - var m = (Method) expr.symbol_reference.node; - if (!m.is_override) { - expr.ccodenode = new CCodeIdentifier (name = m.get_cname ()); - } else { - expr.ccodenode = new CCodeIdentifier (name = m.base_method.get_cname ()); - } - } else if (expr.symbol_reference.node is Field) { - var f = (Field) expr.symbol_reference.node; - var pub_inst = expr.inner.ccodenode; - ref CCodeExpression typed_inst; - if (f.symbol.parent_symbol.node != expr.inner.static_type.type) { - typed_inst = new CCodeFunctionCall (call = new CCodeIdentifier (name = ((Type_) f.symbol.parent_symbol.node).get_upper_case_cname (null))); - ((CCodeFunctionCall) typed_inst).add_argument (pub_inst); - } else { - typed_inst = pub_inst; - } - ref CCodeExpression inst; - if (f.access == MemberAccessibility.PRIVATE) { - inst = new CCodeMemberAccess (inner = typed_inst, member_name = "priv", is_pointer = true); - } else { - inst = typed_inst; - } - expr.ccodenode = new CCodeMemberAccess (inner = inst, member_name = f.get_cname (), is_pointer = true); - } else if (expr.symbol_reference.node is Property) { - var prop = (Property) expr.symbol_reference.node; - var cl = (Class) prop.symbol.parent_symbol.node; - var ccall = new CCodeFunctionCall (call = new CCodeIdentifier (name = "%s_get_%s".printf (cl.get_lower_case_cname (null), prop.name))); - ccall.add_argument (expr.inner.ccodenode); - expr.ccodenode = ccall; - } else if (expr.symbol_reference.node is EnumValue) { - var ev = (EnumValue) expr.symbol_reference.node; - expr.ccodenode = new CCodeConstant (name = ev.get_cname ()); - } else { - expr.ccodenode = new CCodeMemberAccess (inner = (CCodeExpression) expr.inner.ccodenode, member_name = expr.member_name, is_pointer = true); + var pub_inst = expr.inner.ccodenode; + Type_ base_type = null; + if (expr.inner.static_type != null) { + base_type = expr.inner.static_type.type; } + + process_cmember (expr, pub_inst, base_type); } public override void visit_invocation_expression (InvocationExpression expr) { diff --git a/vala/vala/valacodenode.vala b/vala/vala/valacodenode.vala index 88af771..a194caa 100644 --- a/vala/vala/valacodenode.vala +++ b/vala/vala/valacodenode.vala @@ -27,6 +27,7 @@ namespace Vala { public Symbol symbol; public List attributes; public CCodeNode ccodenode; + public bool error; public abstract void accept (CodeVisitor visitor); } diff --git a/vala/vala/valacodevisitor.vala b/vala/vala/valacodevisitor.vala index e64f4ce..d5165c6 100644 --- a/vala/vala/valacodevisitor.vala +++ b/vala/vala/valacodevisitor.vala @@ -48,6 +48,12 @@ namespace Vala { public virtual void visit_end_struct (Struct st) { } + public virtual void visit_begin_interface (Interface iface) { + } + + public virtual void visit_end_interface (Interface iface) { + } + public virtual void visit_begin_enum (Enum en) { } diff --git a/vala/vala/valaconstant.vala b/vala/vala/valaconstant.vala index 9378dc5..80de1d7 100644 --- a/vala/vala/valaconstant.vala +++ b/vala/vala/valaconstant.vala @@ -40,5 +40,19 @@ namespace Vala { visitor.visit_constant (this); } + + string cname; + public string get_cname () { + if (cname == null) { + if (symbol.parent_symbol.node is Type_) { + var t = (Type_) symbol.parent_symbol.node; + cname = "%s_%s".printf (t.get_upper_case_cname (null), name); + } else { + var ns = (Namespace) symbol.parent_symbol.node; + cname = "%s%s".printf (ns.get_cprefix ().up (-1), name); + } + } + return cname; + } } } diff --git a/vala/vala/valaenum.vala b/vala/vala/valaenum.vala index fd34dd4..9a8f54c 100644 --- a/vala/vala/valaenum.vala +++ b/vala/vala/valaenum.vala @@ -52,7 +52,7 @@ namespace Vala { return cname; } - public string get_upper_case_cname () { + public override string get_upper_case_cname (string infix) { return "%s%s".printf (@namespace.get_lower_case_cprefix (), Namespace.camel_case_to_lower_case (name)).up (-1); } diff --git a/vala/vala/valaenumvalue.vala b/vala/vala/valaenumvalue.vala index babacc7..5f40a6f 100644 --- a/vala/vala/valaenumvalue.vala +++ b/vala/vala/valaenumvalue.vala @@ -44,7 +44,7 @@ namespace Vala { public string get_cname () { if (cname == null) { var en = (Enum) symbol.parent_symbol.node; - cname = "%s_%s".printf (en.get_upper_case_cname (), name); + cname = "%s_%s".printf (en.get_upper_case_cname (null), name); } return cname; } diff --git a/vala/vala/valafield.vala b/vala/vala/valafield.vala index 4827dfe..77d6afd 100644 --- a/vala/vala/valafield.vala +++ b/vala/vala/valafield.vala @@ -59,7 +59,7 @@ namespace Vala { void process_ccode_attribute (Attribute a) { foreach (NamedArgument arg in a.args) { - if (arg.name.collate ("cname") == 0) { + if (arg.name == "cname") { /* this will already be checked during semantic analysis */ if (arg.argument is LiteralExpression) { var lit = ((LiteralExpression) arg.argument).literal; @@ -73,7 +73,7 @@ namespace Vala { public void process_attributes () { foreach (Attribute a in attributes) { - if (a.name.collate ("CCode") == 0) { + if (a.name == "CCode") { process_ccode_attribute (a); } } diff --git a/vala/vala/valainterface.vala b/vala/vala/valainterface.vala new file mode 100644 index 0000000..2b2c54c --- /dev/null +++ b/vala/vala/valainterface.vala @@ -0,0 +1,122 @@ +/* valainterface.vala + * + * Copyright (C) 2006 Jürg Billeter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Jürg Billeter + */ + +using GLib; + +namespace Vala { + public class Interface : Type_ { + List type_parameters; + public List base_types; + + List methods; + List properties; + + public static ref Interface new (string name, SourceReference source) { + return (new Interface (name = name, source_reference = source)); + } + + public void add_type_parameter (TypeParameter p) { + type_parameters.append (p); + p.type = this; + } + + public void add_base_type (TypeReference type) { + base_types.append (type); + } + + public void add_method (Method m) { + return_if_fail (m.instance && m.is_abstract && !m.is_virtual && !m.is_override); + + methods.append (m); + } + + public ref List get_methods () { + return methods.copy (); + } + + public void add_property (Property prop) { + properties.append (prop); + } + + public ref List get_properties () { + return properties.copy (); + } + + private string cname; + private string lower_case_csuffix; + + public override string get_cname () { + if (cname == null) { + cname = "%s%s".printf (@namespace.get_cprefix (), name); + } + return cname; + } + + public string get_lower_case_csuffix () { + if (lower_case_csuffix == null) { + lower_case_csuffix = Namespace.camel_case_to_lower_case (name); + } + return lower_case_csuffix; + } + + public void set_lower_case_csuffix (string csuffix) { + this.lower_case_csuffix = csuffix; + } + + public override ref string get_lower_case_cname (string infix) { + if (infix == null) { + infix = ""; + } + return "%s%s%s".printf (@namespace.get_lower_case_cprefix (), infix, get_lower_case_csuffix ()); + } + + public override ref string get_upper_case_cname (string infix) { + return get_lower_case_cname (infix).up (-1); + } + + public override void accept (CodeVisitor visitor) { + visitor.visit_begin_interface (this); + + foreach (TypeReference type in base_types) { + type.accept (visitor); + } + + foreach (TypeParameter p in type_parameters) { + p.accept (visitor); + } + + foreach (Method m in methods) { + m.accept (visitor); + } + + foreach (Property prop in properties) { + prop.accept (visitor); + } + + visitor.visit_end_interface (this); + } + + public override bool is_reference_type () { + return true; + } + } +} diff --git a/vala/vala/valainterfacewriter.vala b/vala/vala/valainterfacewriter.vala index 6709f5f..5f84583 100644 --- a/vala/vala/valainterfacewriter.vala +++ b/vala/vala/valainterfacewriter.vala @@ -259,7 +259,7 @@ namespace Vala { } private void write_identifier (string s) { - if (s.collate ("namespace") == 0) { + if (s == "namespace") { stream.putc ('@'); } write_string (s); diff --git a/vala/vala/valainvocationexpression.vala b/vala/vala/valainvocationexpression.vala index 79ff1c9..322ad18 100644 --- a/vala/vala/valainvocationexpression.vala +++ b/vala/vala/valainvocationexpression.vala @@ -32,6 +32,10 @@ namespace Vala { return (new InvocationExpression (call = call, argument_list = argument_list, source_reference = source)); } + public void add_argument (Expression arg) { + _argument_list.append (arg); + } + public override void accept (CodeVisitor visitor) { call.accept (visitor); foreach (Expression expr in argument_list) { diff --git a/vala/vala/valamethod.vala b/vala/vala/valamethod.vala index ab07d06..9c4c927 100644 --- a/vala/vala/valamethod.vala +++ b/vala/vala/valamethod.vala @@ -78,8 +78,8 @@ namespace Vala { public string get_cname () { if (cname == null) { var parent = symbol.parent_symbol.node; - if (parent is Struct) { - cname = "%s_%s".printf (((Struct) parent).get_lower_case_cname (null), name); + if (parent is Type_) { + cname = "%s_%s".printf (((Type_) parent).get_lower_case_cname (null), name); } else if (parent is Namespace) { cname = "%s%s".printf (((Namespace) parent).get_lower_case_cprefix (), name); } else { @@ -104,7 +104,7 @@ namespace Vala { void process_ccode_attribute (Attribute a) { foreach (NamedArgument arg in a.args) { - if (arg.name.collate ("cname") == 0) { + if (arg.name == "cname") { /* this will already be checked during semantic analysis */ if (arg.argument is LiteralExpression) { var lit = ((LiteralExpression) arg.argument).literal; @@ -118,11 +118,11 @@ namespace Vala { public void process_attributes () { foreach (Attribute a in attributes) { - if (a.name.collate ("CCode") == 0) { + if (a.name == "CCode") { process_ccode_attribute (a); - } else if (a.name.collate ("ReturnsModifiedPointer") == 0) { + } else if (a.name == "ReturnsModifiedPointer") { returns_modified_pointer = true; - } else if (a.name.collate ("InstanceLast") == 0) { + } else if (a.name == "InstanceLast") { instance_last = true; } } diff --git a/vala/vala/valanamespace.vala b/vala/vala/valanamespace.vala index 6704b33..c4e73d7 100644 --- a/vala/vala/valanamespace.vala +++ b/vala/vala/valanamespace.vala @@ -28,6 +28,7 @@ namespace Vala { public SourceReference source_reference { get; construct; } List classes; + List interfaces; List structs; List enums; List fields; @@ -50,6 +51,11 @@ namespace Vala { cl.@namespace = null; } + public void add_interface (Interface iface) { + interfaces.append (iface); + iface.@namespace = this; + } + public void add_struct (Struct st) { structs.append (st); st.@namespace = this; @@ -88,6 +94,10 @@ namespace Vala { cl.accept (visitor); } + foreach (Interface iface in interfaces) { + iface.accept (visitor); + } + foreach (Struct st in structs) { st.accept (visitor); } @@ -183,7 +193,7 @@ namespace Vala { void process_ccode_attribute (Attribute a) { foreach (NamedArgument arg in a.args) { - if (arg.name.collate ("cprefix") == 0) { + if (arg.name == "cprefix") { /* this will already be checked during semantic analysis */ if (arg.argument is LiteralExpression) { var lit = ((LiteralExpression) arg.argument).literal; @@ -191,7 +201,7 @@ namespace Vala { set_cprefix (((StringLiteral) lit).eval ()); } } - } else if (arg.name.collate ("lower_case_cprefix") == 0) { + } else if (arg.name == "lower_case_cprefix") { /* this will already be checked during semantic analysis */ if (arg.argument is LiteralExpression) { var lit = ((LiteralExpression) arg.argument).literal; @@ -199,7 +209,7 @@ namespace Vala { set_lower_case_cprefix (((StringLiteral) lit).eval ()); } } - } else if (arg.name.collate ("cheader_filename") == 0) { + } else if (arg.name == "cheader_filename") { /* this will already be checked during semantic analysis */ if (arg.argument is LiteralExpression) { var lit = ((LiteralExpression) arg.argument).literal; @@ -216,7 +226,7 @@ namespace Vala { public void process_attributes () { foreach (Attribute a in attributes) { - if (a.name.collate ("CCode") == 0) { + if (a.name == "CCode") { process_ccode_attribute (a); } } diff --git a/vala/vala/valasemanticanalyzer.vala b/vala/vala/valasemanticanalyzer.vala index 3ff0cdd..986fa07 100644 --- a/vala/vala/valasemanticanalyzer.vala +++ b/vala/vala/valasemanticanalyzer.vala @@ -29,9 +29,19 @@ namespace Vala { SourceFile current_source_file; List current_using_directives; - + + TypeReference bool_type; + TypeReference string_type; + public void analyze (CodeContext context) { root_symbol = context.root; + + bool_type = new TypeReference (); + bool_type.type = (Type_) root_symbol.lookup ("bool").node; + + string_type = new TypeReference (); + string_type.type = (Type_) root_symbol.lookup ("string").node; + current_symbol = root_symbol; context.accept (this); } @@ -109,7 +119,7 @@ namespace Vala { var base_method = (Method) sym.node; if (base_method.is_abstract || base_method.is_virtual) { m.base_method = base_method; - //break; + break; } } } @@ -168,14 +178,16 @@ namespace Vala { if (stmt.type_reference.type != null) { current_source_file.add_symbol_dependency (stmt.type_reference.type.symbol, SourceFileDependencyType.SOURCE); } + + var decl = new VariableDeclarator (name = stmt.variable_name); + decl.type_reference = stmt.type_reference; - stmt.symbol = new Symbol (node = stmt.type_reference); + stmt.symbol = new Symbol (node = decl); current_symbol.add (stmt.variable_name, stmt.symbol); } public override void visit_boolean_literal (BooleanLiteral expr) { - expr.static_type = new TypeReference (); - expr.static_type.type = (Type_) root_symbol.lookup ("bool").node; + expr.static_type = bool_type; } public override void visit_character_literal (CharacterLiteral expr) { @@ -189,11 +201,12 @@ namespace Vala { } public override void visit_string_literal (StringLiteral expr) { - expr.static_type = new TypeReference (); - expr.static_type.type = (Type_) root_symbol.lookup ("string").node; + expr.static_type = string_type; } public override void visit_null_literal (NullLiteral expr) { + /* empty TypeReference represents null */ + expr.static_type = new TypeReference (); } @@ -271,6 +284,12 @@ namespace Vala { } public override void visit_member_access (MemberAccess expr) { + if (expr.inner.static_type == null + && expr.inner.symbol_reference == null) { + /* if there was an error in the inner expression, skip this check */ + return; + } + if (expr.inner.static_type == null) { if (expr.inner.symbol_reference.node is Namespace || expr.inner.symbol_reference.node is Type_) { expr.symbol_reference = expr.inner.symbol_reference.lookup (expr.member_name); @@ -285,7 +304,7 @@ namespace Vala { if (expr.inner.static_type == null) { Report.error (expr.source_reference, "The name `%s' does not exist in the context of `%s'".printf (expr.member_name, expr.inner.symbol_reference.get_full_name ())); } else { - Report.error (expr.source_reference, "The name `%s' does not exist in the context of `%s'".printf (expr.member_name, expr.inner.static_type.type.symbol.get_full_name ())); + Report.error (expr.source_reference, "The name `%s' does not exist in the context of `%s'".printf (expr.member_name, expr.inner.static_type.to_string ())); } return; } @@ -319,7 +338,7 @@ namespace Vala { return true; } - /* int may be implicitly casted to long */ + /* char may be implicitly casted to unichar */ if (expression_type.type == root_symbol.lookup ("char").node && expected_type.type == root_symbol.lookup ("unichar").node) { return true; } @@ -342,6 +361,11 @@ namespace Vala { } public override void visit_invocation_expression (InvocationExpression expr) { + if (expr.call.symbol_reference == null) { + /* if method resolving didn't succeed, skip this check */ + return; + } + var m = (Method) expr.call.symbol_reference.node; expr.static_type = m.return_type; @@ -362,8 +386,10 @@ namespace Vala { } var arg = (Expression) arg_it.data; - if (!is_type_compatible (arg.static_type, param.type_reference)) { - Report.warning (expr.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.static_type.type.symbol.get_full_name (), param.type_reference.type.symbol.get_full_name ())); + if (arg.static_type != null && !is_type_compatible (arg.static_type, param.type_reference)) { + /* if there was an error in the argument, + * i.e. arg.static_type == null, skip type check */ + Report.error (expr.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.static_type.type.symbol.get_full_name (), param.type_reference.to_string ())); return; } @@ -373,36 +399,181 @@ namespace Vala { } if (!ellipsis && arg_it != null) { - Report.warning (expr.source_reference, "Method `%s' does not take %d arguments".printf (m.symbol.get_full_name (), expr.argument_list.length ())); + Report.error (expr.source_reference, "Method `%s' does not take %d arguments".printf (m.symbol.get_full_name (), expr.argument_list.length ())); return; } } public override void visit_object_creation_expression (ObjectCreationExpression expr) { + if (expr.type_reference.type == null) { + /* if type resolving didn't succeed, skip this check */ + return; + } + current_source_file.add_symbol_dependency (expr.type_reference.type.symbol, SourceFileDependencyType.SOURCE); expr.static_type = expr.type_reference; } public override void visit_unary_expression (UnaryExpression expr) { - expr.static_type = expr.inner.static_type; + if (expr.inner.static_type == null) { + /* if there was an error in the inner expression, skip type check */ + return; + } + + if (expr.operator == UnaryOperator.PLUS || expr.operator == UnaryOperator.MINUS) { + // integer or floating point type + + expr.static_type = expr.inner.static_type; + } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) { + // boolean type + + expr.static_type = expr.inner.static_type; + } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) { + // integer type + + expr.static_type = expr.inner.static_type; + } else if (expr.operator == UnaryOperator.REF) { + // value type + + expr.static_type = expr.inner.static_type; + } else if (expr.operator == UnaryOperator.OUT) { + // reference type + + expr.static_type = expr.inner.static_type; + } else { + assert_not_reached (); + } } public override void visit_cast_expression (CastExpression expr) { + if (expr.type_reference.type == null) { + /* if type resolving didn't succeed, skip this check */ + return; + } + current_source_file.add_symbol_dependency (expr.type_reference.type.symbol, SourceFileDependencyType.SOURCE); expr.static_type = expr.type_reference; } - + + private bool check_binary_type (BinaryExpression expr, string operation) { + if (!is_type_compatible (expr.right.static_type, expr.left.static_type)) { + Report.error (expr.source_reference, "%s: Cannot convert from `%s' to `%s'".printf (operation, expr.right.static_type.to_string (), expr.left.static_type.to_string ())); + return false; + } + + return true; + } + public override void visit_binary_expression (BinaryExpression expr) { - expr.static_type = expr.left.static_type; + if (expr.left.static_type == null + || expr.right.static_type == null) { + /* if there were any errors in inner expressions, skip type check */ + return; + } + + if (expr.left.static_type.type == string_type.type + && expr.operator == BinaryOperator.PLUS) { + if (expr.right.static_type.type != string_type.type) { + Report.error (expr.source_reference, "Operands must be strings"); + } + + expr.static_type = string_type; + } else if (expr.operator == BinaryOperator.PLUS + || expr.operator == BinaryOperator.MINUS + || expr.operator == BinaryOperator.MUL + || expr.operator == BinaryOperator.DIV) { + // TODO: check for integer or floating point type in expr.left + + if (!check_binary_type (expr, "Arithmetic operation")) { + return; + } + + expr.static_type = expr.left.static_type; + } else if (expr.operator == BinaryOperator.MOD + || expr.operator == BinaryOperator.SHIFT_LEFT + || expr.operator == BinaryOperator.SHIFT_RIGHT + || expr.operator == BinaryOperator.BITWISE_XOR) { + // TODO: check for integer type in expr.left + + if (!check_binary_type (expr, "Arithmetic operation")) { + return; + } + + expr.static_type = expr.left.static_type; + } else if (expr.operator == BinaryOperator.LESS_THAN + || expr.operator == BinaryOperator.GREATER_THAN + || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL + || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) { + if (expr.left.static_type.type == string_type.type + && expr.right.static_type.type == string_type.type) { + /* string comparison: convert to a.collate (b) OP 0 */ + + var cmp_call = new InvocationExpression (call = new MemberAccess (inner = expr.left, member_name = "collate")); + cmp_call.add_argument (expr.right); + expr.left = cmp_call; + + expr.right = new LiteralExpression (literal = new IntegerLiteral (value = "0")); + + expr.left.accept (this); + } else { + /* TODO: check for integer or floating point type in expr.left */ + + if (!check_binary_type (expr, "Relational operation")) { + return; + } + } + + expr.static_type = bool_type; + } else if (expr.operator == BinaryOperator.EQUALITY + || expr.operator == BinaryOperator.INEQUALITY) { + /* relational operation */ + + if (!check_binary_type (expr, "Equality operation")) { + return; + } + + if (expr.left.static_type.type == string_type.type + && expr.right.static_type.type == string_type.type) { + /* string comparison: convert to a.collate (b) OP 0 */ + + var cmp_call = new InvocationExpression (call = new MemberAccess (inner = expr.left, member_name = "collate")); + cmp_call.add_argument (expr.right); + expr.left = cmp_call; + + expr.right = new LiteralExpression (literal = new IntegerLiteral (value = "0")); + + expr.left.accept (this); + } + + expr.static_type = bool_type; + } else if (expr.operator == BinaryOperator.BITWISE_AND + || expr.operator == BinaryOperator.BITWISE_OR) { + // integer type or flags type + + expr.static_type = expr.left.static_type; + } else if (expr.operator == BinaryOperator.AND + || expr.operator == BinaryOperator.OR) { + if (expr.left.static_type.type != bool_type.type || expr.right.static_type.type != bool_type.type) { + Report.error (expr.source_reference, "Operands must be boolean"); + } + + expr.static_type = bool_type; + } else { + assert_not_reached (); + } } public override void visit_type_check (TypeCheck expr) { + if (expr.type_reference.type == null) { + /* if type resolving didn't succeed, skip this check */ + return; + } + current_source_file.add_symbol_dependency (expr.type_reference.type.symbol, SourceFileDependencyType.SOURCE); - expr.static_type = new TypeReference (); - expr.static_type.type = (Type_) root_symbol.lookup ("bool").node; + expr.static_type = bool_type; } } } diff --git a/vala/vala/valasourcefile.vala b/vala/vala/valasourcefile.vala index 4806fd1..2108773 100644 --- a/vala/vala/valasourcefile.vala +++ b/vala/vala/valasourcefile.vala @@ -77,7 +77,7 @@ namespace Vala { public string get_cheader_filename () { if (cheader_filename == null) { - var basename = filename.ndup (filename.len (-1) - ".vala".len (-1)); + var basename = filename.ndup ((uint) (filename.len (-1) - ".vala".len (-1))); cheader_filename = "%s.h".printf (basename); } return cheader_filename; @@ -87,7 +87,7 @@ namespace Vala { public string get_csource_filename () { if (csource_filename == null) { - var basename = filename.ndup (filename.len (-1) - ".vala".len (-1)); + var basename = filename.ndup ((uint) (filename.len (-1) - ".vala".len (-1))); csource_filename = "%s.c".printf (basename); } return csource_filename; diff --git a/vala/vala/valastringliteral.vala b/vala/vala/valastringliteral.vala index c1ffa1f..2551e4b 100644 --- a/vala/vala/valastringliteral.vala +++ b/vala/vala/valastringliteral.vala @@ -33,7 +33,7 @@ namespace Vala { public ref string eval () { /* remove quotes */ - var noquotes = value.offset (1).ndup (value.len (-1) - 2); + var noquotes = value.offset (1).ndup ((uint) (value.len (-1) - 2)); /* unescape string */ return noquotes.compress (); } diff --git a/vala/vala/valastruct.vala b/vala/vala/valastruct.vala index f7346bd..8ee7cc1 100644 --- a/vala/vala/valastruct.vala +++ b/vala/vala/valastruct.vala @@ -32,7 +32,6 @@ namespace Vala { public string cname; public string lower_case_csuffix; bool reference_type; - public bool has_private_fields; public static ref Struct new (string name, SourceReference source) { return (new Struct (name = name, source_reference = source)); @@ -49,9 +48,6 @@ namespace Vala { public void add_field (Field f) { fields.append (f); - if (f.access == MemberAccessibility.PRIVATE) { - has_private_fields = true; - } } public ref List get_fields () { @@ -71,12 +67,6 @@ namespace Vala { public override void accept (CodeVisitor visitor) { visitor.visit_begin_struct (this); - visit_children (visitor); - - visitor.visit_end_struct (this); - } - - public void visit_children (CodeVisitor visitor) { foreach (TypeParameter p in type_parameters) { p.accept (visitor); } @@ -92,6 +82,8 @@ namespace Vala { foreach (Method m in methods) { m.accept (visitor); } + + visitor.visit_end_struct (this); } public override string get_cname () { @@ -116,7 +108,7 @@ namespace Vala { this.lower_case_csuffix = csuffix; } - public ref string get_lower_case_cname (string infix) { + public override ref string get_lower_case_cname (string infix) { if (infix == null) { infix = ""; } @@ -133,7 +125,7 @@ namespace Vala { void process_ccode_attribute (Attribute a) { foreach (NamedArgument arg in a.args) { - if (arg.name.collate ("cname") == 0) { + if (arg.name == "cname") { /* this will already be checked during semantic analysis */ if (arg.argument is LiteralExpression) { var lit = ((LiteralExpression) arg.argument).literal; @@ -141,7 +133,7 @@ namespace Vala { set_cname (((StringLiteral) lit).eval ()); } } - } else if (arg.name.collate ("cheader_filename") == 0) { + } else if (arg.name == "cheader_filename") { /* this will already be checked during semantic analysis */ if (arg.argument is LiteralExpression) { var lit = ((LiteralExpression) arg.argument).literal; @@ -158,9 +150,9 @@ namespace Vala { public void process_attributes () { foreach (Attribute a in attributes) { - if (a.name.collate ("CCode") == 0) { + if (a.name == "CCode") { process_ccode_attribute (a); - } else if (a.name.collate ("ReferenceType") == 0) { + } else if (a.name == "ReferenceType") { reference_type = true; } } diff --git a/vala/vala/valasymbolbuilder.vala b/vala/vala/valasymbolbuilder.vala index 96e8290..e731a7a 100644 --- a/vala/vala/valasymbolbuilder.vala +++ b/vala/vala/valasymbolbuilder.vala @@ -54,6 +54,7 @@ namespace Vala { public override void visit_begin_class (Class cl) { if (cl.@namespace.symbol.lookup (cl.name) != null) { + cl.error = true; Report.error (cl.source_reference, "The namespace `%s' already contains a definition for `%s'".printf (cl.@namespace.symbol.get_full_name (), cl.name)); return; } @@ -64,11 +65,17 @@ namespace Vala { } public override void visit_end_class (Class cl) { + if (cl.error) { + /* skip classes with errors */ + return; + } + current_symbol = current_symbol.parent_symbol; } public override void visit_begin_struct (Struct st) { if (st.@namespace.symbol.lookup (st.name) != null) { + st.error = true; Report.error (st.source_reference, "The namespace `%s' already contains a definition for `%s'".printf (st.@namespace.symbol.get_full_name (), st.name)); return; } @@ -79,11 +86,38 @@ namespace Vala { } public override void visit_end_struct (Struct st) { + if (st.error) { + /* skip structs with errors */ + return; + } + + current_symbol = current_symbol.parent_symbol; + } + + public override void visit_begin_interface (Interface iface) { + if (iface.@namespace.symbol.lookup (iface.name) != null) { + iface.error = true; + Report.error (iface.source_reference, "The namespace `%s' already contains a definition for `%s'".printf (iface.@namespace.symbol.get_full_name (), iface.name)); + return; + } + iface.symbol = new Symbol (node = iface); + iface.@namespace.symbol.add (iface.name, iface.symbol); + + current_symbol = iface.symbol; + } + + public override void visit_end_interface (Interface iface) { + if (iface.error) { + /* skip interfaces with errors */ + return; + } + current_symbol = current_symbol.parent_symbol; } public override void visit_begin_enum (Enum en) { if (en.@namespace.symbol.lookup (en.name) != null) { + en.error = true; Report.error (en.source_reference, "The namespace `%s' already contains a definition for `%s'".printf (en.@namespace.symbol.get_full_name (), en.name)); return; } @@ -93,6 +127,11 @@ namespace Vala { } public override void visit_end_enum (Enum en) { + if (en.error) { + /* skip enums with errors */ + return; + } + current_symbol = current_symbol.parent_symbol; } @@ -103,6 +142,7 @@ namespace Vala { public override void visit_constant (Constant c) { if (current_symbol.lookup (c.name) != null) { + c.error = true; Report.error (c.source_reference, "The type `%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), c.name)); return; } @@ -112,6 +152,7 @@ namespace Vala { public override void visit_field (Field f) { if (current_symbol.lookup (f.name) != null) { + f.error = true; Report.error (f.source_reference, "The type `%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), f.name)); return; } @@ -121,6 +162,7 @@ namespace Vala { public override void visit_begin_method (Method m) { if (current_symbol.lookup (m.name) != null) { + m.error = true; Report.error (m.source_reference, "The type `%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), m.name)); return; } @@ -129,13 +171,18 @@ namespace Vala { current_symbol = m.symbol; if (m.instance) { - var type = new TypeReference (); - type.type = (Type_) m.symbol.parent_symbol.node; - current_symbol.add ("this", new Symbol (node = type)); + var decl = new FormalParameter (name = "this", type_reference = new TypeReference ()); + decl.type_reference.type = (Type_) m.symbol.parent_symbol.node; + current_symbol.add (decl.name, new Symbol (node = decl)); } } public override void visit_end_method (Method m) { + if (m.error) { + /* skip methods with errors */ + return; + } + current_symbol = current_symbol.parent_symbol; } @@ -148,6 +195,7 @@ namespace Vala { public override void visit_begin_property (Property prop) { if (current_symbol.lookup (prop.name) != null) { + prop.error = true; Report.error (prop.source_reference, "The type `%s' already contains a definition for `%s'".printf (current_symbol.get_full_name (), prop.name)); return; } @@ -155,12 +203,17 @@ namespace Vala { current_symbol.add (prop.name, prop.symbol); current_symbol = prop.symbol; - var type = new TypeReference (); - type.type = (Type_) prop.symbol.parent_symbol.node; - current_symbol.add ("this", new Symbol (node = type)); + var decl = new FormalParameter (name = "this", type_reference = new TypeReference ()); + decl.type_reference.type = (Type_) prop.symbol.parent_symbol.node; + current_symbol.add (decl.name, new Symbol (node = decl)); } public override void visit_end_property (Property prop) { + if (prop.error) { + /* skip properties with errors */ + return; + } + current_symbol = current_symbol.parent_symbol; } @@ -170,7 +223,10 @@ namespace Vala { current_symbol = acc.symbol; if (acc.writable || acc.construct_) { - current_symbol.add ("value", new Symbol (node = ((Property) current_symbol.parent_symbol.node).type_reference)); + var decl = new VariableDeclarator (name = "value"); + decl.type_reference = ((Property) current_symbol.parent_symbol.node).type_reference; + + current_symbol.add ("value", new Symbol (node = decl)); } if (acc.body == null) { diff --git a/vala/vala/valasymbolresolver.vala b/vala/vala/valasymbolresolver.vala index 18880a9..1378b58 100644 --- a/vala/vala/valasymbolresolver.vala +++ b/vala/vala/valasymbolresolver.vala @@ -64,7 +64,7 @@ namespace Vala { cl.base_class = type.type; } } - if (cl.base_class == null && (cl.name.collate ("Object") != 0 || cl.@namespace.name.collate ("GLib") != 0)) { + if (cl.base_class == null && (cl.name != "Object" || cl.@namespace.name != "GLib")) { cl.base_class = (Class) root_symbol.lookup ("GLib").lookup ("Object").node; } @@ -88,7 +88,7 @@ namespace Vala { } public override void visit_type_reference (TypeReference type) { - if (type.type_name.collate ("void") == 0) { + if (type.type_name == "void") { return; } diff --git a/vala/vala/valatype.vala b/vala/vala/valatype.vala index 6c8e71b..31ba732 100644 --- a/vala/vala/valatype.vala +++ b/vala/vala/valatype.vala @@ -32,6 +32,7 @@ namespace Vala { public abstract string get_cname (); public abstract bool is_reference_type (); public abstract string get_upper_case_cname (string infix); + public abstract string get_lower_case_cname (string infix); public List cheader_filenames; public ref List get_cheader_filenames () { diff --git a/vala/vala/valatypereference.vala b/vala/vala/valatypereference.vala index edf8dc1..7579246 100644 --- a/vala/vala/valatypereference.vala +++ b/vala/vala/valatypereference.vala @@ -136,5 +136,15 @@ namespace Vala { public ref string get_upper_case_cname (string infix) { return type.get_upper_case_cname (infix); } + + public string to_string () { + if (type != null) { + return type.symbol.get_full_name (); + } else if (type_parameter != null) { + return type_parameter.name; + } else { + return "null"; + } + } } } diff --git a/vala/vapi/glib-2.0.vala b/vala/vapi/glib-2.0.vala index ac5e55f..9338360 100644 --- a/vala/vapi/glib-2.0.vala +++ b/vala/vapi/glib-2.0.vala @@ -140,7 +140,7 @@ public struct string { [CCode (cname = "g_strconcat")] public ref string concat (string string2, ...); [CCode (cname = "g_strndup")] - public ref string ndup (int n); + public ref string ndup (uint n); /* FIXME: only UTF-8 */ [CCode (cname = "g_strcompress")] public ref string compress (); [CCode (cname = "g_strsplit")] @@ -158,12 +158,12 @@ public struct string { [CCode (cname = "g_utf8_prev_char")] public string prev_char (); [CCode (cname = "g_utf8_strlen")] - public long len (long max /*= -1*/); + public long len (int max /*= -1*/); [CCode (cname = "g_utf8_strchr")] - public string chr (long len, unichar c); + public string chr (int len, unichar c); [CCode (cname = "g_utf8_strup")] - public ref string up (long len /*= -1*/); + public ref string up (int len /*= -1*/); [CCode (cname = "g_utf8_collate")] public int collate (string str2); } @@ -192,6 +192,7 @@ namespace GLib { public struct Error { } + public static void assert_not_reached (); public static void return_if_fail (bool expr); public enum FileTest {