| @@ -38,7 +38,6 @@ char *l2_token_extract_str(struct l2_token *tok); | |||
| void l2_token_print(struct l2_token *tok, struct l2_io_writer *w); | |||
| struct l2_lexer { | |||
| struct l2_token currtok; | |||
| struct l2_token toks[4]; | |||
| int tokidx; | |||
| int line; | |||
| @@ -49,6 +48,6 @@ struct l2_lexer { | |||
| void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r); | |||
| struct l2_token *l2_lexer_peek(struct l2_lexer *lexer, int count); | |||
| struct l2_token *l2_lexer_get(struct l2_lexer *lexer); | |||
| void l2_lexer_consume(struct l2_lexer *lexer); | |||
| #endif | |||
| @@ -3,6 +3,7 @@ | |||
| #include <stdlib.h> | |||
| static int parse_number(const char *str, double *num) { | |||
| // TODO: Floats | |||
| size_t len = strlen(str); | |||
| *num = 0; | |||
| int power = 1; | |||
| @@ -53,7 +54,7 @@ const char *l2_token_kind_name(enum l2_token_kind kind) { | |||
| } | |||
| void l2_token_free(struct l2_token *tok) { | |||
| if (tok->kind == L2_TOK_STRING) { | |||
| if (tok->kind == L2_TOK_STRING || tok->kind == L2_TOK_IDENT) { | |||
| free(tok->v.str); | |||
| } | |||
| } | |||
| @@ -65,7 +66,7 @@ char *l2_token_extract_str(struct l2_token *tok) { | |||
| } | |||
| void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r) { | |||
| lexer->currtok.kind = L2_TOK_EOF, | |||
| lexer->toks[0].kind = L2_TOK_EOF, | |||
| lexer->tokidx = 0; | |||
| lexer->line = 1; | |||
| lexer->ch = 1; | |||
| @@ -311,15 +312,8 @@ struct l2_token *l2_lexer_peek(struct l2_lexer *lexer, int count) { | |||
| return &lexer->toks[offset]; | |||
| } | |||
| struct l2_token *l2_lexer_get(struct l2_lexer *lexer) { | |||
| l2_token_free(&lexer->currtok); | |||
| if (lexer->tokidx == 0) { | |||
| read_tok(lexer, &lexer->currtok); | |||
| } else { | |||
| memmove(lexer->toks, lexer->toks + 1, lexer->tokidx - 1); | |||
| lexer->tokidx -= 1; | |||
| } | |||
| return &lexer->currtok; | |||
| void l2_lexer_consume(struct l2_lexer *lexer) { | |||
| l2_token_free(&lexer->toks[0]); | |||
| lexer->tokidx -= 1; | |||
| memmove(lexer->toks, lexer->toks + 1, lexer->tokidx * sizeof(*lexer->toks)); | |||
| } | |||
| @@ -9,8 +9,8 @@ static int parse_expression( | |||
| if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON_EQ) { | |||
| char *ident = l2_token_extract_str(tok); | |||
| l2_lexer_get(lexer); // ident | |||
| l2_lexer_get(lexer); // := | |||
| l2_lexer_consume(lexer); // ident | |||
| l2_lexer_consume(lexer); // := | |||
| if (parse_expression(lexer, gen, err) < 0) { | |||
| free(ident); | |||
| @@ -21,11 +21,11 @@ static int parse_expression( | |||
| return 0; | |||
| } else if (tok->kind == L2_TOK_NUMBER) { | |||
| l2_gen_number(gen, tok->v.num); | |||
| l2_lexer_get(lexer); // number | |||
| l2_lexer_consume(lexer); // number | |||
| return 0; | |||
| } else if (tok->kind == L2_TOK_IDENT) { | |||
| char *ident = l2_token_extract_str(tok); | |||
| l2_lexer_get(lexer); // ident | |||
| l2_lexer_consume(lexer); // ident | |||
| l2_gen_namespace_lookup(gen, &ident); | |||
| return 0; | |||
| } | |||
| @@ -18,7 +18,7 @@ static struct l2_vm_value *var_lookup(const char *name) { | |||
| return &vm.values[id]; | |||
| } | |||
| static int exec(const char *str) { | |||
| static int eval(const char *str) { | |||
| r.r.read = l2_io_mem_read; | |||
| r.idx = 0; | |||
| r.len = strlen(str); | |||
| @@ -42,13 +42,21 @@ static int exec(const char *str) { | |||
| return 0; | |||
| } | |||
| describe(exec) { | |||
| test("exec assignment") { | |||
| exec("foo := 10"); | |||
| describe(eval) { | |||
| test("eval assignment") { | |||
| eval("foo := 10"); | |||
| defer(l2_vm_free(&vm)); | |||
| defer(l2_gen_free(&gen)); | |||
| assert(l2_vm_value_type(var_lookup("foo")) == L2_VAL_TYPE_REAL); | |||
| assert(var_lookup("foo")->real == 10); | |||
| } | |||
| test("eval var deref assignment") { | |||
| eval("foo := 10\nbar := foo"); | |||
| defer(l2_vm_free(&vm)); | |||
| defer(l2_gen_free(&gen)); | |||
| l2_vm_print_state(&vm); | |||
| } | |||
| } | |||
| @@ -0,0 +1,81 @@ | |||
| #include "parse/lex.h" | |||
| #include <stdio.h> | |||
| #include <snow/snow.h> | |||
| static struct l2_lexer lexer; | |||
| static struct l2_io_mem_reader r; | |||
| static void lex(const char *str) { | |||
| r.r.read = l2_io_mem_read; | |||
| r.idx = 0; | |||
| r.len = strlen(str); | |||
| r.mem = str; | |||
| l2_lexer_init(&lexer, &r.r); | |||
| } | |||
| describe(lex) { | |||
| test("lex assignment") { | |||
| lex("foo := 10"); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_IDENT); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->v.str, "foo"); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_COLON_EQ); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_NUMBER); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->v.num, 10); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_EOF); | |||
| } | |||
| test("lex var deref assignment") { | |||
| lex("foo := 10\nbar := foo"); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_IDENT); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->v.str, "foo"); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_COLON_EQ); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_NUMBER); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->v.num, 10); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_IDENT); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->v.str, "bar"); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_COLON_EQ); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_IDENT); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->v.str, "foo"); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_EOF); | |||
| } | |||
| test("lex peek multiple") { | |||
| lex("foo := 10"); | |||
| l2_lexer_peek(&lexer, 3); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_IDENT); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->v.str, "foo"); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_COLON_EQ); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_NUMBER); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->v.num, 10); | |||
| l2_lexer_consume(&lexer); | |||
| asserteq(l2_lexer_peek(&lexer, 1)->kind, L2_TOK_EOF); | |||
| } | |||
| } | |||