lily/src/parser.cpp

206 lines
7.8 KiB
C++

extern "C" {
#include "parser.h"
}
#include "parser.hpp"
#include "pattern.hpp"
namespace lily {
std::string tree_str(pgs_tree* tree, const char* source) {
size_t from = PGS_TREE_T_FROM(*tree);
size_t to = PGS_TREE_T_TO(*tree);
return std::string(source + from, to - from);
}
static ast_ptr expr_tree(pgs_tree*, const char*);
static ast_ptr expr_app_bottom(pgs_tree* base, const char* source) {
if(PGS_TREE_NT_COUNT(*base) == 2) {
return expr_tree(PGS_TREE_NT_CHILD(*base, 1), source);
} else {
pgs_tree* child = PGS_TREE_NT_CHILD(*base, 0);
if(isdigit(source[PGS_TREE_T_FROM(*child)])) {
return ast_ptr(new ast_num(atoi(source + PGS_TREE_T_FROM(*child))));
} else {
return ast_ptr(new ast_var(tree_str(child, source)));
}
}
}
static ast_ptr expr_app(pgs_tree* app, const char* source) {
ast_ptr into;
ast_ptr* into_ptr = &into;
while(PGS_TREE_NT_COUNT(*app) > 1) {
ast_app* new_app = new ast_app(nullptr, nullptr);
*into_ptr = ast_ptr(new_app);
into_ptr = &new_app->left;
new_app->right = expr_app_bottom(PGS_TREE_NT_CHILD(*app, 1), source);
app = PGS_TREE_NT_CHILD(*app, 0);
}
*into_ptr = expr_app_bottom(PGS_TREE_NT_CHILD(*app, 0), source);
return into;
}
static ast_ptr expr_mul(pgs_tree* mul, const char* source) {
if(PGS_TREE_NT_COUNT(*mul) == 1) {
return expr_app(PGS_TREE_NT_CHILD(*mul, 0), source);
} else {
pgs_tree* left = PGS_TREE_NT_CHILD(*mul, 0);
pgs_tree* right = PGS_TREE_NT_CHILD(*mul, 2);
pgs_tree* op = PGS_TREE_NT_CHILD(*mul, 1);
enum ast_op::op o =
source[PGS_TREE_T_FROM(*op)] == '*' ? ast_op::op::times : ast_op::op::divide;
ast_ptr aleft = expr_mul(left, source);
ast_ptr aright = expr_app(right, source);
return ast_ptr(new ast_op(o, std::move(aleft), std::move(aright)));
}
}
static ast_ptr expr_add(pgs_tree* add, const char* source) {
if(PGS_TREE_NT_COUNT(*add) == 1) {
return expr_mul(PGS_TREE_NT_CHILD(*add, 0), source);
} else {
pgs_tree* left = PGS_TREE_NT_CHILD(*add, 0);
pgs_tree* right = PGS_TREE_NT_CHILD(*add, 2);
pgs_tree* op = PGS_TREE_NT_CHILD(*add, 1);
enum ast_op::op o =
source[PGS_TREE_T_FROM(*op)] == '+' ? ast_op::op::add : ast_op::op::subtract;
ast_ptr aleft = expr_add(left, source);
ast_ptr aright = expr_mul(right, source);
return ast_ptr(new ast_op(o, std::move(aleft), std::move(aright)));
}
}
template <typename T, int Offset>
static ast_ptr expr_let(pgs_tree* let, const char* source) {
std::string name = tree_str(PGS_TREE_NT_CHILD(*let, Offset + 1), source);
ast_ptr eq_expr = expr_tree(PGS_TREE_NT_CHILD(*PGS_TREE_NT_CHILD(*let, Offset + 3), 1), source);
ast_ptr in_expr = expr_tree(PGS_TREE_NT_CHILD(*PGS_TREE_NT_CHILD(*let, Offset + 5), 1), source);
return ast_ptr(new T(name, std::move(eq_expr), std::move(in_expr)));
}
static pattern_ptr pattern_tree(pgs_tree* tree, const char* source) {
if(PGS_TREE_NT_COUNT(*tree) == 1) {
std::string new_str = tree_str(PGS_TREE_NT_CHILD(*tree, 0), source);
if(isupper(new_str[0])) return pattern_ptr(new pattern_cons(new_str));
else return pattern_ptr(new pattern_var(new_str));
} else {
std::string cons_name = tree_str(PGS_TREE_NT_CHILD(*tree, 0), source);
pattern_cons* new_pattern = new pattern_cons(cons_name);
pattern_ptr ptr = pattern_ptr(new_pattern);
pgs_tree* patterns = PGS_TREE_NT_CHILD(*tree, 2);
while(PGS_TREE_NT_COUNT(*patterns) > 1) {
new_pattern->vnames.push_back(tree_str(PGS_TREE_NT_CHILD(*tree, 0), source));
patterns = PGS_TREE_NT_CHILD(*tree, 2);
}
new_pattern->vnames.push_back(tree_str(PGS_TREE_NT_CHILD(*tree, 0), source));
return ptr;
}
}
static ast_case::branch expr_branch(pgs_tree* c, const char* source) {
ast_case::branch branch;
branch.pattern = pattern_tree(PGS_TREE_NT_CHILD(*c, 0), source);
branch.expr = expr_tree(PGS_TREE_NT_CHILD(*PGS_TREE_NT_CHILD(*c, 2), 1), source);
return branch;
}
static ast_ptr expr_case(pgs_tree* c, const char* source) {
ast_case* new_case = new ast_case();
ast_ptr case_ptr = ast_ptr(new_case);
new_case->of = expr_tree(PGS_TREE_NT_CHILD(*c, 1), source);
pgs_tree* branches = PGS_TREE_NT_CHILD(*c, 4);
while(PGS_TREE_NT_COUNT(*branches) == 2) {
pgs_tree* branch = PGS_TREE_NT_CHILD(*branches, 0);
branches = PGS_TREE_NT_CHILD(*branches, 1);
new_case->branches.push_back(expr_branch(branch, source));
}
new_case->branches.push_back(expr_branch(PGS_TREE_NT_CHILD(*branches, 0), source));
return case_ptr;
}
static ast_ptr expr_tree(pgs_tree* body, const char* source) {
pgs_tree* expr = PGS_TREE_NT_CHILD(*body, 0);
int type = PGS_TREE_NT(*expr);
if(type == PGS_NONTERMINAL_EXPR_ADD) {
return expr_add(expr, source);
} else if(type == PGS_NONTERMINAL_EXPR_LET) {
return expr_let<ast_let, 0>(expr, source);
} else if(type == PGS_NONTERMINAL_EXPR_LETREC) {
return expr_let<ast_letrec, 1>(expr, source);
} else if(type == PGS_NONTERMINAL_EXPR_CASE) {
return expr_case(expr, source);
}
throw error("unknown expression type");
}
static void collect_params(std::vector<std::string>& into, pgs_tree* def, const char* source) {
if(PGS_TREE_NT_COUNT(*def) == 5) {
pgs_tree* params = PGS_TREE_NT_CHILD(*def, 2);
do {
pgs_tree* param = PGS_TREE_NT_CHILD(*def, 0);
params =
(PGS_TREE_NT_COUNT(*def) == 2) ? PGS_TREE_NT_CHILD(*def, 1) : nullptr;
size_t from = PGS_TREE_T_FROM(*param);
size_t to = PGS_TREE_T_TO(*param);
std::string new_string =
std::string(source + from, to - from);
into.push_back(new_string);
} while(params);
}
}
static void add_definition(program& prog, pgs_tree* def, const char* source) {
char kw = source[PGS_TREE_T_FROM(*PGS_TREE_NT_CHILD(*def, 0))];
if(kw == 'd') {
function new_function;
collect_params(new_function.params, def, source);
new_function.body = expr_tree(PGS_TREE_NT_CHILD(*PGS_TREE_NT_CHILD(*def, PGS_TREE_NT_COUNT(*def) - 1), 1), source);
} else if(kw == 't') {
// skip for now
} else {
// skip for now
}
}
static program_ptr build_program(pgs_tree* tree, const char* source) {
program_ptr prog = std::make_unique<program>();
pgs_tree* program = PGS_TREE_NT_CHILD(*tree, 0);
do {
pgs_tree* definition = PGS_TREE_NT_CHILD(*program, 0);
program =
(PGS_TREE_NT_COUNT(*tree) == 2) ? PGS_TREE_NT_CHILD(*tree, 1) : nullptr;
add_definition(*prog, definition, source);
} while(program);
return prog;
}
program_ptr parse(std::string s) {
pgs_state state;
pgs_tree* into;
pgs_error err;
pgs_state_init(&state);
if((err = pgs_do_all(&state, &into, s.c_str())) != PGS_NONE) {
throw error("failed to parse input string");
}
program_ptr prog = build_program(into, s.c_str());
pgs_free_tree(into);
return prog;
}
}