summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.hpp2
-rw-r--r--src/ast/path.hpp4
-rw-r--r--src/common.hpp43
-rw-r--r--src/convert/ast_iterate.cpp72
-rw-r--r--src/convert/ast_iterate.hpp6
-rw-r--r--src/convert/resolve.cpp22
-rw-r--r--src/convert/typecheck_expr.cpp107
-rw-r--r--src/include/serialise.hpp1
-rw-r--r--src/types.hpp1
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; }