/* * MRustC - Rust Compiler * - By John Hodge (Mutabah/thePowersGang) * * mir/from_hir.hpp * - Construction of MIR from the HIR expression tree */ #pragma once #include "mir.hpp" #include #include // for ExprNode_Match class MirBuilder; class ScopeHandle { friend class MirBuilder; const MirBuilder& m_builder; unsigned int idx; ScopeHandle(const MirBuilder& builder, unsigned int idx): m_builder(builder), idx(idx) { } public: ScopeHandle(const ScopeHandle& x) = delete; ScopeHandle(ScopeHandle&& x): m_builder(x.m_builder), idx(x.idx) { x.idx = ~0; } ScopeHandle& operator=(const ScopeHandle& x) = delete; ScopeHandle& operator=(ScopeHandle&& x) = delete; ~ScopeHandle(); }; enum class VarState { Uninit, // No value assigned yet Init, // Initialised and valid at this point MaybeMoved, // Possibly has been moved Moved, // Definitely moved Dropped, // Dropped (out of scope) }; extern ::std::ostream& operator<<(::std::ostream& os, VarState x); struct SplitArm { bool has_early_terminated = false; bool always_early_terminated = false; // Populated on completion ::std::vector changed_var_states; // Indexed by binding bumber ::std::vector var_states; }; TAGGED_UNION(ScopeType, Variables, (Variables, struct { ::std::vector vars; // List of owned variables ::std::vector var_states; // Indexed by position in above list }), (Temporaries, struct { ::std::vector temporaries; // Controlled temporaries ::std::vector states; // Indexed by position in above list }), (Split, struct { ::std::vector arms; }), (Loop, struct { }) ); /// Helper class to construct MIR class MirBuilder { friend class ScopeHandle; ::MIR::Function& m_output; unsigned int m_current_block; bool m_block_active; ::MIR::RValue m_result; bool m_result_valid; ::std::vector variables_valid; ::std::vector temporaries_valid; struct ScopeDef { bool complete = false; ScopeType data; }; ::std::vector m_scopes; ::std::vector m_scope_stack; ScopeHandle m_fcn_scope; public: MirBuilder(::MIR::Function& output); ~MirBuilder(); // - Values ::MIR::LValue new_temporary(const ::HIR::TypeRef& ty); ::MIR::LValue lvalue_or_temp(const ::HIR::TypeRef& ty, ::MIR::RValue val); bool has_result() const { return m_result_valid; } ::MIR::RValue get_result(const Span& sp); ::MIR::LValue get_result_lvalue(const Span& sp); void set_result(const Span& sp, ::MIR::RValue val); // - Statements // Push an assignment. NOTE: This also marks the rvalue as moved void push_stmt_assign(::MIR::LValue dst, ::MIR::RValue val); // Push a drop (likely only used by scope cleanup) void push_stmt_drop(::MIR::LValue val); // - Block management bool block_active() const { return m_block_active; } void set_cur_block(unsigned int new_block); void pause_cur_block(); void end_block(::MIR::Terminator term); ::MIR::BasicBlockId new_bb_linked(); ::MIR::BasicBlockId new_bb_unlinked(); // --- Scopes --- ScopeHandle new_scope_var(const Span& sp); ScopeHandle new_scope_temp(const Span& sp); ScopeHandle new_scope_split(const Span& sp); ScopeHandle new_scope_loop(const Span& sp); void terminate_scope(const Span& sp, ScopeHandle ); void terminate_scope_early(const Span& sp, const ScopeHandle& ); void end_split_arm(const Span& sp, const ScopeHandle& , bool reachable); const ScopeHandle& fcn_scope() const { return m_fcn_scope; } /// Introduce a new variable within the current scope void define_variable(unsigned int idx); private: VarState get_variable_state(unsigned int idx) const; void set_variable_state(unsigned int idx, VarState state); VarState get_temp_state(unsigned int idx) const; void set_temp_state(unsigned int idx, VarState state); void drop_scope_values(const ScopeDef& sd); void complete_scope(ScopeDef& sd); // Helper - Marks a variable/... as moved (and checks if the move is valid) void moved_lvalue(const ::MIR::LValue& lv); }; class MirConverter: public ::HIR::ExprVisitor { public: virtual void destructure_from(const Span& sp, const ::HIR::Pattern& pat, ::MIR::LValue lval, bool allow_refutable=false) = 0; virtual void define_vars_from(const Span& sp, const ::HIR::Pattern& pat) = 0; }; extern void MIR_LowerHIR_Match(MirBuilder& builder, MirConverter& conv, ::HIR::ExprNode_Match& node, ::MIR::LValue match_val);