added tuples and multiple return values

This commit is contained in:
cozis
2022-04-06 13:22:31 +02:00
parent 866648ed16
commit ed63f09b57
17 changed files with 434 additions and 260 deletions
+28 -58
View File
@@ -37,10 +37,8 @@ fun parse(str) {
skip(ctx, isSpace); skip(ctx, isSpace);
if ended(ctx): { if ended(ctx):
print('Source only contains whitespace'); return none, 'Source only contains whitespace';
return none;
}
return parseAny(ctx); return parseAny(ctx);
} }
@@ -53,10 +51,8 @@ fun parseArray(ctx) {
skip(ctx, isSpace); skip(ctx, isSpace);
if ended(ctx): { if ended(ctx):
error("Source ended inside an array"); return none, "Source ended inside an array";
return none;
}
arr = []; arr = [];
@@ -76,27 +72,21 @@ fun parseArray(ctx) {
skip(ctx, isSpace); skip(ctx, isSpace);
if ended(ctx): { if ended(ctx):
error("Source ended inside an array"); return none, "Source ended inside an array";
return none;
}
if current(ctx) == ']': if current(ctx) == ']':
break; break;
if current(ctx) != ',': { if current(ctx) != ',':
error("Bad character inside array"); return none, "Bad character inside array";
return none;
}
next(ctx); # Skip ','. next(ctx); # Skip ','.
skip(ctx, isSpace); skip(ctx, isSpace);
if ended(ctx): { if ended(ctx):
error("Source ended inside an array"); return none, "Source ended inside an array";
return none;
}
} }
next(ctx); next(ctx);
@@ -111,10 +101,8 @@ fun parseObject(ctx) {
skip(ctx, isSpace); skip(ctx, isSpace);
if ended(ctx): { if ended(ctx):
error("Source ended inside an object"); return none, "Source ended inside an object";
return none;
}
obj = {}; obj = {};
@@ -125,10 +113,8 @@ fun parseObject(ctx) {
while true: { while true: {
if current(ctx) != '"': { if current(ctx) != '"':
error("Bad character where a string was expected"); return none, "Bad character where a string was expected";
return none;
}
key = parseString(ctx); key = parseString(ctx);
@@ -137,10 +123,8 @@ fun parseObject(ctx) {
skip(ctx, isSpace); skip(ctx, isSpace);
if current(ctx) != ':': { if current(ctx) != ':':
error("Bad character where ':' was expected"); return none, "Bad character where ':' was expected";
return none;
}
next(ctx); # Skip ':'. next(ctx); # Skip ':'.
@@ -155,27 +139,21 @@ fun parseObject(ctx) {
skip(ctx, isSpace); skip(ctx, isSpace);
if ended(ctx): { if ended(ctx):
error("Source ended inside an arrays"); return none, "Source ended inside an arrays";
return none;
}
if current(ctx) == '}': if current(ctx) == '}':
break; break;
if current(ctx) != ',': { if current(ctx) != ',':
error("Bad character inside array"); return none, "Bad character inside array";
return none;
}
next(ctx); # Skip ','. next(ctx); # Skip ','.
skip(ctx, isSpace); skip(ctx, isSpace);
if ended(ctx): { if ended(ctx):
error("Source ended inside an array"); return none, "Source ended inside an array";
return none;
}
} }
next(ctx); next(ctx);
@@ -198,10 +176,8 @@ fun parseString(ctx) {
next(ctx); next(ctx);
} }
if ended(ctx): { if ended(ctx):
error("Source ended inside a string"); return none, "Source ended inside a string";
return none;
}
next(ctx); # Skip the '"'. next(ctx); # Skip the '"'.
return buff; return buff;
@@ -228,15 +204,11 @@ fun parseNumber(ctx) {
next(ctx); next(ctx);
if ended(ctx): { if ended(ctx):
error("Source string ended unexpectedly after dot"); return none, "Source string ended unexpectedly after dot";
return none;
}
if not isDigit(current(ctx)): { if not isDigit(current(ctx)):
error("Got something other than a digit after dot"); return none, "Got something other than a digit after dot";
return none;
}
fact = 1; fact = 1;
while not ended(ctx): { while not ended(ctx): {
@@ -253,8 +225,6 @@ fun parseNumber(ctx) {
fun parseAny(ctx) { fun parseAny(ctx) {
print('Parsing value\n');
assert(not ended(ctx)); assert(not ended(ctx));
if current(ctx) == '[': if current(ctx) == '[':
+1 -1
View File
@@ -3,7 +3,7 @@
print('Start\n'); print('Start\n');
i = 0; i = 0;
n = 1000; n = 10000000;
while i < n: { while i < n: {
+8
View File
@@ -0,0 +1,8 @@
fun hello()
return 1, "hello";
a, b = hello();
print('a = ', a, '\n');
print('b = ', b, '\n');
+119 -43
View File
@@ -37,24 +37,32 @@
#include "math.h" #include "math.h"
#include "../utils/utf8.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) for(int i = 0; i < (int) argc; i += 1)
Object_Print(argv[i], stdout); Object_Print(argv[i], stdout);
return 0;
return Object_NewNone(Runtime_GetHeap(runtime), error);
} }
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); assert(argc == 1);
(void) runtime; (void) runtime;
(void) error; (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) runtime;
(void) error; (void) error;
@@ -66,29 +74,37 @@ static Object *bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, E
if(!Object_IsString(argv[0])) if(!Object_IsString(argv[0]))
{ {
Error_Report(error, 0, "Argument #%d is not a string", 1); Error_Report(error, 0, "Argument #%d is not a string", 1);
return NULL; return -1;
} }
const char *string; const char *string;
int n; int n;
string = Object_ToString(argv[0],&n,Runtime_GetHeap(runtime),error); string = Object_ToString(argv[0],&n,Runtime_GetHeap(runtime),error);
if (string == NULL) if (string == NULL)
return NULL; return -1;
if(n == 0) if(n == 0)
{ {
Error_Report(error, 0, "Argument #%d is an empty string", 1); 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); int k = utf8_sequence_to_utf32_codepoint(string,n,&ret);
assert(k >= 0); 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); assert(argc == 1);
@@ -97,7 +113,7 @@ static Object *bin_chr(Runtime *runtime, Object **argv, unsigned int argc, Error
if(!Object_IsInt(argv[0])) if(!Object_IsInt(argv[0]))
{ {
Error_Report(error, 0, "Argument #%d is not an integer", 1); 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); int value = Object_ToInt(argv[0],error);
if(error->occurred) if(error->occurred)
return NULL; return -1;
int k = utf8_sequence_from_utf32_codepoint(buff,sizeof(buff),value); 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) if(k<0)
{ {
Error_Report(error, 0, "Argument #%d is not valid utf-32", 1); 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); assert(argc == 1);
int n = Object_Count(argv[0], error); int n = Object_Count(argv[0], error);
if(error->occurred) 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; (void) argv;
@@ -158,7 +190,7 @@ static Object *bin_input(Runtime *runtime, Object **argv, unsigned int argc, Err
{ {
if(str != maybe) free(str); if(str != maybe) free(str);
Error_Report(error, 1, "No memory"); Error_Report(error, 1, "No memory");
return NULL; return -1;
} }
str = tmp; str = tmp;
@@ -175,23 +207,36 @@ static Object *bin_input(Runtime *runtime, Object **argv, unsigned int argc, Err
if(str != maybe) if(str != maybe)
free(str); 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) for(unsigned int i = 0; i < argc; i += 1)
if(!Object_ToBool(argv[i], error)) if(!Object_ToBool(argv[i], error))
{ {
if(!error->occurred) if(!error->occurred)
Error_Report(error, 0, "Assertion failed"); 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); assert(argc == 1);
int length; 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); string = Object_ToString(argv[0], &length, Runtime_GetHeap(runtime), error);
if(string == NULL) if(string == NULL)
return NULL; return -1;
Error_Report(error, 0, "%s", string); 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; 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])) if(!Object_IsString(argv[i]))
{ {
Error_Report(error, 0, "Argument #%d is not a string", i+1); Error_Report(error, 0, "Argument #%d is not a string", i+1);
return NULL; return -1;
} }
total_count += Object_Count(argv[i], error); total_count += Object_Count(argv[i], error);
if(error->occurred) if(error->occurred)
return NULL; return -1;
} }
char starting[128]; char starting[128];
@@ -234,7 +279,7 @@ static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Er
if(buffer == NULL) if(buffer == NULL)
{ {
Error_Report(error, 1, "No memory"); 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: done:
if(starting != buffer) if(starting != buffer)
free(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); assert(argc == 1);
long long int size = Object_ToInt(argv[0], error); long long int size = Object_ToInt(argv[0], error);
if(error->occurred == 1) 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); assert(argc == 3);
long long int offset = Object_ToInt(argv[1], error); 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); 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); assert(argc == 1);
@@ -298,14 +366,22 @@ static Object *bin_bufferToString(Runtime *runtime, Object **argv, unsigned int
buffaddr = Object_GetBufferAddrAndSize(argv[0], &buffsize, error); buffaddr = Object_GetBufferAddrAndSize(argv[0], &buffsize, error);
if(error->occurred) 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[] = { const StaticMapSlot bins_basic[] = {
{ "math", SM_SMAP, .as_smap = bins_math, }, { "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, }, // { "net", SM_SMAP, .as_smap = bins_net, },
{ "newBuffer", SM_FUNCT, .as_funct = bin_newBuffer, .argc = 1 }, { "newBuffer", SM_FUNCT, .as_funct = bin_newBuffer, .argc = 1 },
+3 -1
View File
@@ -27,7 +27,8 @@
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. | ** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
** +--------------------------------------------------------------------------+ ** +--------------------------------------------------------------------------+
*/ */
#warning "Commented out whole file"
/*
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include "files.h" #include "files.h"
@@ -306,3 +307,4 @@ const StaticMapSlot bins_files[] = {
{ "write", SM_FUNCT, .as_funct = bin_write, .argc = 3, }, { "write", SM_FUNCT, .as_funct = bin_write, .argc = 3, },
{ NULL, SM_END, {}, {} }, { NULL, SM_END, {}, {} },
}; };
*/
+21 -10
View File
@@ -33,7 +33,7 @@
#include "math.h" #include "math.h"
#define WRAP_FUNC(name) \ #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); \ assert(argc == 1); \
\ \
@@ -42,45 +42,56 @@
double v = Object_ToFloat(argv[0], error); \ double v = Object_ToFloat(argv[0], error); \
\ \
if(error->occurred) \ 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 \ else \
{ \ { \
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(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; \
} \ } \
} }
#define WRAP_FUNC_2(name) \ #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); \ assert(argc == 2); \
\ \
if(!Object_IsFloat(argv[0])) \ 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]));\ 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])) \ 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]));\ 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); \ double v1 = Object_ToFloat(argv[0], error); \
\ \
if(error->occurred) \ if(error->occurred) \
return NULL; \ return -1; \
\ \
double v2 = Object_ToFloat(argv[1], error); \ double v2 = Object_ToFloat(argv[1], error); \
\ \
if(error->occurred) \ 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) WRAP_FUNC(ceil)
+7 -7
View File
@@ -90,7 +90,7 @@ static const InstrInfo instr_table[] = {
[OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}}, [OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}},
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}}, [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_SELECT] = {"SELECT", 0, NULL},
[OPCODE_INSERT] = {"INSERT", 0, NULL}, [OPCODE_INSERT] = {"INSERT", 0, NULL},
[OPCODE_INSERT2] = {"INSERT2", 0, NULL}, [OPCODE_INSERT2] = {"INSERT2", 0, NULL},
@@ -105,7 +105,7 @@ static const InstrInfo instr_table[] = {
[OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}},
[OPCODE_PUSHMAP] = {"PUSHMAP", 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_JUMPIFNOTANDPOP] = {"JUMPIFNOTANDPOP", 1, (OperandType[]) {OPTP_INT}},
[OPCODE_JUMPIFANDPOP] = {"JUMPIFANDPOP", 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) 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; return 0;
} }
@@ -371,7 +371,7 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
if(opc != info->opcount) if(opc != info->opcount)
{ {
// ERROR: Too many operands were provided. // ERROR: Too many operands were provided.
Error_Report(error, 0, Error_Report(error, 1,
"Instruction %s expects %d operands, but %d were provided", "Instruction %s expects %d operands, but %d were provided",
info->name, info->opcount, opc); info->name, info->opcount, opc);
return 0; return 0;
@@ -409,13 +409,13 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
if(expected_type == OPTP_STRING) 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; return 0;
} }
if(Promise_Size(opv[i].as_promise) != operand_type_sizes[expected_type]) 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, " "Provided promise has a value size of %d, "
"but since %s %s was expected, the promise " "but since %s %s was expected, the promise "
"size must be %d", "size must be %d",
@@ -429,7 +429,7 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
else if(expected_type != provided_type) else if(expected_type != provided_type)
{ {
// ERROR: Wrong operand type provided. // 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", "Instruction %s expects %s %s as operand %d, but %s %s was provided instead",
info->name, info->name,
operand_type_arts[expected_type], operand_type_arts[expected_type],
+1
View File
@@ -68,6 +68,7 @@ typedef enum {
EXPR_INT, EXPR_INT,
EXPR_MAP, EXPR_MAP,
EXPR_CALL, EXPR_CALL,
EXPR_PAIR,
EXPR_LIST, EXPR_LIST,
EXPR_NONE, EXPR_NONE,
EXPR_TRUE, EXPR_TRUE,
+110 -35
View File
@@ -50,6 +50,8 @@
#include "compile.h" #include "compile.h"
#include "ASTi.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) static Opcode exprkind_to_opcode(ExprKind kind)
{ {
switch(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) static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_dest, Error *error)
{ {
assert(node != NULL); assert(node != NULL);
@@ -86,6 +125,10 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
ExprNode *expr = (ExprNode*) node; ExprNode *expr = (ExprNode*) node;
switch(expr->kind) switch(expr->kind)
{ {
case EXPR_PAIR:
Error_Report(error, 0, "Tuple outside of assignment or return statement");
return 0;
case EXPR_NOT: case EXPR_NOT:
case EXPR_POS: case EXPR_POS:
case EXPR_NEG: case EXPR_NEG:
@@ -123,21 +166,52 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
lop = oper->head; lop = oper->head;
rop = lop->next; rop = lop->next;
ExprNode *tuple[32];
int count = 0;
if(!flatten_tuple_tree((ExprNode*) lop, tuple, sizeof(tuple)/sizeof(tuple[0]), &count, error))
return 0;
assert(count > 0);
if(count == 1) /* No tuple. */
{
if(!emit_instr_for_node(exeb, rop, break_dest, error)) if(!emit_instr_for_node(exeb, rop, break_dest, error))
return 0; return 0;
}
if(((ExprNode*) lop)->kind == EXPR_IDENT) else
{ {
const char *name = ((IdentExprNode*) lop)->val; if(((ExprNode*) rop)->kind == EXPR_CALL)
{
Operand op = { .type = OPTP_STRING, .as_string = name }; if(!emit_instr_for_funccall(exeb, (CallExprNode*) rop, break_dest, count, error))
if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, node->offset, node->length))
return 0; return 0;
} }
else if(((ExprNode*) lop)->kind == EXPR_SELECT) else
{ {
Node *idx = ((IndexSelectionExprNode*) lop)->idx; Error_Report(error, 0, "Assigning to %d variables only 1 value", count);
Node *set = ((IndexSelectionExprNode*) lop)->set; 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)) if(!emit_instr_for_node(exeb, set, break_dest, error))
return 0; return 0;
@@ -145,14 +219,23 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
if(!emit_instr_for_node(exeb, idx, break_dest, error)) if(!emit_instr_for_node(exeb, idx, break_dest, error))
return 0; return 0;
if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, node->offset, node->length)) 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; return 0;
} }
else
if(i+1 < count)
{ {
Error_Report(error, 0, "Assignment left operand can't be assigned to"); Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 };
if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, node->offset, 0))
return 0; return 0;
} }
}
return 1; return 1;
} }
@@ -253,25 +336,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
} }
case EXPR_CALL: case EXPR_CALL:
{ return emit_instr_for_funccall(exeb, (CallExprNode*) expr, break_dest, 1, error);
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);
}
case EXPR_SELECT: case EXPR_SELECT:
{ {
@@ -526,10 +591,18 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
{ {
ReturnNode *ret = (ReturnNode*) node; 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; 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 0;
return 1; return 1;
@@ -608,7 +681,8 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de
// Write a return instruction, just // Write a return instruction, just
// in case it didn't already return. // 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; return 0;
} }
@@ -672,7 +746,8 @@ Executable *compile(AST *ast, BPAlloc *alloc, Error *error)
if(!emit_instr_for_node(exeb, ast->root, NULL, error)) if(!emit_instr_for_node(exeb, ast->root, NULL, error))
return 0; 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); exe = ExeBuilder_Finalize(exeb, error);
+35 -17
View File
@@ -83,6 +83,7 @@ typedef enum {
TLCBRK = '{', TLCBRK = '{',
TRCBRK = '}', TRCBRK = '}',
TDOT = '.', TDOT = '.',
TCOMMA = ',',
TDONE = 256, TDONE = 256,
TINT, TINT,
@@ -126,7 +127,7 @@ typedef struct {
} Context; } Context;
static Node *parse_statement(Context *ctx); 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_expression_statement(Context *ctx);
static Node *parse_ifelse_statement(Context *ctx); static Node *parse_ifelse_statement(Context *ctx);
static Node *parse_compound_statement(Context *ctx, TokenKind end); static Node *parse_compound_statement(Context *ctx, TokenKind end);
@@ -141,7 +142,8 @@ static inline _Bool isoper(char c)
return c == '+' || c == '-' || return c == '+' || c == '-' ||
c == '*' || c == '/' || c == '*' || c == '/' ||
c == '<' || c == '>' || c == '<' || c == '>' ||
c == '!' || c == '='; c == '!' || c == '=' ||
c == ',';
} }
/* Symbol: tokenize /* Symbol: tokenize
@@ -322,6 +324,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
{ TGRT, 1, ">" }, { TGRT, 1, ">" },
{ TGEQ, 2, ">=" }, { TGEQ, 2, ">=" },
{ TASS, 1, "=" }, { TASS, 1, "=" },
{ TCOMMA, 1, "," },
}; };
_Bool found = 0; _Bool found = 0;
@@ -598,11 +601,19 @@ static Node *parse_statement(Context *ctx)
next(ctx); // Consume the "return" keyword. next(ctx); // Consume the "return" keyword.
Node *val = parse_expression_statement(ctx); Node *val = parse_expression(ctx, 1);
if(val == NULL) if(val == NULL)
return 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)); ReturnNode *node = BPAlloc_Malloc(ctx->alloc, sizeof(ReturnNode));
if(node == NULL) if(node == NULL)
@@ -638,7 +649,7 @@ static Node *parse_expression_statement(Context *ctx)
{ {
assert(ctx != NULL); assert(ctx != NULL);
Node *expr = parse_expression(ctx); Node *expr = parse_expression(ctx, 1);
if(expr == NULL) if(expr == NULL)
return NULL; return NULL;
@@ -829,7 +840,7 @@ static Node *parse_list_primary_expression(Context *ctx)
while(1) while(1)
{ {
// Parse. // Parse.
Node *item = parse_expression(ctx); Node *item = parse_expression(ctx, 0);
if(item == NULL) if(item == NULL)
return NULL; return NULL;
@@ -940,7 +951,7 @@ static Node *parse_map_primary_expression(Context *ctx)
} }
else else
{ {
key = parse_expression(ctx); key = parse_expression(ctx, 0);
} }
if(key == NULL) if(key == NULL)
@@ -961,7 +972,7 @@ static Node *parse_map_primary_expression(Context *ctx)
next(ctx); next(ctx);
// Parse. // Parse.
Node *item = parse_expression(ctx); Node *item = parse_expression(ctx, 0);
if(item == NULL) if(item == NULL)
return NULL; return NULL;
@@ -1100,7 +1111,7 @@ static Node *parse_primary_expresion(Context *ctx)
{ {
next(ctx); // Consume the '('. next(ctx); // Consume the '('.
Node *node = parse_expression(ctx); Node *node = parse_expression(ctx, 1);
if(node == NULL) if(node == NULL)
return NULL; return NULL;
@@ -1419,7 +1430,7 @@ static Node *parse_postfix_expression(Context *ctx)
while(1) while(1)
{ {
// Parse. // Parse.
Node *arg = parse_expression(ctx); Node *arg = parse_expression(ctx, 0);
if(arg == NULL) if(arg == NULL)
return NULL; return NULL;
@@ -1552,7 +1563,7 @@ static inline _Bool isbinop(Token *tok)
tok->kind == TLEQ || tok->kind == TGEQ || tok->kind == TLEQ || tok->kind == TGEQ ||
tok->kind == TEQL || tok->kind == TNQL || tok->kind == TEQL || tok->kind == TNQL ||
tok->kind == TKWAND || tok->kind == TKWOR || tok->kind == TKWAND || tok->kind == TKWOR ||
tok->kind == '='; tok->kind == '=' || tok->kind == ',';
} }
static inline _Bool isrightassoc(Token *tok) static inline _Bool isrightassoc(Token *tok)
@@ -1593,6 +1604,9 @@ static inline int precedenceof(Token *tok)
case '/': case '/':
return 5; return 5;
case ',':
return 6;
default: default:
return -100000000; return -100000000;
} }
@@ -1601,12 +1615,15 @@ static inline int precedenceof(Token *tok)
return -100000000; 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) while(isbinop(ctx->token) && precedenceof(ctx->token) >= min_prec)
{ {
Token *op = ctx->token; Token *op = ctx->token;
if(op->kind == ',' && allow_toplev_tuples == 0)
break;
next(ctx); next(ctx);
Node *right_expr = parse_prefix_expression(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)))) 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) if(right_expr == NULL)
return 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 TKWAND: temp->base.kind = EXPR_AND; break;
case TKWOR: temp->base.kind = EXPR_OR; break; case TKWOR: temp->base.kind = EXPR_OR; break;
case '=': temp->base.kind = EXPR_ASS; break; case '=': temp->base.kind = EXPR_ASS; break;
case ',': temp->base.kind = EXPR_PAIR; break;
default: default:
UNREACHABLE; UNREACHABLE;
@@ -1670,7 +1688,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
return left_expr; 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); Node *left_expr = parse_prefix_expression(ctx);
@@ -1680,7 +1698,7 @@ static Node *parse_expression(Context *ctx)
if(done(ctx)) if(done(ctx))
return left_expr; 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) static Node *parse_ifelse_statement(Context *ctx)
@@ -1704,7 +1722,7 @@ static Node *parse_ifelse_statement(Context *ctx)
next(ctx); // Consume the "if" keyword. next(ctx); // Consume the "if" keyword.
Node *condition = parse_expression(ctx); Node *condition = parse_expression(ctx, 1);
if(condition == NULL) if(condition == NULL)
return NULL; return NULL;
@@ -1987,7 +2005,7 @@ static Node *parse_while_statement(Context *ctx)
next(ctx); // Consume the "while" keyword. next(ctx); // Consume the "while" keyword.
Node *condition = parse_expression(ctx); Node *condition = parse_expression(ctx, 1);
if(condition == NULL) if(condition == NULL)
return NULL; return NULL;
@@ -2073,7 +2091,7 @@ static Node *parse_dowhile_statement(Context *ctx)
next(ctx); // Consume the "while" keyword. next(ctx); // Consume the "while" keyword.
Node *condition = parse_expression(ctx); Node *condition = parse_expression(ctx, 1);
if(condition == NULL) if(condition == NULL)
return NULL; return NULL;
+6 -3
View File
@@ -159,12 +159,15 @@ static _Bool interpret(Source *src)
Runtime_SetBuiltins(runt, bins); 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 // NOTE: The pointer to the builtins object is invalidated
// now because it may be moved by the garbage collector. // now because it may be moved by the garbage collector.
if(o == NULL) if(retc < 0)
{ {
print_error("Runtime", (Error*) &error); print_error("Runtime", (Error*) &error);
@@ -179,7 +182,7 @@ static _Bool interpret(Source *src)
Runtime_Free(runt); Runtime_Free(runt);
Executable_Free(exe); Executable_Free(exe);
return o != NULL; return retc > -1;
} }
static _Bool disassemble(Source *src) static _Bool disassemble(Source *src)
+4 -5
View File
@@ -120,10 +120,9 @@ Object *Object_Copy(Object *obj, Heap *heap, Error *err)
return type->copy(obj, heap, 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(err != NULL && obj != NULL);
assert(obj);
const TypeObject *type = Object_GetType(obj); const TypeObject *type = Object_GetType(obj);
assert(type); assert(type);
@@ -131,10 +130,10 @@ Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, E
if(type->call == NULL) if(type->call == NULL)
{ {
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); 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) void Object_Print(Object *obj, FILE *fp)
+2 -2
View File
@@ -70,7 +70,7 @@ struct TypeObject {
_Bool (*free)(Object *self, Error *err); _Bool (*free)(Object *self, Error *err);
int (*hash)(Object *self); int (*hash)(Object *self);
Object* (*copy)(Object *self, Heap *heap, Error *err); Object* (*copy)(Object *self, Heap *heap, Error *err);
Object* (*call)(Object *self, Object **argv, unsigned int argc, 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); void (*print)(Object *self, FILE *fp);
unsigned int (*deepsize)(const Object *self); unsigned int (*deepsize)(const Object *self);
@@ -123,7 +123,7 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err);
void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error); void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error);
int Object_Hash (Object *obj); int Object_Hash (Object *obj);
Object* Object_Copy (Object *obj, Heap *heap, Error *err); 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); void Object_Print (Object *obj, FILE *fp);
Object* Object_Select(Object *coll, Object *key, Heap *heap, Error *err); Object* Object_Select(Object *coll, Object *key, Heap *heap, Error *err);
Object* Object_Delete(Object *coll, Object *key, Heap *heap, Error *err); Object* Object_Delete(Object *coll, Object *key, Heap *heap, Error *err);
+5 -5
View File
@@ -57,7 +57,7 @@ static void walk(Object *self, void (*callback)(Object **referer, void *userp),
callback(&func->closure, 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); 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) if(argv2 == NULL)
{ {
Error_Report(error, 1, "No memory"); Error_Report(error, 1, "No memory");
return NULL; return -1;
} }
// Copy the provided arguments. // 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); argv2[i] = Object_NewNone(heap, error);
if(argv2[i] == NULL) if(argv2[i] == NULL)
return 0; return -1;
} }
} }
else else
// The right amount of arguments was provided. // The right amount of arguments was provided.
argv2 = argv; 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. // NOTE: Every object reference is invalidated from here.
if(argv2 != argv) if(argv2 != argv)
free(argv2); free(argv2);
return result; return retc;
} }
static TypeObject t_func = { static TypeObject t_func = {
+7 -10
View File
@@ -43,11 +43,11 @@
typedef struct { typedef struct {
Object base; Object base;
Runtime *runtime; 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; int argc;
} NativeFunctionObject; } 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(self != NULL);
assert(heap != NULL); assert(heap != NULL);
@@ -87,7 +87,7 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
if(argv2 == NULL) if(argv2 == NULL)
{ {
Error_Report(error, 1, "No memory"); Error_Report(error, 1, "No memory");
return NULL; return -1;
} }
// Copy the provided arguments. // Copy the provided arguments.
@@ -102,27 +102,24 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
if(argv2[i] == NULL) if(argv2[i] == NULL)
{ {
free(argv2); free(argv2);
return NULL; return -1;
} }
} }
} }
else UNREACHABLE; else UNREACHABLE;
assert(func->callback != NULL); 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 // NOTE: Since the callback may have executed some bytecode, a GC
// cycle may have been triggered, therefore we must assume // cycle may have been triggered, therefore we must assume
// every object reference that was locally saved is invalidated // every object reference that was locally saved is invalidated
// from here (the returned object is good tho). // 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) if(argv2 != argv)
free(argv2); free(argv2);
return result; return retc;
} }
static TypeObject t_nfunc = { static TypeObject t_nfunc = {
@@ -156,7 +153,7 @@ static TypeObject t_nfunc = {
* The newly created object. If an error occurred, NULL is returned * The newly created object. If an error occurred, NULL is returned
* and information about the error is stored in the [error] argument. * 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); assert(callback != NULL);
+42 -27
View File
@@ -805,11 +805,13 @@ static _Bool step(Runtime *runtime, Error *error)
case OPCODE_CALL: case OPCODE_CALL:
{ {
assert(opc == 1); assert(opc == 2);
assert(ops[0].type == OPTP_INT); assert(ops[0].type == OPTP_INT);
assert(ops[1].type == OPTP_INT);
int argc = ops[0].as_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) if(runtime->frame->used < argc + 1)
{ {
@@ -839,19 +841,32 @@ static _Bool step(Runtime *runtime, Error *error)
(void) Runtime_Pop(runtime, error, argc+1); (void) Runtime_Pop(runtime, error, argc+1);
assert(error->occurred == 0); assert(error->occurred == 0);
Object *obj = Object_Call(callable, argv, argc, runtime->heap, error); Object *rets[8];
// NOTE: Every local object reference is invalidated from here. unsigned int maxrets = sizeof(rets)/sizeof(rets[0]);
if(obj == NULL) int num_rets = Object_Call(callable, argv, argc, rets, maxrets, runtime->heap, error);
{
assert(error->occurred != 0); if(num_rets < 0)
return 0; return 0;
}
// NOTE: Every local object reference is invalidated from here.
assert(error->occurred == 0); assert(error->occurred == 0);
if(!Runtime_Push(runtime, error, obj)) for(int g = 0; g < MIN(num_rets, retc); g += 1)
if(!Runtime_Push(runtime, error, rets[g]))
return 0; 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; return 1;
} }
@@ -1126,7 +1141,14 @@ static _Bool step(Runtime *runtime, Error *error)
} }
case OPCODE_RETURN: case OPCODE_RETURN:
{
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; return 0;
}
case OPCODE_JUMP: case OPCODE_JUMP:
assert(opc == 1); assert(opc == 1);
@@ -1233,7 +1255,7 @@ static _Bool collect(Runtime *runtime, Error *error)
return Heap_StopCollection(runtime->heap); 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(runtime != NULL);
assert(error != NULL); assert(error != NULL);
@@ -1244,7 +1266,7 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
if(runtime->depth == MAX_FRAMES) if(runtime->depth == MAX_FRAMES)
{ {
Error_Report(error, 1, "Maximum nested call limit of %d was reached", 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); assert(runtime->depth < MAX_FRAMES);
@@ -1260,12 +1282,12 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *
frame.used = 0; frame.used = 0;
if(frame.locals == NULL) if(frame.locals == NULL)
return NULL; return -1;
if(frame.exe == NULL) if(frame.exe == NULL)
{ {
Error_Report(error, 1, "Failed to copy executable"); Error_Report(error, 1, "Failed to copy executable");
return NULL; return -1;
} }
// Add the frame to the runtime. // 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. // This is what the function will return.
Object *result = NULL; int retc = -1;
// Push the initial values of the frame. // Push the initial values of the frame.
for(int i = 0; i < argc; i += 1) 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 an error occurred, we want to return NULL.
if(error->occurred == 0) if(error->occurred == 0)
{ {
// If the step function left something retc = MIN(frame.used, maxretc);
// on the stack, we return that. If it
// didn't, we return some other default for(int i = 0; i < retc; i += 1)
// value like "none".
if(frame.used == 0)
{ {
// Nothing to return on the stack. Set to none. rets[i] = Stack_Top(runtime->stack, i - retc + 1);
result = Object_NewNone(runtime->heap, error); assert(rets[i] != NULL);
}
else
{
result = Stack_Top(runtime->stack, 0);
assert(result != NULL);
} }
} }
@@ -1348,5 +1363,5 @@ cleanup:
Executable_Free(frame.exe); Executable_Free(frame.exe);
} }
return result; return retc;
} }
+3 -4
View File
@@ -54,7 +54,7 @@ Executable *Runtime_GetCurrentExecutable(Runtime *runtime);
Snapshot *Snapshot_New(Runtime *runtime); Snapshot *Snapshot_New(Runtime *runtime);
void Snapshot_Free(Snapshot *snapshot); void Snapshot_Free(Snapshot *snapshot);
void Snapshot_Print(Snapshot *snapshot, FILE *fp); 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 { typedef enum {
SM_END, SM_END,
@@ -79,7 +79,7 @@ struct StaticMapSlot {
_Bool as_bool; _Bool as_bool;
long long int as_int; long long int as_int;
double as_float; 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; TypeObject *as_type;
}; };
union { int argc; int length; }; union { int argc; int length; };
@@ -87,8 +87,7 @@ struct StaticMapSlot {
Object *Object_NewStaticMap(const StaticMapSlot *slots, Runtime *runt, Error *error); 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_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 { typedef struct {
Error base; Error base;
Runtime *runtime; Runtime *runtime;