The unified diff between revisions [9a6e8df1..] and [879bb490..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'src/lsc/codegen.c'

#
# old_revision [9a6e8df1d6b102f467702e274d53d90f9151e2c8]
# new_revision [879bb490162f7bfef0afc9c96666267f54996591]
#
# patch "src/lsc/codegen.c"
#  from [3f17dcc09e552288f4a68b0ac58692cffd524364]
#    to [59287d90158eaceceb9a87f9fe6f6c45059c6cb6]
#
============================================================
--- src/lsc/codegen.c	3f17dcc09e552288f4a68b0ac58692cffd524364
+++ src/lsc/codegen.c	59287d90158eaceceb9a87f9fe6f6c45059c6cb6
@@ -95,10 +95,14 @@ struct instr *instr_tail = NULL;
 #define VAR_ARG 1
 #define VAR_REAL 2
 
+#define FN_TYPE_BASE 0xff
+
 #define FN_INT 1
 #define FN_STR 2
 #define FN_LOCAL 3
 
+#define FN_VARARGS 0x100
+
 int fnconst;
 int nargs;
 int local_variable_count = -1;
@@ -146,7 +150,7 @@ void output_functions_action(struct hash
 {
 	int len, pad;
 
-	if (ptr->flags == FN_LOCAL) {
+	if ((ptr->flags & FN_TYPE_BASE) == FN_LOCAL) {
 		len = strlen(ptr->name) + 1 + 16;
 		pad = (4 - (len % 4)) % 4;
 		output_int(len+pad);
@@ -311,7 +315,7 @@ void create_function(char *fnname, int t
 		compiler_error("Function already exists");
 
 	if (output_asm) {
-		switch (type) {
+		switch (type & FN_TYPE_BASE) {
 		case FN_INT:
 			printf("%%fnint %s %d\n", fnname, num);
 			break;
@@ -644,12 +648,14 @@ void codegen(ast *node)
 	case node_ast:
 		switch (node->info.node.tag) {
 		case kind_fndefint:
+		case kind_fndefint_v:
 			assert(sp == 0);
 			assert(node->info.node.head != NULL);
 			assert(node->info.node.head->next != NULL);
 
 			create_function(node->info.node.head->elem->info.string,
-			    FN_INT,
+			    FN_INT | ((node->info.node.tag ==
+				kind_fndefint_v) ? FN_VARARGS : 0),
 			    node->info.node.head->next->elem->info.integer);
 			break;
 		case kind_constant:
@@ -771,20 +777,36 @@ void codegen(ast *node)
 
 //			printf("savedsp = %d\n", savedsp);
 
+			nargs = 0;
+
 			/* Evaluate the arguments first */
 			for (ptr =
 			    node->info.node.head->next->elem->info.node.head;
 			    ptr; ptr = ptr->next) {
 				codegen(ptr->elem);
+				nargs++;
 			}
 
 //			printf("sp = %d\n", sp);
 
+			if (!lookup_function(node->info.node.head->elem, &fn))
+				compiler_error("Function not found");
+
+			if (fn.type & FN_VARARGS) {
+				/*
+				 * The last argument is the number of
+				 * arguments to expect in the case
+				 * of variable argument length.
+				 * This is something only supported for
+				 * builtin functions at present.
+				 */
+				emit_instr_immediate(OP_PUSH, nargs);
+				sp++;
+			}
+
 			emit_instr_immediate(OP_ALLOC, 1);
 			sp++;
 
-			if (!lookup_function(node->info.node.head->elem, &fn))
-				compiler_error("Function not found");
 			switch (fn.type) {
 			case FN_INT:
 				emit_instr_immediate(OP_CALLNUM, fn.num);
@@ -1147,8 +1169,12 @@ void codegen(ast *node)
 			emit_instr_label(OP_B, breaklabel);
 			break;
 		case stmt_return:
-			assert(node->info.node.head == NULL);
-
+			if (node->info.node.head) {
+				/* Return value */
+				codegen(node->info.node.head->elem);
+				emit_instr_imm_const(OP_STORE, sp, fnconst);
+				sp--;
+			}
 			emit_instr_imm_const(OP_POP, sp, fnconst);
 			emit_simple_instr(OP_RET);
 			break;