| void l2_token_print(struct l2_token *tok, struct l2_io_writer *w); | void l2_token_print(struct l2_token *tok, struct l2_io_writer *w); | ||||
| struct l2_lexer { | struct l2_lexer { | ||||
| struct l2_token currtok; | |||||
| struct l2_token toks[4]; | struct l2_token toks[4]; | ||||
| int tokidx; | int tokidx; | ||||
| int line; | int line; | ||||
| void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r); | 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_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 | #endif |
| #include <stdlib.h> | #include <stdlib.h> | ||||
| static int parse_number(const char *str, double *num) { | static int parse_number(const char *str, double *num) { | ||||
| // TODO: Floats | |||||
| size_t len = strlen(str); | size_t len = strlen(str); | ||||
| *num = 0; | *num = 0; | ||||
| int power = 1; | int power = 1; | ||||
| } | } | ||||
| void l2_token_free(struct l2_token *tok) { | 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); | free(tok->v.str); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void l2_lexer_init(struct l2_lexer *lexer, struct l2_io_reader *r) { | 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->tokidx = 0; | ||||
| lexer->line = 1; | lexer->line = 1; | ||||
| lexer->ch = 1; | lexer->ch = 1; | ||||
| return &lexer->toks[offset]; | 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)); | |||||
| } | } |
| if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON_EQ) { | if (tok->kind == L2_TOK_IDENT && tok2->kind == L2_TOK_COLON_EQ) { | ||||
| char *ident = l2_token_extract_str(tok); | 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) { | if (parse_expression(lexer, gen, err) < 0) { | ||||
| free(ident); | free(ident); | ||||
| return 0; | return 0; | ||||
| } else if (tok->kind == L2_TOK_NUMBER) { | } else if (tok->kind == L2_TOK_NUMBER) { | ||||
| l2_gen_number(gen, tok->v.num); | l2_gen_number(gen, tok->v.num); | ||||
| l2_lexer_get(lexer); // number | |||||
| l2_lexer_consume(lexer); // number | |||||
| return 0; | return 0; | ||||
| } else if (tok->kind == L2_TOK_IDENT) { | } else if (tok->kind == L2_TOK_IDENT) { | ||||
| char *ident = l2_token_extract_str(tok); | char *ident = l2_token_extract_str(tok); | ||||
| l2_lexer_get(lexer); // ident | |||||
| l2_lexer_consume(lexer); // ident | |||||
| l2_gen_namespace_lookup(gen, &ident); | l2_gen_namespace_lookup(gen, &ident); | ||||
| return 0; | return 0; | ||||
| } | } |
| return &vm.values[id]; | return &vm.values[id]; | ||||
| } | } | ||||
| static int exec(const char *str) { | |||||
| static int eval(const char *str) { | |||||
| r.r.read = l2_io_mem_read; | r.r.read = l2_io_mem_read; | ||||
| r.idx = 0; | r.idx = 0; | ||||
| r.len = strlen(str); | r.len = strlen(str); | ||||
| return 0; | 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_vm_free(&vm)); | ||||
| defer(l2_gen_free(&gen)); | defer(l2_gen_free(&gen)); | ||||
| assert(l2_vm_value_type(var_lookup("foo")) == L2_VAL_TYPE_REAL); | assert(l2_vm_value_type(var_lookup("foo")) == L2_VAL_TYPE_REAL); | ||||
| assert(var_lookup("foo")->real == 10); | 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); | |||||
| } | |||||
| } | } |
| #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); | |||||
| } | |||||
| } |