diff --git a/examples/json.noja b/examples/json.noja
index 8efd9e5..266c2e4 100644
--- a/examples/json.noja
+++ b/examples/json.noja
@@ -37,10 +37,8 @@ fun parse(str) {
skip(ctx, isSpace);
- if ended(ctx): {
- print('Source only contains whitespace');
- return none;
- }
+ if ended(ctx):
+ return none, 'Source only contains whitespace';
return parseAny(ctx);
}
@@ -53,10 +51,8 @@ fun parseArray(ctx) {
skip(ctx, isSpace);
- if ended(ctx): {
- error("Source ended inside an array");
- return none;
- }
+ if ended(ctx):
+ return none, "Source ended inside an array";
arr = [];
@@ -76,27 +72,21 @@ fun parseArray(ctx) {
skip(ctx, isSpace);
- if ended(ctx): {
- error("Source ended inside an array");
- return none;
- }
+ if ended(ctx):
+ return none, "Source ended inside an array";
if current(ctx) == ']':
break;
- if current(ctx) != ',': {
- error("Bad character inside array");
- return none;
- }
+ if current(ctx) != ',':
+ return none, "Bad character inside array";
next(ctx); # Skip ','.
skip(ctx, isSpace);
- if ended(ctx): {
- error("Source ended inside an array");
- return none;
- }
+ if ended(ctx):
+ return none, "Source ended inside an array";
}
next(ctx);
@@ -111,10 +101,8 @@ fun parseObject(ctx) {
skip(ctx, isSpace);
- if ended(ctx): {
- error("Source ended inside an object");
- return none;
- }
+ if ended(ctx):
+ return none, "Source ended inside an object";
obj = {};
@@ -125,10 +113,8 @@ fun parseObject(ctx) {
while true: {
- if current(ctx) != '"': {
- error("Bad character where a string was expected");
- return none;
- }
+ if current(ctx) != '"':
+ return none, "Bad character where a string was expected";
key = parseString(ctx);
@@ -137,10 +123,8 @@ fun parseObject(ctx) {
skip(ctx, isSpace);
- if current(ctx) != ':': {
- error("Bad character where ':' was expected");
- return none;
- }
+ if current(ctx) != ':':
+ return none, "Bad character where ':' was expected";
next(ctx); # Skip ':'.
@@ -155,27 +139,21 @@ fun parseObject(ctx) {
skip(ctx, isSpace);
- if ended(ctx): {
- error("Source ended inside an arrays");
- return none;
- }
+ if ended(ctx):
+ return none, "Source ended inside an arrays";
if current(ctx) == '}':
break;
- if current(ctx) != ',': {
- error("Bad character inside array");
- return none;
- }
+ if current(ctx) != ',':
+ return none, "Bad character inside array";
next(ctx); # Skip ','.
skip(ctx, isSpace);
- if ended(ctx): {
- error("Source ended inside an array");
- return none;
- }
+ if ended(ctx):
+ return none, "Source ended inside an array";
}
next(ctx);
@@ -198,10 +176,8 @@ fun parseString(ctx) {
next(ctx);
}
- if ended(ctx): {
- error("Source ended inside a string");
- return none;
- }
+ if ended(ctx):
+ return none, "Source ended inside a string";
next(ctx); # Skip the '"'.
return buff;
@@ -228,15 +204,11 @@ fun parseNumber(ctx) {
next(ctx);
- if ended(ctx): {
- error("Source string ended unexpectedly after dot");
- return none;
- }
+ if ended(ctx):
+ return none, "Source string ended unexpectedly after dot";
- if not isDigit(current(ctx)): {
- error("Got something other than a digit after dot");
- return none;
- }
+ if not isDigit(current(ctx)):
+ return none, "Got something other than a digit after dot";
fact = 1;
while not ended(ctx): {
@@ -253,8 +225,6 @@ fun parseNumber(ctx) {
fun parseAny(ctx) {
- print('Parsing value\n');
-
assert(not ended(ctx));
if current(ctx) == '[':
diff --git a/examples/makegarbage.noja b/examples/makegarbage.noja
index fdb9f4d..7b791ac 100644
--- a/examples/makegarbage.noja
+++ b/examples/makegarbage.noja
@@ -3,7 +3,7 @@
print('Start\n');
i = 0;
-n = 1000;
+n = 10000000;
while i < n: {
diff --git a/examples/return.noja b/examples/return.noja
new file mode 100644
index 0000000..9305d3d
--- /dev/null
+++ b/examples/return.noja
@@ -0,0 +1,8 @@
+
+fun hello()
+ return 1, "hello";
+
+a, b = hello();
+
+print('a = ', a, '\n');
+print('b = ', b, '\n');
\ No newline at end of file
diff --git a/src/builtins/basic.c b/src/builtins/basic.c
index b8092c9..3434f29 100644
--- a/src/builtins/basic.c
+++ b/src/builtins/basic.c
@@ -37,24 +37,32 @@
#include "math.h"
#include "../utils/utf8.h"
-static Object *bin_print(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_print(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
+ (void) runtime;
+ (void) rets;
+ (void) maxretc;
+ (void) error;
+
for(int i = 0; i < (int) argc; i += 1)
Object_Print(argv[i], stdout);
-
- return Object_NewNone(Runtime_GetHeap(runtime), error);
+ return 0;
}
-static Object *bin_type(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_type(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
assert(argc == 1);
(void) runtime;
(void) error;
- return (Object*) argv[0]->type;
+
+ if(maxretc == 0)
+ return 0;
+ rets[0] = (Object*) argv[0]->type;
+ return 1;
}
-static Object *bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
(void) runtime;
(void) error;
@@ -66,29 +74,37 @@ static Object *bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, E
if(!Object_IsString(argv[0]))
{
Error_Report(error, 0, "Argument #%d is not a string", 1);
- return NULL;
+ return -1;
}
const char *string;
int n;
string = Object_ToString(argv[0],&n,Runtime_GetHeap(runtime),error);
if (string == NULL)
- return NULL;
+ return -1;
if(n == 0)
{
Error_Report(error, 0, "Argument #%d is an empty string", 1);
- return NULL;
+ return -1;
}
int k = utf8_sequence_to_utf32_codepoint(string,n,&ret);
assert(k >= 0);
-
- return Object_FromInt(ret,Runtime_GetHeap(runtime),error);
+
+ Object *temp = Object_FromInt(ret,Runtime_GetHeap(runtime),error);
+
+ if(temp == NULL)
+ return -1;
+
+ if(maxretc == 0)
+ return 0;
+ rets[0] = temp;
+ return 1;
}
-static Object *bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
assert(argc == 1);
@@ -97,7 +113,7 @@ static Object *bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Error
if(!Object_IsInt(argv[0]))
{
Error_Report(error, 0, "Argument #%d is not an integer", 1);
- return NULL;
+ return -1;
}
@@ -106,7 +122,7 @@ static Object *bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Error
int value = Object_ToInt(argv[0],error);
if(error->occurred)
- return NULL;
+ return -1;
int k = utf8_sequence_from_utf32_codepoint(buff,sizeof(buff),value);
@@ -114,25 +130,41 @@ static Object *bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Error
if(k<0)
{
Error_Report(error, 0, "Argument #%d is not valid utf-32", 1);
- return NULL;
+ return -1;
}
- return Object_FromString(buff,k,Runtime_GetHeap(runtime),error);
+ Object *temp = Object_FromString(buff,k,Runtime_GetHeap(runtime),error);
+
+ if(temp == NULL)
+ return -1;
+
+ if(maxretc == 0)
+ return 0;
+ rets[0] = temp;
+ return 1;
}
-static Object *bin_count(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_count(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
assert(argc == 1);
int n = Object_Count(argv[0], error);
if(error->occurred)
- return NULL;
+ return -1;
- return Object_FromInt(n, Runtime_GetHeap(runtime), error);
+ Object *temp = Object_FromInt(n, Runtime_GetHeap(runtime), error);
+
+ if(temp == NULL)
+ return -1;
+
+ if(maxretc == 0)
+ return 0;
+ rets[0] = temp;
+ return 1;
}
-static Object *bin_input(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_input(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
(void) argv;
@@ -158,7 +190,7 @@ static Object *bin_input(Runtime *runtime, Object **argv, unsigned int argc, Err
{
if(str != maybe) free(str);
Error_Report(error, 1, "No memory");
- return NULL;
+ return -1;
}
str = tmp;
@@ -175,23 +207,36 @@ static Object *bin_input(Runtime *runtime, Object **argv, unsigned int argc, Err
if(str != maybe)
free(str);
- return res;
+ if(res == NULL)
+ return -1;
+
+ if(maxretc == 0)
+ return 0;
+ rets[0] = res;
+ return 1;
}
-static Object *bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
+ (void) runtime;
+ (void) rets;
+ (void) maxretc;
+
for(unsigned int i = 0; i < argc; i += 1)
if(!Object_ToBool(argv[i], error))
{
if(!error->occurred)
Error_Report(error, 0, "Assertion failed");
- return NULL;
+ return -1;
}
- return Object_NewNone(Runtime_GetHeap(runtime), error);
+ return 0;
}
-static Object *bin_error(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_error(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
+ (void) rets;
+ (void) maxretc;
+
assert(argc == 1);
int length;
@@ -200,13 +245,13 @@ static Object *bin_error(Runtime *runtime, Object **argv, unsigned int argc, Err
string = Object_ToString(argv[0], &length, Runtime_GetHeap(runtime), error);
if(string == NULL)
- return NULL;
+ return -1;
Error_Report(error, 0, "%s", string);
- return NULL;
+ return -1;
}
-static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
unsigned int total_count = 0;
@@ -215,13 +260,13 @@ static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Er
if(!Object_IsString(argv[i]))
{
Error_Report(error, 0, "Argument #%d is not a string", i+1);
- return NULL;
+ return -1;
}
total_count += Object_Count(argv[i], error);
if(error->occurred)
- return NULL;
+ return -1;
}
char starting[128];
@@ -234,7 +279,7 @@ static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Er
if(buffer == NULL)
{
Error_Report(error, 1, "No memory");
- return NULL;
+ return -1;
}
}
@@ -260,35 +305,58 @@ static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Er
done:
if(starting != buffer)
free(buffer);
- return result;
+
+ if(result == NULL)
+ return -1;
+
+ if(maxretc == 0)
+ return 0;
+ rets[0] = result;
+ return 1;
}
-static Object *bin_newBuffer(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_newBuffer(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
assert(argc == 1);
long long int size = Object_ToInt(argv[0], error);
if(error->occurred == 1)
- return NULL;
+ return -1;
- return Object_NewBuffer(size, Runtime_GetHeap(runtime), error);
+ Object *temp = Object_NewBuffer(size, Runtime_GetHeap(runtime), error);
+
+ if(temp == NULL)
+ return -1;
+
+ if(maxretc == 0)
+ return 0;
+ rets[0] = temp;
+ return 1;
}
-static Object *bin_sliceBuffer(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_sliceBuffer(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
assert(argc == 3);
long long int offset = Object_ToInt(argv[1], error);
- if(error->occurred == 1) return NULL;
+ if(error->occurred == 1) return -1;
long long int length = Object_ToInt(argv[2], error);
- if(error->occurred == 1) return NULL;
+ if(error->occurred == 1) return -1;
- return Object_SliceBuffer(argv[0], offset, length, Runtime_GetHeap(runtime), error);
+ Object *temp = Object_SliceBuffer(argv[0], offset, length, Runtime_GetHeap(runtime), error);
+
+ if(temp == NULL)
+ return -1;
+
+ if(maxretc == 0)
+ return 0;
+ rets[0] = temp;
+ return 1;
}
-static Object *bin_bufferToString(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
+static int bin_bufferToString(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error)
{
assert(argc == 1);
@@ -298,14 +366,22 @@ static Object *bin_bufferToString(Runtime *runtime, Object **argv, unsigned int
buffaddr = Object_GetBufferAddrAndSize(argv[0], &buffsize, error);
if(error->occurred)
- return NULL;
+ return -1;
- return Object_FromString(buffaddr, buffsize, Runtime_GetHeap(runtime), error);
+ Object *temp = Object_FromString(buffaddr, buffsize, Runtime_GetHeap(runtime), error);
+
+ if(temp == NULL)
+ return -1;
+
+ if(maxretc == 0)
+ return 0;
+ rets[0] = temp;
+ return 1;
}
const StaticMapSlot bins_basic[] = {
{ "math", SM_SMAP, .as_smap = bins_math, },
- { "files", SM_SMAP, .as_smap = bins_files, },
+// { "files", SM_SMAP, .as_smap = bins_files, },
// { "net", SM_SMAP, .as_smap = bins_net, },
{ "newBuffer", SM_FUNCT, .as_funct = bin_newBuffer, .argc = 1 },
diff --git a/src/builtins/files.c b/src/builtins/files.c
index 15638a2..5c38932 100644
--- a/src/builtins/files.c
+++ b/src/builtins/files.c
@@ -27,7 +27,8 @@
** | with The Noja Interpreter. If not, see . |
** +--------------------------------------------------------------------------+
*/
-
+#warning "Commented out whole file"
+/*
#include
#include
#include "files.h"
@@ -305,4 +306,5 @@ const StaticMapSlot bins_files[] = {
{ "read", SM_FUNCT, .as_funct = bin_read, .argc = 3, },
{ "write", SM_FUNCT, .as_funct = bin_write, .argc = 3, },
{ NULL, SM_END, {}, {} },
-};
\ No newline at end of file
+};
+*/
\ No newline at end of file
diff --git a/src/builtins/math.c b/src/builtins/math.c
index 211f745..56b01ff 100644
--- a/src/builtins/math.c
+++ b/src/builtins/math.c
@@ -33,7 +33,7 @@
#include "math.h"
#define WRAP_FUNC(name) \
- static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
+ static int bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error) \
{ \
assert(argc == 1); \
\
@@ -42,45 +42,56 @@
double v = Object_ToFloat(argv[0], error); \
\
if(error->occurred) \
- return NULL; \
+ return -1; \
\
- return Object_FromFloat(name(v), Runtime_GetHeap(runtime), error); \
+ if(maxretc > 0) \
+ { \
+ rets[0] = Object_FromFloat(name(v), Runtime_GetHeap(runtime), error); \
+ if(rets[0] == NULL) \
+ return -1; \
+ return 1; \
+ } \
+ return 0; \
} \
else \
{ \
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
- return NULL; \
+ return -1; \
} \
}
#define WRAP_FUNC_2(name) \
- static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
+ static int bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error) \
{ \
assert(argc == 2); \
\
if(!Object_IsFloat(argv[0])) \
{ \
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
- return NULL; \
+ return -1; \
} \
\
if(!Object_IsFloat(argv[1])) \
{ \
Error_Report(error, 0, "Expected second argument to be a float, but it's a %s", Object_GetName(argv[1]));\
- return NULL; \
+ return -1; \
} \
\
double v1 = Object_ToFloat(argv[0], error); \
\
if(error->occurred) \
- return NULL; \
+ return -1; \
\
double v2 = Object_ToFloat(argv[1], error); \
\
if(error->occurred) \
- return NULL; \
+ return -1; \
\
- return Object_FromFloat(name(v1, v2), Runtime_GetHeap(runtime), error); \
+ Object *res = Object_FromFloat(name(v1, v2), Runtime_GetHeap(runtime), error); \
+ if(res == NULL) return -1; \
+ if(maxretc == 0) return 0; \
+ rets[0] = res; \
+ return 1; \
}
WRAP_FUNC(ceil)
diff --git a/src/common/executable.c b/src/common/executable.c
index 6cbabd9..98d8a9b 100644
--- a/src/common/executable.c
+++ b/src/common/executable.c
@@ -90,7 +90,7 @@ static const InstrInfo instr_table[] = {
[OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}},
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}},
- [OPCODE_CALL] = {"CALL", 1, (OperandType[]) {OPTP_INT}},
+ [OPCODE_CALL] = {"CALL", 2, (OperandType[]) {OPTP_INT, OPTP_INT}},
[OPCODE_SELECT] = {"SELECT", 0, NULL},
[OPCODE_INSERT] = {"INSERT", 0, NULL},
[OPCODE_INSERT2] = {"INSERT2", 0, NULL},
@@ -105,7 +105,7 @@ static const InstrInfo instr_table[] = {
[OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}},
[OPCODE_PUSHMAP] = {"PUSHMAP", 1, (OperandType[]) {OPTP_INT}},
- [OPCODE_RETURN] = {"RETURN", 0, NULL},
+ [OPCODE_RETURN] = {"RETURN", 1, (OperandType[]) {OPTP_INT}},
[OPCODE_JUMPIFNOTANDPOP] = {"JUMPIFNOTANDPOP", 1, (OperandType[]) {OPTP_INT}},
[OPCODE_JUMPIFANDPOP] = {"JUMPIFANDPOP", 1, (OperandType[]) {OPTP_INT}},
@@ -299,7 +299,7 @@ Executable *ExeBuilder_Finalize(ExeBuilder *exeb, Error *error)
if(exeb->promc > 0)
{
- Error_Report(error, 0, "There are still %d unfulfilled promises", exeb->promc);
+ Error_Report(error, 1, "There are still %d unfulfilled promises", exeb->promc);
return 0;
}
@@ -371,7 +371,7 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
if(opc != info->opcount)
{
// ERROR: Too many operands were provided.
- Error_Report(error, 0,
+ Error_Report(error, 1,
"Instruction %s expects %d operands, but %d were provided",
info->name, info->opcount, opc);
return 0;
@@ -409,13 +409,13 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
if(expected_type == OPTP_STRING)
{
- Error_Report(error, 0, "Promise values can't be provided as string operands");
+ Error_Report(error, 1, "Promise values can't be provided as string operands");
return 0;
}
if(Promise_Size(opv[i].as_promise) != operand_type_sizes[expected_type])
{
- Error_Report(error, 0,
+ Error_Report(error, 1,
"Provided promise has a value size of %d, "
"but since %s %s was expected, the promise "
"size must be %d",
@@ -429,7 +429,7 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
else if(expected_type != provided_type)
{
// ERROR: Wrong operand type provided.
- Error_Report(error, 0,
+ Error_Report(error, 1,
"Instruction %s expects %s %s as operand %d, but %s %s was provided instead",
info->name,
operand_type_arts[expected_type],
diff --git a/src/compiler/ASTi.h b/src/compiler/ASTi.h
index 98ad2c7..b20b073 100644
--- a/src/compiler/ASTi.h
+++ b/src/compiler/ASTi.h
@@ -68,6 +68,7 @@ typedef enum {
EXPR_INT,
EXPR_MAP,
EXPR_CALL,
+ EXPR_PAIR,
EXPR_LIST,
EXPR_NONE,
EXPR_TRUE,
diff --git a/src/compiler/compile.c b/src/compiler/compile.c
index be247dc..6151cb2 100644
--- a/src/compiler/compile.c
+++ b/src/compiler/compile.c
@@ -50,6 +50,8 @@
#include "compile.h"
#include "ASTi.h"
+static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_dest, Error *error);
+
static Opcode exprkind_to_opcode(ExprKind kind)
{
switch(kind)
@@ -75,6 +77,43 @@ static Opcode exprkind_to_opcode(ExprKind kind)
}
}
+static _Bool emit_instr_for_funccall(ExeBuilder *exeb, CallExprNode *expr, Promise *break_dest, int returns, Error *error)
+{
+ Node *arg = expr->argv;
+
+ while(arg)
+ {
+ if(!emit_instr_for_node(exeb, arg, break_dest, error))
+ return 0;
+
+ arg = arg->next;
+ }
+
+ if(!emit_instr_for_node(exeb, expr->func, break_dest, error))
+ return 0;
+
+ Operand ops[2];
+ ops[0] = (Operand) { .type = OPTP_INT, .as_int = expr->argc };
+ ops[1] = (Operand) { .type = OPTP_INT, .as_int = returns };
+ return ExeBuilder_Append(exeb, error, OPCODE_CALL, ops, 2, expr->base.base.offset, expr->base.base.length);
+}
+
+static _Bool flatten_tuple_tree(ExprNode *root, ExprNode **tuple, int max, int *count, Error *error)
+{
+ if(root->kind == EXPR_PAIR)
+ return flatten_tuple_tree((ExprNode*) ((OperExprNode*) root)->head, tuple, max, count, error) &&
+ flatten_tuple_tree((ExprNode*) ((OperExprNode*) root)->head->next, tuple, max, count, error);
+
+ if(max == *count)
+ {
+ Error_Report(error, 0, "Static buffer is too small");
+ return 0;
+ }
+
+ tuple[(*count)++] = root;
+ return 1;
+}
+
static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_dest, Error *error)
{
assert(node != NULL);
@@ -86,6 +125,10 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
ExprNode *expr = (ExprNode*) node;
switch(expr->kind)
{
+ case EXPR_PAIR:
+ Error_Report(error, 0, "Tuple outside of assignment or return statement");
+ return 0;
+
case EXPR_NOT:
case EXPR_POS:
case EXPR_NEG:
@@ -123,35 +166,75 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
lop = oper->head;
rop = lop->next;
- if(!emit_instr_for_node(exeb, rop, break_dest, error))
+ ExprNode *tuple[32];
+ int count = 0;
+
+ if(!flatten_tuple_tree((ExprNode*) lop, tuple, sizeof(tuple)/sizeof(tuple[0]), &count, error))
return 0;
- if(((ExprNode*) lop)->kind == EXPR_IDENT)
+ assert(count > 0);
+
+ if(count == 1) /* No tuple. */
{
- const char *name = ((IdentExprNode*) lop)->val;
-
- Operand op = { .type = OPTP_STRING, .as_string = name };
- if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, node->offset, node->length))
- return 0;
- }
- else if(((ExprNode*) lop)->kind == EXPR_SELECT)
- {
- Node *idx = ((IndexSelectionExprNode*) lop)->idx;
- Node *set = ((IndexSelectionExprNode*) lop)->set;
-
- if(!emit_instr_for_node(exeb, set, break_dest, error))
- return 0;
-
- if(!emit_instr_for_node(exeb, idx, break_dest, error))
- return 0;
-
- if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, node->offset, node->length))
+ if(!emit_instr_for_node(exeb, rop, break_dest, error))
return 0;
}
else
{
- Error_Report(error, 0, "Assignment left operand can't be assigned to");
- return 0;
+ if(((ExprNode*) rop)->kind == EXPR_CALL)
+ {
+ if(!emit_instr_for_funccall(exeb, (CallExprNode*) rop, break_dest, count, error))
+ return 0;
+ }
+ else
+ {
+ Error_Report(error, 0, "Assigning to %d variables only 1 value", count);
+ return 0;
+ }
+ }
+
+ for(int i = 0; i < count; i += 1)
+ {
+ ExprNode *tuple_item = tuple[count-i-1];
+ switch(tuple_item->kind)
+ {
+ case EXPR_IDENT:
+ {
+ const char *name = ((IdentExprNode*) tuple_item)->val;
+
+ Operand op = { .type = OPTP_STRING, .as_string = name };
+ if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, tuple_item->base.offset, tuple_item->base.length))
+ return 0;
+ break;
+ }
+
+ case EXPR_SELECT:
+ {
+ Node *idx = ((IndexSelectionExprNode*) tuple_item)->idx;
+ Node *set = ((IndexSelectionExprNode*) tuple_item)->set;
+
+ if(!emit_instr_for_node(exeb, set, break_dest, error))
+ return 0;
+
+ if(!emit_instr_for_node(exeb, idx, break_dest, error))
+ return 0;
+
+ if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, tuple_item->base.offset, tuple_item->base.length))
+ return 0;
+ break;
+ }
+
+ default:
+ Error_Report(error, 0, "Assigning to something that it can't be assigned to");
+ return 0;
+ }
+
+ if(i+1 < count)
+ {
+ Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 };
+ if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, node->offset, 0))
+ return 0;
+ }
}
return 1;
@@ -253,25 +336,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
}
case EXPR_CALL:
- {
- CallExprNode *p = (CallExprNode*) expr;
-
- Node *arg = p->argv;
-
- while(arg)
- {
- if(!emit_instr_for_node(exeb, arg, break_dest, error))
- return 0;
-
- arg = arg->next;
- }
-
- if(!emit_instr_for_node(exeb, p->func, break_dest, error))
- return 0;
-
- Operand op = { .type = OPTP_INT, .as_int = p->argc };
- return ExeBuilder_Append(exeb, error, OPCODE_CALL, &op, 1, node->offset, node->length);
- }
+ return emit_instr_for_funccall(exeb, (CallExprNode*) expr, break_dest, 1, error);
case EXPR_SELECT:
{
@@ -526,10 +591,18 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
{
ReturnNode *ret = (ReturnNode*) node;
- if(!emit_instr_for_node(exeb, ret->val, break_dest, error))
+ ExprNode *tuple[32];
+ int count = 0;
+
+ if(!flatten_tuple_tree((ExprNode*) ret->val, tuple, sizeof(tuple)/sizeof(tuple[0]), &count, error))
return 0;
- if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, ret->base.offset, ret->base.length))
+ for(int i = 0; i < count; i += 1)
+ if(!emit_instr_for_node(exeb, (Node*) tuple[i], break_dest, error))
+ return 0;
+
+ Operand op = (Operand) { .type = OPTP_INT, .as_int = count };
+ if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, &op, 1, ret->base.offset, ret->base.length))
return 0;
return 1;
@@ -608,7 +681,8 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
// Write a return instruction, just
// in case it didn't already return.
- if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, func->body->offset, 0))
+ Operand op = (Operand) { .type = OPTP_INT, .as_int = 0 };
+ if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, &op, 1, func->body->offset, 0))
return 0;
}
@@ -672,7 +746,8 @@ Executable *compile(AST *ast, BPAlloc *alloc, Error *error)
if(!emit_instr_for_node(exeb, ast->root, NULL, error))
return 0;
- if(ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, Source_GetSize(ast->src), 0))
+ Operand op = (Operand) { .type = OPTP_INT, .as_int = 0 };
+ if(ExeBuilder_Append(exeb, error, OPCODE_RETURN, &op, 1, Source_GetSize(ast->src), 0))
{
exe = ExeBuilder_Finalize(exeb, error);
diff --git a/src/compiler/parse.c b/src/compiler/parse.c
index 9e15754..16034ec 100644
--- a/src/compiler/parse.c
+++ b/src/compiler/parse.c
@@ -83,6 +83,7 @@ typedef enum {
TLCBRK = '{',
TRCBRK = '}',
TDOT = '.',
+ TCOMMA = ',',
TDONE = 256,
TINT,
@@ -126,7 +127,7 @@ typedef struct {
} Context;
static Node *parse_statement(Context *ctx);
-static Node *parse_expression(Context *ctx);
+static Node *parse_expression(Context *ctx, _Bool allow_toplev_tuples);
static Node *parse_expression_statement(Context *ctx);
static Node *parse_ifelse_statement(Context *ctx);
static Node *parse_compound_statement(Context *ctx, TokenKind end);
@@ -141,7 +142,8 @@ static inline _Bool isoper(char c)
return c == '+' || c == '-' ||
c == '*' || c == '/' ||
c == '<' || c == '>' ||
- c == '!' || c == '=';
+ c == '!' || c == '=' ||
+ c == ',';
}
/* Symbol: tokenize
@@ -311,17 +313,18 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
int size;
const char *text;
} optable[] = {
- { TADD, 1, "+" },
- { TSUB, 1, "-" },
- { TMUL, 1, "*" },
- { TDIV, 1, "/" },
- { TEQL, 2, "==" },
- { TNQL, 2, "!=" },
- { TLSS, 1, "<" },
- { TLEQ, 2, "<=" },
- { TGRT, 1, ">" },
- { TGEQ, 2, ">=" },
- { TASS, 1, "=" },
+ { TADD, 1, "+" },
+ { TSUB, 1, "-" },
+ { TMUL, 1, "*" },
+ { TDIV, 1, "/" },
+ { TEQL, 2, "==" },
+ { TNQL, 2, "!=" },
+ { TLSS, 1, "<" },
+ { TLEQ, 2, "<=" },
+ { TGRT, 1, ">" },
+ { TGEQ, 2, ">=" },
+ { TASS, 1, "=" },
+ { TCOMMA, 1, "," },
};
_Bool found = 0;
@@ -598,11 +601,19 @@ static Node *parse_statement(Context *ctx)
next(ctx); // Consume the "return" keyword.
- Node *val = parse_expression_statement(ctx);
+ Node *val = parse_expression(ctx, 1);
if(val == NULL)
return NULL;
+ if(current(ctx) != ';')
+ {
+ Error_Report(ctx->error, 0, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset);
+ return NULL;
+ }
+
+ next(ctx); // Consume the ';'.
+
ReturnNode *node = BPAlloc_Malloc(ctx->alloc, sizeof(ReturnNode));
if(node == NULL)
@@ -638,7 +649,7 @@ static Node *parse_expression_statement(Context *ctx)
{
assert(ctx != NULL);
- Node *expr = parse_expression(ctx);
+ Node *expr = parse_expression(ctx, 1);
if(expr == NULL)
return NULL;
@@ -829,7 +840,7 @@ static Node *parse_list_primary_expression(Context *ctx)
while(1)
{
// Parse.
- Node *item = parse_expression(ctx);
+ Node *item = parse_expression(ctx, 0);
if(item == NULL)
return NULL;
@@ -940,7 +951,7 @@ static Node *parse_map_primary_expression(Context *ctx)
}
else
{
- key = parse_expression(ctx);
+ key = parse_expression(ctx, 0);
}
if(key == NULL)
@@ -961,7 +972,7 @@ static Node *parse_map_primary_expression(Context *ctx)
next(ctx);
// Parse.
- Node *item = parse_expression(ctx);
+ Node *item = parse_expression(ctx, 0);
if(item == NULL)
return NULL;
@@ -1100,7 +1111,7 @@ static Node *parse_primary_expresion(Context *ctx)
{
next(ctx); // Consume the '('.
- Node *node = parse_expression(ctx);
+ Node *node = parse_expression(ctx, 1);
if(node == NULL)
return NULL;
@@ -1419,7 +1430,7 @@ static Node *parse_postfix_expression(Context *ctx)
while(1)
{
// Parse.
- Node *arg = parse_expression(ctx);
+ Node *arg = parse_expression(ctx, 0);
if(arg == NULL)
return NULL;
@@ -1552,7 +1563,7 @@ static inline _Bool isbinop(Token *tok)
tok->kind == TLEQ || tok->kind == TGEQ ||
tok->kind == TEQL || tok->kind == TNQL ||
tok->kind == TKWAND || tok->kind == TKWOR ||
- tok->kind == '=';
+ tok->kind == '=' || tok->kind == ',';
}
static inline _Bool isrightassoc(Token *tok)
@@ -1592,6 +1603,9 @@ static inline int precedenceof(Token *tok)
case '*':
case '/':
return 5;
+
+ case ',':
+ return 6;
default:
return -100000000;
@@ -1601,12 +1615,15 @@ static inline int precedenceof(Token *tok)
return -100000000;
}
-static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
+static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec, _Bool allow_toplev_tuples)
{
while(isbinop(ctx->token) && precedenceof(ctx->token) >= min_prec)
{
Token *op = ctx->token;
+ if(op->kind == ',' && allow_toplev_tuples == 0)
+ break;
+
next(ctx);
Node *right_expr = parse_prefix_expression(ctx);
@@ -1616,7 +1633,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
while(isbinop(ctx->token) && (precedenceof(ctx->token) > precedenceof(op) || (precedenceof(ctx->token) == precedenceof(op) && isrightassoc(ctx->token))))
{
- right_expr = parse_expression_2(ctx, right_expr, precedenceof(op) + 1);
+ right_expr = parse_expression_2(ctx, right_expr, precedenceof(op) + 1, allow_toplev_tuples);
if(right_expr == NULL)
return NULL;
@@ -1652,6 +1669,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
case TKWAND: temp->base.kind = EXPR_AND; break;
case TKWOR: temp->base.kind = EXPR_OR; break;
case '=': temp->base.kind = EXPR_ASS; break;
+ case ',': temp->base.kind = EXPR_PAIR; break;
default:
UNREACHABLE;
@@ -1670,7 +1688,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
return left_expr;
}
-static Node *parse_expression(Context *ctx)
+static Node *parse_expression(Context *ctx, _Bool allow_toplev_tuples)
{
Node *left_expr = parse_prefix_expression(ctx);
@@ -1680,7 +1698,7 @@ static Node *parse_expression(Context *ctx)
if(done(ctx))
return left_expr;
- return parse_expression_2(ctx, left_expr, -1000000000);
+ return parse_expression_2(ctx, left_expr, -1000000000, allow_toplev_tuples);
}
static Node *parse_ifelse_statement(Context *ctx)
@@ -1704,7 +1722,7 @@ static Node *parse_ifelse_statement(Context *ctx)
next(ctx); // Consume the "if" keyword.
- Node *condition = parse_expression(ctx);
+ Node *condition = parse_expression(ctx, 1);
if(condition == NULL)
return NULL;
@@ -1987,7 +2005,7 @@ static Node *parse_while_statement(Context *ctx)
next(ctx); // Consume the "while" keyword.
- Node *condition = parse_expression(ctx);
+ Node *condition = parse_expression(ctx, 1);
if(condition == NULL)
return NULL;
@@ -2073,7 +2091,7 @@ static Node *parse_dowhile_statement(Context *ctx)
next(ctx); // Consume the "while" keyword.
- Node *condition = parse_expression(ctx);
+ Node *condition = parse_expression(ctx, 1);
if(condition == NULL)
return NULL;
diff --git a/src/main.c b/src/main.c
index 27c202b..1b9bff6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -159,12 +159,15 @@ static _Bool interpret(Source *src)
Runtime_SetBuiltins(runt, bins);
- Object *o = run(runt, (Error*) &error, exe, 0, NULL, NULL, 0);
+ Object *rets[8];
+ unsigned int maxretc = sizeof(rets)/sizeof(rets[0]);
+
+ int retc = run(runt, (Error*) &error, exe, 0, NULL, NULL, 0, rets, maxretc);
// NOTE: The pointer to the builtins object is invalidated
// now because it may be moved by the garbage collector.
- if(o == NULL)
+ if(retc < 0)
{
print_error("Runtime", (Error*) &error);
@@ -179,7 +182,7 @@ static _Bool interpret(Source *src)
Runtime_Free(runt);
Executable_Free(exe);
- return o != NULL;
+ return retc > -1;
}
static _Bool disassemble(Source *src)
diff --git a/src/objects/objects.c b/src/objects/objects.c
index 5fbf1e4..1981938 100644
--- a/src/objects/objects.c
+++ b/src/objects/objects.c
@@ -120,10 +120,9 @@ Object *Object_Copy(Object *obj, Heap *heap, Error *err)
return type->copy(obj, heap, err);
}
-Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, Error *err)
+int Object_Call(Object *obj, Object **argv, unsigned int argc, Object **rets, unsigned int maxrets, Heap *heap, Error *err)
{
- assert(err);
- assert(obj);
+ assert(err != NULL && obj != NULL);
const TypeObject *type = Object_GetType(obj);
assert(type);
@@ -131,10 +130,10 @@ Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, E
if(type->call == NULL)
{
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
- return NULL;
+ return -1;
}
- return type->call(obj, argv, argc, heap, err);
+ return type->call(obj, argv, argc, rets, maxrets, heap, err);
}
void Object_Print(Object *obj, FILE *fp)
diff --git a/src/objects/objects.h b/src/objects/objects.h
index ba792fc..9a78b4a 100644
--- a/src/objects/objects.h
+++ b/src/objects/objects.h
@@ -66,12 +66,12 @@ struct TypeObject {
unsigned int size;
AtomicType atomic;
- _Bool (*init)(Object *self, Error *err);
- _Bool (*free)(Object *self, Error *err);
- int (*hash)(Object *self);
- Object* (*copy)(Object *self, Heap *heap, Error *err);
- Object* (*call)(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *err);
- void (*print)(Object *self, FILE *fp);
+ _Bool (*init)(Object *self, Error *err);
+ _Bool (*free)(Object *self, Error *err);
+ int (*hash)(Object *self);
+ Object* (*copy)(Object *self, Heap *heap, Error *err);
+ int (*call)(Object *self, Object **argv, unsigned int argc, Object **rets, unsigned int maxrets, Heap *heap, Error *err);
+ void (*print)(Object *self, FILE *fp);
unsigned int (*deepsize)(const Object *self);
// Collections.
@@ -123,7 +123,7 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err);
void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error);
int Object_Hash (Object *obj);
Object* Object_Copy (Object *obj, Heap *heap, Error *err);
-Object* Object_Call (Object *obj, Object **argv, unsigned int argc, Heap *heap, Error *err);
+int Object_Call (Object *obj, Object **argv, unsigned int argc, Object **rets, unsigned int maxrets, Heap *heap, Error *err);
void Object_Print (Object *obj, FILE *fp);
Object* Object_Select(Object *coll, Object *key, Heap *heap, Error *err);
Object* Object_Delete(Object *coll, Object *key, Heap *heap, Error *err);
diff --git a/src/runtime/o_func.c b/src/runtime/o_func.c
index 486b094..5037fda 100644
--- a/src/runtime/o_func.c
+++ b/src/runtime/o_func.c
@@ -57,7 +57,7 @@ static void walk(Object *self, void (*callback)(Object **referer, void *userp),
callback(&func->closure, userp);
}
-static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error)
+static int call(Object *self, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Heap *heap, Error *error)
{
assert(self != NULL && heap != NULL && error != NULL);
@@ -88,7 +88,7 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
if(argv2 == NULL)
{
Error_Report(error, 1, "No memory");
- return NULL;
+ return -1;
}
// Copy the provided arguments.
@@ -101,21 +101,21 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
argv2[i] = Object_NewNone(heap, error);
if(argv2[i] == NULL)
- return 0;
+ return -1;
}
}
else
// The right amount of arguments was provided.
argv2 = argv;
- Object *result = run(func->runtime, error, func->exe, func->index, func->closure, argv2, expected_argc);
+ int retc = run(func->runtime, error, func->exe, func->index, func->closure, argv2, expected_argc, rets, maxretc);
// NOTE: Every object reference is invalidated from here.
if(argv2 != argv)
free(argv2);
- return result;
+ return retc;
}
static TypeObject t_func = {
diff --git a/src/runtime/o_nfunc.c b/src/runtime/o_nfunc.c
index 623704c..540f245 100644
--- a/src/runtime/o_nfunc.c
+++ b/src/runtime/o_nfunc.c
@@ -43,11 +43,11 @@
typedef struct {
Object base;
Runtime *runtime;
- Object *(*callback)(Runtime *runtime, Object **argv, unsigned int argc, Error *error);
+ int (*callback)(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error);
int argc;
} NativeFunctionObject;
-static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error)
+static int call(Object *self, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Heap *heap, Error *error)
{
assert(self != NULL);
assert(heap != NULL);
@@ -87,7 +87,7 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
if(argv2 == NULL)
{
Error_Report(error, 1, "No memory");
- return NULL;
+ return -1;
}
// Copy the provided arguments.
@@ -102,27 +102,24 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
if(argv2[i] == NULL)
{
free(argv2);
- return NULL;
+ return -1;
}
}
}
else UNREACHABLE;
assert(func->callback != NULL);
- Object *result = func->callback(func->runtime, argv2, argc2, error);
+ int retc = func->callback(func->runtime, argv2, argc2, rets, maxretc, error);
// NOTE: Since the callback may have executed some bytecode, a GC
// cycle may have been triggered, therefore we must assume
// every object reference that was locally saved is invalidated
// from here (the returned object is good tho).
- if(result == NULL && error->occurred == 0)
- Error_Report(error, 1, "Native callback returned NULL but didn't report errors");
-
if(argv2 != argv)
free(argv2);
- return result;
+ return retc;
}
static TypeObject t_nfunc = {
@@ -156,7 +153,7 @@ static TypeObject t_nfunc = {
* The newly created object. If an error occurred, NULL is returned
* and information about the error is stored in the [error] argument.
*/
-Object *Object_FromNativeFunction(Runtime *runtime, Object *(*callback)(Runtime*, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error)
+Object *Object_FromNativeFunction(Runtime *runtime, int (*callback)(Runtime*, Object**, unsigned int, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error)
{
assert(callback != NULL);
diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c
index 4683ee7..28bfa8b 100644
--- a/src/runtime/runtime.c
+++ b/src/runtime/runtime.c
@@ -77,7 +77,7 @@ int Runtime_GetCurrentIndex(Runtime *runtime)
Executable *Runtime_GetCurrentExecutable(Runtime *runtime)
{
if(runtime->depth == 0)
- return NULL;
+ return NULL;
else
return runtime->frame->exe;
}
@@ -805,11 +805,13 @@ static _Bool step(Runtime *runtime, Error *error)
case OPCODE_CALL:
{
- assert(opc == 1);
+ assert(opc == 2);
assert(ops[0].type == OPTP_INT);
+ assert(ops[1].type == OPTP_INT);
int argc = ops[0].as_int;
- assert(argc >= 0);
+ int retc = ops[1].as_int;
+ assert(argc >= 0 && retc > 0);
if(runtime->frame->used < argc + 1)
{
@@ -839,19 +841,32 @@ static _Bool step(Runtime *runtime, Error *error)
(void) Runtime_Pop(runtime, error, argc+1);
assert(error->occurred == 0);
- Object *obj = Object_Call(callable, argv, argc, runtime->heap, error);
- // NOTE: Every local object reference is invalidated from here.
-
- if(obj == NULL)
- {
- assert(error->occurred != 0);
+ Object *rets[8];
+ unsigned int maxrets = sizeof(rets)/sizeof(rets[0]);
+
+ int num_rets = Object_Call(callable, argv, argc, rets, maxrets, runtime->heap, error);
+
+ if(num_rets < 0)
return 0;
- }
+
+ // NOTE: Every local object reference is invalidated from here.
assert(error->occurred == 0);
- if(!Runtime_Push(runtime, error, obj))
- return 0;
+ for(int g = 0; g < MIN(num_rets, retc); g += 1)
+ if(!Runtime_Push(runtime, error, rets[g]))
+ return 0;
+
+ for(int g = 0; g < retc - num_rets; g += 1)
+ {
+ Object *temp = Object_NewNone(Runtime_GetHeap(runtime), error);
+
+ if(temp == NULL)
+ return NULL;
+
+ if(!Runtime_Push(runtime, error, temp))
+ return 0;
+ }
return 1;
}
@@ -1126,7 +1141,14 @@ static _Bool step(Runtime *runtime, Error *error)
}
case OPCODE_RETURN:
- return 0;
+ {
+ assert(opc == 1);
+ assert(ops[0].type == OPTP_INT);
+ int retc = ops[0].as_int;
+ assert(retc >= 0);
+ assert(retc == runtime->frame->used);
+ return 0;
+ }
case OPCODE_JUMP:
assert(opc == 1);
@@ -1233,7 +1255,7 @@ static _Bool collect(Runtime *runtime, Error *error)
return Heap_StopCollection(runtime->heap);
}
-Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc)
+int run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc, Object **rets, int maxretc)
{
assert(runtime != NULL);
assert(error != NULL);
@@ -1244,7 +1266,7 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
if(runtime->depth == MAX_FRAMES)
{
Error_Report(error, 1, "Maximum nested call limit of %d was reached", MAX_FRAMES);
- return NULL;
+ return -1;
}
assert(runtime->depth < MAX_FRAMES);
@@ -1260,12 +1282,12 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
frame.used = 0;
if(frame.locals == NULL)
- return NULL;
+ return -1;
if(frame.exe == NULL)
{
Error_Report(error, 1, "Failed to copy executable");
- return NULL;
+ return -1;
}
// Add the frame to the runtime.
@@ -1275,7 +1297,7 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
}
// This is what the function will return.
- Object *result = NULL;
+ int retc = -1;
// Push the initial values of the frame.
for(int i = 0; i < argc; i += 1)
@@ -1317,19 +1339,12 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
// If an error occurred, we want to return NULL.
if(error->occurred == 0)
{
- // If the step function left something
- // on the stack, we return that. If it
- // didn't, we return some other default
- // value like "none".
- if(frame.used == 0)
+ retc = MIN(frame.used, maxretc);
+
+ for(int i = 0; i < retc; i += 1)
{
- // Nothing to return on the stack. Set to none.
- result = Object_NewNone(runtime->heap, error);
- }
- else
- {
- result = Stack_Top(runtime->stack, 0);
- assert(result != NULL);
+ rets[i] = Stack_Top(runtime->stack, i - retc + 1);
+ assert(rets[i] != NULL);
}
}
@@ -1348,5 +1363,5 @@ cleanup:
Executable_Free(frame.exe);
}
- return result;
+ return retc;
}
\ No newline at end of file
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index 174af81..c62ee43 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -54,7 +54,7 @@ Executable *Runtime_GetCurrentExecutable(Runtime *runtime);
Snapshot *Snapshot_New(Runtime *runtime);
void Snapshot_Free(Snapshot *snapshot);
void Snapshot_Print(Snapshot *snapshot, FILE *fp);
-Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc);
+int run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc, Object **rets, int maxretc);
typedef enum {
SM_END,
@@ -79,7 +79,7 @@ struct StaticMapSlot {
_Bool as_bool;
long long int as_int;
double as_float;
- Object *(*as_funct)(Runtime*, Object**, unsigned int, Error*);
+ int (*as_funct)(Runtime*, Object**, unsigned int, Object**, unsigned int, Error*);
TypeObject *as_type;
};
union { int argc; int length; };
@@ -87,8 +87,7 @@ struct StaticMapSlot {
Object *Object_NewStaticMap(const StaticMapSlot *slots, Runtime *runt, Error *error);
Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Object *closure, Heap *heap, Error *error);
-Object *Object_FromNativeFunction(Runtime *runtime, Object *(*callback)(Runtime*, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error);
-
+Object *Object_FromNativeFunction(Runtime *runtime, int (*callback)(Runtime*, Object**, unsigned int, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error);
typedef struct {
Error base;
Runtime *runtime;