diff --git a/example.ls b/example.ls index 82cfa77..e4225a4 100644 --- a/example.ls +++ b/example.ls @@ -1,3 +1,4 @@ +/* func fib(n number) number { if (n == 0 || n == 1) { return n @@ -7,6 +8,30 @@ func fib(n number) number { } n := fib(8); +*/ -n -log +n := 2 + +if n == 0 { + g := 2 + + g + log + + f := 13 + + f + log +} else { + z := 100 + + z + log +} + +if n == 2 { + t := 33 + + t + log +} diff --git a/src/ast.cpp b/src/ast.cpp index dd19a14..6812224 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -138,6 +138,7 @@ struct ASTNode_If { ASTNode* condition; ASTNode* block; + ASTNode* elseBlock; }; struct Parameter { @@ -354,6 +355,26 @@ ASTNode ast_makeIf(ASTNode condition, ASTNode block) { node.cIf.block = (ASTNode*) malloc(sizeof(block)); *node.cIf.block = block; + node.cIf.elseBlock = 0; + + return node; +} + +ASTNode ast_makeIf(ASTNode condition, ASTNode block, ASTNode elseBlock) { + assert(block.type == AST_NODE_ROOT && elseBlock.type == AST_NODE_ROOT); + + ASTNode node = {}; + node.type = AST_NODE_IF; + + node.cIf.condition = (ASTNode*) malloc(sizeof(condition)); + *node.cIf.condition = condition; + + node.cIf.block = (ASTNode*) malloc(sizeof(block)); + *node.cIf.block = block; + + node.cIf.elseBlock = (ASTNode*) malloc(sizeof(elseBlock)); + *node.cIf.elseBlock = elseBlock; + return node; } @@ -557,15 +578,34 @@ bool ast_writeBytecode(ASTNode* node, Hunk* hunk, Scope* scope) { hunk_write(hunk, OP_JUMP_IF_FALSE, 0); hunk_write(hunk, 0, 0); - Instruction offsetPos = hunk_getCount(hunk) - 1; + Instruction nextStatementPos = hunk_getCount(hunk) - 1; if (!ast_writeBytecode(node->cIf.block, hunk, &inner)) { return false; } - Instruction ifEndPos = hunk_getCount(hunk) - 1; + if (node->cIf.elseBlock != 0) { + Scope elseInner = {}; + scope_init(&elseInner, scope); + + hunk_write(hunk, OP_JUMP, 0); + hunk_write(hunk, 0, 0); + + Instruction exitBlockPos = hunk_getCount(hunk) - 1; + + hunk->code[nextStatementPos] = hunk_getCount(hunk) - 1 - nextStatementPos; - hunk->code[offsetPos] = ifEndPos - offsetPos; + if (!ast_writeBytecode(node->cIf.elseBlock, hunk, &elseInner)) { + return false; + } + + Instruction endOfElsePos = hunk_getCount(hunk) - 1; + hunk->code[exitBlockPos] = endOfElsePos - exitBlockPos; + } else { + Instruction ifEndPos = hunk_getCount(hunk) - 1; + + hunk->code[nextStatementPos] = ifEndPos - nextStatementPos; + } } break; case AST_NODE_NUMBER: { diff --git a/src/bytecode.cpp b/src/bytecode.cpp index 7f7a142..4f60301 100644 --- a/src/bytecode.cpp +++ b/src/bytecode.cpp @@ -45,6 +45,7 @@ enum OPCode : Instruction { OP_TEST_OR, // || OP_TEST_AND, // && + OP_JUMP, OP_JUMP_IF_FALSE, OP_LOG, @@ -125,6 +126,7 @@ int hunk_disassembleInstruction(Hunk* hunk, int offset) { SIMPLE_INSTRUCTION(OP_TEST_OR); SIMPLE_INSTRUCTION2(OP_SET_LOCAL); + SIMPLE_INSTRUCTION2(OP_JUMP); SIMPLE_INSTRUCTION2(OP_JUMP_IF_FALSE); SIMPLE_INSTRUCTION2(OP_CALL); SIMPLE_INSTRUCTION2(OP_RETURN); @@ -297,6 +299,8 @@ ProgramResult vm_run(VM* vm) { Value name = vm_stack_pop(vm); if (name.type != VALUE_STRING) { + logf("ERROR: Expecting name in string format\n"); + return PROGRAM_RESULT_RUNTIME_ERROR; } @@ -307,6 +311,8 @@ ProgramResult vm_run(VM* vm) { Value name = vm_stack_pop(vm); if (name.type != VALUE_STRING) { + logf("ERROR: Expecting name in string format\n"); + return PROGRAM_RESULT_RUNTIME_ERROR; } @@ -326,6 +332,8 @@ ProgramResult vm_run(VM* vm) { int arity = (int) READ(); if (func.type != VALUE_FUNCTION) { + logf("ERROR Expecting func to be a function\n"); + return PROGRAM_RESULT_RUNTIME_ERROR; } @@ -361,6 +369,12 @@ ProgramResult vm_run(VM* vm) { frame->ip += jumpOffset; } } break; + case OP_JUMP: + { + Instruction jumpOffset = READ(); + + frame->ip += jumpOffset; + } break; case OP_NEGATE: { Value v = vm_stack_pop(vm); @@ -401,6 +415,7 @@ ProgramResult vm_run(VM* vm) { Value b = vm_stack_pop(vm); \ Value a = vm_stack_pop(vm); \ if (!VALUE_IS_NUMBER(a) || !VALUE_IS_NUMBER(b)) { \ + logf("ERROR: values should be numbers\n");\ return PROGRAM_RESULT_RUNTIME_ERROR; \ } \ Value c = {}; \ @@ -419,6 +434,8 @@ ProgramResult vm_run(VM* vm) { Value a = vm_stack_pop(vm); if (!VALUE_IS_BOOL(a) || !VALUE_IS_BOOL(b)) { + logf("ERROR: values should be bools\n"); + return PROGRAM_RESULT_RUNTIME_ERROR; } @@ -435,6 +452,8 @@ ProgramResult vm_run(VM* vm) { Value a = vm_stack_pop(vm); if (!VALUE_IS_BOOL(a) || !VALUE_IS_BOOL(b)) { + logf("ERROR: values should be bools\n"); + return PROGRAM_RESULT_RUNTIME_ERROR; } diff --git a/src/lexer.cpp b/src/lexer.cpp index 386d804..e36a4a7 100644 --- a/src/lexer.cpp +++ b/src/lexer.cpp @@ -15,6 +15,7 @@ enum TokenType : uint32 { TOKEN_FALSE, TOKEN_IF, + TOKEN_ELSE, TOKEN_FUNC, TOKEN_RETURN, TOKEN_VAR, @@ -140,6 +141,7 @@ Token scanner_readIdentifier(Scanner* scn) { // true // false // if + // else // func // var // return @@ -148,6 +150,8 @@ Token scanner_readIdentifier(Scanner* scn) { t.type = TOKEN_TRUE; } else if (strncmp(t.start, "func", 4) == 0) { t.type = TOKEN_FUNC; + } else if (strncmp(t.start, "else", 4) == 0) { + t.type = TOKEN_ELSE; } } else if (t.len == 5) { if (strncmp(t.start, "false", 5) == 0) { diff --git a/src/main.cpp b/src/main.cpp index 7f4400e..14f2c29 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -113,6 +113,10 @@ int main(int argc, char** argv) { hunk_write(&hunk, OP_RETURN, 0); hunk_write(&hunk, 0, 0); +#ifdef DEBUG + hunk_disassemble(&hunk, "main"); +#endif + VM vm = {0}; vm_load(&vm, &hunk); diff --git a/src/parser.cpp b/src/parser.cpp index 521b115..24e18c4 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -337,9 +337,19 @@ bool parser_parseIf(Parser* p, ASTNode* node) { ASTNode block = {}; if (parser_parseBlock(p, &block)) { - *node = ast_makeIf(condition, block); + if (parser_expect(p, TOKEN_ELSE)) { + ASTNode elseBlock = {}; - return true; + if (parser_parseBlock(p, &elseBlock)) { + *node = ast_makeIf(condition, block, elseBlock); + + return true; + } + } else { + *node = ast_makeIf(condition, block); + + return true; + } } } } diff --git a/src/typing.cpp b/src/typing.cpp index 7339e16..666f032 100644 --- a/src/typing.cpp +++ b/src/typing.cpp @@ -561,10 +561,25 @@ bool typeCheck(ASTNode* node, SymbolTable* symbols) { return false; } - SymbolTable childSymbols = {}; - symbolTable_init(&childSymbols, symbols); + { + SymbolTable childSymbols = {}; + symbolTable_init(&childSymbols, symbols); + + if (!typeCheck(node->cIf.block, &childSymbols)) { + return false; + } + } - return typeCheck(node->cIf.block, &childSymbols); + if (node->cIf.elseBlock != 0) { + SymbolTable childSymbols = {}; + symbolTable_init(&childSymbols, symbols); + + if (!typeCheck(node->cIf.elseBlock, &childSymbols)) { + return false; + } + } + + return true; } break; case AST_NODE_RETURN: { diff --git a/src/value.cpp b/src/value.cpp index 4258c98..efabfff 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -166,5 +166,3 @@ bool value_equals(Value left, Value right) { return false; } - -