ADD: bool literals.
parent
664ae63adf
commit
05ba4cb99c
|
@ -11,4 +11,4 @@ BODY ::= expr*
|
||||||
VARDECL ::= opar decl ident EXPR cpar
|
VARDECL ::= opar decl ident EXPR cpar
|
||||||
FUNDECL ::= opar decl opar ident PARAMS cpar EXPR cpar
|
FUNDECL ::= opar decl opar ident PARAMS cpar EXPR cpar
|
||||||
FUNCALL ::= opar ident EXPR* cpar
|
FUNCALL ::= opar ident EXPR* cpar
|
||||||
LITERAL ::= int | ident
|
LITERAL ::= bool | int | ident
|
||||||
|
|
|
@ -66,7 +66,6 @@ namespace jk
|
||||||
size_t addr = program->push_constant(Value::make_code(code));
|
size_t addr = program->push_constant(Value::make_code(code));
|
||||||
program->push_instr(OPCODE_PUSH_CONST, addr);
|
program->push_instr(OPCODE_PUSH_CONST, addr);
|
||||||
program->push_instr(OPCODE_MK_FUNCTION);
|
program->push_instr(OPCODE_MK_FUNCTION);
|
||||||
//program->push_instr(OpcodeType opcode)
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NODE_IDENT: {
|
case NODE_IDENT: {
|
||||||
|
@ -91,6 +90,12 @@ namespace jk
|
||||||
program->push_instr(OPCODE_PUSH_CONST, addr);
|
program->push_instr(OPCODE_PUSH_CONST, addr);
|
||||||
} break;
|
} 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:
|
default:
|
||||||
std::cerr << "cannot compile unknown node '"
|
std::cerr << "cannot compile unknown node '"
|
||||||
<< NodeTypeStr[node->type()] << "'" << std::endl;
|
<< NodeTypeStr[node->type()] << "'" << std::endl;
|
||||||
|
|
|
@ -6,6 +6,11 @@ namespace jk
|
||||||
: m_logger { logger }
|
: m_logger { logger }
|
||||||
, m_loc { loc }
|
, m_loc { loc }
|
||||||
{
|
{
|
||||||
|
std::vector<std::tuple<NodeType, std::string, bool>> keywords = {
|
||||||
|
{NODE_BOOL, "true", true},
|
||||||
|
{NODE_BOOL, "false", true},
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<std::tuple<NodeType, std::string, bool>> texts = {
|
std::vector<std::tuple<NodeType, std::string, bool>> texts = {
|
||||||
{NODE_RARROW, "->", false},
|
{NODE_RARROW, "->", false},
|
||||||
{NODE_DECL, "$", false},
|
{NODE_DECL, "$", false},
|
||||||
|
@ -15,6 +20,7 @@ namespace jk
|
||||||
|
|
||||||
for (auto text: texts)
|
for (auto text: texts)
|
||||||
{
|
{
|
||||||
|
m_texts.push_back(std::get<1>(text));
|
||||||
m_scanners.push_back(std::bind(&Lexer::scan_text,
|
m_scanners.push_back(std::bind(&Lexer::scan_text,
|
||||||
this,
|
this,
|
||||||
std::get<0>(text),
|
std::get<0>(text),
|
||||||
|
@ -22,6 +28,15 @@ namespace jk
|
||||||
std::get<2>(text)));
|
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_ident, this));
|
||||||
m_scanners.push_back(std::bind(&Lexer::scan_int, this));
|
m_scanners.push_back(std::bind(&Lexer::scan_int, this));
|
||||||
}
|
}
|
||||||
|
@ -103,6 +118,24 @@ namespace jk
|
||||||
return m_source[index];
|
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()
|
void Lexer::skip_spaces()
|
||||||
{
|
{
|
||||||
while (more(m_cursor)
|
while (more(m_cursor)
|
||||||
|
@ -169,6 +202,36 @@ namespace jk
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<ScanInfo> 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<text.size(); i++)
|
||||||
|
{
|
||||||
|
if (at(m_cursor + i) != text[i])
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cursor + text.size() < m_source.size()
|
||||||
|
&& !is_sep(m_cursor + text.size()))
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ScanInfo {
|
||||||
|
m_cursor + text.size(),
|
||||||
|
type,
|
||||||
|
has_value ? text : ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<ScanInfo> Lexer::scan_ident() const
|
std::optional<ScanInfo> Lexer::scan_ident() const
|
||||||
{
|
{
|
||||||
auto car = [](char c){
|
auto car = [](char c){
|
||||||
|
|
|
@ -34,9 +34,11 @@ namespace jk
|
||||||
size_t m_cursor;
|
size_t m_cursor;
|
||||||
std::string m_source;
|
std::string m_source;
|
||||||
std::vector<scanner_t> m_scanners;
|
std::vector<scanner_t> m_scanners;
|
||||||
|
std::vector<std::string> m_texts;
|
||||||
|
|
||||||
bool more(size_t index) const;
|
bool more(size_t index) const;
|
||||||
char at(size_t index) const;
|
char at(size_t index) const;
|
||||||
|
bool is_sep(size_t index) const;
|
||||||
|
|
||||||
void skip_spaces();
|
void skip_spaces();
|
||||||
|
|
||||||
|
@ -44,6 +46,11 @@ namespace jk
|
||||||
std::optional<ScanInfo> scan_text(NodeType type,
|
std::optional<ScanInfo> scan_text(NodeType type,
|
||||||
std::string const& text,
|
std::string const& text,
|
||||||
bool has_value) const;
|
bool has_value) const;
|
||||||
|
|
||||||
|
std::optional<ScanInfo> scan_keyword(NodeType type,
|
||||||
|
std::string const& text,
|
||||||
|
bool has_value) const;
|
||||||
|
|
||||||
std::optional<ScanInfo> scan_ident() const;
|
std::optional<ScanInfo> scan_ident() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#define NODE_TYPE(G) \
|
#define NODE_TYPE(G) \
|
||||||
G(NODE_PROG), \
|
G(NODE_PROG), \
|
||||||
G(NODE_INT), \
|
G(NODE_INT), \
|
||||||
|
G(NODE_BOOL), \
|
||||||
G(NODE_OPAR), \
|
G(NODE_OPAR), \
|
||||||
G(NODE_CPAR), \
|
G(NODE_CPAR), \
|
||||||
G(NODE_IDENT), \
|
G(NODE_IDENT), \
|
||||||
|
|
|
@ -220,6 +220,7 @@ namespace jk
|
||||||
std::shared_ptr<Node> Parser::parse_literal()
|
std::shared_ptr<Node> Parser::parse_literal()
|
||||||
{
|
{
|
||||||
if (type_is(NODE_INT)
|
if (type_is(NODE_INT)
|
||||||
|
|| type_is(NODE_BOOL)
|
||||||
|| type_is(NODE_IDENT))
|
|| type_is(NODE_IDENT))
|
||||||
{
|
{
|
||||||
return consume();
|
return consume();
|
||||||
|
|
|
@ -48,6 +48,10 @@ namespace jk
|
||||||
push(std::make_shared<Type>(TYPE_INT));
|
push(std::make_shared<Type>(TYPE_INT));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case NODE_BOOL: {
|
||||||
|
push(std::make_shared<Type>(TYPE_BOOL));
|
||||||
|
} break;
|
||||||
|
|
||||||
case NODE_IDENT: {
|
case NODE_IDENT: {
|
||||||
std::string ident = node->repr();
|
std::string ident = node->repr();
|
||||||
auto entry = m_sym->find(ident);
|
auto entry = m_sym->find(ident);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define TYPE_TYPE(G) \
|
#define TYPE_TYPE(G) \
|
||||||
G(TYPE_NIL), \
|
G(TYPE_NIL), \
|
||||||
G(TYPE_INT), \
|
G(TYPE_INT), \
|
||||||
|
G(TYPE_BOOL), \
|
||||||
G(TYPE_FUNCTION), \
|
G(TYPE_FUNCTION), \
|
||||||
G(TYPE_CODE), \
|
G(TYPE_CODE), \
|
||||||
G(TYPE_REF)
|
G(TYPE_REF)
|
||||||
|
|
|
@ -20,6 +20,14 @@ namespace jk
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*static*/ std::shared_ptr<Value> Value::make_bool(bool val)
|
||||||
|
{
|
||||||
|
auto value = std::make_shared<Value>();
|
||||||
|
value->m_type = std::make_shared<Type>(TYPE_BOOL);
|
||||||
|
value->m_bool_val = val;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/*static*/ std::shared_ptr<Value>
|
/*static*/ std::shared_ptr<Value>
|
||||||
Value::make_function(std::shared_ptr<Function> val)
|
Value::make_function(std::shared_ptr<Function> val)
|
||||||
{
|
{
|
||||||
|
@ -68,6 +76,7 @@ namespace jk
|
||||||
{
|
{
|
||||||
case TYPE_NIL: return "<nil>";
|
case TYPE_NIL: return "<nil>";
|
||||||
case TYPE_INT: return std::to_string(*m_int_val);
|
case TYPE_INT: return std::to_string(*m_int_val);
|
||||||
|
case TYPE_BOOL: return *m_bool_val ? "true" : "false";
|
||||||
case TYPE_REF: return "<ref:" + std::to_string(*m_ref_val) + ">";
|
case TYPE_REF: return "<ref:" + std::to_string(*m_ref_val) + ">";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace jk
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<Value> make_nil();
|
static std::shared_ptr<Value> make_nil();
|
||||||
static std::shared_ptr<Value> make_int(int val);
|
static std::shared_ptr<Value> make_int(int val);
|
||||||
|
static std::shared_ptr<Value> make_bool(bool val);
|
||||||
static std::shared_ptr<Value> make_function(std::shared_ptr<Function>
|
static std::shared_ptr<Value> make_function(std::shared_ptr<Function>
|
||||||
val);
|
val);
|
||||||
static std::shared_ptr<Value> make_code(std::shared_ptr<Code> val);
|
static std::shared_ptr<Value> make_code(std::shared_ptr<Code> val);
|
||||||
|
@ -23,6 +24,8 @@ namespace jk
|
||||||
virtual ~Value() = default;
|
virtual ~Value() = default;
|
||||||
|
|
||||||
int as_int() const { return *m_int_val; }
|
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; }
|
size_t as_ref() const { return *m_ref_val; }
|
||||||
|
|
||||||
std::shared_ptr<Function> as_function() const;
|
std::shared_ptr<Function> as_function() const;
|
||||||
|
@ -35,6 +38,7 @@ namespace jk
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Type> m_type;
|
std::shared_ptr<Type> m_type;
|
||||||
std::optional<int> m_int_val;
|
std::optional<int> m_int_val;
|
||||||
|
std::optional<bool> m_bool_val;
|
||||||
std::shared_ptr<Function> m_function_val;
|
std::shared_ptr<Function> m_function_val;
|
||||||
std::shared_ptr<Code> m_code_val;
|
std::shared_ptr<Code> m_code_val;
|
||||||
std::optional<size_t> m_ref_val;
|
std::optional<size_t> m_ref_val;
|
||||||
|
|
|
@ -81,3 +81,18 @@ TEST_CASE_METHOD(LexerTest, "Lexer_lambda")
|
||||||
test_next(*lexer, "RARROW");
|
test_next(*lexer, "RARROW");
|
||||||
test_end(*lexer);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -71,3 +71,9 @@ TEST_CASE_METHOD(ParserTest, "Parser_fundecl")
|
||||||
")))",
|
")))",
|
||||||
" ($ (f x y) (add y x)) ");
|
" ($ (f x y) (add y x)) ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_METHOD(ParserTest, "Parser_bool")
|
||||||
|
{
|
||||||
|
test_parser("PROG(VARDECL(IDENT[hello],BOOL[true]))",
|
||||||
|
"($ hello true)");
|
||||||
|
}
|
||||||
|
|
Reference in New Issue