* The link between a method and generated code.
*/
public abstract class Vala.CCodeMethodModule : CCodeStructModule {
+
+ private bool ellipses_to_valist = false;
+
public override bool method_has_wrapper (Method method) {
return (method.get_attribute ("NoWrapper") == null);
}
// do not generate _new functions for creation methods of abstract classes
if (!(m is CreationMethod && cl != null && cl.is_abstract)) {
+ bool etv_tmp = ellipses_to_valist;
+ ellipses_to_valist = false;
generate_cparameters (m, decl_space, cparam_map, function, null, carg_map, new CCodeFunctionCall (new CCodeIdentifier ("fake")));
+ ellipses_to_valist = etv_tmp;
decl_space.add_function_declaration (function);
}
}
cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ bool etv_tmp = ellipses_to_valist;
+ ellipses_to_valist = false;
generate_cparameters (m, decl_space, cparam_map, function);
+ ellipses_to_valist = etv_tmp;
decl_space.add_function_declaration (function);
+
+ if (m.is_variadic ()) {
+ // _constructv function
+ function = new CCodeFunction (get_constructv_name ((CreationMethod) m));
+ function.modifiers |= CCodeModifiers.STATIC;
+
+ cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ generate_cparameters (m, decl_space, cparam_map, function);
+
+ decl_space.add_function_declaration (function);
+ }
+ }
+ }
+
+ private string get_constructv_name (CreationMethod m) {
+ const string infix = "constructv";
+
+ var parent = m.parent_symbol as Class;
+
+ if (m.name == ".new") {
+ return "%s%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (parent), infix);
+ } else {
+ return "%s%s_%s".printf (CCodeBaseModule.get_ccode_lower_case_prefix (parent), infix, m.name);
}
}
ccode.add_expression (register_call);
}
+ /**
+ * This function generates the code the given method. If the method is
+ * a constructor, _construct is generated, unless it's variadic, in which
+ * case _constructv is generated (and _construct is generated together
+ * with _new in visit_creation_method).
+ */
public override void visit_method (Method m) {
+ string real_name = get_ccode_real_name (m);
+ if (m is CreationMethod && m.is_variadic ()) {
+ real_name = get_constructv_name ((CreationMethod) m);
+ }
+
push_context (new EmitContext (m));
push_line (m.source_reference);
}
if (profile) {
- string prefix = "_vala_prof_%s".printf (get_ccode_real_name (m));
+ string prefix = "_vala_prof_%s".printf (real_name);
cfile.add_include ("stdio.h");
}
CCodeFunction function;
- function = new CCodeFunction (get_ccode_real_name (m));
+ function = new CCodeFunction (real_name);
if (m.is_inline) {
function.modifiers |= CCodeModifiers.INLINE;
}
+ if (m is CreationMethod && m.is_variadic ()) {
+ function.modifiers |= CCodeModifiers.STATIC;
+ }
+
var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
generate_cparameters (m, cfile, cparam_map, function);
}
} else {
if (m.body != null) {
- function = new CCodeFunction (get_ccode_real_name (m) + "_co", "gboolean");
+ function = new CCodeFunction (real_name + "_co", "gboolean");
// data struct to hold parameters, local variables, and the return value
function.add_parameter (new CCodeParameter ("_data_", Symbol.lower_case_to_camel_case (get_ccode_const_name (m)) + "Data*"));
}
if (profile) {
- string prefix = "_vala_prof_%s".printf (get_ccode_real_name (m));
+ string prefix = "_vala_prof_%s".printf (real_name);
var level = new CCodeIdentifier (prefix + "_level");
ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, level)));
}
if (profile) {
- string prefix = "_vala_prof_%s".printf (get_ccode_real_name (m));
+ string prefix = "_vala_prof_%s".printf (real_name);
var level = new CCodeIdentifier (prefix + "_level");
ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeUnaryExpression (CCodeUnaryOperator.PREFIX_DECREMENT, level)));
}
cparam = new CCodeParameter (get_variable_cname (param.name), ctypename);
+ } else if (ellipses_to_valist) {
+ cparam = new CCodeParameter ("_vala_va_list", "va_list");
} else {
cparam = new CCodeParameter.with_ellipsis ();
}
public override void visit_creation_method (CreationMethod m) {
push_line (m.source_reference);
- bool visible = !m.is_private_symbol ();
-
+ ellipses_to_valist = true;
visit_method (m);
+ ellipses_to_valist = false;
if (m.source_type == SourceFileType.FAST) {
return;
// do not generate _new functions for creation methods of abstract classes
if (current_type_symbol is Class && !current_class.is_compact && !current_class.is_abstract) {
- var vfunc = new CCodeFunction (get_ccode_name (m));
+ // _new function
+ create_aux_constructor (m, get_ccode_name (m), false);
- var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
- var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+ // _construct function (if visit_method generated _constructv)
+ if (m.is_variadic ()) {
+ create_aux_constructor (m, get_ccode_real_name (m), true);
+ }
+ }
- push_function (vfunc);
+ pop_line ();
+ }
+
+ private void create_aux_constructor (CreationMethod m, string func_name, bool self_as_first_parameter) {
+ var vfunc = new CCodeFunction (func_name);
+ if (m.is_private_symbol ()) {
+ vfunc.modifiers |= CCodeModifiers.STATIC;
+ }
- var vcall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
+ var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
+ var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+
+ push_function (vfunc);
+
+ string constructor = (m.is_variadic ()) ? get_constructv_name (m) : get_ccode_real_name (m);
+ var vcall = new CCodeFunctionCall (new CCodeIdentifier (constructor));
+
+ if (self_as_first_parameter) {
+ cparam_map.set (get_param_pos (get_ccode_instance_pos (m)), new CCodeParameter ("object_type", "GType"));
+ vcall.add_argument (get_variable_cexpression ("object_type"));
+ } else {
vcall.add_argument (new CCodeIdentifier (get_ccode_type_id (current_class)));
+ }
- generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
- ccode.add_return (vcall);
- if (!visible) {
- vfunc.modifiers |= CCodeModifiers.STATIC;
+ generate_cparameters (m, cfile, cparam_map, vfunc, null, carg_map, vcall);
+
+ if (m.is_variadic ()) {
+ int last_pos = -1;
+ int second_last_pos = -1;
+ foreach (int pos in cparam_map.get_keys ()) {
+ if (pos > last_pos) {
+ second_last_pos = last_pos;
+ last_pos = pos;
+ } else if (pos > second_last_pos) {
+ second_last_pos = pos;
+ }
}
- pop_function ();
+ var va_start = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
+ va_start.add_argument (new CCodeIdentifier ("_vala_va_list_obj"));
+ va_start.add_argument (carg_map.get (second_last_pos));
- cfile.add_function (vfunc);
+ ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("_vala_va_list_obj"));
+ ccode.add_expression (va_start);
+
+ vcall.add_argument (new CCodeIdentifier("_vala_va_list_obj"));
}
- pop_line ();
+ ccode.add_return (vcall);
+
+ pop_function ();
+
+ cfile.add_function (vfunc);
}
}
--- /dev/null
+public class Foo {
+
+ public GLib.GenericArray<string> paramlist;
+ public bool used_test;
+
+ public Foo (string msg, ...) throws Error {
+ string arg = msg;
+ va_list args = va_list ();
+ paramlist = new GLib.GenericArray<string> ();
+ while (arg != null) {
+ paramlist.add (arg);
+ arg = args.arg ();
+ }
+ used_test = false;
+ }
+
+ public Foo.test (string msg) {
+ paramlist = new GLib.GenericArray<string> ();
+ paramlist.add (msg);
+ used_test = true;
+ }
+
+}
+
+public class Bar : Foo {
+
+ public Bar (string text) throws Error {
+ base (text, "bye");
+ }
+
+ public Bar.other (int num, ...) {
+ try {
+ base ("hey");
+ } catch (Error e) {
+ }
+ }
+
+}
+
+void main () {
+ Foo foo;
+
+ foo = new Foo ("one", "two", "three");
+ assert (!foo.used_test);
+ assert (foo.paramlist.length == 3);
+ assert (foo.paramlist[0] == "one");
+ assert (foo.paramlist[1] == "two");
+ assert (foo.paramlist[2] == "three");
+
+ foo = new Foo.test ("meh");
+ assert (foo.used_test);
+ assert (foo.paramlist.length == 1);
+ assert (foo.paramlist[0] == "meh");
+
+ foo = new Bar ("hello");
+ assert (!foo.used_test);
+ assert (foo.paramlist.length == 2);
+ assert (foo.paramlist[0] == "hello");
+ assert (foo.paramlist[1] == "bye");
+
+ foo = new Bar.other (1, 2, 3);
+ assert (!foo.used_test);
+ assert (foo.paramlist.length == 1);
+ assert (foo.paramlist[0] == "hey");
+}