From 05ba4cb99cf0e96211b3df80146b1d606f1a7437 Mon Sep 17 00:00:00 2001 From: bog Date: Sun, 10 Sep 2023 14:39:23 +0200 Subject: [PATCH] ADD: bool literals. --- doc/grammar.bnf | 2 +- lib/Compiler.cpp | 7 +++++- lib/Lexer.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++ lib/Lexer.hpp | 7 ++++++ lib/Node.hpp | 1 + lib/Parser.cpp | 1 + lib/StaticPass.cpp | 4 +++ lib/Type.hpp | 1 + lib/Value.cpp | 9 +++++++ lib/Value.hpp | 4 +++ tests/Lexer.cpp | 15 +++++++++++ tests/Parser.cpp | 6 +++++ 12 files changed, 118 insertions(+), 2 deletions(-) diff --git a/doc/grammar.bnf b/doc/grammar.bnf index 41ec2cc..99c83ea 100644 --- a/doc/grammar.bnf +++ b/doc/grammar.bnf @@ -11,4 +11,4 @@ BODY ::= expr* VARDECL ::= opar decl ident EXPR cpar FUNDECL ::= opar decl opar ident PARAMS cpar EXPR cpar FUNCALL ::= opar ident EXPR* cpar -LITERAL ::= int | ident +LITERAL ::= bool | int | ident diff --git a/lib/Compiler.cpp b/lib/Compiler.cpp index 45f489c..77f7408 100644 --- a/lib/Compiler.cpp +++ b/lib/Compiler.cpp @@ -66,7 +66,6 @@ namespace jk size_t addr = program->push_constant(Value::make_code(code)); program->push_instr(OPCODE_PUSH_CONST, addr); program->push_instr(OPCODE_MK_FUNCTION); - //program->push_instr(OpcodeType opcode) } break; case NODE_IDENT: { @@ -91,6 +90,12 @@ namespace jk program->push_instr(OPCODE_PUSH_CONST, addr); } break; + case NODE_BOOL: { + auto value = Value::make_bool(node->repr() == "true"); + size_t addr = program->push_constant(value); + program->push_instr(OPCODE_PUSH_CONST, addr); + } break; + default: std::cerr << "cannot compile unknown node '" << NodeTypeStr[node->type()] << "'" << std::endl; diff --git a/lib/Lexer.cpp b/lib/Lexer.cpp index b973caa..7238a70 100644 --- a/lib/Lexer.cpp +++ b/lib/Lexer.cpp @@ -6,6 +6,11 @@ namespace jk : m_logger { logger } , m_loc { loc } { + std::vector> keywords = { + {NODE_BOOL, "true", true}, + {NODE_BOOL, "false", true}, + }; + std::vector> texts = { {NODE_RARROW, "->", false}, {NODE_DECL, "$", false}, @@ -15,6 +20,7 @@ namespace jk for (auto text: texts) { + m_texts.push_back(std::get<1>(text)); m_scanners.push_back(std::bind(&Lexer::scan_text, this, std::get<0>(text), @@ -22,6 +28,15 @@ namespace jk std::get<2>(text))); } + for (auto kw: keywords) + { + m_scanners.push_back(std::bind(&Lexer::scan_keyword, + this, + std::get<0>(kw), + std::get<1>(kw), + std::get<2>(kw))); + } + m_scanners.push_back(std::bind(&Lexer::scan_ident, this)); m_scanners.push_back(std::bind(&Lexer::scan_int, this)); } @@ -103,6 +118,24 @@ namespace jk return m_source[index]; } + bool Lexer::is_sep(size_t index) const + { + if (std::isspace(at(index))) + { + return true; + } + + for (auto txt: m_texts) + { + if (txt == std::string(1, at(index))) + { + return true; + } + } + + return false; + } + void Lexer::skip_spaces() { while (more(m_cursor) @@ -169,6 +202,36 @@ namespace jk }; } + std::optional Lexer::scan_keyword(NodeType type, + std::string const& text, + bool has_value) const + { + if (m_cursor + text.size() > m_source.size()) + { + return std::nullopt; + } + + for (size_t i=0; i Lexer::scan_ident() const { auto car = [](char c){ diff --git a/lib/Lexer.hpp b/lib/Lexer.hpp index 67bea27..0c43901 100644 --- a/lib/Lexer.hpp +++ b/lib/Lexer.hpp @@ -34,9 +34,11 @@ namespace jk size_t m_cursor; std::string m_source; std::vector m_scanners; + std::vector m_texts; bool more(size_t index) const; char at(size_t index) const; + bool is_sep(size_t index) const; void skip_spaces(); @@ -44,6 +46,11 @@ namespace jk std::optional scan_text(NodeType type, std::string const& text, bool has_value) const; + + std::optional scan_keyword(NodeType type, + std::string const& text, + bool has_value) const; + std::optional scan_ident() const; }; } diff --git a/lib/Node.hpp b/lib/Node.hpp index 73908f5..17de4f4 100644 --- a/lib/Node.hpp +++ b/lib/Node.hpp @@ -7,6 +7,7 @@ #define NODE_TYPE(G) \ G(NODE_PROG), \ G(NODE_INT), \ + G(NODE_BOOL), \ G(NODE_OPAR), \ G(NODE_CPAR), \ G(NODE_IDENT), \ diff --git a/lib/Parser.cpp b/lib/Parser.cpp index c2662a0..825b0f8 100644 --- a/lib/Parser.cpp +++ b/lib/Parser.cpp @@ -220,6 +220,7 @@ namespace jk std::shared_ptr Parser::parse_literal() { if (type_is(NODE_INT) + || type_is(NODE_BOOL) || type_is(NODE_IDENT)) { return consume(); diff --git a/lib/StaticPass.cpp b/lib/StaticPass.cpp index 3f97509..53b6e06 100644 --- a/lib/StaticPass.cpp +++ b/lib/StaticPass.cpp @@ -48,6 +48,10 @@ namespace jk push(std::make_shared(TYPE_INT)); } break; + case NODE_BOOL: { + push(std::make_shared(TYPE_BOOL)); + } break; + case NODE_IDENT: { std::string ident = node->repr(); auto entry = m_sym->find(ident); diff --git a/lib/Type.hpp b/lib/Type.hpp index efdb58c..9511072 100644 --- a/lib/Type.hpp +++ b/lib/Type.hpp @@ -6,6 +6,7 @@ #define TYPE_TYPE(G) \ G(TYPE_NIL), \ G(TYPE_INT), \ + G(TYPE_BOOL), \ G(TYPE_FUNCTION), \ G(TYPE_CODE), \ G(TYPE_REF) diff --git a/lib/Value.cpp b/lib/Value.cpp index 7c43422..15578e5 100644 --- a/lib/Value.cpp +++ b/lib/Value.cpp @@ -20,6 +20,14 @@ namespace jk return value; } + /*static*/ std::shared_ptr Value::make_bool(bool val) + { + auto value = std::make_shared(); + value->m_type = std::make_shared(TYPE_BOOL); + value->m_bool_val = val; + return value; + } + /*static*/ std::shared_ptr Value::make_function(std::shared_ptr val) { @@ -68,6 +76,7 @@ namespace jk { case TYPE_NIL: return ""; case TYPE_INT: return std::to_string(*m_int_val); + case TYPE_BOOL: return *m_bool_val ? "true" : "false"; case TYPE_REF: return ""; default: diff --git a/lib/Value.hpp b/lib/Value.hpp index 25436ca..b74364a 100644 --- a/lib/Value.hpp +++ b/lib/Value.hpp @@ -14,6 +14,7 @@ namespace jk public: static std::shared_ptr make_nil(); static std::shared_ptr make_int(int val); + static std::shared_ptr make_bool(bool val); static std::shared_ptr make_function(std::shared_ptr val); static std::shared_ptr make_code(std::shared_ptr val); @@ -23,6 +24,8 @@ namespace jk virtual ~Value() = default; int as_int() const { return *m_int_val; } + int as_bool() const { return *m_bool_val; } + size_t as_ref() const { return *m_ref_val; } std::shared_ptr as_function() const; @@ -35,6 +38,7 @@ namespace jk private: std::shared_ptr m_type; std::optional m_int_val; + std::optional m_bool_val; std::shared_ptr m_function_val; std::shared_ptr m_code_val; std::optional m_ref_val; diff --git a/tests/Lexer.cpp b/tests/Lexer.cpp index 098db6f..5f435fd 100644 --- a/tests/Lexer.cpp +++ b/tests/Lexer.cpp @@ -81,3 +81,18 @@ TEST_CASE_METHOD(LexerTest, "Lexer_lambda") test_next(*lexer, "RARROW"); test_end(*lexer); } + +TEST_CASE_METHOD(LexerTest, "Lexer_bools") +{ + auto lexer = jk::Factory(m_logger, "tests/lexer").make_lexer(); + lexer->scan(" true false truea afalse (true) false!"); + test_next(*lexer, "BOOL[true]"); + test_next(*lexer, "BOOL[false]"); + test_next(*lexer, "IDENT[truea]"); + test_next(*lexer, "IDENT[afalse]"); + test_next(*lexer, "OPAR"); + test_next(*lexer, "BOOL[true]"); + test_next(*lexer, "CPAR"); + test_next(*lexer, "IDENT[false!]"); + test_end(*lexer); +} diff --git a/tests/Parser.cpp b/tests/Parser.cpp index 451e179..2fc11f7 100644 --- a/tests/Parser.cpp +++ b/tests/Parser.cpp @@ -71,3 +71,9 @@ TEST_CASE_METHOD(ParserTest, "Parser_fundecl") ")))", " ($ (f x y) (add y x)) "); } + +TEST_CASE_METHOD(ParserTest, "Parser_bool") +{ + test_parser("PROG(VARDECL(IDENT[hello],BOOL[true]))", + "($ hello true)"); +}