diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ast/ast.hpp | 2 | ||||
-rw-r--r-- | src/ast/path.hpp | 4 | ||||
-rw-r--r-- | src/common.hpp | 43 | ||||
-rw-r--r-- | src/convert/ast_iterate.cpp | 72 | ||||
-rw-r--r-- | src/convert/ast_iterate.hpp | 6 | ||||
-rw-r--r-- | src/convert/resolve.cpp | 22 | ||||
-rw-r--r-- | src/convert/typecheck_expr.cpp | 107 | ||||
-rw-r--r-- | src/include/serialise.hpp | 1 | ||||
-rw-r--r-- | src/types.hpp | 1 |
9 files changed, 216 insertions, 42 deletions
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 64726ecd..261deb47 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -554,7 +554,7 @@ class Flat ::std::vector< ::std::pair< ::std::string,Function> > m_functions;
public:
- const ::std::vector< ::std::pair<::std::string, Function> >& functions() const { return m_functions; }
+ const ::std::vector< ::std::pair< ::std::string, Function> >& functions() const { return m_functions; }
const ::std::vector<CStruct>& structs() const { return m_structs; }
};
diff --git a/src/ast/path.hpp b/src/ast/path.hpp index cfdf16c2..4ff128c6 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -178,8 +178,8 @@ public: ::std::vector<PathNode>& nodes() { return m_nodes; } const ::std::vector<PathNode>& nodes() const { return m_nodes; } - PathNode& operator[](size_t idx) { return m_nodes[idx]; } - const PathNode& operator[](size_t idx) const { return m_nodes[idx]; } + PathNode& operator[](int idx) { if(idx>=0) return m_nodes[idx]; else return m_nodes[size()+idx]; } + const PathNode& operator[](int idx) const { if(idx>=0) return m_nodes[idx]; else return m_nodes[size()+idx]; } bool operator==(const Path& x) const; diff --git a/src/common.hpp b/src/common.hpp index c73db0e8..0736f2fc 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -28,6 +28,49 @@ struct RepeatLitStr } }; +template<typename T> +class slice +{ + T* m_first; + unsigned int m_len; +public: + slice(::std::vector<T>& v): + m_first(&v[0]), + m_len(v.size()) + {} + + ::std::vector<T> to_vec() const { + return ::std::vector<T>(begin(), end()); + } + + unsigned int size() const { + return m_len; + } + T& operator[](unsigned int i) const { + assert(i < m_len); + return m_first[i]; + } + + T* begin() const { return m_first; } + T* end() const { return m_first + m_len; } +}; + +template<typename T> +::std::ostream& operator<<(::std::ostream& os, slice<T> s) { + if( s.size() > 0 ) + { + bool is_first = true; + for( const auto& i : s ) + { + if(!is_first) + os << ", "; + is_first = false; + os << i; + } + } + return os; +} + namespace rust { template<typename T> diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp index 26ef2191..4d147c70 100644 --- a/src/convert/ast_iterate.cpp +++ b/src/convert/ast_iterate.cpp @@ -73,11 +73,66 @@ void CASTIterator::handle_pattern(AST::Pattern& pat, const TypeRef& type_hint) break; case AST::Pattern::TUPLE: // Tuple is handled by subpattern code + if( type_hint.is_wildcard() ) + { + for( auto& sp : pat.sub_patterns() ) + handle_pattern(sp, (const TypeRef&)TypeRef()); + } + else if( !type_hint.is_tuple() ) + { + throw ::std::runtime_error("Tuple pattern on non-tuple value"); + } + else + { + if( type_hint.sub_types().size() != pat.sub_patterns().size() ) + { + throw ::std::runtime_error("Tuple pattern count doesn't match"); + } + for( unsigned int i = 0; i < pat.sub_patterns().size(); i ++ ) + { + handle_pattern(pat.sub_patterns()[i], type_hint.sub_types()[i]); + } + } break; case AST::Pattern::TUPLE_STRUCT: // Resolve the path! // - TODO: Restrict to types and enum variants handle_path( pat.path(), CASTIterator::MODE_TYPE ); + // Handle sub-patterns + if( type_hint.is_wildcard() ) + { + for( auto& sp : pat.sub_patterns() ) + handle_pattern(sp, (const TypeRef&)TypeRef()); + } + else if( !type_hint.is_path() ) + { + throw ::std::runtime_error("Tuple struct pattern on non-tuple value"); + } + else + { + auto& hint_path = type_hint.path(); + auto& pat_path = pat.path(); + DEBUG("Pat: " << pat.path() << ", Type: " << type_hint.path()); + switch( hint_path.binding_type() ) + { + case AST::Path::UNBOUND: + throw ::std::runtime_error("Unbound path in pattern"); + case AST::Path::ENUM: { + // The pattern's path must refer to a variant of the hint path + // - Actual type params are checked by the 'handle_pattern_enum' code + if( pat_path.binding_type() != AST::Path::ENUM_VAR ) + throw ::std::runtime_error(FMT("Paths in pattern are invalid")); + if( &pat_path.bound_enum() != &hint_path.bound_enum() ) + throw ::std::runtime_error(FMT("Paths in pattern are invalid")); + auto& enm = pat_path.bound_enum(); + auto idx = pat_path.bound_idx(); + auto& var = enm.variants().at(idx); + handle_pattern_enum(pat_path[-2].args(), hint_path[-1].args(), enm.params(), var, pat.sub_patterns()); + break; } + default: + throw ::std::runtime_error(FMT("Bad type in tuple struct pattern : " << type_hint.path())); + } + } break; } // Extract bindings and add to namespace @@ -89,8 +144,16 @@ void CASTIterator::handle_pattern(AST::Pattern& pat, const TypeRef& type_hint) local_variable( false, pat.binding(), type_hint ); } } - for( auto& subpat : pat.sub_patterns() ) - handle_pattern(subpat, (const TypeRef&)TypeRef()); +} +void CASTIterator::handle_pattern_enum( + ::std::vector<TypeRef>& pat_args, const ::std::vector<TypeRef>& hint_args, + const AST::TypeParams& enum_params, const AST::StructItem& var, + ::std::vector<AST::Pattern>& sub_patterns + ) +{ + // This implementation doesn't attempt to do anything with types, just propagates _ + for( auto& sp : sub_patterns ) + handle_pattern(sp, (const TypeRef&)TypeRef()); } void CASTIterator::handle_module(AST::Path path, AST::Module& mod) @@ -142,6 +205,8 @@ void CASTIterator::handle_module(AST::Path path, AST::Module& mod) } void CASTIterator::handle_function(AST::Path path, AST::Function& fcn) { + INDENT(); + DEBUG("(" << path << ", ..."); start_scope(); handle_params(fcn.params()); @@ -157,10 +222,13 @@ void CASTIterator::handle_function(AST::Path path, AST::Function& fcn) if( fcn.code().is_valid() ) { + INDENT(); handle_expr( fcn.code().node() ); + UNINDENT(); } end_scope(); + UNINDENT(); } void CASTIterator::handle_impl(AST::Path modpath, AST::Impl& impl) { diff --git a/src/convert/ast_iterate.hpp b/src/convert/ast_iterate.hpp index 756d8ca2..979831a5 100644 --- a/src/convert/ast_iterate.hpp +++ b/src/convert/ast_iterate.hpp @@ -11,6 +11,7 @@ class ExprNode; class Pattern; class TypeParams; class Impl; +template<typename T> struct Item; }; @@ -36,6 +37,11 @@ public: virtual void end_scope(); virtual void handle_pattern(AST::Pattern& pat, const TypeRef& type_hint); + virtual void handle_pattern_enum( + ::std::vector<TypeRef>& pat_args, const ::std::vector<TypeRef>& hint_args, + const AST::TypeParams& enum_params, const AST::Item<TypeRef>& var, + ::std::vector<AST::Pattern>& sub_patterns + ); virtual void handle_module(AST::Path path, AST::Module& mod); diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 4c79a401..3c10a133 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -457,15 +457,31 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod }
}
-void SetCrateName_Mod(::std::string name, AST::Module& mod)
+void SetCrateName_Type(const AST::Crate& crate, ::std::string name, TypeRef& type)
+{
+ if( type.is_path() )
+ {
+ type.path().set_crate(name);
+ type.path().resolve(crate);
+ }
+}
+
+void SetCrateName_Mod(const AST::Crate& crate, ::std::string name, AST::Module& mod)
{
for(auto& submod : mod.submods())
- SetCrateName_Mod(name, submod.first);
+ SetCrateName_Mod(crate, name, submod.first);
// Imports 'use' statements
for(auto& imp : mod.imports())
+ {
imp.data.set_crate(name);
+ imp.data.resolve(crate);
+ }
// TODO: All other types
+ for(auto& fcn : mod.functions())
+ {
+ SetCrateName_Type(crate, name, fcn.data.rettype());
+ }
}
@@ -478,7 +494,7 @@ void ResolvePaths(AST::Crate& crate) // Pre-process external crates to tag all paths
for(auto& ec : crate.extern_crates())
{
- SetCrateName_Mod(ec.first, ec.second.root_module());
+ SetCrateName_Mod(crate, ec.first, ec.second.root_module());
}
// Handle 'use' statements in an initial parss
diff --git a/src/convert/typecheck_expr.cpp b/src/convert/typecheck_expr.cpp index 3c39d9a4..852f1c12 100644 --- a/src/convert/typecheck_expr.cpp +++ b/src/convert/typecheck_expr.cpp @@ -38,6 +38,12 @@ public: virtual void handle_params(AST::TypeParams& params) override; + virtual void handle_pattern_enum( + ::std::vector<TypeRef>& pat_args, const ::std::vector<TypeRef>& hint_args, + const AST::TypeParams& enum_params, const AST::StructItem& var, + ::std::vector<AST::Pattern>& sub_patterns + ) override; + virtual void handle_function(AST::Path path, AST::Function& fcn) override; // - Ignore all non-function items on this pass virtual void handle_enum(AST::Path path, AST::Enum& ) override {} @@ -49,6 +55,10 @@ private: const TypeRef& get_local_type(const char* name); const TypeRef& get_type_param(const char* name); + void check_enum_variant( + ::std::vector<TypeRef>& path_args, const ::std::vector<TypeRef>& argtypes, + const AST::TypeParams& params, const AST::StructItem& var + ); void iterate_traits(::std::function<bool(const TypeRef& trait)> fcn); }; class CTC_NodeVisitor: @@ -112,6 +122,32 @@ void CTypeChecker::handle_params(AST::TypeParams& params) assert(m_scopes.back().params.size() == 0); m_scopes.back().params = trs; } +void CTypeChecker::handle_pattern_enum( + ::std::vector<TypeRef>& pat_args, const ::std::vector<TypeRef>& hint_args, + const AST::TypeParams& enum_params, const AST::StructItem& var, + ::std::vector<AST::Pattern>& sub_patterns + ) +{ + check_enum_variant(pat_args, hint_args, enum_params, var); + + // Ensure that sub_patterns is the same length as the variant + assert(var.data.is_tuple()); + const auto& var_types = var.data.sub_types(); + if( sub_patterns.size() != var_types.size() ) + throw ::std::runtime_error(FMT("Enum pattern size mismatch")); + for( unsigned int i = 0; i < sub_patterns.size(); i ++ ) + { + // TODO: Need to propagate types through here correctly. + // - hint_args -> enum -> this + TypeRef arg = var_types[i]; + arg.resolve_args([&](const char *name){ + int i = enum_params.find_name(name); + if(i < 0) throw ""; + return hint_args[i]; + }); + handle_pattern(sub_patterns[i], var_types[i]); + } +} TypeRef& CTypeChecker::get_local_var(const char* name) { @@ -211,6 +247,40 @@ void CTypeChecker::iterate_traits(::std::function<bool(const TypeRef& trait)> fc } } +void CTypeChecker::check_enum_variant(::std::vector<TypeRef>& path_args, const ::std::vector<TypeRef>& argtypes, const AST::TypeParams& params, const AST::StructItem& var) +{ + // We know the enum, but it might have type params, need to handle that case + if( params.n_params() > 0 ) + { + // 1. Obtain the pattern set from the path (should it be pre-marked with _ types?) + while( path_args.size() < params.n_params() ) + path_args.push_back( TypeRef() ); + DEBUG("path_args = [" << path_args << "]"); + // 2. Create a pattern from the argument types and the format of the variant + DEBUG("argtypes = [" << argtypes << "]"); + ::std::vector<TypeRef> item_args(params.n_params()); + DEBUG("variant type = " << var.data << ""); + var.data.match_args( + TypeRef(TypeRef::TagTuple(), argtypes), + [&](const char *name, const TypeRef& t) { + DEBUG("Binding " << name << " to type " << t); + int idx = params.find_name(name); + if( idx == -1 ) { + throw ::std::runtime_error(FMT("Can't find generic " << name)); + } + item_args.at(idx).merge_with( t ); + } + ); + DEBUG("item_args = [" << item_args << "]"); + // 3. Merge the two sets of arguments + for( unsigned int i = 0; i < path_args.size(); i ++ ) + { + path_args[i].merge_with( item_args[i] ); + } + DEBUG("new path_args = [" << path_args << "]"); + } +} + /// Named value - leaf void CTC_NodeVisitor::visit(AST::ExprNode_NamedValue& node) { @@ -507,40 +577,9 @@ void CTC_NodeVisitor::visit(AST::ExprNode_CallPath& node) { const AST::Enum& enm = node.m_path.bound_enum(); const unsigned int idx = node.m_path.bound_idx(); - const auto& var = enm.variants().at(idx); - - const auto& params = enm.params(); - // We know the enum, but it might have type params, need to handle that case - - if( params.n_params() > 0 ) - { - // 1. Obtain the pattern set from the path (should it be pre-marked with _ types?) - auto& path_args = node.m_path[node.m_path.size()-2].args(); - while( path_args.size() < params.n_params() ) - path_args.push_back( TypeRef() ); - DEBUG("path_args = [" << path_args << "]"); - // 2. Create a pattern from the argument types and the format of the variant - DEBUG("argtypes = [" << argtypes << "]"); - ::std::vector<TypeRef> item_args(enm.params().n_params()); - DEBUG("variant type = " << var.data << ""); - var.data.match_args( - TypeRef(TypeRef::TagTuple(), argtypes), - [&](const char *name, const TypeRef& t) { - DEBUG("Binding " << name << " to type " << t); - int idx = params.find_name(name); - if( idx == -1 ) { - throw ::std::runtime_error(FMT("Can't find generic " << name)); - } - item_args.at(idx).merge_with( t ); - }); - DEBUG("item_args = [" << item_args << "]"); - // 3. Merge the two sets of arguments - for( unsigned int i = 0; i < path_args.size(); i ++ ) - { - path_args[i].merge_with( item_args[i] ); - } - DEBUG("new path_args = [" << path_args << "]"); - } + + auto& path_node_enum = node.m_path[node.m_path.size()-2]; + m_tc.check_enum_variant(path_node_enum.args(), argtypes, enm.params(), enm.variants().at(idx)); AST::Path p = node.m_path; p.nodes().pop_back(); diff --git a/src/include/serialise.hpp b/src/include/serialise.hpp index 000f8141..3949c8ae 100644 --- a/src/include/serialise.hpp +++ b/src/include/serialise.hpp @@ -7,6 +7,7 @@ #include <string> #include <map> #include <memory> +#include <stdexcept> class Serialiser; class Deserialiser; diff --git a/src/types.hpp b/src/types.hpp index 4864e703..d15c77ab 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -159,6 +159,7 @@ public: bool is_path() const { return m_class == PATH; }
bool is_type_param() const { return m_class == GENERIC; }
bool is_reference() const { return m_class == REFERENCE; }
+ bool is_tuple() const { return m_class == TUPLE; }
const ::std::string& type_param() const { assert(is_type_param()); return m_path[0].name(); }
AST::Path& path() { assert(is_path() || m_class == ASSOCIATED); return m_path; }
const AST::Path& path() const { assert(is_path() || m_class == ASSOCIATED); return m_path; }
|