;
invocation_expression
- : primary_expression OPEN_PARENS opt_argument_list CLOSE_PARENS
+ : primary_expression open_parens opt_argument_list CLOSE_PARENS
{
ValaSourceReference *src = src(@1);
$$ = VALA_EXPRESSION (vala_invocation_expression_new ($1, src));
;
object_creation_expression
- : NEW type OPEN_PARENS opt_named_argument_list CLOSE_PARENS
+ : NEW type open_parens opt_named_argument_list CLOSE_PARENS
{
ValaSourceReference *src = src(@2);
$$ = VALA_EXPRESSION (vala_object_creation_expression_new ($2, $4, src));
;
typeof_expression
- : TYPEOF OPEN_PARENS type_name CLOSE_PARENS
+ : TYPEOF open_parens type_name CLOSE_PARENS
{
ValaSourceReference *src = src(@1);
$$ = VALA_EXPRESSION (vala_typeof_expression_new ($3, src));
g_object_unref (src);
g_object_unref ($2);
}
+ | OP_INC unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_INCREMENT, $2, src));
+ g_object_unref ($2);
+ g_object_unref (src);
+ }
+ | OP_DEC unary_expression
+ {
+ ValaSourceReference *src = src(@1);
+ $$ = VALA_EXPRESSION (vala_unary_expression_new (VALA_UNARY_OPERATOR_DECREMENT, $2, src));
+ g_object_unref ($2);
+ g_object_unref (src);
+ }
| REF unary_expression
{
ValaSourceReference *src = src(@1);
;
if_statement
- : comment IF OPEN_PARENS expression CLOSE_PARENS embedded_statement
+ : comment IF open_parens expression CLOSE_PARENS embedded_statement
{
ValaSourceReference *src = src_com(@4, $1);
$$ = VALA_STATEMENT (vala_if_statement_new ($4, $6, NULL, src));
g_object_unref ($4);
g_object_unref ($6);
}
- | comment IF OPEN_PARENS expression CLOSE_PARENS embedded_statement ELSE embedded_statement
+ | comment IF open_parens expression CLOSE_PARENS embedded_statement ELSE embedded_statement
{
ValaSourceReference *src = src_com(@4, $1);
$$ = VALA_STATEMENT (vala_if_statement_new ($4, $6, $8, src));
;
switch_statement
- : comment SWITCH OPEN_PARENS expression CLOSE_PARENS switch_block
+ : comment SWITCH open_parens expression CLOSE_PARENS switch_block
{
ValaSourceReference *src = src_com(@4, $1);
$$ = VALA_STATEMENT (vala_switch_statement_new ($4, src));
;
while_statement
- : WHILE OPEN_PARENS expression CLOSE_PARENS embedded_statement
+ : WHILE open_parens expression CLOSE_PARENS embedded_statement
{
ValaSourceReference *src = src(@1);
$$ = VALA_STATEMENT (vala_while_statement_new ($3, $5, src));
;
do_statement
- : DO embedded_statement WHILE OPEN_PARENS expression CLOSE_PARENS SEMICOLON
+ : DO embedded_statement WHILE open_parens expression CLOSE_PARENS SEMICOLON
{
ValaSourceReference *src = src(@1);
$$ = VALA_STATEMENT (vala_do_statement_new ($2, $5, src));
: type
;
+open_parens
+ : OPEN_PARENS
+ | OPEN_CAST_PARENS
+ ;
+
%%
extern FILE *yyin;
using GLib;
-namespace Vala {
- public class Namespace : CodeNode {
- public string name { get; construct; }
-
- List<Class> classes;
- List<Interface> interfaces;
- List<Struct> structs;
- List<Enum> enums;
- List<Flags> flags_;
- List<Callback> callbacks;
- List<Field> fields;
- List<Method> methods;
-
- public string cprefix;
- public string lower_case_cprefix;
-
- public static ref Namespace! new (string! name, SourceReference source) {
- return (new Namespace (name = name, source_reference = source));
- }
-
- public void add_class (Class! cl) {
- classes.append (cl);
- cl.@namespace = this;
- }
-
- public void remove_class (Class! cl) {
- classes.remove (cl);
- 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;
- }
-
- public void remove_struct (Struct! st) {
- structs.remove (st);
- st.@namespace = null;
- }
-
- public void add_enum (Enum! en) {
- enums.append (en);
- en.@namespace = this;
- }
-
- public void add_flags (Flags! fl) {
- flags_.append (fl);
- fl.@namespace = this;
- }
-
- public void add_callback (Callback! cb) {
- callbacks.append (cb);
- cb.@namespace = this;
- }
+/**
+ * Represents a namespace declaration in the source code.
+ */
+public class Vala.Namespace : CodeNode {
+ /**
+ * The name of this namespace.
+ */
+ public string name { get; set; }
- public ref List<Struct> get_structs () {
- return structs.copy ();
- }
+ private List<Class> classes;
+ private List<Interface> interfaces;
+ private List<Struct> structs;
+ private List<Enum> enums;
+ private List<Flags> flags_;
+ private List<Callback> callbacks;
+ private List<Field> fields;
+ private List<Method> methods;
+
+ private string cprefix;
+ private string lower_case_cprefix;
+
+ private List<string> cheader_filenames;
+
+ /**
+ * Creates a new namespace.
+ *
+ * @param name namespace name
+ * @param source reference to source code
+ * @return newly created namespace
+ */
+ public static ref Namespace! new (string! name, SourceReference source) {
+ return (new Namespace (name = name, source_reference = source));
+ }
+
+ /**
+ * Adds the specified class to this namespace.
+ *
+ * @param cl a class
+ */
+ public void add_class (Class! cl) {
+ classes.append (cl);
+ cl.@namespace = this;
+ }
+
+ /**
+ * Adds the specified interface to this namespace.
+ *
+ * @param iface an interface
+ */
+ public void add_interface (Interface! iface) {
+ interfaces.append (iface);
+ iface.@namespace = this;
+ }
+
+ /**
+ * Adds the specified struct to this namespace.
+ *
+ * @param st a struct
+ */
+ public void add_struct (Struct! st) {
+ structs.append (st);
+ st.@namespace = this;
+ }
+
+ /**
+ * Adds the specified enum to this namespace.
+ *
+ * @param en an enum
+ */
+ public void add_enum (Enum! en) {
+ enums.append (en);
+ en.@namespace = this;
+ }
+
+ /**
+ * Adds the specified flags to this namespace.
+ *
+ * @param fl a flags
+ */
+ public void add_flags (Flags! fl) {
+ flags_.append (fl);
+ fl.@namespace = this;
+ }
+
+ /**
+ * Adds the specified callback to this namespace.
+ *
+ * @param cb a callback
+ */
+ public void add_callback (Callback! cb) {
+ callbacks.append (cb);
+ cb.@namespace = this;
+ }
- public ref List<Class> get_classes () {
- return classes.copy ();
- }
-
- public void add_field (Field! f) {
- fields.append (f);
- }
-
- public void add_method (Method! m) {
- methods.append (m);
- }
-
- public override void accept (CodeVisitor! visitor) {
- visitor.visit_begin_namespace (this);
+ /**
+ * Returns a copy of the list of structs.
+ *
+ * @return struct list
+ */
+ public ref List<Struct> get_structs () {
+ return structs.copy ();
+ }
- foreach (Class cl in classes) {
- cl.accept (visitor);
- }
+ /**
+ * Returns a copy of the list of classes.
+ *
+ * @return class list
+ */
+ public ref List<Class> get_classes () {
+ return classes.copy ();
+ }
+
+ /**
+ * Adds the specified field to this namespace.
+ *
+ * @param f a field
+ */
+ public void add_field (Field! f) {
+ fields.append (f);
+ }
+
+ /**
+ * Adds the specified method to this namespace.
+ *
+ * @param m a method
+ */
+ public void add_method (Method! m) {
+ methods.append (m);
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_namespace (this);
- foreach (Interface iface in interfaces) {
- iface.accept (visitor);
- }
+ foreach (Class cl in classes) {
+ cl.accept (visitor);
+ }
- foreach (Struct st in structs) {
- st.accept (visitor);
- }
+ foreach (Interface iface in interfaces) {
+ iface.accept (visitor);
+ }
- foreach (Enum en in enums) {
- en.accept (visitor);
- }
+ foreach (Struct st in structs) {
+ st.accept (visitor);
+ }
- foreach (Flags fl in flags_) {
- fl.accept (visitor);
- }
+ foreach (Enum en in enums) {
+ en.accept (visitor);
+ }
- foreach (Callback cb in callbacks) {
- cb.accept (visitor);
- }
+ foreach (Flags fl in flags_) {
+ fl.accept (visitor);
+ }
- foreach (Field f in fields) {
- f.accept (visitor);
- }
+ foreach (Callback cb in callbacks) {
+ cb.accept (visitor);
+ }
- foreach (Method m in methods) {
- m.accept (visitor);
- }
+ foreach (Field f in fields) {
+ f.accept (visitor);
+ }
- visitor.visit_end_namespace (this);
+ foreach (Method m in methods) {
+ m.accept (visitor);
}
- public static ref string camel_case_to_lower_case (string camel_case) {
- String result = String.new ("");
-
- string i = camel_case;
-
- bool first = true;
- while (i.len () > 0) {
- unichar c = i.get_char ();
- if (c.isupper () && !first) {
- /* current character is upper case and
- * we're not at the beginning */
- string t = i.prev_char ();
- bool prev_upper = t.get_char ().isupper ();
- t = i.next_char ();
- bool next_upper = t.get_char ().isupper ();
- if (!prev_upper || (i.len () >= 2 && !next_upper)) {
- /* previous character wasn't upper case or
- * next character isn't upper case*/
- int len = result.str.len ();
- if (len != 1 && result.str.offset (len - 2).get_char () != '_') {
- /* we're not creating 1 character words */
- result.append_c ('_');
- }
+ visitor.visit_end_namespace (this);
+ }
+
+ /**
+ * Converts a string from CamelCase to lower_case.
+ *
+ * @param camel_case a string in camel case
+ * @return the specified string converted to lower case
+ */
+ public static ref string! camel_case_to_lower_case (string! camel_case) {
+ String result = String.new ("");
+
+ string i = camel_case;
+
+ bool first = true;
+ while (i.len () > 0) {
+ unichar c = i.get_char ();
+ if (c.isupper () && !first) {
+ /* current character is upper case and
+ * we're not at the beginning */
+ string t = i.prev_char ();
+ bool prev_upper = t.get_char ().isupper ();
+ t = i.next_char ();
+ bool next_upper = t.get_char ().isupper ();
+ if (!prev_upper || (i.len () >= 2 && !next_upper)) {
+ /* previous character wasn't upper case or
+ * next character isn't upper case*/
+ int len = result.str.len ();
+ if (len != 1 && result.str.offset (len - 2).get_char () != '_') {
+ /* we're not creating 1 character words */
+ result.append_c ('_');
}
}
-
- result.append_unichar (c.tolower ());
-
- first = false;
- i = i.next_char ();
}
- return result.str;
+ result.append_unichar (c.tolower ());
+
+ first = false;
+ i = i.next_char ();
}
- public string get_cprefix () {
- if (cprefix == null) {
- if (name == null) {
- cprefix = "";
- } else {
- cprefix = name;
- }
+ return result.str;
+ }
+
+ /**
+ * Returns the camel case string to be prepended to the name of members
+ * of this namespace when used in C code.
+ *
+ * @return the camel case prefix to be used in C code
+ */
+ public string! get_cprefix () {
+ if (cprefix == null) {
+ if (name == null) {
+ cprefix = "";
+ } else {
+ cprefix = name;
}
- return cprefix;
- }
-
- public void set_cprefix (string cprefix) {
- this.cprefix = cprefix;
}
-
- public string get_lower_case_cprefix () {
- if (lower_case_cprefix == null) {
- if (name == null) {
- lower_case_cprefix = "";
- } else {
- lower_case_cprefix = "%s_".printf (camel_case_to_lower_case (name));
- }
+ return cprefix;
+ }
+
+ private void set_cprefix (string cprefix) {
+ this.cprefix = cprefix;
+ }
+
+ /**
+ * Returns the lower case string to be prepended to the name of members
+ * of this namespace when used in C code.
+ *
+ * @return the lower case prefix to be used in C code
+ */
+ public string! get_lower_case_cprefix () {
+ if (lower_case_cprefix == null) {
+ if (name == null) {
+ lower_case_cprefix = "";
+ } else {
+ lower_case_cprefix = "%s_".printf (camel_case_to_lower_case (name));
}
- return lower_case_cprefix;
}
-
- public void set_lower_case_cprefix (string cprefix) {
- this.lower_case_cprefix = cprefix;
- }
-
- List<string> cheader_filenames;
-
- public ref List<string> get_cheader_filenames () {
- if (cheader_filenames == null) {
- cheader_filenames.append (source_reference.file.get_cheader_filename ());
- }
- return cheader_filenames.copy ();
+ return lower_case_cprefix;
+ }
+
+ private void set_lower_case_cprefix (string cprefix) {
+ this.lower_case_cprefix = cprefix;
+ }
+
+ /**
+ * Returns a list of C header filenames users of this namespace must
+ * include.
+ *
+ * @return list of C header filenames for this namespace
+ */
+ public ref List<string> get_cheader_filenames () {
+ if (cheader_filenames == null) {
+ cheader_filenames.append (source_reference.file.get_cheader_filename ());
}
-
- void process_ccode_attribute (Attribute! a) {
- foreach (NamedArgument arg in a.args) {
- if (arg.name == "cprefix") {
- /* this will already be checked during semantic analysis */
- if (arg.argument is LiteralExpression) {
- var lit = ((LiteralExpression) arg.argument).literal;
- if (lit is StringLiteral) {
- set_cprefix (((StringLiteral) lit).eval ());
- }
+ return cheader_filenames.copy ();
+ }
+
+ private void process_ccode_attribute (Attribute! a) {
+ foreach (NamedArgument arg in a.args) {
+ if (arg.name == "cprefix") {
+ /* this will already be checked during semantic analysis */
+ if (arg.argument is LiteralExpression) {
+ var lit = ((LiteralExpression) arg.argument).literal;
+ if (lit is StringLiteral) {
+ set_cprefix (((StringLiteral) lit).eval ());
}
- } 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;
- if (lit is StringLiteral) {
- set_lower_case_cprefix (((StringLiteral) lit).eval ());
- }
+ }
+ } 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;
+ if (lit is StringLiteral) {
+ set_lower_case_cprefix (((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 (",")) {
- cheader_filenames.append (filename);
- }
+ }
+ } 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 (",")) {
+ cheader_filenames.append (filename);
}
}
}
}
}
-
- public void process_attributes () {
- foreach (Attribute a in attributes) {
- if (a.name == "CCode") {
- process_ccode_attribute (a);
- }
+ }
+
+ /**
+ * Process all associated attributes.
+ */
+ public void process_attributes () {
+ foreach (Attribute a in attributes) {
+ if (a.name == "CCode") {
+ process_ccode_attribute (a);
}
}
}
}
public override void visit_if_statement (IfStatement! stmt) {
+ if (stmt.condition.error) {
+ /* if there was an error in the condition, skip this check */
+ stmt.error = true;
+ return;
+ }
+
if (stmt.condition.static_type.data_type != bool_type.data_type) {
stmt.error = true;
Report.error (stmt.condition.source_reference, "Condition must be boolean");
var local_sym = ns.namespace_symbol.lookup (expr.member_name);
if (local_sym != null) {
if (expr.symbol_reference != null) {
+ expr.error = true;
Report.error (expr.source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (expr.member_name, expr.symbol_reference.get_full_name (), local_sym.get_full_name ()));
return;
}
} else {
if (expr.inner.error) {
/* if there was an error in the inner expression, skip this check */
+ expr.error = true;
return;
}
var msym = expr.call.symbol_reference;
+ if (msym == null) {
+ /* if no symbol found, skip this check */
+ expr.error = true;
+ return;
+ }
+
List<FormalParameter> params;
if (msym.node is VariableDeclarator) {
}
public override void visit_element_access (ElementAccess! expr) {
- if (expr.container.static_type == null || expr.index.static_type == null) {
+ if (expr.container.error || expr.index.error) {
/* don't proceed if a child expression failed */
+ expr.error = true;
return;
}
}
public override void visit_unary_expression (UnaryExpression! expr) {
- if (expr.inner.static_type == null) {
+ if (expr.inner.error) {
/* if there was an error in the inner expression, skip type check */
+ expr.error = true;
return;
}
// integer type
expr.static_type = expr.inner.static_type;
+ } else if (expr.operator == UnaryOperator.INCREMENT) {
+ // integer type
+
+ expr.static_type = expr.inner.static_type;
+ } else if (expr.operator == UnaryOperator.DECREMENT) {
+ // 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 {
- assert_not_reached ();
+ expr.error = true;
+ Report.error (expr.source_reference, "internal error: unsupported unary operator");
+ return;
}
}
}
public override void visit_binary_expression (BinaryExpression! expr) {
- if (expr.left.static_type == null
- || expr.right.static_type == null) {
+ if (expr.left.error || expr.right.error) {
/* if there were any errors in inner expressions, skip type check */
+ expr.error = true;
return;
}
if (expr.left.static_type.data_type == string_type.data_type
&& expr.operator == BinaryOperator.PLUS) {
if (expr.right.static_type.data_type != string_type.data_type) {
+ expr.error = true;
Report.error (expr.source_reference, "Operands must be strings");
+ return;
}
expr.static_type = string_type;
// TODO: check for integer or floating point type in expr.left
if (!check_binary_type (expr, "Arithmetic operation")) {
+ expr.error = true;
return;
}
// TODO: check for integer type in expr.left
if (!check_binary_type (expr, "Arithmetic operation")) {
+ expr.error = true;
return;
}
/* TODO: check for integer or floating point type in expr.left */
if (!check_binary_type (expr, "Relational operation")) {
+ expr.error = true;
return;
}
}
if (!is_type_compatible (expr.right.static_type, expr.left.static_type)
&& !is_type_compatible (expr.left.static_type, expr.right.static_type)) {
Report.error (expr.source_reference, "Equality operation: `%s' and `%s' are incompatible, comparison would always evaluate to false".printf (expr.right.static_type.to_string (), expr.left.static_type.to_string ()));
+ expr.error = true;
return;
}
} else if (expr.operator == BinaryOperator.AND
|| expr.operator == BinaryOperator.OR) {
if (expr.left.static_type.data_type != bool_type.data_type || expr.right.static_type.data_type != bool_type.data_type) {
+ expr.error = true;
Report.error (expr.source_reference, "Operands must be boolean");
}
public override void visit_type_check (TypeCheck! expr) {
if (expr.type_reference.data_type == null) {
/* if type resolving didn't succeed, skip this check */
+ expr.error = true;
return;
}
}
public override void visit_begin_assignment (Assignment! a) {
+ if (!(a.left is MemberAccess)) {
+ a.error = true;
+ Report.error (a.source_reference, "unsupported lvalue in assignment");
+ return;
+ }
+
var ma = (MemberAccess) a.left;
+ if (ma.error || ma.symbol_reference == null) {
+ a.error = true;
+ /* if no symbol found, skip this check */
+ return;
+ }
+
if (ma.symbol_reference.node is Signal) {
var sig = (Signal) ma.symbol_reference.node;
}
public override void visit_end_assignment (Assignment! a) {
- if (!(a.left is MemberAccess)) {
+ if (a.error || a.left.error || a.right.error) {
a.error = true;
- Report.error (a.source_reference, "unsupported lvalue in assignment");
return;
}
var sig = (Signal) ma.symbol_reference.node;
if (a.right.symbol_reference == null) {
- a.right.error = true;
+ a.error = true;
Report.error (a.right.source_reference, "unsupported expression for signal handler");
return;
}