diff --git a/src/data.hpp b/src/data.hpp new file mode 100644 index 0000000..256a7e4 --- /dev/null +++ b/src/data.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include +#include "type.hpp" + +namespace lily { + struct constructor { + int parent_type; + int tag; + std::vector params; + }; +} diff --git a/src/main.cpp b/src/main.cpp index 2b4943d..8298a1e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,11 @@ int main() { try { - lily::parse("defn add x y = { x + y }"); + lily::parse( + "data Bool = { True, False }\n" + "data Color = { Red, Black }\n" + "data IntList = { Nil, Cons(Int, Int) }\n" + "defn add x y = { x + y }"); } catch(lily::error& e) { std::cout << e.message << std::endl; } diff --git a/src/parser.cpp b/src/parser.cpp index 7064497..4892307 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -146,9 +146,9 @@ namespace lily { 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); + pgs_tree* param = PGS_TREE_NT_CHILD(*params, 0); params = - (PGS_TREE_NT_COUNT(*def) == 2) ? PGS_TREE_NT_CHILD(*def, 1) : nullptr; + (PGS_TREE_NT_COUNT(*params) == 2) ? PGS_TREE_NT_CHILD(*params, 1) : nullptr; size_t from = PGS_TREE_T_FROM(*param); size_t to = PGS_TREE_T_TO(*param); @@ -160,16 +160,62 @@ namespace lily { } } + static type_ptr type_tree(program& prog, pgs_tree* type, const char* source) { + std::string str = tree_str(PGS_TREE_NT_CHILD(*type, 0), source); + if(!prog.types.count(str)) throw error("unknown type"); + + return prog.types[str]; + } + + static void collect_type_params(program& prog, std::vector& into, pgs_tree* params, const char* source) { + while(true) { + pgs_tree* param = PGS_TREE_NT_CHILD(*params, 0); + into.push_back(type_tree(prog, param, source)); + + if(PGS_TREE_NT_COUNT(*params) == 1) break; + params = PGS_TREE_NT_CHILD(*params, 2); + } + } + + static void collect_constructors(program& prog, int parent, pgs_tree* def, const char* source) { + int id = 0; + while(true) { + constructor cons; + cons.tag = id++; + cons.parent_type = parent; + + pgs_tree* elem = PGS_TREE_NT_CHILD(*def, 0); + std::string name = tree_str(PGS_TREE_NT_CHILD(*elem, 0), source); + if(PGS_TREE_NT_COUNT(*elem) > 1) + collect_type_params(prog, cons.params, PGS_TREE_NT_CHILD(*elem, 2), source); + prog.constructors[name] = std::move(cons); + + if(PGS_TREE_NT_COUNT(*def) == 1) break; + def = PGS_TREE_NT_CHILD(*def, 2); + } + } + 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') { + size_t str_from = PGS_TREE_T_FROM(*PGS_TREE_NT_CHILD(*def, 0)); + if(source[str_from]== 't') { + // skip for now + } else if(source[str_from + 1] == 'e') { + std::string function_name = tree_str(PGS_TREE_NT_CHILD(*def, 1), source); + if(prog.functions.count(function_name)) throw error("cannot redefine function"); + 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 + + prog.functions[function_name] = std::move(new_function); } else { - // skip for now + std::string data_name = tree_str(PGS_TREE_NT_CHILD(*def, 1), source); + if(prog.types.count(data_name)) throw error("cannot redefine type"); + + int new_type = prog.next_free_type_id++; + collect_constructors(prog, new_type, + PGS_TREE_NT_CHILD(*PGS_TREE_NT_CHILD(*def, PGS_TREE_NT_COUNT(*def) - 1), 1), source); + prog.types[data_name] = type_ptr(new type_int(new_type)); } } @@ -180,7 +226,7 @@ namespace lily { do { pgs_tree* definition = PGS_TREE_NT_CHILD(*program, 0); program = - (PGS_TREE_NT_COUNT(*tree) == 2) ? PGS_TREE_NT_CHILD(*tree, 1) : nullptr; + (PGS_TREE_NT_COUNT(*program) == 2) ? PGS_TREE_NT_CHILD(*program, 1) : nullptr; add_definition(*prog, definition, source); } while(program); @@ -188,6 +234,31 @@ namespace lily { return prog; } + static void dump_program(program& prog) { + std::cout << "Constructors:" << std::endl; + for(auto& pair : prog.constructors) { + std::cout << " " << pair.first << std::endl; + } + std::cout << std::endl; + + std::cout << "Types:" << std::endl; + for(auto& pair : prog.types) { + std::cout << " " << pair.first << std::endl; + } + std::cout << std::endl; + + std::cout << "Functions:" << std::endl; + for(auto& pair : prog.functions) { + function& f = pair.second; + std::cout << " " << pair.first; + for(auto& param : f.params) { + std::cout << " " << param; + } + std::cout << std::endl; + } + std::cout << std::endl; + } + program_ptr parse(std::string s) { pgs_state state; pgs_tree* into; @@ -199,7 +270,14 @@ namespace lily { } program_ptr prog = build_program(into, s.c_str()); + dump_program(*prog); pgs_free_tree(into); return prog; } + + program::program() { + types["Int"] = type_ptr(new type_int(type_id_int)); + types["String"] = type_ptr(new type_int(type_id_str)); + next_free_type_id = type_id_last; + } } diff --git a/src/parser.hpp b/src/parser.hpp index cd9a245..f979840 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -4,10 +4,17 @@ #include "error.hpp" #include "ast.hpp" #include "function.hpp" +#include "type.hpp" +#include "data.hpp" namespace lily { struct program { + int next_free_type_id; + std::map types; + std::map constructors; std::map functions; + + program(); }; typedef std::unique_ptr program_ptr; diff --git a/src/type.hpp b/src/type.hpp new file mode 100644 index 0000000..f71ea5c --- /dev/null +++ b/src/type.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include + +namespace lily { + enum reserved_types { + type_id_int = 0, + type_id_str, + type_id_last + }; + + struct type { + virtual ~type() = default; + }; + + typedef std::shared_ptr type_ptr; + + struct type_int : type { + int type_id; + + type_int(int id) : type_id(id) {} + }; + + struct type_func : type { + type_ptr left; + type_ptr right; + + type_func(type_ptr l, type_ptr r) : + left(std::move(l)), right(std::move(r)) {} + }; +} +