diff options
Diffstat (limited to 'src/hir_conv/constant_evaluation.cpp')
-rw-r--r-- | src/hir_conv/constant_evaluation.cpp | 154 |
1 files changed, 110 insertions, 44 deletions
diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 909c70da..47a0db6d 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -41,6 +41,13 @@ namespace { } return ::HIR::Literal( mv$(vals) ); ), + (Variant, + ::std::vector< ::HIR::Literal> vals; + for(const auto& val : e.vals) { + vals.push_back( clone_literal(val) ); + } + return ::HIR::Literal::make_Variant({ e.idx, mv$(vals) }); + ), (Integer, return ::HIR::Literal(e); ), @@ -194,16 +201,6 @@ namespace { TODO(sp, "Could not find function for " << path << " - " << rv.tag_str()); } } - const ::HIR::Struct& get_struct(const Span& sp, const ::HIR::Crate& crate, const ::HIR::SimplePath& path) - { - auto rv = get_ent_fullpath(sp, crate, path, EntNS::Type); - TU_IFLET( EntPtr, rv, Struct, e, - return *e; - ) - else { - TODO(sp, "Could not find struct for " << path << " - " << rv.tag_str()); - } - } ::HIR::Literal evaluate_constant_hir(const Span& sp, const ::HIR::Crate& crate, NewvalState newval_state, const ::HIR::ExprNode& expr, ::std::vector< ::HIR::Literal> args) { @@ -421,16 +418,37 @@ namespace { } void visit(::HIR::ExprNode_TupleVariant& node) override { - if( ! node.m_is_struct ) { - TODO(node.span(), "_TupleVariant - Enum"); - } + ::std::vector< ::HIR::Literal> vals; for(const auto& vn : node.m_args ) { vn->visit(*this); assert( !m_rv.is_Invalid() ); vals.push_back( mv$(m_rv) ); } - m_rv = ::HIR::Literal::make_List(mv$(vals)); + + if( node.m_is_struct ) + { + const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); + ASSERT_BUG(node.span(), ent.is_Struct(), "_TupleVariant with m_is_struct set pointing to " << ent.tag_str()); + //const auto& str = ent.as_Struct(); + + m_rv = ::HIR::Literal::make_List(mv$(vals)); + } + else + { + const auto& varname = node.m_path.m_path.m_components.back(); + auto tmp_path = node.m_path.m_path; + tmp_path.m_components.pop_back(); + const auto& ent = m_crate.get_typeitem_by_path(node.span(), tmp_path); + ASSERT_BUG(node.span(), ent.is_Enum(), "_TupleVariant with m_is_struct clear pointing to " << ent.tag_str()); + const auto& enm = ent.as_Enum(); + + auto it = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&x){ return x.first == varname; } ); + ASSERT_BUG(node.span(), it != enm.m_variants.end(), "_TupleVariant points to unknown variant - " << node.m_path); + unsigned int var_idx = it - enm.m_variants.begin(); + + m_rv = ::HIR::Literal::make_Variant({var_idx, mv$(vals)}); + } } void visit(::HIR::ExprNode_CallPath& node) override { TRACE_FUNCTION_FR("_CallPath - " << node.m_path, m_rv); @@ -495,7 +513,29 @@ namespace { ) } void visit(::HIR::ExprNode_UnitVariant& node) override { - TODO(node.span(), "Unit varant/struct constructors in constant context"); + if( node.m_is_struct ) + { + const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); + ASSERT_BUG(node.span(), ent.is_Struct(), "_UnitVariant with m_is_struct set pointing to " << ent.tag_str()); + //const auto& str = ent.as_Struct(); + + m_rv = ::HIR::Literal::make_List({}); + } + else + { + const auto& varname = node.m_path.m_path.m_components.back(); + auto tmp_path = node.m_path.m_path; + tmp_path.m_components.pop_back(); + const auto& ent = m_crate.get_typeitem_by_path(node.span(), tmp_path); + ASSERT_BUG(node.span(), ent.is_Enum(), "_UnitVariant with m_is_struct clear pointing to " << ent.tag_str()); + const auto& enm = ent.as_Enum(); + + auto it = ::std::find_if( enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&x){ return x.first == varname; } ); + ASSERT_BUG(node.span(), it != enm.m_variants.end(), "_UnitVariant points to unknown variant - " << node.m_path); + unsigned int var_idx = it - enm.m_variants.begin(); + + m_rv = ::HIR::Literal::make_Variant({var_idx, {}}); + } } void visit(::HIR::ExprNode_PathValue& node) override { TRACE_FUNCTION_FR("_PathValue - " << node.m_path, m_rv); @@ -541,37 +581,49 @@ namespace { void visit(::HIR::ExprNode_StructLiteral& node) override { TRACE_FUNCTION_FR("_StructLiteral - " << node.m_path, m_rv); - 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"); + // TODO: Fix for enums - see _UnitVariant and _TupleVariant + const auto& ent = m_crate.get_typeitem_by_path(node.span(), node.m_path.m_path); + TU_IFLET( ::HIR::TypeItem, ent, Struct, str, + ASSERT_BUG(node.span(), node.m_is_struct, "_StructLiteral with m_is_struct clear pointing to a struct"); + 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()); } - 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); + else { + vals.resize( fields.size() ); } - 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"); + 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)); + m_rv = ::HIR::Literal::make_List(mv$(vals)); + ) + else TU_IFLET( ::HIR::TypeItem, ent, Enum, enm, + ASSERT_BUG(node.span(), !node.m_is_struct, "_StructLiteral with m_is_struct set pointing to an enum"); + TODO(node.span(), "Handle Enum _UnitVariant - " << node.m_path); + ) + else { + BUG(node.span(), "Could not find struct/enum for " << node.m_path << " - " << ent.tag_str()); + } } void visit(::HIR::ExprNode_Tuple& node) override { ::std::vector< ::HIR::Literal> vals; @@ -762,6 +814,7 @@ namespace { uint64_t mask; switch(te) { + // Integers mask down case ::HIR::CoreType::I8: case ::HIR::CoreType::U8: mask = 0xFF; @@ -791,6 +844,15 @@ namespace { default: TODO(sp, "RValue::Cast to " << e.type << ", val = " << inval); } + ), + // Allow casting any integer value to a pointer (TODO: Ensure that the pointer is sized?) + (Pointer, + TU_IFLET( ::HIR::Literal, inval, Integer, i, + val = ::HIR::Literal(i); + ) + else { + BUG(sp, "Invalid cast of " << inval.tag_str() << " to " << e.type); + } ) ) ), @@ -932,6 +994,7 @@ namespace { void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override { visit_type(item.m_type); + assert(item.m_value); item.m_value_res = evaluate_constant(item.m_value->span(), m_crate, NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$") }, item.m_value, {}); DEBUG("constant: " << item.m_type << " = " << item.m_value_res); visit_expr(item.m_value); @@ -939,9 +1002,12 @@ namespace { void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override { visit_type(item.m_type); - item.m_value_res = evaluate_constant(item.m_value->span(), m_crate, NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$") }, item.m_value, {}); - DEBUG("static: " << item.m_type << " = " << item.m_value_res); - visit_expr(item.m_value); + if( item.m_value ) + { + item.m_value_res = evaluate_constant(item.m_value->span(), m_crate, NewvalState { m_new_values, *m_mod_path, FMT(p.get_name() << "$") }, item.m_value, {}); + DEBUG("static: " << item.m_type << " = " << item.m_value_res); + visit_expr(item.m_value); + } } void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override { for(auto& var : item.m_variants) |