Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fast nockma eval #2580

Merged
merged 10 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,13 @@ jobs:
with:
version: 0.5.3.0
extra-args: >-
--ghc-opt -XDerivingStrategies --ghc-opt -XImportQualifiedPost
--ghc-opt -XMultiParamTypeClasses --ghc-opt -XStandaloneDeriving
--ghc-opt -XTemplateHaskell --ghc-opt -XUnicodeSyntax
--ghc-opt -XDerivingStrategies
--ghc-opt -XImportQualifiedPost
--ghc-opt -XMultiParamTypeClasses
--ghc-opt -XPatternSynonyms
--ghc-opt -XStandaloneDeriving
--ghc-opt -XTemplateHaskell
--ghc-opt -XUnicodeSyntax
build-and-test-linux:
runs-on: ubuntu-22.04
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ ormolu:
--ghc-opt -XStandaloneDeriving \
--ghc-opt -XUnicodeSyntax \
--ghc-opt -XDerivingStrategies \
--ghc-opt -XPatternSynonyms \
--ghc-opt -XMultiParamTypeClasses \
--ghc-opt -XTemplateHaskell \
--ghc-opt -XImportQualifiedPost \
Expand Down
6 changes: 5 additions & 1 deletion app/Commands/Dev/Nockma/Eval.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Commands.Dev.Nockma.Eval where

