diff options
Diffstat (limited to 'src/hir_conv/constant_evaluation.cpp')
-rw-r--r-- | src/hir_conv/constant_evaluation.cpp | 302 |
1 files changed, 279 insertions, 23 deletions
diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 2544f85c..e64dd289 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -1,33 +1,176 @@ /* * Evaluate constants + * + * HACK - Should be replaced with a reentrant typeck/mir pass */ #include "main_bindings.hpp" #include <hir/hir.hpp> #include <hir/expr.hpp> #include <hir/visitor.hpp> - +#include <algorithm> namespace { - ::HIR::Function& get_function(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path) + ::HIR::Literal clone_literal(const ::HIR::Literal& v) + { + TU_MATCH(::HIR::Literal, (v), (e), + (Invalid, + return ::HIR::Literal(); + ), + (List, + ::std::vector< ::HIR::Literal> vals; + for(const auto& val : e) { + vals.push_back( clone_literal(val) ); + } + return ::HIR::Literal( mv$(vals) ); + ), + (Integer, + return ::HIR::Literal(e); + ), + (Float, + return ::HIR::Literal(e); + ), + (String, + return ::HIR::Literal(e); + ) + ) + throw ""; + } + + enum class EntType { + Function, + Constant, + Struct, + }; + const void* get_ent_simplepath(const Span& sp, const ::HIR::Crate& crate, const ::HIR::SimplePath& path, EntType et) + { + if( path.m_crate_name != "" ) + TODO(sp, "get_ent_simplepath in crate"); + + const ::HIR::Module* mod = &crate.m_root_module; + for( unsigned int i = 0; i < path.m_components.size() - 1; i ++ ) + { + const auto& pc = path.m_components[i]; + auto it = mod->m_mod_items.find( pc ); + if( it == mod->m_mod_items.end() ) { + BUG(sp, "Couldn't find component " << i << " of " << path); + } + TU_MATCH_DEF( ::HIR::TypeItem, (it->second->ent), (e2), + ( + BUG(sp, "Node " << i << " of path " << path << " wasn't a module"); + ), + (Module, + mod = &e2; + ) + ) + } + + switch( et ) + { + case EntType::Function: { + auto it = mod->m_value_items.find( path.m_components.back() ); + if( it == mod->m_value_items.end() ) { + return nullptr; + } + + TU_IFLET( ::HIR::ValueItem, it->second->ent, Function, e, + return &e; + ) + else { + BUG(sp, "Path " << path << " didn't point to a functon"); + } + } break; + case EntType::Constant: { + auto it = mod->m_value_items.find( path.m_components.back() ); + if( it == mod->m_value_items.end() ) { + return nullptr; + } + + TU_IFLET( ::HIR::ValueItem, it->second->ent, Constant, e, + return &e; + ) + else { + BUG(sp, "Path " << path << " didn't point to a functon"); + } + } break; + case EntType::Struct: { + auto it = mod->m_mod_items.find( path.m_components.back() ); + if( it == mod->m_mod_items.end() ) { + return nullptr; + } + + TU_IFLET( ::HIR::TypeItem, it->second->ent, Struct, e, + return &e; + ) + else { + BUG(sp, "Path " << path << " didn't point to a struct"); + } + } break; + } + throw ""; + } + const void* get_ent_fullpath(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path, EntType et) { TU_MATCH(::HIR::Path::Data, (path.m_data), (e), (Generic, - TODO(sp, "get_function(path = " << path << ")"); + return get_ent_simplepath(sp, crate, e.m_path, et); ), (UfcsInherent, // Easy (ish) - TODO(sp, "get_function(path = " << path << ")"); + for( const auto& impl : crate.m_type_impls ) + { + if( ! impl.matches_type(*e.type) ) { + continue ; + } + switch( et ) + { + case EntType::Function: { + auto fit = impl.m_methods.find(e.item); + if( fit == impl.m_methods.end() ) + continue ; + return &fit->second; + } break; + case EntType::Struct: + break; + case EntType::Constant: + break; + } + } + return nullptr; ), (UfcsKnown, - TODO(sp, "get_function(path = " << path << ")"); + TODO(sp, "get_ent_fullpath(path = " << path << ")"); ), (UfcsUnknown, // TODO - Since this isn't known, can it be searched properly? - TODO(sp, "get_function(path = " << path << ")"); + TODO(sp, "get_ent_fullpath(path = " << path << ")"); ) ) throw ""; } + const ::HIR::Function& get_function(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path) + { + auto* rv_p = reinterpret_cast<const ::HIR::Function*>( get_ent_fullpath(sp, crate, path, EntType::Function) ); + if( !rv_p ) { + TODO(sp, "get_function(path = " << path << ")"); + } + return *rv_p; + } + const ::HIR::Struct& get_struct(const Span& sp, const ::HIR::Crate& crate, const ::HIR::SimplePath& path) + { + auto rv_p = reinterpret_cast<const ::HIR::Struct*>( get_ent_simplepath(sp, crate, path, EntType::Struct) ); + if( !rv_p ) { + BUG(sp, "Could not find struct name in " << path); + } + return *rv_p; + } + const ::HIR::Constant& get_constant(const Span& sp, const ::HIR::Crate& crate, const ::HIR::Path& path) + { + auto rv_p = reinterpret_cast<const ::HIR::Constant*>( get_ent_fullpath(sp, crate, path, EntType::Constant) ); + if( !rv_p ) { + BUG(sp, "Could not find constant in " << path); + } + return *rv_p; + } ::HIR::Literal evaluate_constant(const ::HIR::Crate& crate, const ::HIR::ExprNode& expr) { @@ -35,6 +178,7 @@ namespace { public ::HIR::ExprVisitor { const ::HIR::Crate& m_crate; + ::std::vector< ::std::pair< ::std::string, ::HIR::Literal > > m_values; ::HIR::Literal m_rv; @@ -47,7 +191,8 @@ namespace { } void visit(::HIR::ExprNode_Block& node) override { - TODO(node.span(), "ExprNode_Block"); + for(const auto& e : node.m_nodes) + e->visit(*this); } void visit(::HIR::ExprNode_Return& node) override { TODO(node.span(), "ExprNode_Return"); @@ -169,10 +314,33 @@ namespace { } } void visit(::HIR::ExprNode_UniOp& node) override { - TODO(node.span(), "ExprNode_UniOp"); + node.m_value->visit(*this); + auto val = mv$(m_rv); + + switch(node.m_op) + { + case ::HIR::ExprNode_UniOp::Op::Ref: + case ::HIR::ExprNode_UniOp::Op::RefMut: + TODO(node.span(), "&/&mut in constant"); + break; + case ::HIR::ExprNode_UniOp::Op::Invert: + TU_MATCH_DEF(::HIR::Literal, (val), (e), + ( throw ""; ), + (Integer, m_rv = ::HIR::Literal(~e); ), + (Float, ERROR(node.span(), E0000, "not operator on float in constant"); ) + ) + case ::HIR::ExprNode_UniOp::Op::Negate: + TU_MATCH_DEF(::HIR::Literal, (val), (e), + ( throw ""; ), + (Integer, m_rv = ::HIR::Literal(-e); ), + (Float, m_rv = ::HIR::Literal(-e); ) + ) + } } void visit(::HIR::ExprNode_Cast& node) override { - TODO(node.span(), "ExprNode_Cast"); + node.m_value->visit(*this); + //auto val = mv$(m_rv); + //DEBUG("ExprNode_Cast - val = " << val << " as " << node.m_type); } void visit(::HIR::ExprNode_Index& node) override { badnode(node); @@ -182,17 +350,35 @@ namespace { } void visit(::HIR::ExprNode_CallPath& node) override { - ::std::vector<HIR::Literal> arg_vals; - for(const auto& arg : node.m_args) { - arg->visit(*this); - arg_vals.push_back( mv$(m_rv) ); + auto& fcn = get_function(node.span(), m_crate, node.m_path); + // TODO: Set m_const during parse + //if( ! fcn.m_const ) { + // ERROR(node.span(), E0000, "Calling non-const function in const context - " << node.m_path); + //} + if( fcn.m_args.size() != node.m_args.size() ) { + ERROR(node.span(), E0000, "Incorrect argument count for " << node.m_path); + } + for(unsigned int i = 0; i < fcn.m_args.size(); i ++ ) + { + const auto& pattern = fcn.m_args[i].first; + node.m_args[i]->visit(*this); + auto arg_val = mv$(m_rv); + TU_IFLET(::HIR::Pattern::Data, pattern.m_data, Any, e, + m_values.push_back( ::std::make_pair(pattern.m_binding.m_name, mv$(arg_val)) ); + ) + else { + ERROR(node.span(), E0000, "Constant functions can't have destructuring pattern argments"); + } } - auto& fcn = get_function(node.span(), m_crate, node.m_path); - if( ! fcn.m_const ) { - ERROR(node.span(), E0000, "Calling non-const function in const context"); + const_cast<HIR::ExprNode&>(*fcn.m_code).visit( *this ); + assert( ! m_rv.is_Invalid() ); + //TODO(node.span(), "exec const fn - " << node.m_path); + + for(unsigned int i = 0; i < fcn.m_args.size(); i ++ ) + { + m_values.pop_back(); } - TODO(node.span(), "exec const fn - " << node.m_path); } void visit(::HIR::ExprNode_CallValue& node) override { badnode(node); @@ -226,20 +412,85 @@ namespace { ) } void visit(::HIR::ExprNode_PathValue& node) override { - TODO(node.span(), "ExprNode_PathValue"); + const auto& c = get_constant(node.span(), m_crate, node.m_path); + if( c.m_value_res.is_Invalid() ) { + const_cast<HIR::ExprNode&>(*c.m_value).visit(*this); + } + else { + m_rv = clone_literal(c.m_value_res); + } } void visit(::HIR::ExprNode_Variable& node) override { - TODO(node.span(), "ExprNode_Variable"); + for(auto it = m_values.rbegin(); it != m_values.rend(); ++it) + { + if( it->first == node.m_name) { + TU_MATCH_DEF(::HIR::Literal, (it->second), (e), + ( + m_rv = mv$(it->second); + ), + (Integer, + m_rv = ::HIR::Literal(e); + ), + (Float, + m_rv = ::HIR::Literal(e); + ) + ) + return; + } + } + ERROR(node.span(), E0000, "Couldn't find variable " << node.m_name); } void visit(::HIR::ExprNode_StructLiteral& node) override { - TODO(node.span(), "ExprNode_StructLiteral"); + const auto& str = get_struct(node.span(), m_crate, node.m_path.m_path); + const auto& fields = str.m_data.as_Named(); + + ::std::vector< ::HIR::Literal> vals; + if( node.m_base_value ) { + node.m_base_value->visit(*this); + auto base_val = mv$(m_rv); + if( !base_val.is_List() || base_val.as_List().size() != fields.size() ) { + BUG(node.span(), "Struct literal base value had an incorrect field count"); + } + vals = mv$(base_val.as_List()); + } + else { + vals.resize( fields.size() ); + } + for( const auto& val_set : node.m_values ) { + unsigned int idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& v) { return v.first == val_set.first; } ) - fields.begin(); + if( idx == fields.size() ) { + ERROR(node.span(), E0000, "Field name " << val_set.first << " isn't a member of " << node.m_path); + } + val_set.second->visit(*this); + vals[idx] = mv$(m_rv); + } + for( unsigned int i = 0; i < vals.size(); i ++ ) { + const auto& val = vals[i]; + if( val.is_Invalid() ) { + ERROR(node.span(), E0000, "Field " << fields[i].first << " wasn't set"); + } + } + + m_rv = ::HIR::Literal::make_List(mv$(vals)); } void visit(::HIR::ExprNode_Tuple& node) override { - TODO(node.span(), "ExprNode_Tuple"); + ::std::vector< ::HIR::Literal> vals; + for(const auto& vn : node.m_vals ) { + vn->visit(*this); + assert( !m_rv.is_Invalid() ); + vals.push_back( mv$(m_rv) ); + } + m_rv = ::HIR::Literal::make_List(mv$(vals)); } void visit(::HIR::ExprNode_ArrayList& node) override { - TODO(node.span(), "ExprNode_ArrayList"); + ::std::vector< ::HIR::Literal> vals; + for(const auto& vn : node.m_vals ) { + vn->visit(*this); + assert( !m_rv.is_Invalid() ); + vals.push_back( mv$(m_rv) ); + } + m_rv = ::HIR::Literal::make_List(mv$(vals)); } void visit(::HIR::ExprNode_ArraySized& node) override { TODO(node.span(), "ExprNode_ArraySized"); @@ -288,7 +539,12 @@ namespace { void visit_constant(::HIR::Constant& item) override { item.m_value_res = evaluate_constant(m_crate, *item.m_value); - DEBUG("constant = " << item.m_value_res); + DEBUG("constant: " << item.m_type << " = " << item.m_value_res); + } + void visit_static(::HIR::Static& item) override + { + item.m_value_res = evaluate_constant(m_crate, *item.m_value); + DEBUG("static: " << item.m_type << " = " << item.m_value_res); } void visit_expr(::HIR::ExprPtr& expr) override { |