diff options
Diffstat (limited to 'src/mir/from_hir.cpp')
-rw-r--r-- | src/mir/from_hir.cpp | 347 |
1 files changed, 346 insertions, 1 deletions
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index d7c7992c..25fd4295 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -9,6 +9,7 @@ #include "mir.hpp" #include "mir_ptr.hpp" #include <hir/expr.hpp> +#include <hir/hir.hpp> #include <algorithm> namespace { @@ -416,6 +417,340 @@ namespace { this->push_stmt_assign(mv$(dst), mv$(val)); } } + + void visit(::HIR::ExprNode_BinOp& node) override + { + this->visit_node_ptr(node.m_left); + auto left = this->lvalue_or_temp( node.m_left->m_res_type, this->get_result(node.m_left->span()) ); + + this->visit_node_ptr(node.m_right); + auto right = this->lvalue_or_temp( node.m_right->m_res_type, this->get_result(node.m_right->span()) ); + + auto res = this->new_temporary(node.m_res_type); + ::MIR::eBinOp op; + switch(node.m_op) + { + case ::HIR::ExprNode_BinOp::Op::CmpEqu: op = ::MIR::eBinOp::EQ; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpNEqu:op = ::MIR::eBinOp::NE; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpLt: op = ::MIR::eBinOp::LT; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpLtE: op = ::MIR::eBinOp::LE; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGt: op = ::MIR::eBinOp::GT; if(0) + case ::HIR::ExprNode_BinOp::Op::CmpGtE: op = ::MIR::eBinOp::GE; + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_BinOp({ mv$(left), op, mv$(right) })); + break; + + case ::HIR::ExprNode_BinOp::Op::Xor: op = ::MIR::eBinOp::BIT_XOR; if(0) + case ::HIR::ExprNode_BinOp::Op::Or : op = ::MIR::eBinOp::BIT_OR ; if(0) + case ::HIR::ExprNode_BinOp::Op::And: op = ::MIR::eBinOp::BIT_AND; + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_BinOp({ mv$(left), op, mv$(right) })); + break; + + case ::HIR::ExprNode_BinOp::Op::Shr: op = ::MIR::eBinOp::BIT_SHR; if(0) + case ::HIR::ExprNode_BinOp::Op::Shl: op = ::MIR::eBinOp::BIT_SHL; + // TODO: Overflow checks + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_BinOp({ mv$(left), op, mv$(right) })); + break; + + case ::HIR::ExprNode_BinOp::Op::BoolAnd: + TODO(node.span(), "&&"); + break; + case ::HIR::ExprNode_BinOp::Op::BoolOr: + TODO(node.span(), "||"); + break; + + case ::HIR::ExprNode_BinOp::Op::Add: op = ::MIR::eBinOp::ADD; if(0) + case ::HIR::ExprNode_BinOp::Op::Sub: op = ::MIR::eBinOp::SUB; if(0) + case ::HIR::ExprNode_BinOp::Op::Mul: op = ::MIR::eBinOp::MUL; if(0) + case ::HIR::ExprNode_BinOp::Op::Div: op = ::MIR::eBinOp::DIV; if(0) + case ::HIR::ExprNode_BinOp::Op::Mod: op = ::MIR::eBinOp::MOD; + // TODO: Overflow checks + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_BinOp({ mv$(left), op, mv$(right) })); + break; + } + this->set_result( node.span(), mv$(res) ); + } + + void visit(::HIR::ExprNode_UniOp& node) override + { + this->visit_node_ptr(node.m_value); + auto val = this->lvalue_or_temp( node.m_value->m_res_type, this->get_result(node.m_value->span()) ); + + auto res = this->new_temporary(node.m_res_type); + switch(node.m_op) + { + case ::HIR::ExprNode_UniOp::Op::Ref: + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(val) })); + break; + case ::HIR::ExprNode_UniOp::Op::RefMut: + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Unique, mv$(val) })); + break; + case ::HIR::ExprNode_UniOp::Op::Invert: + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_UniOp({ mv$(val), ::MIR::eUniOp::INV })); + break; + case ::HIR::ExprNode_UniOp::Op::Negate: + this->push_stmt_assign(res.as_Temporary(), ::MIR::RValue::make_UniOp({ mv$(val), ::MIR::eUniOp::NEG })); + break; + } + this->set_result( node.span(), mv$(res) ); + } + void visit(::HIR::ExprNode_Cast& node) override + { + this->visit_node_ptr(node.m_value); + TODO(node.span(), "MIR _Cast"); + } + void visit(::HIR::ExprNode_Unsize& node) override + { + this->visit_node_ptr(node.m_value); + TODO(node.span(), "MIR _Unsize"); + } + void visit(::HIR::ExprNode_Index& node) override + { + this->visit_node_ptr(node.m_index); + auto index = this->lvalue_or_temp( node.m_index->m_res_type, this->get_result(node.m_index->span()) ); + + this->visit_node_ptr(node.m_value); + auto value = this->lvalue_or_temp( node.m_value->m_res_type, this->get_result(node.m_value->span()) ); + + if( false ) + { + ::MIR::RValue limit_val; + TU_MATCH_DEF(::HIR::TypeRef::Data, (node.m_value->m_res_type.m_data), (e), + ( + BUG(node.span(), "Indexing unsupported type " << node.m_value->m_res_type); + ), + (Array, + limit_val = ::MIR::Constant( e.size_val ); + ), + (Slice, + limit_val = ::MIR::RValue::make_DstMeta({ value.clone() }); + ) + ) + + auto limit_lval = this->lvalue_or_temp(node.m_index->m_res_type, mv$(limit_val)); + + auto cmp_res = this->new_temporary( ::HIR::CoreType::Bool ); + this->push_stmt_assign(cmp_res.clone(), ::MIR::RValue::make_BinOp({ index.clone(), ::MIR::eBinOp::GE, mv$(limit_lval) })); + auto arm_panic = this->new_bb_unlinked(); + auto arm_continue = this->new_bb_unlinked(); + this->end_block( ::MIR::Terminator::make_If({ mv$(cmp_res), arm_panic, arm_continue }) ); + + this->set_cur_block( arm_panic ); + // TODO: Call an "index fail" method which always panics. + //this->end_block( ::MIR::Terminator::make_Panic({}) ); + this->end_block( ::MIR::Terminator::make_Diverge({}) ); + + this->set_cur_block( arm_continue ); + } + + this->set_result( node.span(), ::MIR::LValue::make_Index({ box$(index), box$(value) }) ); + } + + void visit(::HIR::ExprNode_Deref& node) override + { + this->visit_node_ptr(node.m_value); + auto val = this->lvalue_or_temp( node.m_value->m_res_type, this->get_result(node.m_value->span()) ); + + this->set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) ); + } + + void visit(::HIR::ExprNode_TupleVariant& node) override + { + ::std::vector< ::MIR::LValue> values; + values.reserve( node.m_args.size() ); + for(auto& arg : node.m_args) + { + this->visit_node_ptr(arg); + values.push_back( this->lvalue_or_temp( arg->m_res_type, this->get_result(arg->span()) ) ); + } + + this->set_result( node.span(), ::MIR::RValue::make_Struct({ + node.m_path.clone(), + mv$(values) + }) ); + } + + void visit(::HIR::ExprNode_CallPath& node) override + { + ::std::vector< ::MIR::LValue> values; + values.reserve( node.m_args.size() ); + for(auto& arg : node.m_args) + { + this->visit_node_ptr(arg); + values.push_back( this->lvalue_or_temp( arg->m_res_type, this->get_result(arg->span()) ) ); + } + + // TODO: Obtain function type for this function + auto fcn_val = this->new_temporary( ::HIR::TypeRef(::HIR::FunctionType { + } ) ); + + auto panic_block = this->new_bb_unlinked(); + auto next_block = this->new_bb_unlinked(); + auto res = this->new_temporary( node.m_res_type ); + this->end_block(::MIR::Terminator::make_Call({ + next_block, panic_block, + res.clone(), mv$(fcn_val), + mv$(values) + })); + + this->set_cur_block(panic_block); + // TODO: Proper panic handling + this->end_block( ::MIR::Terminator::make_Diverge({}) ); + + this->set_cur_block( next_block ); + this->set_result( node.span(), mv$(res) ); + } + + void visit(::HIR::ExprNode_CallValue& node) override + { + BUG(node.span(), "Leftover _CallValue"); + } + void visit(::HIR::ExprNode_CallMethod& node) override + { + BUG(node.span(), "Leftover _CallValue"); + } + void visit(::HIR::ExprNode_Field& node) override + { + this->visit_node_ptr(node.m_value); + auto val = this->get_result_lvalue(node.m_value->span()); + + unsigned int idx; + if( '0' <= node.m_field[0] && node.m_field[0] <= '9' ) { + ::std::stringstream(node.m_field) >> idx; + } + else { + const auto& str = *node.m_value->m_res_type.m_data.as_Path().binding.as_Struct(); + const auto& fields = str.m_data.as_Named(); + idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); + } + this->set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); + } + void visit(::HIR::ExprNode_Literal& node) override + { + TODO(node.span(), "Primitive literals"); + } + void visit(::HIR::ExprNode_UnitVariant& node) override + { + this->set_result( node.span(), ::MIR::RValue::make_Struct({ + node.m_path.clone(), + {} + }) ); + } + void visit(::HIR::ExprNode_PathValue& node) override + { + this->set_result( node.span(), ::MIR::LValue::make_Static(node.m_path.clone()) ); + } + void visit(::HIR::ExprNode_Variable& node) override + { + this->set_result( node.span(), ::MIR::LValue::make_Variable(node.m_slot) ); + } + + void visit(::HIR::ExprNode_StructLiteral& node) override + { + ::MIR::LValue base_val; + if( node.m_base_value ) + { + this->visit_node_ptr(node.m_base_value); + base_val = this->get_result_lvalue(node.m_base_value->span()); + } + + const ::HIR::t_struct_fields* fields_ptr = nullptr; + TU_MATCH(::HIR::TypeRef::TypePathBinding, (node.m_res_type.m_data.as_Path().binding), (e), + (Unbound, ), + (Opaque, ), + (Enum, + const auto& var_name = node.m_path.m_path.m_components.back(); + const auto& enm = *e; + auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; }); + assert(it != enm.m_variants.end()); + fields_ptr = &it->second.as_Struct(); + ), + (Struct, + fields_ptr = &e->m_data.as_Named(); + ) + ) + assert(fields_ptr); + const ::HIR::t_struct_fields& fields = *fields_ptr; + + ::std::vector<bool> values_set; + ::std::vector< ::MIR::LValue> values; + values.resize( fields.size() ); + values_set.resize( fields.size() ); + + for(auto& ent : node.m_values) + { + auto idx = ::std::find_if(fields.begin(), fields.end(), [&](const auto&x){ return x.first == ent.first; }) - fields.begin(); + assert( !values_set[idx] ); + values_set[idx] = true; + this->visit_node_ptr(ent.second); + values.at(idx) = this->lvalue_or_temp( ent.second->m_res_type, this->get_result(ent.second->span()) ); + } + for(unsigned int i = 0; i < values.size(); i ++) + { + if( !values_set[i] ) { + if( !node.m_base_value) { + ERROR(node.span(), E0000, "Field '" << fields[i].first << "' not specified"); + } + values[i] = ::MIR::LValue::make_Field({ box$( base_val.clone() ), i }); + } + else { + // Drop unused part of the base + if( node.m_base_value) { + this->push_stmt_drop( ::MIR::LValue::make_Field({ box$( base_val.clone() ), i }) ); + } + } + } + + this->set_result( node.span(), ::MIR::RValue::make_Struct({ + node.m_path.clone(), + mv$(values) + }) ); + } + + void visit(::HIR::ExprNode_Tuple& node) override + { + ::std::vector< ::MIR::LValue> values; + values.reserve( node.m_vals.size() ); + for(auto& arg : node.m_vals) + { + this->visit_node_ptr(arg); + values.push_back( this->lvalue_or_temp( arg->m_res_type, this->get_result(arg->span()) ) ); + } + + this->set_result( node.span(), ::MIR::RValue::make_Tuple({ + mv$(values) + }) ); + } + + void visit(::HIR::ExprNode_ArrayList& node) override + { + ::std::vector< ::MIR::LValue> values; + values.reserve( node.m_vals.size() ); + for(auto& arg : node.m_vals) + { + this->visit_node_ptr(arg); + values.push_back( this->lvalue_or_temp( arg->m_res_type, this->get_result(arg->span()) ) ); + } + + this->set_result( node.span(), ::MIR::RValue::make_Array({ + mv$(values) + }) ); + } + + void visit(::HIR::ExprNode_ArraySized& node) override + { + this->visit_node_ptr( node.m_val ); + auto value = this->lvalue_or_temp( node.m_val->m_res_type, this->get_result(node.m_val->span()) ); + + this->set_result( node.span(), ::MIR::RValue::make_SizedArray({ + mv$(value), + static_cast<unsigned int>(node.m_size_val) + }) ); + } + + void visit(::HIR::ExprNode_Closure& node) override + { + TODO(node.span(), "_Closure"); + } }; } @@ -424,9 +759,19 @@ namespace { { ::MIR::Function fcn; + ExprVisitor_Conv ev { fcn }; + // 1. Apply destructuring to arguments + unsigned int i = 0; + for( const auto& arg : args ) + { + ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); + } + // 2. Destructure code + ::HIR::ExprNode& root_node = const_cast<::HIR::ExprNode&>(*ptr); + root_node.visit( ev ); - return ::MIR::FunctionPointer(); + return ::MIR::FunctionPointer(new ::MIR::Function(mv$(fcn))); } |