From 26730b078d594732c403c2ed20d2bc3b72bebbc2 Mon Sep 17 00:00:00 2001 From: Harrison Shoebridge Date: Sat, 13 Oct 2018 18:35:57 +1100 Subject: [PATCH] Add other values, if statements and equality checking --- example.ls | 5 ++- src/ast.cpp | 101 ++++++++++++++++++++++++++++++++++++----------- src/bytecode.cpp | 62 +++++++++++++++++++++++++++-- src/lexer.cpp | 24 +++++++++-- src/parser.cpp | 42 ++++++++++++++++++-- vendor/uslib | 2 +- 6 files changed, 199 insertions(+), 37 deletions(-) diff --git a/example.ls b/example.ls index 689dd51..d702cb1 100644 --- a/example.ls +++ b/example.ls @@ -1,10 +1,13 @@ +a := 11; y := 33; -x := y * 2; +x := a * 3; z := true; x; +if x == y; + /* if x == 10 { x; diff --git a/src/ast.cpp b/src/ast.cpp index 63839c2..ddfbb79 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -87,7 +87,10 @@ enum ASTNodeType : uint32 { AST_NODE_MULTIPLY, AST_NODE_DIVIDE, + AST_NODE_TEST_EQUAL, + AST_NODE_IDENTIFIER, + AST_NODE_VALUE, AST_NODE_NUMBER }; @@ -107,6 +110,10 @@ struct ASTNode_Identifier { Token token; }; +struct ASTNode_Value { + Value val; +}; + struct ASTNode_Number { int number; }; @@ -122,11 +129,17 @@ struct ASTNode { ASTNode_Binary assignmentDeclaration; ASTNode_Binary assignment; + ASTNode_Binary binary; + ASTNode_Binary add; ASTNode_Binary subtract; ASTNode_Binary multiply; ASTNode_Binary divide; + ASTNode_Binary equality; + + ASTNode_Value value; + ASTNode_Identifier identifier; ASTNode_Number number; }; @@ -157,7 +170,18 @@ ASTNode ast_makeIdentifier(Token t) { node.identifier.token = t; return node; -}; +} + +ASTNode ast_makeValue(Value v, Token t) { + ASTNode node = {}; + node.type = AST_NODE_VALUE; + + node.line = t.line; + + node.value.val = v; + + return node; +} ASTNode ast_makeOperator(ASTNodeType op, Token t) { ASTNode node = {}; @@ -165,20 +189,12 @@ ASTNode ast_makeOperator(ASTNodeType op, Token t) { switch (op) { case AST_NODE_ADD: - { - node.type = AST_NODE_ADD; - } break; case AST_NODE_SUBTRACT: - { - node.type = AST_NODE_SUBTRACT; - } break; case AST_NODE_MULTIPLY: - { - node.type = AST_NODE_MULTIPLY; - } break; case AST_NODE_DIVIDE: + case AST_NODE_TEST_EQUAL: { - node.type = AST_NODE_DIVIDE; + node.type = op; } break; default: { @@ -251,6 +267,29 @@ ASTNode ast_makeAssignment(ASTNode left, ASTNode right, Token t) { return node; } +bool ast_checkType(ASTNode n, ValueType vt) { + switch (n.type) { + case AST_NODE_ADD: + case AST_NODE_SUBTRACT: + case AST_NODE_MULTIPLY: + case AST_NODE_DIVIDE: + { + return ast_checkType(*n.binary.left, vt) && ast_checkType(*n.binary.right, vt); + } break; + case AST_NODE_NUMBER: + { + return (vt == VALUE_NUMBER) ? true : false; + } break; + + case AST_NODE_VALUE: + { + return (vt == n.value.val.type); + } break; + default: + return false; + } +} + #define IS_USED(op) ((op).add.left != 0 && (op).add.right != 0) bool ast_nodeHasValue(ASTNode n) { if (!(n.type == AST_NODE_NUMBER || n.type == AST_NODE_IDENTIFIER)) { @@ -295,27 +334,20 @@ bool ast_writeBytecode(ASTNode* node, Hunk* hunk, Scope* scope) { assert(left->type == AST_NODE_IDENTIFIER); ASTNode* right = node->assignmentDeclaration.right; - assert(ast_nodeHasValue(*right)); + // assert(ast_nodeHasValue(*right)); // write instructions to push right side onto stack if (!ast_writeBytecode(right, hunk, scope)) { return false; } - if (!scope_exists(scope, left->identifier.token.start, left->identifier.token.len)) { + Variable var = {}; + if (!scope_get(scope, left->identifier.token.start, left->identifier.token.len, &var)) { printf("ERROR: variable doesn't exist!\n"); return false; } - Variable var = {}; - var.start = left->identifier.token.start; - var.len = left->identifier.token.len; - - var.index = hunk_addLocal(hunk, value_make(VALUE_NUMBER)); - - scope_set(scope, var); - hunk_write(hunk, OP_SET_LOCAL, node->line); hunk_write(hunk, var.index, node->line); } break; @@ -325,7 +357,7 @@ bool ast_writeBytecode(ASTNode* node, Hunk* hunk, Scope* scope) { assert(left->type == AST_NODE_IDENTIFIER); ASTNode* right = node->assignmentDeclaration.right; - assert(ast_nodeHasValue(*right)); + // assert(ast_nodeHasValue(*right)); // write instructions to push right side onto stack if (!ast_writeBytecode(right, hunk, scope)) { @@ -342,7 +374,6 @@ bool ast_writeBytecode(ASTNode* node, Hunk* hunk, Scope* scope) { var.start = left->identifier.token.start; var.len = left->identifier.token.len; - // TODO(harrison): replace local, don't just make a new one var.index = hunk_addLocal(hunk, value_make(VALUE_NUMBER)); scope_set(scope, var); @@ -350,10 +381,26 @@ bool ast_writeBytecode(ASTNode* node, Hunk* hunk, Scope* scope) { hunk_write(hunk, OP_SET_LOCAL, node->line); hunk_write(hunk, var.index, node->line); } break; + case AST_NODE_TEST_EQUAL: + { + ASTNode* left = node->equality.left; + ASTNode* right = node->equality.right; + + // write instructions to push left side onto stack + if(!ast_writeBytecode(left, hunk, scope)) { + return false; + } + + // write instructions to push right side onto stack + if(!ast_writeBytecode(right, hunk, scope)) { + return false; + } + + hunk_write(hunk, OP_TEST_EQ, node->line); + } break; case AST_NODE_ADD: { ASTNode* left = node->add.left; - ASTNode* right = node->add.right; // write instructions to push left side onto stack @@ -428,6 +475,12 @@ bool ast_writeBytecode(ASTNode* node, Hunk* hunk, Scope* scope) { hunk_write(hunk, OP_CONSTANT, node->line); hunk_write(hunk, constant, node->line); } break; + case AST_NODE_VALUE: + { + int constant = hunk_addConstant(hunk, node->value.val); + hunk_write(hunk, OP_CONSTANT, node->line); + hunk_write(hunk, constant, node->line); + } break; case AST_NODE_IDENTIFIER: { Variable var = {}; diff --git a/src/bytecode.cpp b/src/bytecode.cpp index 144c83d..f01d47f 100644 --- a/src/bytecode.cpp +++ b/src/bytecode.cpp @@ -16,7 +16,14 @@ enum OPCode : Instruction { OP_ADD, OP_SUBTRACT, OP_MULTIPLY, - OP_DIVIDE + OP_DIVIDE, + + // OP tgt, tlt, teq + OP_TEST_EQ, // == + OP_TEST_GT, // > + OP_TEST_LT, // < + OP_TEST_OR, // || + OP_TEST_AND // && }; enum ValueType { @@ -26,7 +33,6 @@ enum ValueType { // VALUE_OBJ }; - #define VALUE_IS_NUMBER(v) ((v).type == VALUE_NUMBER) #define VALUE_IS_BOOL(v) ((v).type == VALUE_BOOL) @@ -68,6 +74,15 @@ Value value_make(float t) { return v; } +Value value_make(bool t) { + Value v = {}; + v.type = VALUE_BOOL; + + v.as.boolean = t; + + return v; +} + void value_print(Value v) { switch (v.type) { case VALUE_NUMBER: @@ -77,10 +92,12 @@ void value_print(Value v) { case VALUE_BOOL: { printf(v.as.boolean ? "true" : "false"); + + break; } default: { - printf("unknown"); + printf("unknown: %d", v.type); } }; } @@ -91,6 +108,31 @@ void value_println(Value v) { printf("\n"); } +bool value_equals(Value left, Value right) { + if (left.type != right.type) { + // TODO(harrison): this should not be possible. We need a type system. + + assert(!"Can't compare variables of different types"); + } + + switch (left.type) { + case VALUE_BOOL: + { + return left.as.boolean == right.as.boolean; + } break; + case VALUE_NUMBER: + { + return us_equals(left.as.number, right.as.number); + } break; + default: + { + assert(!"Unknown type"); + } + } + + return false; +} + // Constants keeps track of all the available constants in a program. Zero is initialisation. // TODO(harrison): force constants count to fit within the maximum addressable space by opcodes (256) #define CONSTANTS_CAPACITY_GROW(c) ( ((c) < 8) ? 8 : (c)*2 ) @@ -192,6 +234,8 @@ int hunk_disassembleInstruction(Hunk* hunk, int offset) { SIMPLE_INSTRUCTION(OP_MULTIPLY); SIMPLE_INSTRUCTION(OP_DIVIDE); + SIMPLE_INSTRUCTION(OP_TEST_EQ); + case OP_CONSTANT: { int idx = hunk->code[offset + 1]; @@ -216,7 +260,6 @@ int hunk_disassembleInstruction(Hunk* hunk, int offset) { return offset + 2; } break; - default: { printf("Unknown opcode: %d\n", in); @@ -325,7 +368,18 @@ ProgramResult vm_run(VM* vm) { vm_stack_push(vm, v); } break; + case OP_TEST_EQ: + { + Value b = vm_stack_pop(vm); + Value a = vm_stack_pop(vm); + Value c = {}; + c.type = VALUE_BOOL; + + c.as.boolean = value_equals(a, b); + + vm_stack_push(vm, c); + } break; #define BINARY_OP(op) \ Value b = vm_stack_pop(vm); \ Value a = vm_stack_pop(vm); \ diff --git a/src/lexer.cpp b/src/lexer.cpp index 7e2a2b1..7bb723c 100644 --- a/src/lexer.cpp +++ b/src/lexer.cpp @@ -12,6 +12,7 @@ enum TokenType : uint32 { TOKEN_TRUE, TOKEN_FALSE, + TOKEN_IF, TOKEN_ASSIGNMENT, TOKEN_ASSIGNMENT_DECLARATION, @@ -21,6 +22,8 @@ enum TokenType : uint32 { TOKEN_MULTIPLY, TOKEN_DIVIDE, + TOKEN_EQUALS, + TOKEN_BRACKET_OPEN, TOKEN_BRACKET_CLOSE, }; @@ -117,6 +120,7 @@ Token scanner_readIdentifier(Scanner* scn) { // true // false + // if if (t.len == 4) { if (strncmp(t.start, "true", 4) == 0) { t.type = TOKEN_TRUE; @@ -125,6 +129,10 @@ Token scanner_readIdentifier(Scanner* scn) { if (strncmp(t.start, "false", 5) == 0) { t.type = TOKEN_FALSE; } + } else if (t.len == 2) { + if (strncmp(t.start, "if", 2) == 0) { + t.type = TOKEN_IF; + } } return t; @@ -200,11 +208,19 @@ Token scanner_getToken(Scanner* scn) { switch (*scn->head) { case '=': { - t.type = TOKEN_ASSIGNMENT; - t.start = scn->head; - t.len = 1; + if (scanner_peek(scn) == '=') { + t.type = TOKEN_EQUALS; + t.start = scn->head; + t.len = 2; - scn->head += t.len; + scn->head += t.len; + } else { + t.type = TOKEN_ASSIGNMENT; + t.start = scn->head; + t.len = 1; + + scn->head += t.len; + } } break; case ':': { diff --git a/src/parser.cpp b/src/parser.cpp index 3ab205c..6405a27 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -91,7 +91,7 @@ array_for(ASTNode); // - group addition and subtraction together // - becomes: B(B(B(N * N) + B(N * Bx)) + I) // therefore everything has been reduced into a single binary expression -bool parser_parseExpression(Parser* p, ASTNode* node, TokenType endOn = TOKEN_SEMICOLON) { +bool parser_parseNumericalExpression(Parser* p, ASTNode* node, TokenType endOn = TOKEN_SEMICOLON) { array(ASTNode) expression = array_ASTNode_init(); while (true) { @@ -108,6 +108,8 @@ bool parser_parseExpression(Parser* p, ASTNode* node, TokenType endOn = TOKEN_SE n = ast_makeOperator(AST_NODE_MULTIPLY, t); } else if (parser_expect(p, TOKEN_DIVIDE, &t)) { n = ast_makeOperator(AST_NODE_DIVIDE, t); + } else if (parser_expect(p, TOKEN_EQUALS, &t)) { + n = ast_makeOperator(AST_NODE_TEST_EQUAL, t); } else if (parser_expect(p, TOKEN_IDENTIFIER, &t)) { if (!parser_parseIdentifier(p, &n, t)) { return false; @@ -131,7 +133,7 @@ bool parser_parseExpression(Parser* p, ASTNode* node, TokenType endOn = TOKEN_SE array(ASTNode) working = array_ASTNode_init(); - ASTNodeType precedenceOrder[] = {AST_NODE_MULTIPLY, AST_NODE_DIVIDE, AST_NODE_ADD, AST_NODE_SUBTRACT }; + ASTNodeType precedenceOrder[] = { AST_NODE_TEST_EQUAL, AST_NODE_MULTIPLY, AST_NODE_DIVIDE, AST_NODE_ADD, AST_NODE_SUBTRACT }; for (ASTNodeType currentOP : precedenceOrder) { psize i = 0; @@ -203,9 +205,13 @@ bool parser_parseExpression(Parser* p, ASTNode* node, TokenType endOn = TOKEN_SE return true; } +bool parser_parseBooleanExpression(Parser* p, ASTNode* node) { + return false; +} + bool parser_parseBrackets(Parser* p, ASTNode* node) { if (parser_expect(p, TOKEN_BRACKET_OPEN)) { - if (parser_parseExpression(p, node, TOKEN_BRACKET_CLOSE)) { + if (parser_parseNumericalExpression(p, node, TOKEN_BRACKET_CLOSE)) { if (parser_expect(p, TOKEN_BRACKET_CLOSE)) { return true; } @@ -215,6 +221,31 @@ bool parser_parseBrackets(Parser* p, ASTNode* node) { return false; } +bool parser_parseExpression(Parser* p, ASTNode* node) { + printf("parsing expression\n"); + + Token t; + + if (parser_expect(p, TOKEN_TRUE, &t)) { + *node = ast_makeValue(value_make(true), t); + + return true; + } else if (parser_expect(p, TOKEN_FALSE, &t)) { + *node = ast_makeValue(value_make(false), t); + + return true; + } else if (parser_parseNumericalExpression(p, node)) { + return true; + } else if (parser_expect(p, TOKEN_IDENTIFIER, &t)) { + if (parser_parseIdentifier(p, node, t)) { + return true; + } + } + + + return false; +} + bool parser_parseStatement(Parser* p, ASTNode* node) { printf("beginning parse statemetn\n"); @@ -266,6 +297,11 @@ bool parser_parseStatement(Parser* p, ASTNode* node) { Token t = *p->head; printf("%.*s %d\n", t.len, t.start, t.type); + } else if (parser_expect(p, TOKEN_IF, &tIdent)) { + ASTNode condition = {}; + if (parser_parseExpression(p, &condition)) { + *node = condition; + } } printf("failed parse statemetn\n"); diff --git a/vendor/uslib b/vendor/uslib index 66590d2..6f9966a 160000 --- a/vendor/uslib +++ b/vendor/uslib @@ -1 +1 @@ -Subproject commit 66590d2c161cf31af38d8bc6ca85b996973bdccd +Subproject commit 6f9966a4dc1aec6946ed0ebff73717d0ff8e9e61