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
+120 -44
View File
@@ -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 },
+4 -2
View File
@@ -27,7 +27,8 @@
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
** +--------------------------------------------------------------------------+
*/
#warning "Commented out whole file"
/*
#include <assert.h>
#include <errno.h>
#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, {}, {} },
};
};
*/
+21 -10
View File
@@ -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)
+7 -7
View File
@@ -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],
+1
View File
@@ -68,6 +68,7 @@ typedef enum {
EXPR_INT,
EXPR_MAP,
EXPR_CALL,
EXPR_PAIR,
EXPR_LIST,
EXPR_NONE,
EXPR_TRUE,
+120 -45
View File
@@ -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);
+46 -28
View File
@@ -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;
+6 -3
View File
@@ -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)
+4 -5
View File
@@ -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)
+7 -7
View File
@@ -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);
+5 -5
View File
@@ -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 = {
+7 -10
View File
@@ -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);
+46 -31
View File
@@ -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;
}
+3 -4
View File
@@ -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;