From 749f6c0a9564385aa11e83cbb8550f8c53c0cec8 Mon Sep 17 00:00:00 2001 From: bog Date: Sun, 10 Sep 2023 08:06:34 +0200 Subject: [PATCH] ADD: var declaration. --- core/core.cpp | 16 +++++++++++++++ doc/grammar.bnf | 6 +++++- lib/Compiler.cpp | 24 ++++++++++------------ lib/Lexer.cpp | 1 + lib/Node.hpp | 4 +++- lib/Parser.cpp | 27 ++++++++++++++++++++++--- lib/Parser.hpp | 1 + lib/StaticPass.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++++- lib/StaticPass.hpp | 4 ++++ lib/VM.cpp | 1 - lib/Value.cpp | 1 + src/main.cpp | 5 +++-- tests/Lexer.cpp | 8 ++++++++ tests/Parser.cpp | 10 ++++++++++ 14 files changed, 136 insertions(+), 22 deletions(-) diff --git a/core/core.cpp b/core/core.cpp index 50befc8..1c20b4d 100644 --- a/core/core.cpp +++ b/core/core.cpp @@ -3,4 +3,20 @@ extern "C" void lib(jk::Loader& loader) { + loader.declare("dump", [](auto args){ + std::string sep; + + for (auto arg: args) + { + std::cout << sep << arg->string(); + sep = " "; + } + + if (args.empty() == false) + { + std::cout << std::endl; + } + + return jk::Value::make_nil(); + }); } diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 8f35903..050043d 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -1,4 +1,8 @@ PROG ::= FUNCALL* -EXPR ::= LITERAL | FUNCALL +EXPR ::= +LITERAL +| FUNCALL +| VARDECL +VARDECL ::= opar decl ident EXPR cpar FUNCALL ::= opar ident EXPR* cpar LITERAL ::= int | ident diff --git a/lib/Compiler.cpp b/lib/Compiler.cpp index 0891381..111d1e6 100644 --- a/lib/Compiler.cpp +++ b/lib/Compiler.cpp @@ -36,18 +36,19 @@ namespace jk program->push_instr(OPCODE_CALL, node->size() - 1); } break; + case NODE_VARDECL: { + std::string ident = node->child(0).lock()->repr(); + auto entry = m_sym->find(ident); + assert(entry); + + compile(node->child(1).lock(), program); + program->push_instr(OPCODE_STORE, entry->addr); + } break; + case NODE_IDENT: { std::string ident = node->repr(); auto sym = m_sym->find(ident); - - if (!sym) - { - m_logger.log(LOG_ERROR, node->loc(), - std::string() - + "'" - + ident - + "' is undefined"); - } + assert(sym); OpcodeType op_load = OPCODE_LOAD; @@ -56,10 +57,7 @@ namespace jk op_load = OPCODE_LOAD_GLOBAL; } - if (sym->type->type() == TYPE_FUNCTION) - { - program->push_instr(op_load, sym->addr); - } + program->push_instr(op_load, sym->addr); } break; diff --git a/lib/Lexer.cpp b/lib/Lexer.cpp index 7e4b020..a65b352 100644 --- a/lib/Lexer.cpp +++ b/lib/Lexer.cpp @@ -7,6 +7,7 @@ namespace jk , m_loc { loc } { std::vector> texts = { + {NODE_DECL, "$", false}, {NODE_OPAR, "(", false}, {NODE_CPAR, ")", false} }; diff --git a/lib/Node.hpp b/lib/Node.hpp index e37eddf..5363772 100644 --- a/lib/Node.hpp +++ b/lib/Node.hpp @@ -10,7 +10,9 @@ G(NODE_OPAR), \ G(NODE_CPAR), \ G(NODE_IDENT), \ - G(NODE_FUNCALL), + G(NODE_DECL), \ + G(NODE_FUNCALL), \ + G(NODE_VARDECL) namespace jk diff --git a/lib/Parser.cpp b/lib/Parser.cpp index 3e46a9f..573b7f7 100644 --- a/lib/Parser.cpp +++ b/lib/Parser.cpp @@ -91,7 +91,7 @@ namespace jk while (m_cursor < m_tokens.size()) { - root->add_child(parse_funcall()); + root->add_child(parse_expr()); } return root; @@ -99,14 +99,33 @@ namespace jk std::shared_ptr Parser::parse_expr() { - if (type_is(NODE_OPAR)) + if (type_is(NODE_OPAR) + && type_is(NODE_IDENT, 1)) { return parse_funcall(); } + if (type_is(NODE_OPAR) + && type_is(NODE_DECL, 1)) + { + return parse_vardecl(); + } + return parse_literal(); } + std::shared_ptr Parser::parse_vardecl() + { + auto root = std::make_shared(NODE_VARDECL, "", loc()); + consume(NODE_OPAR); + consume(NODE_DECL); + root->add_child(consume(NODE_IDENT)); + root->add_child(parse_expr()); + consume(NODE_CPAR); + + return root; + } + std::shared_ptr Parser::parse_funcall() { auto root = std::make_shared(NODE_FUNCALL, "", loc()); @@ -134,8 +153,10 @@ namespace jk loc(), std::string() + "unexpected token '" + + NodeTypeStr[current()->type()] + + "' ('" + current()->repr() - + "'"); + + "')"); abort(); } diff --git a/lib/Parser.hpp b/lib/Parser.hpp index 93d3b41..d96c09f 100644 --- a/lib/Parser.hpp +++ b/lib/Parser.hpp @@ -31,6 +31,7 @@ namespace jk std::shared_ptr parse_prog(); std::shared_ptr parse_expr(); + std::shared_ptr parse_vardecl(); std::shared_ptr parse_funcall(); std::shared_ptr parse_literal(); }; diff --git a/lib/StaticPass.cpp b/lib/StaticPass.cpp index 8de75cd..bbe99a5 100644 --- a/lib/StaticPass.cpp +++ b/lib/StaticPass.cpp @@ -21,11 +21,46 @@ namespace jk for (size_t i=0; isize(); i++) { pass(node->child(i).lock()); + pop(); } } break; - case NODE_FUNCALL: { + case NODE_INT: { + push(std::make_shared(TYPE_INT)); + } break; + case NODE_IDENT: { + std::string ident = node->repr(); + auto entry = m_sym->find(ident); + + if (!entry) + { + m_logger.log(LOG_ERROR, node->loc(), + std::string() + + "'" + + ident + + "' is undefined"); + } + + push(entry->type); + } break; + + case NODE_VARDECL: { + std::string ident = node->child(0).lock()->repr(); + pass(node->child(1).lock()); + auto type = pop(); + m_sym->declare(ident, type, node->loc()); + push(type); + } break; + + case NODE_FUNCALL: { + for (size_t i=0; isize(); i++) + { + pass(node->child(i).lock()); + pop(); + } + // TODO find actual returned type + push(std::make_shared(TYPE_NIL)); } break; default: @@ -34,4 +69,17 @@ namespace jk abort(); } } + + void StaticPass::push(std::shared_ptr type) + { + m_types.push_back(type); + } + + std::shared_ptr StaticPass::pop() + { + auto type = m_types.back(); + m_types.pop_back(); + + return type; + } } diff --git a/lib/StaticPass.hpp b/lib/StaticPass.hpp index 3910b73..8d00b94 100644 --- a/lib/StaticPass.hpp +++ b/lib/StaticPass.hpp @@ -18,6 +18,10 @@ namespace jk private: std::shared_ptr m_sym; Logger& m_logger; + std::vector> m_types; + + void push(std::shared_ptr type); + std::shared_ptr pop(); }; } diff --git a/lib/VM.cpp b/lib/VM.cpp index b7bab75..d426f69 100644 --- a/lib/VM.cpp +++ b/lib/VM.cpp @@ -137,5 +137,4 @@ namespace jk m_stack.pop_back(); return param; } - } diff --git a/lib/Value.cpp b/lib/Value.cpp index b72e204..7c43422 100644 --- a/lib/Value.cpp +++ b/lib/Value.cpp @@ -68,6 +68,7 @@ namespace jk { case TYPE_NIL: return ""; case TYPE_INT: return std::to_string(*m_int_val); + case TYPE_REF: return ""; default: std::cerr << "cannot stringify value '" diff --git a/src/main.cpp b/src/main.cpp index d3315b6..a9894b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -83,8 +83,6 @@ int main(int argc, char** argv) auto sym = std::make_shared(logger); - auto static_pass = std::make_shared(sym, logger); - static_pass->pass(ast); auto compiler = std::make_shared(sym, logger); auto program = std::make_shared(); @@ -92,6 +90,9 @@ int main(int argc, char** argv) auto loader = std::make_shared(vm, sym); loader->load(); + auto static_pass = std::make_shared(sym, logger); + static_pass->pass(ast); + compiler->compile(ast, program); if (debug_mode) diff --git a/tests/Lexer.cpp b/tests/Lexer.cpp index 5a957fd..b7d71f3 100644 --- a/tests/Lexer.cpp +++ b/tests/Lexer.cpp @@ -65,3 +65,11 @@ TEST_CASE_METHOD(LexerTest, "Lexer_funcall") test_next(*lexer, "IDENT[salut/monde]"); test_end(*lexer); } + +TEST_CASE_METHOD(LexerTest, "Lexer_vardecl") +{ + auto lexer = jk::Factory(m_logger, "tests/lexer").make_lexer(); + lexer->scan(" $ "); + test_next(*lexer, "DECL"); + test_end(*lexer); +} diff --git a/tests/Parser.cpp b/tests/Parser.cpp index 33db916..4c18aab 100644 --- a/tests/Parser.cpp +++ b/tests/Parser.cpp @@ -34,3 +34,13 @@ TEST_CASE_METHOD(ParserTest, "Parser_funcall") test_parser("PROG(FUNCALL(IDENT[hello],INT[1],INT[2],IDENT[bim!]))", " (hello 1 2 bim!) "); } + +TEST_CASE_METHOD(ParserTest, "Parser_vardecl") +{ + test_parser("PROG(VARDECL(IDENT[hello],INT[4]))", + " ($ hello 4) "); + + test_parser("PROG(VARDECL(IDENT[world]," + "FUNCALL(IDENT[f],INT[3],INT[2])))", + " ($ world (f 3 2)) "); +}