diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e8713f..97b1d8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,5 +2,5 @@ cmake_minimum_required(VERSION 3.0) project(lily) set(CMAKE_CXX_STANDARD 14) -add_executable(lily src/main.cpp src/parser.cpp src/parser.c src/type.cpp src/type_manager.cpp src/ast.cpp src/type_checker.cpp) +add_executable(lily src/main.cpp src/parser.cpp src/parser.c src/type.cpp src/type_manager.cpp src/ast.cpp src/type_checker.cpp src/pattern.cpp) target_include_directories(lily PUBLIC src) diff --git a/src/ast.cpp b/src/ast.cpp index c011bd5..3caa55c 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -65,6 +65,32 @@ namespace lily { } type* ast_case::check(type_manager& mgr, std::shared_ptr env) { - throw error("unimplemented"); + type* ctype = of->check(mgr, env); + type* pattern_type = nullptr; + type* branch_type = nullptr; + for(auto& branch : branches) { + auto new_env = std::make_shared(); + new_env->set_parent(env.get()); + type* new_type = branch.pattern->check_modifying(mgr, new_env); + + if(!pattern_type) { + pattern_type = new_type; + } else { + if(!pattern_type->unify_with(new_type)) + throw error("incompatible pattern types"); + } + if(!pattern_type->unify_with(ctype)) + throw error("pattern type doesn't match case value type"); + + type* new_branch_type = branch.expr->check(mgr, new_env); + if(!branch_type) { + branch_type = new_branch_type; + } else { + if(!branch_type->unify_with(new_branch_type)) + throw error("branches have incompatible types"); + } + } + + return branch_type; } } diff --git a/src/main.cpp b/src/main.cpp index d40831d..e6267a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,8 @@ int main() { "data IntList = { Nil, Cons(Int, IntList) }\n" "defn other x y = { 3 }\n" "defn add x y = { x + y }\n" - "defn ones = { Cons 1 ones }"); + "defn ones = { Cons 1 ones }\n" + "defn len l = { case l of { Nil -> { 0 } Cons(x, xs) -> { 1 + len xs } } }"); } catch(lily::error& e) { std::cout << e.message << std::endl; } diff --git a/src/parser.cpp b/src/parser.cpp index 2b2dfbe..8cbe3f2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -95,10 +95,10 @@ namespace lily { 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(*patterns, 0), source)); + patterns = PGS_TREE_NT_CHILD(*patterns, 2); } - new_pattern->vnames.push_back(tree_str(PGS_TREE_NT_CHILD(*tree, 0), source)); + new_pattern->vnames.push_back(tree_str(PGS_TREE_NT_CHILD(*patterns, 0), source)); return ptr; } } diff --git a/src/pattern.cpp b/src/pattern.cpp new file mode 100644 index 0000000..7dbc7b8 --- /dev/null +++ b/src/pattern.cpp @@ -0,0 +1,32 @@ +#include "pattern.hpp" +#include "error.hpp" +#include "type_checker.hpp" +#include "type_manager.hpp" + +namespace lily { + type* pattern_var::check_modifying(type_manager& mgr, std::shared_ptr env) { + type* parameter = mgr.create_type(); + env->set_type(name, parameter); + return parameter; + } + + type* pattern_cons::check_modifying(type_manager& mgr, std::shared_ptr env) { + type* constructor_type = env->get_identifier_type(name); + int arity = constructor_type->arity(); + if(arity != vnames.size()) + throw error("invalid number of arguments to constructor"); + + if(arity == 0) { + return constructor_type; + } else { + type_func* func_type; + type* current = constructor_type; + int index = 0; + while((func_type = dynamic_cast(current))) { + env->set_type(vnames[index++], func_type->left); + current = func_type->right; + } + return current; + } + } +} diff --git a/src/pattern.hpp b/src/pattern.hpp index ba0629b..4c1153d 100644 --- a/src/pattern.hpp +++ b/src/pattern.hpp @@ -4,8 +4,13 @@ #include namespace lily { + class type_manager; + class type_env; + struct type; + struct pattern { virtual ~pattern() = default; + virtual type* check_modifying(type_manager& mgr, std::shared_ptr env) = 0; }; typedef std::unique_ptr pattern_ptr; @@ -16,6 +21,7 @@ namespace lily { pattern_var(std::string n) : name(std::move(n)) {} ~pattern_var() = default; + type* check_modifying(type_manager& mgr, std::shared_ptr env); }; struct pattern_cons : pattern { @@ -25,5 +31,6 @@ namespace lily { pattern_cons(std::string n) : name(std::move(n)) {} ~pattern_cons() = default; + type* check_modifying(type_manager& mgr, std::shared_ptr env); }; } diff --git a/src/type.hpp b/src/type.hpp index 564a720..398d384 100644 --- a/src/type.hpp +++ b/src/type.hpp @@ -13,6 +13,7 @@ namespace lily { struct type { virtual ~type() = default; virtual bool unify_with(type* other) = 0; + virtual int arity() { return 0; } }; struct type_internal : type { @@ -49,6 +50,7 @@ namespace lily { type_func(type* l, type* r) : left(l), right(r) {} bool unify_with(type* other); + int arity() { return right->arity() + 1; } }; }