import Commands.Base hiding (Atom)
import Commands.Dev.Nockma.Eval.Options
import Juvix.Compiler.Nockma.Evaluator.Options
import Juvix.Compiler.Nockma.Pretty
import Juvix.Compiler.Nockma.Translation.FromAsm
import Juvix.Compiler.Nockma.Translation.FromSource qualified as Nockma
Expand All @@ -13,7 +14,10 @@ runCommand opts = do
case parsedTerm of
Left err -> exitJuvixError (JuvixError err)
Right (TermCell c) -> do
res <- runOutputSem @(Term Natural) (say . ppTrace) (evalCompiledNock' (c ^. cellLeft) (c ^. cellRight))
res <-
runReader defaultEvalOptions
. runOutputSem @(Term Natural) (say . ppTrace)
$ evalCompiledNock' (c ^. cellLeft) (c ^. cellRight)
ret <- getReturn res
putStrLn (ppPrint ret)
Right TermAtom {} -> exitFailMsg "Expected nockma input to be a cell"
Expand Down
8 changes: 5 additions & 3 deletions app/Commands/Dev/Nockma/Repl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Control.Exception (throwIO)
import Control.Monad.State.Strict qualified as State
import Data.String.Interpolate (__i)
import Juvix.Compiler.Nockma.Evaluator (NockEvalError, evalRepl, fromReplTerm, programAssignments)
import Juvix.Compiler.Nockma.Evaluator.Options
import Juvix.Compiler.Nockma.Language
import Juvix.Compiler.Nockma.Pretty (ppPrint)
import Juvix.Compiler.Nockma.Pretty qualified as Nockma
Expand Down Expand Up @@ -133,9 +134,10 @@ evalStatement = \case
prog <- getProgram
et <-
liftIO
$ runM
. runError @(ErrNockNatural Natural)
. runError @NockEvalError
. runM
. runReader defaultEvalOptions
. runError @(ErrNockNatural Natural)
. runError @NockEvalError
$ evalRepl (putStrLn . Nockma.ppTrace) prog s t
case et of
Left e -> error (show e)
Expand Down
1 change: 1 addition & 0 deletions package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ default-extensions:
- NoFieldSelectors
- NoImplicitPrelude
- OverloadedStrings
- PatternSynonyms
- QuasiQuotes
- RecordWildCards
- TemplateHaskell
Expand Down
85 changes: 69 additions & 16 deletions src/Juvix/Compiler/Nockma/Evaluator.hs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
module Juvix.Compiler.Nockma.Evaluator
( module Juvix.Compiler.Nockma.Evaluator,
module Juvix.Compiler.Nockma.Evaluator.Error,
module Juvix.Compiler.Nockma.Evaluator.Options,
)
where

import Juvix.Compiler.Nockma.Evaluator.Error
import Juvix.Compiler.Nockma.Evaluator.Options
import Juvix.Compiler.Nockma.Language
import Juvix.Compiler.Nockma.Pretty
import Juvix.Prelude hiding (Atom, Path)
Expand Down Expand Up @@ -45,7 +47,7 @@ subTermT = go
subTerm :: (Member (Error NockEvalError) r) => Term a -> Path -> Sem r (Term a)
subTerm term pos = do
case term ^? subTermT pos of
Nothing -> throw @NockEvalError (error "")
Nothing -> throw (InvalidPath "subterm")
Just t -> return t

setSubTerm :: (Member (Error NockEvalError) r) => Term a -> Path -> Term a -> Sem r (Term a)
Expand All @@ -55,11 +57,25 @@ setSubTerm term pos repTerm =
| isNothing (getFirst old) -> throw @NockEvalError (error "")
| otherwise -> return new

parseCell :: forall r a. (Members '[Error NockEvalError, Error (ErrNockNatural a)] r, NockNatural a) => Cell a -> Sem r (ParsedCell a)
parseCell ::
forall r a.
(Members '[Error NockEvalError, Error (ErrNockNatural a)] r, NockNatural a) =>
Cell a ->
Sem r (ParsedCell a)
parseCell c = case c ^. cellLeft of
TermAtom a -> ParsedOperatorCell <$> parseOperatorCell a (c ^. cellRight)
TermAtom a -> operatorOrStdlibCall a (c ^. cellRight) (c ^. cellInfo . unIrrelevant)
TermCell l -> return (ParsedAutoConsCell (AutoConsCell l (c ^. cellRight)))
where
operatorOrStdlibCall :: Atom a -> Term a -> Maybe (StdlibCall a) -> Sem r (ParsedCell a)
operatorOrStdlibCall a t mcall = do
opCell <- parseOperatorCell a t
return $ case mcall of
Nothing -> ParsedOperatorCell opCell
Just call -> ParsedStdlibCallCell (parseStdlibCall opCell call)

parseStdlibCall :: OperatorCell a -> StdlibCall a -> StdlibCallCell a
parseStdlibCall op call = StdlibCallCell call op

parseOperatorCell :: Atom a -> Term a -> Sem r (OperatorCell a)
parseOperatorCell a t = do
op <- nockOp a
Expand All @@ -84,7 +100,7 @@ programAssignments mprog =
-- | The stack provided in the replExpression has priority
evalRepl ::
forall r a.
(PrettyCode a, Members '[Error NockEvalError, Error (ErrNockNatural a)] r, NockNatural a) =>
(PrettyCode a, Integral a, Members '[Reader EvalOptions, Error NockEvalError, Error (ErrNockNatural a)] r, NockNatural a) =>
(Term a -> Sem r ()) ->
Maybe (Program a) ->
Maybe (Term a) ->
Expand All @@ -105,20 +121,57 @@ evalRepl handleTrace mprog defaultStack expr = do
namedTerms :: HashMap Text (Term a)
namedTerms = programAssignments mprog

eval :: forall r a. (PrettyCode a, Members '[Output (Term a), Error NockEvalError, Error (ErrNockNatural a)] r, NockNatural a) => Term a -> Term a -> Sem r (Term a)
eval ::
forall r a.
(PrettyCode a, Integral a, Members '[Reader EvalOptions, Output (Term a), Error NockEvalError, Error (ErrNockNatural a)] r, NockNatural a) =>
Term a ->
Term a ->
Sem r (Term a)
eval stack = \case
TermAtom a -> throw (ExpectedCell ("eval " <> ppTrace a))
TermCell c -> do
pc <- parseCell c
case pc of
TermCell c ->
parseCell c >>= \case
ParsedAutoConsCell a -> goAutoConsCell a
ParsedOperatorCell o -> goOperatorCell o
ParsedStdlibCallCell o -> do
ignore <- asks (^. evalIgnoreStdlibCalls)
if
| ignore -> goOperatorCell (o ^. stdlibCallRaw)
| otherwise -> goStdlibCall (o ^. stdlibCallCell)
where
goStdlibCall :: StdlibCall a -> Sem r (Term a)
goStdlibCall StdlibCall {..} = do
args' <- eval stack _stdlibCallArgs
let binArith :: (a -> a -> a) -> Sem r (Term a)
binArith f = case args' of
TCell (TAtom l) (TAtom r) -> return (TCell (TAtom (f l r)) stack)
_ -> error "expected a cell with two atoms"

unaArith :: (a -> a) -> Sem r (Term a)
unaArith f = case args' of
TAtom n -> return (TCell (TAtom (f n)) stack)
_ -> error "expected an atom"

binCmp :: (a -> a -> Bool) -> Sem r (Term a)
binCmp f = case args' of
TCell (TAtom l) (TAtom r) -> return (TCell (TermAtom (nockBool (f l r))) stack)
_ -> error "expected a cell with two atoms"

case _stdlibCallFunction of
StdlibDec -> unaArith pred
StdlibAdd -> binArith (+)
StdlibMul -> binArith (*)
StdlibSub -> binArith (-)
StdlibDiv -> binArith div
StdlibMod -> binArith mod
StdlibLt -> binCmp (<)
StdlibLe -> binCmp (<=)

goAutoConsCell :: AutoConsCell a -> Sem r (Term a)
goAutoConsCell c = do
_cellLeft <- eval stack (TermCell (c ^. autoConsCellLeft))
_cellRight <- eval stack (c ^. autoConsCellRight)
return (TermCell Cell {..})
l' <- eval stack (TermCell (c ^. autoConsCellLeft))
r' <- eval stack (c ^. autoConsCellRight)
return (TermCell (Cell l' r'))

goOperatorCell :: OperatorCell a -> Sem r (Term a)
goOperatorCell c = case c ^. operatorCellOp of
Expand Down Expand Up @@ -149,7 +202,7 @@ eval stack = \case

goOpTrace :: Sem r (Term a)
goOpTrace = do
Cell tr a <- asCell "OpTrace" (c ^. operatorCellTerm)
Cell' tr a _ <- asCell "OpTrace" (c ^. operatorCellTerm)
tr' <- eval stack tr
output tr'
eval stack a
Expand All @@ -164,13 +217,13 @@ eval stack = \case
goOpPush = do
cellTerm <- asCell "OpPush" (c ^. operatorCellTerm)
l <- eval stack (cellTerm ^. cellLeft)
let s = TermCell Cell {_cellLeft = l, _cellRight = stack}
let s = TermCell (Cell l stack)
eval s (cellTerm ^. cellRight)

goOpReplace :: Sem r (Term a)
goOpReplace = do
Cell rot1 t2 <- asCell "OpReplace 1" (c ^. operatorCellTerm)
Cell ro t1 <- asCell "OpReplace 2" rot1
Cell' rot1 t2 _ <- asCell "OpReplace 1" (c ^. operatorCellTerm)
Cell' ro t1 _ <- asCell "OpReplace 2" rot1
r <- asPath ro
t1' <- eval stack t1
t2' <- eval stack t2
Expand All @@ -187,7 +240,7 @@ eval stack = \case
goOpIf = do
cellTerm <- asCell "OpIf 1" (c ^. operatorCellTerm)
let t0 = cellTerm ^. cellLeft
Cell t1 t2 <- asCell "OpIf 2" (cellTerm ^. cellRight)
Cell' t1 t2 _ <- asCell "OpIf 2" (cellTerm ^. cellRight)
cond <- eval stack t0 >>= asBool
if
| cond -> eval stack t1
Expand Down
12 changes: 12 additions & 0 deletions src/Juvix/Compiler/Nockma/Evaluator/Options.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Juvix.Compiler.Nockma.Evaluator.Options where

import Juvix.Prelude.Base

newtype EvalOptions = EvalOptions
{ _evalIgnoreStdlibCalls :: Bool
}

defaultEvalOptions :: EvalOptions
defaultEvalOptions = EvalOptions False

makeLenses ''EvalOptions
Loading