diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ast/expr.cpp | 122 | ||||
-rw-r--r-- | src/ast/expr.hpp | 92 | ||||
-rw-r--r-- | src/convert/typecheck_expr.cpp | 108 | ||||
-rw-r--r-- | src/parse/expr.cpp | 11 |
4 files changed, 255 insertions, 78 deletions
diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp index 7cde198f..026a54c1 100644 --- a/src/ast/expr.cpp +++ b/src/ast/expr.cpp @@ -10,8 +10,7 @@ void Expr::visit_nodes(NodeVisitor& v) } ::std::ostream& operator<<(::std::ostream& os, const Expr& pat) { - os << "Expr(TODO)"; - return os; + return os << "Expr(TODO)"; } SERIALISE_TYPE(Expr::, "Expr", { s.item(m_node); @@ -220,5 +219,124 @@ SERIALISE_TYPE_S(ExprNode_BinOp, { s.item(m_right); }) + +void NodeVisitor::visit(ExprNode_Block& node) +{ + DEBUG("DEF - ExprNode_Block"); + INDENT(); + for( auto& child : node.m_nodes ) + visit(child); + UNINDENT(); +} +void NodeVisitor::visit(ExprNode_Macro& node) +{ + DEBUG("DEF - ExprNode_Macro"); +} +void NodeVisitor::visit(ExprNode_Return& node) +{ + DEBUG("DEF - ExprNode_Return"); + visit(node.m_value); +} +void NodeVisitor::visit(ExprNode_LetBinding& node) +{ + DEBUG("DEF - ExprNode_LetBinding"); + // TODO: Handle recurse into Let pattern + visit(node.m_value); +} +void NodeVisitor::visit(ExprNode_Assign& node) +{ + DEBUG("DEF - ExprNode_Assign"); + INDENT(); + visit(node.m_slot); + visit(node.m_value); + UNINDENT(); +} +void NodeVisitor::visit(ExprNode_CallPath& node) +{ + DEBUG("DEF - ExprNode_CallPath"); + INDENT(); + for( auto& arg : node.m_args ) + visit(arg); + UNINDENT(); +} +void NodeVisitor::visit(ExprNode_CallMethod& node) +{ + DEBUG("DEF - ExprNode_CallMethod"); + INDENT(); + visit(node.m_val); + for( auto& arg : node.m_args ) + visit(arg); + UNINDENT(); +} +void NodeVisitor::visit(ExprNode_CallObject& node) +{ + DEBUG("DEF - ExprNode_CallObject"); + INDENT(); + visit(node.m_val); + for( auto& arg : node.m_args ) + visit(arg); + UNINDENT(); +} +void NodeVisitor::visit(ExprNode_Match& node) +{ + DEBUG("DEF - ExprNode_Match"); + INDENT(); + visit(node.m_val); + for( auto& arm : node.m_arms ) + visit(arm.second); + UNINDENT(); +} +void NodeVisitor::visit(ExprNode_If& node) +{ + DEBUG("DEF - ExprNode_If"); + INDENT(); + visit(node.m_cond); + visit(node.m_true); + visit(node.m_false); + UNINDENT(); +} + +void NodeVisitor::visit(ExprNode_Integer& node) +{ + DEBUG("DEF - ExprNode_Integer"); + // LEAF +} +void NodeVisitor::visit(ExprNode_StructLiteral& node) +{ + DEBUG("DEF - ExprNode_StructLiteral"); + visit(node.m_base_value); + for( auto& val : node.m_values ) + visit(val.second); +} +void NodeVisitor::visit(ExprNode_Tuple& node) +{ + DEBUG("DEF - ExprNode_Tuple"); + for( auto& val : node.m_values ) + visit(val); +} +void NodeVisitor::visit(ExprNode_NamedValue& node) +{ + DEBUG("DEF - ExprNode_NamedValue"); + // LEAF +} + +void NodeVisitor::visit(ExprNode_Field& node) +{ + DEBUG("DEF - ExprNode_Field"); + visit(node.m_obj); +} +void NodeVisitor::visit(ExprNode_Cast& node) +{ + DEBUG("DEF - ExprNode_Cast"); + visit(node.m_value); +} +void NodeVisitor::visit(ExprNode_BinOp& node) +{ + DEBUG("DEF - ExprNode_BinOp"); + visit(node.m_left); + visit(node.m_right); +} + + }; diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index db55c80c..ad2f906d 100644 --- a/src/ast/expr.hpp +++ b/src/ast/expr.hpp @@ -20,11 +20,14 @@ class NodeVisitor; class ExprNode: public Serialisable { + TypeRef m_res_type; public: virtual ~ExprNode() = 0; virtual void visit(NodeVisitor& nv) = 0; + TypeRef& get_res_type() { return m_res_type; } + static ::std::unique_ptr<ExprNode> from_deserialiser(Deserialiser& d); }; @@ -82,11 +85,13 @@ struct ExprNode_LetBinding: public ExprNode { Pattern m_pat; + TypeRef m_type; unique_ptr<ExprNode> m_value; ExprNode_LetBinding() {} - ExprNode_LetBinding(Pattern pat, unique_ptr<ExprNode>&& value): + ExprNode_LetBinding(Pattern pat, TypeRef type, unique_ptr<ExprNode>&& value): m_pat( move(pat) ), + m_type( move(type) ), m_value( move(value) ) { } @@ -342,79 +347,30 @@ struct ExprNode_BinOp: class NodeVisitor { public: - void visit(const unique_ptr<ExprNode>& cnode) { + inline void visit(const unique_ptr<ExprNode>& cnode) { if(cnode.get()) cnode->visit(*this); } - virtual void visit(ExprNode_Block& node) { - for( auto& child : node.m_nodes ) - visit(child); - } - virtual void visit(ExprNode_Macro& node) { - } - virtual void visit(ExprNode_Return& node) { - visit(node.m_value); - } - virtual void visit(ExprNode_LetBinding& node) { - // TODO: Handle recurse into Let pattern - visit(node.m_value); - } - virtual void visit(ExprNode_Assign& node) { - visit(node.m_slot); - visit(node.m_value); - } - virtual void visit(ExprNode_CallPath& node) { - for( auto& arg : node.m_args ) - visit(arg); - } - virtual void visit(ExprNode_CallMethod& node) { - visit(node.m_val); - for( auto& arg : node.m_args ) - visit(arg); - } - virtual void visit(ExprNode_CallObject& node) { - visit(node.m_val); - for( auto& arg : node.m_args ) - visit(arg); - } - virtual void visit(ExprNode_Match& node) { - visit(node.m_val); - for( auto& arm : node.m_arms ) - visit(arm.second); - } - virtual void visit(ExprNode_If& node) { - visit(node.m_cond); - visit(node.m_true); - visit(node.m_false); - } + virtual void visit(ExprNode_Block& node); + virtual void visit(ExprNode_Macro& node); + virtual void visit(ExprNode_Return& node); + virtual void visit(ExprNode_LetBinding& node); + virtual void visit(ExprNode_Assign& node); + virtual void visit(ExprNode_CallPath& node); + virtual void visit(ExprNode_CallMethod& node); + virtual void visit(ExprNode_CallObject& node); + virtual void visit(ExprNode_Match& node); + virtual void visit(ExprNode_If& node); - virtual void visit(ExprNode_Integer& node) { - // LEAF - } - virtual void visit(ExprNode_StructLiteral& node) { - visit(node.m_base_value); - for( auto& val : node.m_values ) - visit(val.second); - } - virtual void visit(ExprNode_Tuple& node) { - for( auto& val : node.m_values ) - visit(val); - } - virtual void visit(ExprNode_NamedValue& node) { - // LEAF - } + virtual void visit(ExprNode_Integer& node); + virtual void visit(ExprNode_StructLiteral& node); + virtual void visit(ExprNode_Tuple& node); + virtual void visit(ExprNode_NamedValue& node); - virtual void visit(ExprNode_Field& node) { - visit(node.m_obj); - } - virtual void visit(ExprNode_Cast& node) { - visit(node.m_value); - } - virtual void visit(ExprNode_BinOp& node) { - visit(node.m_left); - visit(node.m_right); - } + virtual void visit(ExprNode_Field& node); + virtual void visit(ExprNode_Cast& node); + virtual void visit(ExprNode_BinOp& node); }; class Expr: diff --git a/src/convert/typecheck_expr.cpp b/src/convert/typecheck_expr.cpp index 60a63a5b..43043fdb 100644 --- a/src/convert/typecheck_expr.cpp +++ b/src/convert/typecheck_expr.cpp @@ -9,6 +9,9 @@ class CTypeChecker: public CASTIterator { + friend class CTC_NodeVisitor; +protected: + void lookup_method(const TypeRef& type, const char* name); public: virtual void handle_function(AST::Path path, AST::Function& fcn) override; // - Ignore all non-function items on this pass @@ -16,31 +19,124 @@ public: virtual void handle_struct(AST::Path path, AST::Struct& str) override {} virtual void handle_alias(AST::Path path, AST::TypeAlias& ) override {} }; -class CNodeVisitor: +class CTC_NodeVisitor: public AST::NodeVisitor { CTypeChecker& m_tc; public: - CNodeVisitor(CTypeChecker& tc): + CTC_NodeVisitor(CTypeChecker& tc): m_tc(tc) {} - void visit(AST::ExprNode_LetBinding& node) override; + virtual void visit(AST::ExprNode_LetBinding& node) override; + + virtual void visit(AST::ExprNode_Match& node) override; + + virtual void visit(AST::ExprNode_CallMethod& node) override; }; void CTypeChecker::handle_function(AST::Path path, AST::Function& fcn) { - CNodeVisitor nv(*this); + DEBUG("(path = " << path << ")"); + CTC_NodeVisitor nv(*this); if( fcn.code().is_valid() ) { fcn.code().visit_nodes(nv); } } -void CNodeVisitor::visit(AST::ExprNode_LetBinding& node) +void CTypeChecker::lookup_method(const TypeRef& type, const char* name) +{ + DEBUG("(type = " << type << ", name = " << name << ")"); + // 1. Look for inherent methods on the type + // 2. Iterate all in-scope traits, and locate an impl of that trait for this type + //for(auto traitptr : m_scope_traits ) + //{ + // if( !traitptr ) continue; + // const auto& trait = *traitptr; + // if( trait.has_method(name) && trait.find_impl(type) ) + // { + // } + //} +} + +void CTC_NodeVisitor::visit(AST::ExprNode_LetBinding& node) { - // TODO: + DEBUG("ExprNode_LetBinding"); + + // Evaluate value + AST::NodeVisitor::visit(node.m_value); + + const TypeRef& bind_type = node.m_type; + const TypeRef& val_type = node.m_value->get_res_type(); + + // Obtain resultant type from value + // Compare to binding type + // - If both concrete, but different : error + if( !bind_type.is_wildcard() && !val_type.is_wildcard() ) + { + if( bind_type != val_type ) { + throw ::std::runtime_error( FMT("Type mismatch on let, expected " << bind_type << ", got " << val_type) ); + } + } + // - If value type concrete, but binding not : set binding to value + else if( !val_type.is_wildcard() ) + { + node.m_type = val_type; + } + // - If binding concrete, but value not : reverse propagate type (set result type of value node to binding type) + else if( !bind_type.is_wildcard() ) + { + // TODO: Check that value's current bind type's requirements fit this type + node.m_value->get_res_type() = bind_type; + } + // - If neither concrete, merge requirements of both + else + { + throw ::std::runtime_error("TODO - Merge type requirements"); + } + + m_tc.handle_pattern(node.m_pat, node.m_type); +} + +void CTC_NodeVisitor::visit(AST::ExprNode_Match& node) +{ + DEBUG("ExprNode_Match"); + AST::NodeVisitor::visit(node.m_val); + + for( auto& arm : node.m_arms ) + { + m_tc.start_scope(); + m_tc.handle_pattern(arm.first, node.m_val->get_res_type()); + AST::NodeVisitor::visit(arm.second); + m_tc.end_scope(); + } +} + +void CTC_NodeVisitor::visit(AST::ExprNode_CallMethod& node) +{ + DEBUG("ExprNode_CallMethod"); + + AST::NodeVisitor::visit(node.m_val); + + for( auto& arg : node.m_args ) + { + AST::NodeVisitor::visit(arg); + } + + // Locate method + const TypeRef& type = node.m_val->get_res_type(); + if( type.is_wildcard() ) + { + // No idea (yet) + // - TODO: Support case where a trait is known + } + else + { + // - Search for a method on this type + //const Function& fcn = type.lookup_method(node.m_method.name()); + } } void Typecheck_Expr(AST::Crate& crate) diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 3899a3c3..e74432f4 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -134,10 +134,17 @@ ExprNodeP Parse_Stmt(TokenStream& lex, bool& opt_semicolon) case TOK_RWORD_LET: {
//ret.append();
AST::Pattern pat = Parse_Pattern(lex);
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+ TypeRef type;
+ if( GET_TOK(tok, lex) == TOK_COLON ) {
+ type = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+ }
+ else {
+ CHECK_TOK(tok, TOK_EQUAL);
+ }
ExprNodeP val = Parse_Expr1(lex);
opt_semicolon = false;
- return NEWNODE( AST::ExprNode_LetBinding, ::std::move(pat), ::std::move(val) );
+ return NEWNODE( AST::ExprNode_LetBinding, ::std::move(pat), ::std::move(type), ::std::move(val) );
}
case TOK_RWORD_RETURN:
return NEWNODE( AST::ExprNode_Return, Parse_Expr1(lex) );
|