ADD: var declaration.

main
bog 2023-09-10 08:06:34 +02:00
parent e8e4906cfc
commit 749f6c0a95
14 changed files with 136 additions and 22 deletions

View File

@ -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();
});
}

View File

@ -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

View File

@ -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<compile_error>(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);
}
} break;

View File

@ -7,6 +7,7 @@ namespace jk
, m_loc { loc }
{
std::vector<std::tuple<NodeType, std::string, bool>> texts = {
{NODE_DECL, "$", false},
{NODE_OPAR, "(", false},
{NODE_CPAR, ")", false}
};

View File

@ -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

View File

@ -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<Node> 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<Node> Parser::parse_vardecl()
{
auto root = std::make_shared<Node>(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<Node> Parser::parse_funcall()
{
auto root = std::make_shared<Node>(NODE_FUNCALL, "", loc());
@ -134,8 +153,10 @@ namespace jk
loc(),
std::string()
+ "unexpected token '"
+ NodeTypeStr[current()->type()]
+ "' ('"
+ current()->repr()
+ "'");
+ "')");
abort();
}

View File

@ -31,6 +31,7 @@ namespace jk
std::shared_ptr<Node> parse_prog();
std::shared_ptr<Node> parse_expr();
std::shared_ptr<Node> parse_vardecl();
std::shared_ptr<Node> parse_funcall();
std::shared_ptr<Node> parse_literal();
};

View File

@ -21,11 +21,46 @@ namespace jk
for (size_t i=0; i<node->size(); i++)
{
pass(node->child(i).lock());
pop();
}
} break;
case NODE_FUNCALL: {
case NODE_INT: {
push(std::make_shared<Type>(TYPE_INT));
} break;
case NODE_IDENT: {
std::string ident = node->repr();
auto entry = m_sym->find(ident);
if (!entry)
{
m_logger.log<symbolic_error>(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; i<node->size(); i++)
{
pass(node->child(i).lock());
pop();
}
// TODO find actual returned type
push(std::make_shared<Type>(TYPE_NIL));
} break;
default:
@ -34,4 +69,17 @@ namespace jk
abort();
}
}
void StaticPass::push(std::shared_ptr<Type> type)
{
m_types.push_back(type);
}
std::shared_ptr<Type> StaticPass::pop()
{
auto type = m_types.back();
m_types.pop_back();
return type;
}
}

View File

@ -18,6 +18,10 @@ namespace jk
private:
std::shared_ptr<SymTable> m_sym;
Logger& m_logger;
std::vector<std::shared_ptr<Type>> m_types;
void push(std::shared_ptr<Type> type);
std::shared_ptr<Type> pop();
};
}

View File

@ -137,5 +137,4 @@ namespace jk
m_stack.pop_back();
return param;
}
}

View File

@ -68,6 +68,7 @@ namespace jk
{
case TYPE_NIL: return "<nil>";
case TYPE_INT: return std::to_string(*m_int_val);
case TYPE_REF: return "<ref:" + std::to_string(*m_ref_val) + ">";
default:
std::cerr << "cannot stringify value '"

View File

@ -83,8 +83,6 @@ int main(int argc, char** argv)
auto sym = std::make_shared<jk::SymTable>(logger);
auto static_pass = std::make_shared<jk::StaticPass>(sym, logger);
static_pass->pass(ast);
auto compiler = std::make_shared<jk::Compiler>(sym, logger);
auto program = std::make_shared<jk::Program>();
@ -92,6 +90,9 @@ int main(int argc, char** argv)
auto loader = std::make_shared<jk::Loader>(vm, sym);
loader->load();
auto static_pass = std::make_shared<jk::StaticPass>(sym, logger);
static_pass->pass(ast);
compiler->compile(ast, program);
if (debug_mode)

View File

@ -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);
}

View File

@ -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)) ");
}