{-# LANGUAGE OverloadedLists #-} -- | Evaluate STG 'Program's. module Stg.Machine.Evaluate ( evalStep, ) where import Data.Foldable import qualified Data.Stack as S import qualified Stg.Machine.Evaluate.ErrorTransitions as Error import qualified Stg.Machine.Evaluate.ValidTransitions as Valid import Stg.Machine.Types -- | Perform a single STG machine evaluation step. evalStep :: StgState -> StgState evalStep state = let state' = stgRule state in state' { stgSteps = stgSteps state' + 1 } -- | Transition rules detailed in the 1992 paper, along with error rules to -- help if none of them applies. -- -- This is the place to modify the ruleset of the machine, for example -- 'Valid.rule1819' can be removed to yield a less efficient, yet equally -- correct, STG implementation. rules :: [StgState -> Maybe StgState] rules = [ Valid.rule1_functionApp , Valid.rule2_enterNonUpdatable , Valid.rule3_let , Valid.rule1819_casePrimopShortcut -- before rule 4 because it takes -- precedence over it in certain cases! , Valid.rule4_case , Valid.rule5_constructorApp , Valid.rule6_algebraicNormalMatch , Valid.rule7_algebraicUnboundDefaultMatch , Valid.rule8_algebraicBoundDefaultMatch , Valid.rule9_primitiveLiteralEval , Valid.rule10_primitiveLiteralApp , Valid.rule11_primitiveNormalMatch , Valid.rule12_primitiveBoundDefaultMatch , Valid.rule13_primitiveUnboundDefaultMatch , Valid.rule14_primop , Valid.rule15_enterUpdatable , Valid.rule16_missingReturnUpdate , Valid.rule17a_missingArgUpdate , Error.updatableClosureWithArgs , Error.returnWithEmptyReturnStack , Error.functionArgumentNotInScope , Error.constructorArgumentNotInScope , Error.primopArgumentNotInScope , Error.algReturnToPrimAlts , Error.primReturnToAlgAlts , Error.enterBlackhole , Error.updateClosureWithPrimitive , Error.nonAlgPrimScrutinee , Error.divisionByZero , Error.badConArity ] -- | Apply a single applicable STG evaluation rule to continue to the next step. stgRule :: StgState -> StgState stgRule state = case asum [ rule state | rule <- rules ] of Nothing -> noRulesApply state Just state' -> state' -- | Fallback if none of the known rules applies. noRulesApply :: StgState -> StgState noRulesApply s = s { stgInfo = Info NoRulesApply detail } where detail = case stgStack s of S.Empty -> [] _else -> [Detail_StackNotEmpty]