+2006-07-04 Jürg Billeter <j@bitron.ch>
+
+ * vala/parser.y: support implicit namespace specification in callback
+ declaration
+ * vala/valasemanticanalyzer.vala, vala/valamemorymanager.vala,
+ vala/valacodegenerator.vala: support callbacks
+ * vala/valaassignment.vala, vala/valabinaryexpression.vala: improve
+ documentation
+ * vala/valabooleanliteral.vala, vala/valabreakstatement.vala,
+ vala/valacallback.vala: add interface documentation, use implicit
+ namespace specification
+ * vala/valacallback.vala: add matches_method method, mark as
+ non-reference type
+ * ccode/valaccodetypedefinition.vala: replace typedef_name by
+ declarator, add interface documentation, use implicit namespace
+ specification
+ * tests/test-013.vala: test break
+ * tests/test-014.vala: test callback
+ * tests/Makefile.am: update
+
2006-07-04 Jürg Billeter <j@bitron.ch>
* vala/valablock.vala: add interface documentation, use implicit
using GLib;
-namespace Vala {
- public class CCodeTypeDefinition : CCodeNode {
- public string type_name { get; construct; }
- public string typedef_name { get; construct; }
+/**
+ * Represents a typedef in the C code.
+ */
+public class Vala.CCodeTypeDefinition : CCodeNode {
+ /**
+ * The type name.
+ */
+ public string type_name { get; set; }
+
+ /**
+ * The type declarator.
+ */
+ public CCodeDeclarator declarator { get; set; }
+
+ public override void write (CCodeWriter writer) {
+ writer.write_indent ();
+ writer.write_string ("typedef ");
+
+ writer.write_string (type_name);
+
+ writer.write_string (" ");
+
+ declarator.write (writer);
- public override void write (CCodeWriter writer) {
- writer.write_indent ();
- writer.write_string ("typedef ");
- writer.write_string (type_name);
- writer.write_string (" ");
- writer.write_string (typedef_name);
- writer.write_string (";");
- writer.write_newline ();
- }
+ writer.write_string (";");
+ writer.write_newline ();
}
}
test-010.vala \
test-011.vala \
test-012.vala \
+ test-013.vala \
+ test-014.vala \
$(NULL)
--- /dev/null
+using GLib;
+
+class Maman.Bar {
+ static int main (int argc, string[] argv) {
+ stdout.printf ("Break Test: 1");
+
+ int i;
+ for (i = 0; i < 10; i++) {
+ stdout.printf (" 2");
+ break;
+ }
+
+ stdout.printf (" 3\n");
+
+ return 0;
+ }
+}
--- /dev/null
+using GLib;
+
+callback int Maman.ActionCallback ();
+
+class Maman.Bar {
+ static int do_action () {
+ return 2;
+ }
+
+ static int main (int argc, string[] argv) {
+ stdout.printf ("Callback Test: 1");
+
+ ActionCallback cb = do_action;
+
+ stdout.printf (" %d", cb ());
+
+ stdout.printf (" 3\n");
+
+ return 0;
+ }
+}
vala_namespace_add_callback (current_namespace, $1);
g_object_unref ($1);
}
+
+ if (current_namespace_implicit) {
+ /* current namespace has been declared implicitly */
+ current_namespace = vala_source_file_get_global_namespace (current_source_file);
+ current_namespace_implicit = FALSE;
+ }
}
| field_declaration
{
;
callback_declaration
- : comment opt_attributes opt_access_modifier CALLBACK type identifier_or_new OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON
+ : comment opt_attributes opt_access_modifier CALLBACK type IDENTIFIER opt_name_specifier OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS SEMICOLON
{
GList *l;
+ char *name = $6;
+
+ if ($7 != NULL) {
+ ValaSourceReference *ns_src = src(@6);
+ current_namespace = vala_namespace_new ($6, ns_src);
+ g_free ($6);
+ g_object_unref (ns_src);
+ current_namespace_implicit = TRUE;
+
+ vala_source_file_add_namespace (current_source_file, current_namespace);
+ g_object_unref (current_namespace);
+
+ name = $7;
+ }
ValaSourceReference *src = src_com(@6, $1);
- $$ = vala_callback_new ($6, $5, src);
+ $$ = vala_callback_new (name, $5, src);
g_object_unref (src);
if ($3 != 0) {
VALA_DATA_TYPE($$)->access = $3;
}
VALA_CODE_NODE($$)->attributes = $2;
- for (l = $8; l != NULL; l = l->next) {
+ for (l = $9; l != NULL; l = l->next) {
vala_callback_add_parameter ($$, l->data);
g_object_unref (l->data);
}
- if ($8 != NULL) {
- g_list_free ($8);
+ if ($9 != NULL) {
+ g_list_free ($9);
}
g_object_unref ($5);
- g_free ($6);
+ g_free (name);
}
;
/**
* Represents an assignment expression in the source code.
+ *
+ * Supports =, |=, &=, ^=, +=, -=, *=, /=, %=, <<=, >>=.
*/
public class Vala.Assignment : Expression {
/**
/**
* Represents an expression with two operands in the source code.
+ *
+ * Supports +, -, *, /, %, <<, >>, <, >, <=, >=, ==, !=, &, |, ^, &&, ||.
*/
public class Vala.BinaryExpression : Expression {
/**
using GLib;
-namespace Vala {
- public class BooleanLiteral : Literal {
- public bool value { get; set; }
+/**
+ * Represents a literal boolean, i.e. true or false.
+ */
+public class Vala.BooleanLiteral : Literal {
+ /**
+ * The literal value.
+ */
+ public bool value { get; set; }
- public static ref BooleanLiteral! new (bool b, SourceReference source) {
- return (new BooleanLiteral (value = b, source_reference = source));
- }
-
- public override void accept (CodeVisitor! visitor) {
- visitor.visit_boolean_literal (this);
- }
+ /**
+ * Creates a new boolean literal.
+ *
+ * @param b boolean value
+ * @param source reference to source code
+ * @return newly created boolean literal
+ */
+ public static ref BooleanLiteral! new (bool b, SourceReference source) {
+ return (new BooleanLiteral (value = b, source_reference = source));
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_boolean_literal (this);
}
}
using GLib;
-namespace Vala {
- public class BreakStatement : Statement {
- public static ref BreakStatement! new (SourceReference source) {
- return (new BreakStatement (source_reference = source));
- }
-
- public override void accept (CodeVisitor! visitor) {
- visitor.visit_break_statement (this);
- }
+/**
+ * Represents a break statement in the source code.
+ */
+public class Vala.BreakStatement : Statement {
+ /**
+ * Creates a new break statement.
+ *
+ * @param source reference to source code
+ * @return newly created break statement
+ */
+ public static ref BreakStatement! new (SourceReference source) {
+ return (new BreakStatement (source_reference = source));
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_break_statement (this);
}
}
using GLib;
-namespace Vala {
- public class Callback : DataType {
- public TypeReference return_type { get; set; }
- private List<FormalParameter> parameters;
-
- public static ref Callback new (string! name, TypeReference return_type, SourceReference source) {
- return (new Callback (name = name, return_type = return_type, source_reference = source));
+/**
+ * Represents a function callback type.
+ */
+public class Vala.Callback : DataType {
+ /**
+ * The return type of this callback.
+ */
+ public TypeReference return_type { get; set; }
+
+ private List<FormalParameter> parameters;
+ private string cname;
+
+ /**
+ * Creates a new callback.
+ *
+ * @param name callback type name
+ * @param return_type return type
+ * @param source reference to source code
+ * @return newly created callback
+ */
+ public static ref Callback new (string! name, TypeReference return_type, SourceReference source) {
+ return (new Callback (name = name, return_type = return_type, source_reference = source));
+ }
+
+ /**
+ * Append paramater to this callback function.
+ *
+ * @param param a formal parameter
+ */
+ public void add_parameter (FormalParameter! param) {
+ parameters.append (param);
+ }
+
+ /**
+ * Return copy of parameter list.
+ *
+ * @return parameter list
+ */
+ public ref List<FormalParameter> get_parameters () {
+ return parameters.copy ();
+ }
+
+ /**
+ * Checks whether the arguments and return type of the specified method
+ * matches this callback.
+ *
+ * @param m a method
+ * @return true if the specified method is compatible to this callback
+ */
+ public bool matches_method (Method! m) {
+ if (m.return_type.type != return_type.type) {
+ return false;
}
- public void add_parameter (FormalParameter! param) {
- parameters.append (param);
+ var method_params = m.get_parameters ();
+ var method_params_it = method_params;
+ foreach (FormalParameter param in parameters) {
+ /* method is allowed to accept less arguments */
+ if (method_params_it == null) {
+ break;
+ }
+
+ var method_param = (FormalParameter) method_params_it.data;
+ if (method_param.type_reference.type != param.type_reference.type) {
+ return false;
+ }
+
+ method_params_it = method_params_it.next;
}
- public ref List<FormalParameter> get_parameters () {
- return parameters.copy ();
+ /* method may not expect more arguments */
+ if (method_params_it != null) {
+ return false;
}
- public override void accept (CodeVisitor! visitor) {
- visitor.visit_begin_callback (this);
-
- return_type.accept (visitor);
-
- foreach (FormalParameter! param in parameters) {
- param.accept (visitor);
- }
-
- visitor.visit_end_callback (this);
+ return true;
+ }
+
+ public override void accept (CodeVisitor! visitor) {
+ visitor.visit_begin_callback (this);
+
+ return_type.accept (visitor);
+
+ foreach (FormalParameter! param in parameters) {
+ param.accept (visitor);
}
- private string cname;
- public override string! get_cname () {
- if (cname == null) {
- cname = "%s%s".printf (@namespace.get_cprefix (), name);
- }
- return cname;
- }
+ visitor.visit_end_callback (this);
+ }
- public override bool is_reference_type () {
- return true;
- }
-
- public override string get_ref_function () {
- return "";
- }
-
- public override string get_free_function () {
- return "";
+ public override string! get_cname () {
+ if (cname == null) {
+ cname = "%s%s".printf (@namespace.get_cprefix (), name);
}
+ return cname;
+ }
+
+ public override bool is_reference_type () {
+ return false;
}
}
foreach (Namespace ns in namespaces) {
var structs = ns.get_structs ();
foreach (Struct st in structs) {
- header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (st.get_cname ()), typedef_name = st.get_cname ()));
+ header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (st.get_cname ()), declarator = new CCodeVariableDeclarator (name = st.get_cname ())));
}
var classes = ns.get_classes ();
foreach (Class cl in classes) {
- header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (cl.get_cname ()), typedef_name = cl.get_cname ()));
- header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%sClass".printf (cl.get_cname ()), typedef_name = "%sClass".printf (cl.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (cl.get_cname ()), declarator = new CCodeVariableDeclarator (name = cl.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%sClass".printf (cl.get_cname ()), declarator = new CCodeVariableDeclarator (name = "%sClass".printf (cl.get_cname ()))));
}
}
}
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 (type_struct.name), typedef_name = "%sClass".printf (cl.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (instance_struct.name), declarator = new CCodeVariableDeclarator (name = cl.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (type_struct.name), declarator = new CCodeVariableDeclarator (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 ())));
+ header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (instance_priv_struct.name), declarator = new CCodeVariableDeclarator (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");
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 ())));
+ header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct _%s".printf (iface.get_cname ()), declarator = new CCodeVariableDeclarator (name = iface.get_cname ())));
+ header_type_declaration.append (new CCodeTypeDefinition (type_name = "struct %s".printf (type_struct.name), declarator = new CCodeVariableDeclarator (name = "%sInterface".printf (iface.get_cname ()))));
}
type_struct.add_field ("GTypeInterface", "parent");
cenum.add_value (ev.get_cname (), null);
}
+ public override void visit_end_callback (Callback! cb) {
+ var ctypedef = new CCodeTypeDefinition ();
+
+ ctypedef.type_name = cb.return_type.get_cname ();
+
+ var cfundecl = new CCodeFunctionDeclarator (name = cb.get_cname ());
+ foreach (FormalParameter param in cb.get_parameters ()) {
+ cfundecl.add_parameter ((CCodeFormalParameter) param.ccodenode);
+ }
+ ctypedef.declarator = cfundecl;
+
+ if (cb.access == MemberAccessibility.PUBLIC) {
+ header_type_declaration.append (ctypedef);
+ } else {
+ source_type_member_declaration.append (ctypedef);
+ }
+ }
+
public override void visit_constant (Constant! c) {
if (c.symbol.parent_symbol.node is DataType) {
var t = (DataType) c.symbol.parent_symbol.node;
public override void visit_end_invocation_expression (InvocationExpression! expr) {
var ccall = new CCodeFunctionCall (call = (CCodeExpression) expr.call.ccodenode);
- var m = (Method) expr.call.symbol_reference.node;
- var base_method = m;
- if (m.is_override) {
- base_method = m.base_method;
+ Method m = null;
+ List<FormalParameter> params;
+ if (expr.call.symbol_reference.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) expr.call.symbol_reference.node;
+ var cb = (Callback) decl.type_reference.type;
+ params = cb.get_parameters ();
+ } else {
+ m = (Method) expr.call.symbol_reference.node;
+ params = m.get_parameters ();
}
/* explicitly use strong reference as ccall gets unrefed
* at end of inner block
*/
ref CCodeExpression instance;
- if (m.instance) {
+ if (m != null && m.instance) {
+ var base_method = m;
+ if (m.is_override) {
+ base_method = m.base_method;
+ }
+
var req_cast = false;
if (expr.call is SimpleName) {
instance = new CCodeIdentifier (name = "self");
}
}
- var params = m.get_parameters ();
var i = 1;
foreach (Expression arg in expr.argument_list) {
/* explicitly use strong reference as ccall gets
params = params.next;
}
- if (m.instance && m.instance_last) {
+ if (m != null && m.instance && m.instance_last) {
ccall.add_argument (instance);
}
- if (m.instance && m.returns_modified_pointer) {
+ if (m != null && m.instance && m.returns_modified_pointer) {
expr.ccodenode = new CCodeAssignment (left = instance, right = ccall);
} else {
expr.ccodenode = ccall;
List<FormalParameter> params;
var msym = expr.call.symbol_reference;
- if (msym.node is Callback) {
- var cb = (Callback) msym.node;
+ if (msym.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) msym.node;
+ var cb = (Callback) decl.type_reference.type;
params = cb.get_parameters ();
} else {
var m = (Method) msym.node;
public override void visit_variable_declarator (VariableDeclarator! decl) {
if (decl.type_reference == null) {
/* var type */
+
+ if (decl.initializer == null) {
+ decl.error = true;
+ Report.error (decl.source_reference, "var declaration not allowed without initializer");
+ return;
+ }
+ if (decl.initializer.static_type == null) {
+ decl.error = true;
+ Report.error (decl.source_reference, "var declaration not allowed with non-typed initializer");
+ return;
+ }
+
decl.type_reference = decl.initializer.static_type.copy ();
decl.type_reference.is_lvalue_ref = decl.type_reference.is_ref;
decl.type_reference.is_ref = false;
}
-
- if (decl.initializer != null && memory_management) {
- if (decl.initializer.static_type.is_ref) {
- /* rhs transfers ownership of the expression */
- if (!decl.type_reference.is_lvalue_ref) {
- /* lhs doesn't own the value
- * promote lhs type */
+
+ if (decl.initializer != null) {
+ if (decl.initializer.static_type == null) {
+ if (decl.initializer.symbol_reference.node is Method &&
+ decl.type_reference.type is Callback) {
+ var m = (Method) decl.initializer.symbol_reference.node;
+ var cb = (Callback) decl.type_reference.type;
- decl.type_reference.is_lvalue_ref = true;
+ /* check whether method matches callback type */
+ if (!cb.matches_method (m)) {
+ decl.error = true;
+ Report.error (decl.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ()));
+ return;
+ }
+
+ decl.initializer.static_type = decl.type_reference;
+ } else {
+ decl.error = true;
+ Report.error (decl.source_reference, "expression type not allowed as initializer");
+ return;
+ }
+ }
+
+ if (memory_management) {
+ if (decl.initializer.static_type.is_ref) {
+ /* rhs transfers ownership of the expression */
+ if (!decl.type_reference.is_lvalue_ref) {
+ /* lhs doesn't own the value
+ * promote lhs type */
+
+ decl.type_reference.is_lvalue_ref = true;
+ }
}
}
}
TypeReference ret_type;
List<FormalParameter> params;
- if (msym.node is Callback) {
- var cb = (Callback) msym.node;
- ret_type = cb.return_type;
- params = cb.get_parameters ();
- } else {
+ if (msym.node is VariableDeclarator) {
+ var decl = (VariableDeclarator) msym.node;
+ if (decl.type_reference.type is Callback) {
+ var cb = (Callback) decl.type_reference.type;
+ ret_type = cb.return_type;
+ params = cb.get_parameters ();
+ } else {
+ expr.error = true;
+ Report.error (expr.source_reference, "invocation not supported in this context");
+ return;
+ }
+ } else if (msym.node is Method) {
var m = (Method) msym.node;
ret_type = m.return_type;
params = m.parameters;
+ } else {
+ expr.error = true;
+ Report.error (expr.source_reference, "invocation not supported in this context");
+ return;
}
expr.static_type = ret_type;
var sig = (Signal) a.left.symbol_reference.node;
} else if (a.left.symbol_reference.node is Property) {
var prop = (Property) a.left.symbol_reference.node;
+ } else if (a.left.symbol_reference.node is VariableDeclarator && a.right.static_type == null) {
+ var decl = (VariableDeclarator) a.left.symbol_reference.node;
+ if (a.right.symbol_reference.node is Method &&
+ decl.type_reference.type is Callback) {
+ var m = (Method) a.right.symbol_reference.node;
+ var cb = (Callback) decl.type_reference.type;
+
+ /* check whether method matches callback type */
+ if (!cb.matches_method (m)) {
+ decl.error = true;
+ Report.error (a.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ()));
+ return;
+ }
+
+ a.right.static_type = decl.type_reference;
+ } else {
+ a.error = true;
+ Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt");
+ return;
+ }
} else if (a.left.static_type != null && a.right.static_type != null) {
- if (!is_type_compatible (a.right.static_type, a.left.static_type)) {
+ if (!is_type_compatible (a.right.static_type, a.left.static_type)) {
/* if there was an error on either side,
* i.e. a.{left|right}.static_type == null, skip type check */
Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.static_type.to_string (), a.left.static_type.to_string ()));