added parsing ad compilation of function declarations
This commit is contained in:
@@ -76,6 +76,7 @@ gcc src/main.c src/debug.c \
|
|||||||
temp/objects/o_string.o \
|
temp/objects/o_string.o \
|
||||||
temp/runtime/runtime.o \
|
temp/runtime/runtime.o \
|
||||||
temp/runtime/runtime_error.o \
|
temp/runtime/runtime_error.o \
|
||||||
|
temp/runtime/o_func.o \
|
||||||
temp/common/executable.o \
|
temp/common/executable.o \
|
||||||
-o build/noja $FLAGS -Lbuild/ -lnoja-compile -lnoja-objects -lxjson
|
-o build/noja $FLAGS -Lbuild/ -lnoja-compile -lnoja-objects -lxjson
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
fun hello()
|
||||||
|
{
|
||||||
|
print;('hello');
|
||||||
|
}
|
||||||
|
|
||||||
|
return hello;
|
||||||
@@ -57,6 +57,7 @@ static const InstrInfo instr_table[] = {
|
|||||||
[OPCODE_PUSHTRU] = {"PUSHTRU", 0, NULL},
|
[OPCODE_PUSHTRU] = {"PUSHTRU", 0, NULL},
|
||||||
[OPCODE_PUSHFLS] = {"PUSHFLS", 0, NULL},
|
[OPCODE_PUSHFLS] = {"PUSHFLS", 0, NULL},
|
||||||
[OPCODE_PUSHNNE] = {"PUSHNNE", 0, NULL},
|
[OPCODE_PUSHNNE] = {"PUSHNNE", 0, NULL},
|
||||||
|
[OPCODE_PUSHFUN] = {"PUSHFUN", 2, (OperandType[]) {OPTP_INT, OPTP_INT}},
|
||||||
|
|
||||||
[OPCODE_RETURN] = {"RETURN", 0, NULL},
|
[OPCODE_RETURN] = {"RETURN", 0, NULL},
|
||||||
|
|
||||||
@@ -319,7 +320,7 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
|
|||||||
// ERROR: Too many operands were provided.
|
// ERROR: Too many operands were provided.
|
||||||
Error_Report(error, 0,
|
Error_Report(error, 0,
|
||||||
"Instruction %s expects %d operands, but %d were provided",
|
"Instruction %s expects %d operands, but %d were provided",
|
||||||
info->name, opc, info->opcount);
|
info->name, info->opcount, opc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ typedef enum {
|
|||||||
OPCODE_PUSHTRU,
|
OPCODE_PUSHTRU,
|
||||||
OPCODE_PUSHFLS,
|
OPCODE_PUSHFLS,
|
||||||
OPCODE_PUSHNNE,
|
OPCODE_PUSHNNE,
|
||||||
|
OPCODE_PUSHFUN,
|
||||||
OPCODE_RETURN,
|
OPCODE_RETURN,
|
||||||
OPCODE_JUMPIFNOTANDPOP,
|
OPCODE_JUMPIFNOTANDPOP,
|
||||||
OPCODE_JUMP,
|
OPCODE_JUMP,
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ typedef enum {
|
|||||||
NODE_IFELSE,
|
NODE_IFELSE,
|
||||||
NODE_COMP,
|
NODE_COMP,
|
||||||
NODE_RETURN,
|
NODE_RETURN,
|
||||||
|
NODE_FUNC,
|
||||||
|
NODE_ARG,
|
||||||
} NodeKind;
|
} NodeKind;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -93,4 +95,17 @@ typedef struct {
|
|||||||
Node base;
|
Node base;
|
||||||
Node *val;
|
Node *val;
|
||||||
} ReturnNode;
|
} ReturnNode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Node base;
|
||||||
|
char *name;
|
||||||
|
Node *argv;
|
||||||
|
int argc;
|
||||||
|
Node *body;
|
||||||
|
} FunctionNode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Node base;
|
||||||
|
char *name;
|
||||||
|
} ArgumentNode;
|
||||||
#endif
|
#endif
|
||||||
@@ -241,6 +241,86 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case NODE_FUNC:
|
||||||
|
{
|
||||||
|
FunctionNode *func = (FunctionNode*) node;
|
||||||
|
|
||||||
|
Promise *func_index = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int));
|
||||||
|
Promise *jump_index = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int));
|
||||||
|
|
||||||
|
if(func_index == NULL || jump_index == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "No memory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push function.
|
||||||
|
{
|
||||||
|
Operand ops[2] = {
|
||||||
|
{ .type = OPTP_PROMISE, .as_promise = func_index },
|
||||||
|
{ .type = OPTP_INT, .as_int = func->argc },
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHFUN, ops, 2, func->base.offset, func->base.length))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign variable.
|
||||||
|
Operand op = (Operand) { .type = OPTP_STRING, .as_string = func->name };
|
||||||
|
if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, func->base.offset, func->base.length))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Pop function object.
|
||||||
|
op = (Operand) { .type = OPTP_INT, .as_int = 1 };
|
||||||
|
if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, func->base.offset, func->base.length))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Jump after the function code.
|
||||||
|
op = (Operand) { .type = OPTP_PROMISE, .as_promise = jump_index };
|
||||||
|
if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, func->base.offset, func->base.length))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// This is the function code index.
|
||||||
|
long long int temp = ExeBuilder_InstrCount(exeb);
|
||||||
|
Promise_Resolve(func_index, &temp, sizeof(temp));
|
||||||
|
|
||||||
|
// Compile the function body.
|
||||||
|
{
|
||||||
|
// Assign the arguments.
|
||||||
|
|
||||||
|
if(func->argv)
|
||||||
|
assert(func->argv->kind == NODE_ARG);
|
||||||
|
|
||||||
|
ArgumentNode *arg = (ArgumentNode*) func->argv;
|
||||||
|
|
||||||
|
while(arg)
|
||||||
|
{
|
||||||
|
op = (Operand) { .type = OPTP_STRING, .as_string = arg->name };
|
||||||
|
if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, arg->base.offset, arg->base.length))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
op = (Operand) { .type = OPTP_INT, .as_int = 1 };
|
||||||
|
if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, arg->base.offset, arg->base.length))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
assert(arg->base.next->kind == NODE_ARG);
|
||||||
|
|
||||||
|
arg = (ArgumentNode*) arg->base.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!emit_instr_for_node(exeb, func->body, error))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the first index after the function code.
|
||||||
|
temp = ExeBuilder_InstrCount(exeb);
|
||||||
|
Promise_Resolve(jump_index, &temp, sizeof(temp));
|
||||||
|
|
||||||
|
Promise_Free(func_index);
|
||||||
|
Promise_Free(jump_index);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
+180
-12
@@ -25,6 +25,7 @@ typedef enum {
|
|||||||
TIDENT,
|
TIDENT,
|
||||||
|
|
||||||
TKWIF,
|
TKWIF,
|
||||||
|
TKWFUN,
|
||||||
TKWELSE,
|
TKWELSE,
|
||||||
TKWNONE,
|
TKWNONE,
|
||||||
TKWTRUE,
|
TKWTRUE,
|
||||||
@@ -51,6 +52,7 @@ static Node *parse_expression(Context *ctx);
|
|||||||
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);
|
||||||
|
static Node *parse_function_definition(Context *ctx);
|
||||||
|
|
||||||
static inline _Bool isoper(char c)
|
static inline _Bool isoper(char c)
|
||||||
{
|
{
|
||||||
@@ -125,6 +127,10 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error)
|
|||||||
{
|
{
|
||||||
tok->kind = TKWIF;
|
tok->kind = TKWIF;
|
||||||
}
|
}
|
||||||
|
else if(matchstr(str + tok->offset, tok->length, "fun"))
|
||||||
|
{
|
||||||
|
tok->kind = TKWFUN;
|
||||||
|
}
|
||||||
else if(matchstr(str + tok->offset, tok->length, "else"))
|
else if(matchstr(str + tok->offset, tok->length, "else"))
|
||||||
{
|
{
|
||||||
tok->kind = TKWELSE;
|
tok->kind = TKWELSE;
|
||||||
@@ -397,6 +403,9 @@ static Node *parse_statement(Context *ctx)
|
|||||||
node->val = val;
|
node->val = val;
|
||||||
return (Node*) node;
|
return (Node*) node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case TKWFUN:
|
||||||
|
return parse_function_definition(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error_Report(ctx->error, 0, "Got token \"%.*s\" where the start of a statement was expected",
|
Error_Report(ctx->error, 0, "Got token \"%.*s\" where the start of a statement was expected",
|
||||||
@@ -551,6 +560,20 @@ static Node *parse_string_primary_expression(Context *ctx)
|
|||||||
return (Node*) node;
|
return (Node*) node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *copy_token_text(Context *ctx)
|
||||||
|
{
|
||||||
|
char *copy = BPAlloc_Malloc(ctx->alloc, ctx->token->length + 1);
|
||||||
|
|
||||||
|
if(copy == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(copy, ctx->src + ctx->token->offset, ctx->token->length);
|
||||||
|
|
||||||
|
copy[ctx->token->length] = '\0';
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
static Node *parse_primary_expresion(Context *ctx)
|
static Node *parse_primary_expresion(Context *ctx)
|
||||||
{
|
{
|
||||||
assert(ctx != NULL);
|
assert(ctx != NULL);
|
||||||
@@ -789,11 +812,8 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
case TIDENT:
|
case TIDENT:
|
||||||
{
|
{
|
||||||
char *copy;
|
char *copy = copy_token_text(ctx);
|
||||||
int copyl;
|
int copyl = ctx->token->length;
|
||||||
|
|
||||||
{
|
|
||||||
copy = BPAlloc_Malloc(ctx->alloc, ctx->token->length + 1);
|
|
||||||
|
|
||||||
if(copy == NULL)
|
if(copy == NULL)
|
||||||
{
|
{
|
||||||
@@ -801,12 +821,6 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
copyl = ctx->token->length;
|
|
||||||
memcpy(copy, ctx->src + ctx->token->offset, copyl);
|
|
||||||
copy[copyl] = '\0';
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
IdentExprNode *node;
|
IdentExprNode *node;
|
||||||
{
|
{
|
||||||
node = BPAlloc_Malloc(ctx->alloc, sizeof(IdentExprNode));
|
node = BPAlloc_Malloc(ctx->alloc, sizeof(IdentExprNode));
|
||||||
@@ -966,7 +980,6 @@ static Node *parse_expression(Context *ctx)
|
|||||||
static Node *parse_ifelse_statement(Context *ctx)
|
static Node *parse_ifelse_statement(Context *ctx)
|
||||||
{
|
{
|
||||||
assert(ctx != NULL);
|
assert(ctx != NULL);
|
||||||
assert(ctx->token != NULL);
|
|
||||||
|
|
||||||
if(done(ctx))
|
if(done(ctx))
|
||||||
{
|
{
|
||||||
@@ -1077,3 +1090,158 @@ static Node *parse_compound_statement(Context *ctx, TokenKind end)
|
|||||||
|
|
||||||
return (Node*) node;
|
return (Node*) node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Node *parse_function_definition(Context *ctx)
|
||||||
|
{
|
||||||
|
assert(ctx != NULL);
|
||||||
|
|
||||||
|
if(done(ctx))
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 0, "Source ended where a function definition was expected");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current(ctx) != TKWFUN)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function definition was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = current_token(ctx)->offset;
|
||||||
|
|
||||||
|
if(next(ctx) != TIDENT)
|
||||||
|
{
|
||||||
|
if(done(ctx))
|
||||||
|
Error_Report(ctx->error, 0, "Source ended where an identifier was expected as function name");
|
||||||
|
else
|
||||||
|
Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where an identifier was expected as function name", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *name = copy_token_text(ctx);
|
||||||
|
|
||||||
|
if(name == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(next(ctx) != '(')
|
||||||
|
{
|
||||||
|
if(done(ctx))
|
||||||
|
Error_Report(ctx->error, 0, "Source ended where a function argument list was expected");
|
||||||
|
else
|
||||||
|
Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function argument list was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *argv = NULL;
|
||||||
|
int argc = 0;
|
||||||
|
|
||||||
|
if(next(ctx) != ')')
|
||||||
|
{
|
||||||
|
// Parse arguments.
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
if(done(ctx))
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 0, "Source ended inside a function argument list");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current(ctx) != TIDENT)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function argument name was expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *arg_name = copy_token_text(ctx);
|
||||||
|
|
||||||
|
if(arg_name == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgumentNode *arg;
|
||||||
|
{
|
||||||
|
// Make argument node.
|
||||||
|
arg = BPAlloc_Malloc(ctx->alloc, sizeof(ArgumentNode));
|
||||||
|
|
||||||
|
if(arg == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg->base.kind = NODE_ARG;
|
||||||
|
arg->base.next = NULL;
|
||||||
|
arg->base.offset = current_token(ctx)->offset;
|
||||||
|
arg->base.length = current_token(ctx)->length;
|
||||||
|
arg->name = arg_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add it to the list.
|
||||||
|
argc += 1;
|
||||||
|
arg->base.next = argv;
|
||||||
|
argv = (Node*) arg;
|
||||||
|
|
||||||
|
// Get either ',' or ')'.
|
||||||
|
|
||||||
|
if(next(ctx) == ')')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(done(ctx))
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 0, "Source ended inside a function argument list");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(current(ctx) != ',')
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where inside function argument list, where either ',' or ')' were expected", ctx->token->length, ctx->src + ctx->token->offset);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now prepare for the next identifier.
|
||||||
|
next(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next(ctx); // Consume the ')'.
|
||||||
|
|
||||||
|
if(done(ctx))
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 0, "Source ended before function body");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *body = parse_statement(ctx);
|
||||||
|
|
||||||
|
if(body == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
FunctionNode *func;
|
||||||
|
{
|
||||||
|
// Make argument node.
|
||||||
|
func = BPAlloc_Malloc(ctx->alloc, sizeof(FunctionNode));
|
||||||
|
|
||||||
|
if(func == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(ctx->error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
func->base.kind = NODE_FUNC;
|
||||||
|
func->base.next = NULL;
|
||||||
|
func->base.offset = offset;
|
||||||
|
func->base.length = body->offset + body->length - offset;
|
||||||
|
func->name = name;
|
||||||
|
func->argv = argv;
|
||||||
|
func->argc = argc;
|
||||||
|
func->body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Node*) func;
|
||||||
|
}
|
||||||
+54
-3
@@ -1,4 +1,5 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "../utils/defs.h"
|
#include "../utils/defs.h"
|
||||||
#include "../objects/objects.h"
|
#include "../objects/objects.h"
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
@@ -7,7 +8,7 @@ typedef struct {
|
|||||||
Object base;
|
Object base;
|
||||||
Runtime *runtime;
|
Runtime *runtime;
|
||||||
Executable *exe;
|
Executable *exe;
|
||||||
int index;
|
int index, argc;
|
||||||
} FunctionObject;
|
} FunctionObject;
|
||||||
|
|
||||||
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error);
|
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error);
|
||||||
@@ -28,16 +29,64 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
|
|||||||
FunctionObject *func = (FunctionObject*) self;
|
FunctionObject *func = (FunctionObject*) self;
|
||||||
|
|
||||||
assert(func->exe != NULL);
|
assert(func->exe != NULL);
|
||||||
|
assert(func->argc >= 0);
|
||||||
assert(func->index >= 0);
|
assert(func->index >= 0);
|
||||||
|
|
||||||
return run(func->runtime, error, func->exe, func->index, argv, argc);
|
// Make sure the right amount of arguments is provided.
|
||||||
|
|
||||||
|
Object **argv2;
|
||||||
|
|
||||||
|
int expected_argc = func->argc;
|
||||||
|
|
||||||
|
if(expected_argc < (int) argc)
|
||||||
|
{
|
||||||
|
// Nothing to be done. By using
|
||||||
|
// the right argc the additional
|
||||||
|
// arguments are ignored implicitly.
|
||||||
|
argv2 = argv;
|
||||||
|
}
|
||||||
|
else if(expected_argc > (int) argc)
|
||||||
|
{
|
||||||
|
// Some arguments are missing.
|
||||||
|
argv2 = malloc(sizeof(Object*) * expected_argc);
|
||||||
|
|
||||||
|
if(argv2 == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the provided arguments.
|
||||||
|
for(int i = 0; i < (int) argc; i += 1)
|
||||||
|
argv2[i] = argv[i];
|
||||||
|
|
||||||
|
// Set the unspecified arguments to none.
|
||||||
|
for(int i = argc; i < expected_argc; i += 1)
|
||||||
|
{
|
||||||
|
argv2[i] = Object_NewNone(heap, error);
|
||||||
|
|
||||||
|
if(argv2[i] == NULL)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// The right amount of arguments was provided.
|
||||||
|
argv2 = argv;
|
||||||
|
|
||||||
|
Object *result = run(func->runtime, error, func->exe, func->index, argv2, expected_argc);
|
||||||
|
|
||||||
|
if(argv2 != argv)
|
||||||
|
free(argv2);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, Heap *heap, Error *error)
|
Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Heap *heap, Error *error)
|
||||||
{
|
{
|
||||||
assert(runtime != NULL);
|
assert(runtime != NULL);
|
||||||
assert(exe != NULL);
|
assert(exe != NULL);
|
||||||
assert(index >= 0);
|
assert(index >= 0);
|
||||||
|
assert(argc >= 0);
|
||||||
assert(heap != NULL);
|
assert(heap != NULL);
|
||||||
assert(error != NULL);
|
assert(error != NULL);
|
||||||
|
|
||||||
@@ -57,5 +106,7 @@ Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, He
|
|||||||
func->runtime = runtime;
|
func->runtime = runtime;
|
||||||
func->exe = exe_copy;
|
func->exe = exe_copy;
|
||||||
func->index = index;
|
func->index = index;
|
||||||
|
func->argc = argc;
|
||||||
|
|
||||||
return (Object*) func;
|
return (Object*) func;
|
||||||
}
|
}
|
||||||
@@ -531,6 +531,22 @@ static _Bool step(Runtime *runtime, Error *error)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OPCODE_PUSHFUN:
|
||||||
|
{
|
||||||
|
assert(opc == 2);
|
||||||
|
assert(ops[0].type == OPTP_INT);
|
||||||
|
assert(ops[1].type == OPTP_INT);
|
||||||
|
|
||||||
|
Object *obj = Object_FromNojaFunction(runtime, runtime->frame->exe, ops[0].as_int, ops[1].as_int, runtime->heap, error);
|
||||||
|
|
||||||
|
if(obj == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if(!Runtime_Push(runtime, error, obj))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
case OPCODE_RETURN:
|
case OPCODE_RETURN:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -20,5 +20,5 @@ void Snapshot_Print(Snapshot *snapshot, FILE *fp);
|
|||||||
|
|
||||||
Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object **argv, int argc);
|
Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object **argv, int argc);
|
||||||
|
|
||||||
Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int offset, Heap *heap, Error *error);
|
Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Heap *heap, Error *error);
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user