From 583e0b431a6581206368968d56287a858d53b10a Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Tue, 26 Oct 2021 13:34:44 +0200 Subject: Add initial parameter support for function calls --- src/bytecode/chunk.c | 3 +- src/bytecode/chunk.h | 6 ++++ src/bytecode/compiler.h | 83 ++++++++++++++++++++++++++++++++++++++----------- src/bytecode/debug.h | 6 ++++ src/bytecode/ops.h | 1 + src/bytecode/vm.h | 18 +++++++++-- 6 files changed, 95 insertions(+), 22 deletions(-) (limited to 'src/bytecode') diff --git a/src/bytecode/chunk.c b/src/bytecode/chunk.c index 8b87d0d..e566e78 100644 --- a/src/bytecode/chunk.c +++ b/src/bytecode/chunk.c @@ -9,6 +9,7 @@ chunk_init(StringView name) { array_init(chunk->lines, 0); array_init(chunk->name, name.n); array_insert(chunk->name, name.start, name.n); + array_init(chunk->params, 0); return chunk; } @@ -22,6 +23,7 @@ chunk_free(Chunk *chunk) { array_free(chunk->constants); array_free(chunk->lines); array_free(chunk->name); + array_free(chunk->params); free(chunk); } @@ -43,4 +45,3 @@ add_constant(Chunk *chunk, Object obj) { array_push(chunk->constants, obj); return pos; } - diff --git a/src/bytecode/chunk.h b/src/bytecode/chunk.h index 1e88ea0..a3e02d1 100755 --- a/src/bytecode/chunk.h +++ b/src/bytecode/chunk.h @@ -12,10 +12,16 @@ typedef struct LineInfo { } LineInfo; typedef struct Chunk { + // Program code. u8 *code; + // Compile time constants. Object *constants; + // Contains debugging information for every code operation. LineInfo *lines; + // Chunk name. char *name; + // Parameters + StringView *params; } Chunk; #define NEW_CHUNK(NAME) chunk_init((StringView){(NAME), sizeof(NAME)}) diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h index e20b4f1..9389ab4 100755 --- a/src/bytecode/compiler.h +++ b/src/bytecode/compiler.h @@ -106,9 +106,6 @@ compile_list_binary_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { break; } parse_tree(chunk, compiler); - if (tok.type == TOKEN_SYMBOL) { - add_code(chunk, OP_GET, tok.line, tok.column); - } n++; } emit_constant(chunk, start, FIXNUM_VAL(n)); @@ -142,9 +139,6 @@ compile_list_unary_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { return; } parse_tree(chunk, compiler); - if (tok.type == TOKEN_SYMBOL) { - add_code(chunk, OP_GET, tok.line, tok.column); - } add_code(chunk, op, start.line, start.column); n++; if (n > 1) { @@ -231,9 +225,6 @@ compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { return; } parse_tree(chunk, compiler); - if (expr.type == TOKEN_SYMBOL) { - add_code(chunk, OP_GET, expr.line, expr.column); - } if (peek_token(compiler).type != TOKEN_RPAREN) { error_push((Error){ .type = ERR_TYPE_COMPILER, @@ -250,8 +241,44 @@ compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { void compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) { Object fun = make_lambda(name); - // FIXME: skipping arguments for now. Assuming nil. - next_token(compiler); + + // Prepeare parameters. + Token tok = next_token(compiler); + if (tok.type == TOKEN_LPAREN){ + while (has_next_token(compiler)) { + Token tok = next_token(compiler); + if (tok.type == TOKEN_EOF) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_UNBALANCED_PAREN, + .line = start.line, + .col = start.column, + }); + return; + } + if (tok.type == TOKEN_RPAREN) { + break; + } + if (tok.type != TOKEN_SYMBOL) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_WRONG_ARG_TYPE, + .line = tok.line, + .col = tok.column, + }); + return; + } + array_push(fun.chunk->params, tok.value); + } + } else if (tok.type != TOKEN_NIL) { + error_push((Error){ + .type = ERR_TYPE_COMPILER, + .value = ERR_WRONG_ARG_TYPE, + .line = tok.line, + .col = tok.column, + }); + return; + } // Compile body. while (has_next_token(compiler)) { @@ -297,6 +324,7 @@ compile_call_op(Chunk *chunk, Compiler *compiler, Token start, Token name) { // FIXME: skipping arguments for now. Assuming nil. // Compile body. + size_t n = 0; while (has_next_token(compiler)) { Token tok = peek_token(compiler); if (tok.type == TOKEN_EOF) { @@ -312,6 +340,7 @@ compile_call_op(Chunk *chunk, Compiler *compiler, Token start, Token name) { next_token(compiler); break; } + parse_tree(chunk, compiler); } if (name.type == TOKEN_SYMBOL) { Object obj = make_symbol(name.value); @@ -471,8 +500,24 @@ parse_tree(Chunk *chunk, Compiler *compiler) { return; } break; case TOKEN_SYMBOL: { - Object obj = make_symbol(tok.value); - emit_constant(chunk, tok, obj); + bool found = false; + size_t idx = 0; + // NOTE: This is dumb and potentially slow. + for (size_t i = 0; i < array_size(chunk->params); i++) { + if (sv_equal(&tok.value, &chunk->params[i])) { + found = true; + idx = i; + break; + } + } + if (!found) { + Object obj = make_symbol(tok.value); + emit_constant(chunk, tok, obj); + return; + } + + add_code(chunk, OP_LOCAL, tok.line, tok.column); + add_code(chunk, idx, tok.line, tok.column); return; } break; case TOKEN_NIL: { @@ -500,14 +545,16 @@ compile(Token *tokens) { .tokens = tokens, .current = 0, }; - Token start_tok = peek_token(&compiler); - while (has_next_token(&compiler) && peek_token(&compiler).type != TOKEN_EOF) { + Token main_start = peek_token(&compiler); + while (has_next_token(&compiler)) { + Token start = peek_token(&compiler); parse_tree(chunk, &compiler); - if (peek_token(&compiler).type != TOKEN_EOF) { - add_code(chunk, OP_DROP, start_tok.line, start_tok.column); + if (peek_token(&compiler).type == TOKEN_EOF) { + break; } + add_code(chunk, OP_DROP, start.line, start.column); } - add_code(chunk, OP_RETURN, start_tok.line, start_tok.column); + add_code(chunk, OP_RETURN, main_start.line, main_start.column); return chunk; } diff --git a/src/bytecode/debug.h b/src/bytecode/debug.h index 8c4a2eb..06d48b0 100755 --- a/src/bytecode/debug.h +++ b/src/bytecode/debug.h @@ -10,6 +10,7 @@ size_t disassemble_instruction(Chunk *chunk, size_t offset); static const char* ops_str[] = { // Load/store ops. [OP_CONSTANT] = "OP_CONSTANT", + [OP_LOCAL] = "OP_LOCAL", [OP_DEF] = "OP_DEF", [OP_SET] = "OP_SET", [OP_GET] = "OP_GET", @@ -74,6 +75,11 @@ disassemble_instruction(Chunk *chunk, size_t offset) { } u8 instruction = chunk->code[offset]; switch (instruction) { + case OP_LOCAL: { + u8 local = chunk->code[offset + 1]; + printf("%-16s %4d\n", ops_str[instruction], local); + return offset + 2; + } break; case OP_CONSTANT: { u8 constant = chunk->code[offset + 1]; printf("%-16s %4d -> ", ops_str[instruction], constant); diff --git a/src/bytecode/ops.h b/src/bytecode/ops.h index 7a43b91..501a37f 100755 --- a/src/bytecode/ops.h +++ b/src/bytecode/ops.h @@ -4,6 +4,7 @@ typedef enum Ops { // Load/store ops. OP_CONSTANT, + OP_LOCAL, OP_DEF, OP_SET, OP_GET, diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h index 0ce6dec..98c94fa 100755 --- a/src/bytecode/vm.h +++ b/src/bytecode/vm.h @@ -19,6 +19,8 @@ typedef struct CallFrame { // Object *locals; // Return counter. u8 *rp; + // Starting point of the locals for this procedure. + size_t stack_offset; } CallFrame; typedef struct VM { @@ -149,8 +151,7 @@ vm_interpret(VM *vm) { return; } - u8 *last = frame->chunk->code + array_size(frame->chunk->code); - while (vm->pc < last) { + while (true) { #ifdef DEBUG_TRACE_EXECUTION printf("stack: [ "); for (size_t i = 0; i < array_size(vm->stack); i++) { @@ -164,6 +165,10 @@ vm_interpret(VM *vm) { #endif u8 instruction = *vm->pc++; switch (instruction) { + case OP_LOCAL: { + u8 local = *vm->pc++; + array_push(vm->stack, vm->stack[frame->stack_offset + local]); + } break; case OP_CONSTANT: { u8 constant = *vm->pc++; Object obj = frame->chunk->constants[constant]; @@ -256,7 +261,11 @@ vm_interpret(VM *vm) { } break; case OP_CALL: { Object proc = array_pop(vm->stack); - CallFrame new_frame = (CallFrame){proc.chunk, vm->pc}; + CallFrame new_frame = (CallFrame){ + .chunk = proc.chunk, + .rp = vm->pc, + .stack_offset = array_size(vm->stack) - array_size(proc.chunk->params), + }; array_push(vm->frames, new_frame); frame = &vm->frames[array_size(vm->frames) - 1]; vm->pc = frame->chunk->code; @@ -272,6 +281,9 @@ vm_interpret(VM *vm) { } vm->pc = frame->rp; array_head(vm->frames)->size--; + Object ret = array_pop(vm->stack); + array_head(vm->stack)->size = frame->stack_offset; + array_push(vm->stack, ret); frame = &vm->frames[array_size(vm->frames) - 1]; } break; case OP_DROP: { -- cgit v1.2.1