summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/expr.cpp122
-rw-r--r--src/ast/expr.hpp92
-rw-r--r--src/convert/typecheck_expr.cpp108
-rw-r--r--src/parse/expr.cpp11
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) );