// Copyright (c) 2016-2021 Fabian Schuiki //! An implementation of lazy compiler passes. // #![deny(missing_docs)] use std; use std::cell::RefCell; use std::collections::HashMap; use std::fmt; use crate::hir; use crate::score::*; use crate::score::{ScoreBoard, ScoreContext}; use crate::ty::Ty; use crate::typeck::TypeckContext; use moore_common::score::{NodeStorage, Result}; use moore_common::NodeId; /// A lazily evaluated node. pub enum LazyNode { /// Evaluation is currently running. Running, /// The callback which will provide the desired output. Pending(F), } impl fmt::Debug for LazyNode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { LazyNode::Running => write!(f, "running"), LazyNode::Pending(_) => write!(f, "pending"), } } } /// A table of lazy compiler phases. pub struct LazyPhaseTable<'sb, 'ast: 'sb, 'ctx: 'sb> { /// The score board. pub sb: &'sb ScoreBoard<'ast, 'ctx>, /// The lazy HIR table. pub hir: LazyPhase>, /// The lazy typeck table. pub typeck: RefCell>, /// The lazy typeval table. pub typeval: RefCell>, } impl<'sb, 'ast, 'ctx> LazyPhaseTable<'sb, 'ast, 'ctx> { /// Create a new phase table. pub fn new(sb: &'sb ScoreBoard<'ast, 'ctx>) -> LazyPhaseTable<'sb, 'ast, 'ctx> { LazyPhaseTable { sb: sb, hir: LazyPhase::new(), typeck: RefCell::new(HashMap::new()), typeval: RefCell::new(HashMap::new()), } } } /// A table of tasks needed to perform a compiler phase. pub struct LazyPhase { pub table: RefCell, } impl LazyPhase where T: Default, { /// Create a new lazy phase. pub fn new() -> LazyPhase { LazyPhase { table: RefCell::new(Default::default()), } } /// Schedule a task to be lazily executed. pub fn schedule(&self, id: I, f: F) where T: NodeStorage>, { self.table.borrow_mut().set(id, LazyNode::Pending(f)); } /// Run a task. pub fn run<'lazy, 'sb, 'ast, 'ctx, I, R>( &self, id: I, ctx: &ScoreContext<'lazy, 'sb, 'ast, 'ctx>, ) -> Result where I: Copy + fmt::Debug, T: NodeStorage< I, Node = LazyNode< Box Fn(&'a ScoreContext<'b, 'sb, 'ast, 'ctx>) -> Result + 'sb>, >, >, { let task = self.table.borrow_mut().set(id, LazyNode::Running); match task { Some(LazyNode::Pending(f)) => f(ctx), Some(LazyNode::Running) => panic!("recursion when running task for {:?}", id), None => panic!("no task scheduled for {:?}", id), } } } /// A callback to lazily lower a node to HIR. pub type LazyHir<'sb, 'ast, 'ctx, R> = Box Fn(&'a ScoreContext<'b, 'sb, 'ast, 'ctx>) -> Result + 'sb>; /// A callback to lazily typeck a node. pub type LazyTypeck<'sb, 'ast, 'ctx> = Box Fn(&'a TypeckContext<'b, 'c, 'sb, 'ast, 'ctx>) -> Result<()> + 'sb>; /// A callback to lazily evaluate the type of a node. pub type LazyTypeval<'sb, 'ast, 'ctx> = Box Fn(&'a TypeckContext<'b, 'c, 'sb, 'ast, 'ctx>) -> Result<&'ctx Ty> + 'sb>; /// A table of pending or running HIR lowerings. node_storage!(LazyHirTable<'sb, 'ast, 'ctx> where ('ast: 'sb, 'ctx: 'sb): // Miscellaneous subtype_inds: SubtypeIndRef => LazyNode>, // Expressions exprs: ExprRef => LazyNode>, aggregates: AggregateRef => LazyNode>, // Declarations const_decls: ConstDeclRef => LazyNode>>, signal_decls: SignalDeclRef => LazyNode>>, var_decls: VarDeclRef => LazyNode>>, file_decls: FileDeclRef => LazyNode>>, type_decls: TypeDeclRef => LazyNode>, // Sequential statements wait_stmts: WaitStmtRef => LazyNode>>, assert_stmts: AssertStmtRef => LazyNode>>, report_stmts: ReportStmtRef => LazyNode>>, sig_assign_stmts: SigAssignStmtRef => LazyNode>>, var_assign_stmts: VarAssignStmtRef => LazyNode>>, call_stmt: CallStmtRef => LazyNode>>, if_stmt: IfStmtRef => LazyNode>>, case_stmt: CaseStmtRef => LazyNode>>, loop_stmt: LoopStmtRef => LazyNode>>, nexit_stmt: NexitStmtRef => LazyNode>>, return_stmt: ReturnStmtRef => LazyNode>>, null_stmt: NullStmtRef => LazyNode>>, ); impl<'sb, 'ast, 'ctx> Default for LazyHirTable<'sb, 'ast, 'ctx> { fn default() -> LazyHirTable<'sb, 'ast, 'ctx> { LazyHirTable::new() } } /// A table of pending or running type checks. pub type LazyTypeckTable<'sb, 'ast, 'ctx> = HashMap>>; /// A table of pending or running type evaluations. pub type LazyTypevalTable<'sb, 'ast, 'ctx> = HashMap>>;