5 Commits
Author SHA1 Message Date
msyds 3aac990fac
build / build (push) Failing after 1m45s
2026-08-24 11:13:34 -06:00
msyds 6a6d92bcda 2026-08-24 10:41:30 -06:00
msyds b5c823f5fe continue takes var 2026-08-24 10:41:19 -06:00
msyds f6bc2947ef
build / build (push) Failing after 11m35s
2026-08-24 09:54:19 -06:00
msyds 1b5c93b030 2026-08-24 06:58:16 -06:00
13 changed files with 98 additions and 573 deletions
+13 -11
View File
@@ -14,9 +14,9 @@ build-type: Simple
-- extra-source-files: -- extra-source-files:
flag doctest flag doctest
description: enable the doctest suite description: enable the doctest suite
default: True default: True
manual: True manual: True
common ghcstuffs-dev common ghcstuffs-dev
ghc-options: ghc-options:
@@ -60,7 +60,6 @@ library
Gyehoek.CPS.Close Gyehoek.CPS.Close
Gyehoek.CPS.Convert Gyehoek.CPS.Convert
Gyehoek.CPS.Eval Gyehoek.CPS.Eval
Gyehoek.CPS.Lower
Gyehoek.CPS.Stackify Gyehoek.CPS.Stackify
Gyehoek.CPS.Syntax Gyehoek.CPS.Syntax
Gyehoek.Driver Gyehoek.Driver
@@ -77,6 +76,7 @@ library
Gyehoek.Sexp.QQ Gyehoek.Sexp.QQ
Gyehoek.Sexp.Read Gyehoek.Sexp.Read
Gyehoek.Sexp.Syntax Gyehoek.Sexp.Syntax
Gyehoek.Stack.Lower
Gyehoek.Stack.Syntax Gyehoek.Stack.Syntax
Gyehoek.Stack.VM Gyehoek.Stack.VM
Gyehoek.Wasm Gyehoek.Wasm
@@ -162,13 +162,15 @@ test-suite test
-- https://github.com/martijnbastiaan/doctest-parallel/pull/66 -- https://github.com/martijnbastiaan/doctest-parallel/pull/66
test-suite doctest test-suite doctest
import: ghcstuffs, ghcstuffs-dev import: ghcstuffs, ghcstuffs-dev
type: exitcode-stdio-1.0 type: exitcode-stdio-1.0
hs-source-dirs: test hs-source-dirs: test
build-depends: base build-depends: base
default-extensions: CPP default-extensions: CPP
main-is: doctest.hs main-is: doctest.hs
if flag(doctest) if flag(doctest)
build-depends: doctest-parallel >=0.1 build-depends: doctest-parallel >=0.1
else else
cpp-options: "-DGYEHOEK_NO_DOCTEST" cpp-options: -DGYEHOEK_NO_DOCTEST
+4 -3
View File
@@ -105,12 +105,13 @@ convertLambda
=> List Name -> Scm.Exp -> Eff es Lambda => List Name -> Scm.Exp -> Eff es Lambda
convertLambda bs m = do convertLambda bs m = do
ktail <- gensym' "lambda-tail" ktail <- gensym' "lambda-tail"
m' <- convert m $ pure . ExpContinue ktail . (:[]) m' <- convert m $ pure . ExpContinue (ValVar ktail) . (:[])
pure [cps|(λ (##{bs} #{ktail}) #{m'})|] pure [cps|(λ (##{bs} #{ktail}) #{m'})|]
convertProgram :: forall es. (GenSym :> es) => Scm.Program -> Eff es Program convertProgram :: forall es. (GenSym :> es) => Scm.Program -> Eff es Program
convertProgram p = convertProgram p = do
MkProgram <$> telescope (convert @es) (p ^.. each . _Left) (pure . Halt) MkProgram <$> telescope (convert @es) (p ^.. each . _Left) (pure . nothalt)
where nothalt = ExpContinue (ValVar "main-ktail")
convertExp :: forall es. (GenSym :> es) => Scm.Exp -> Eff es Exp convertExp :: forall es. (GenSym :> es) => Scm.Exp -> Eff es Exp
convertExp e = convert e (pure . Halt1) convertExp e = convert e (pure . Halt1)
-325
View File
@@ -1,325 +0,0 @@
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultilineStrings #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE RecursiveDo #-}
{- HLINT ignore "Use camelCase" -}
module Gyehoek.CPS.Lower
(lower, lowerProgram) where
import Gyehoek.CPS.Syntax
import Data.Vector.Strict (Vector)
import Control.Lens hiding (op)
import Numeric.Natural
import qualified Data.Vector.Strict as V
import Gyehoek.Wasm qualified as Wasm
import Gyehoek.Wasm hiding (Expr)
import Control.Monad.Fix
import Data.Text qualified as T
import Data.Foldable (fold)
import Gyehoek.Jalmot
import Gyehoek.Sexp qualified as S
import Gyehoek.Prelude
data Env = MkEnv
{ vars :: Vector Name
, kvars :: Vector Name
}
deriving (Show, Generic)
type instance Index Env = Natural
type instance IxValue Env = Name
instance Ixed Env where
ix i = #vars . ix (fromIntegral i)
tonat :: Integral a => a -> Natural
tonat = fromIntegral
-- | @makeSmallFixnum@ emits an expression injecting the i32 on top
-- of the stack into the SCM unitype.
makeSmallFixnum :: Wasm.Expr
makeSmallFixnum = [expr|
(@gyehoek "construct small fixnum")
(i32.const 1)
i32.shl
ref.i31
|]
getArgRegister :: Natural -> S.Datum
getArgRegister n = S.Symbol [i|$arg#{n}|]
-- | Given an expression @e@ leaving a @ref eq@ atop the stack,
-- @pushArg rt n e@ sets the nth slot of the arg-passing array to the
-- result of @e@.
pushArg :: Natural -> Wasm.Expr -> Wasm.Expr
pushArg n e = [expr|
(@gyehoek begin pushArg)
##{e}
(global.set #{reg})
(@gyehoek end pushArg)
|]
where reg = getArgRegister n
-- | Pop the nth arg from the arg-passing array onto the stack.
popArg :: Natural -> Wasm.Expr
popArg n = [expr|
(@gyehoek begin popArg)
(global.get #{reg})
ref.as_non_null
(@gyehoek end popArg)
|]
where reg = getArgRegister n
lowerVal :: (HasCallStack, GenMod :> es) => Env -> Val -> Eff es Wasm.Expr
lowerVal g (ValImm imm) =
pure $ case imm of
ImmInt n -> [expr|
(i32.const #{n})
##{makeSmallFixnum}
|]
ImmBool b -> [expr|
(i32.const #{b'})
ref.i31
|]
where b' :: Int = if b then 0b11 else 0b01
_ -> _
lowerVal g (ValVar x) = do
pure [expr|(global.get #{l})|]
where
l = getArgRegister . fromIntegral . succ $ V.elemIndex x g.vars ^?! _Just
lower' :: (GenMod :> es) => Env -> Exp -> Eff es Wasm.Expr
lower' g (Halt [v]) = do
arg <- pushArg 0 <$> lowerVal g v
pure [expr|
##{arg}
(return_call $halt (i32.const 1))
|]
lower' g e@(ExpPrim p k) =
case p of
PrimAdd x y -> lowerBinOp "i32.add" g x y k
PrimMul x y -> lowerBinOp "i32.mul" g x y k
lower' g (ExpIf c t f) = do
c' <- lowerVal g c
t' <- lower' g t
f' <- lower' g f
pure [expr|
##{c'}
(call $gh-truthy?)
(if (then ##{t'})
(else ##{f'}))
|]
lower' g (ExpLetRec [(r,AbsKappa kap)] e) = do
idx <- lowerKappa g kap
let g' = g & #kvars <>~ [r]
e' <- lower' g' e
pure [expr|
(@gyehoek "push cont" :idx #{idx})
(array.set $cont-stack-type
(global.get $cont-stack)
(global.get $cont-stack-top)
(ref.func #{idx}))
(global.set $cont-stack-top
(i32.add (global.get $cont-stack-top)
(i32.const 1)))
##{e'}
|]
lower' g (ExpLetRec [(r,AbsLambda lam)] e) = do
idx <- lowerLambda g lam
let g' = g & #vars <>~ [r]
let n = succ $ length g.vars
e' <- lower' g' e
let reg = getArgRegister . fromIntegral $ n
pure [expr|
(i32.const 0)
(ref.func #{idx})
(struct.new $closure)
(global.set #{reg})
##{e'}
|]
lower' g e@(ExpApply f xs ktail) = do
let nargs = length xs
f' <- lowerVal g f
let l = succ $ V.elemIndex ktail g.kvars ^?! _Just
args <- fold <$>
itraverse (\i -> fmap (pushArg $ tonat i) . lowerVal g) xs
pure [expr|
(@gyehoek "load args")
##{args}
(i32.const 1)
##{f'}
(ref.cast (ref $closure))
(struct.get $closure $code)
(return_call_ref $cont-type)
(@gyehoek todo
(f' ##{f'})
(ktail #{l}))
|]
lower' g e@(ExpContinue k xs) = do
let nargs = length xs
args <- fold <$>
itraverse (\i -> fmap (pushArg $ tonat i) . lowerVal g) xs
pure [expr|
(@gyehoek "push args")
##{args}
(@gyehoek "nargs")
(i32.const #{nargs})
(@gyehoek "pop cont stack")
(global.get $cont-stack-top)
(i32.const #{l})
i32.sub
(global.set $cont-stack-top)
(global.get $cont-stack)
(global.get $cont-stack-top)
(array.get $cont-stack-type)
ref.as_non_null
(return_call_ref $cont-type)
|]
where
l = succ $ V.elemIndex k g.kvars ^?! _Just
lower' g e = error . S.encodeOrShow' S.datumIso $ e
lowerKappa :: GenMod :> es => Env -> Kappa -> Eff es Idx
lowerKappa g e@(MkKappa xs m) = do
let g' = g & #vars <>~ V.fromList xs
m' <- lower' g' m
idx <- Wasm.defineFunction [wat|
(func (param i32)
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
##{m'})
|]
Wasm.emit [wats|(elem declare funcref (ref.func #{idx}))|]
pure idx
lowerLambda :: GenMod :> es => Env -> Lambda -> Eff es Idx
lowerLambda g e@(MkLambda xs ktail m) = do
let g' = g & #vars .~ V.fromList xs
& #kvars <>~ [ktail]
m' <- lower' g' m
idx <- Wasm.defineFunction [wat|
(func (param i32)
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
##{m'})
|]
Wasm.emit [wats|(elem declare funcref (ref.func #{idx}))|]
pure idx
lowerBinOp
:: (GenMod :> es)
=> Text -> Env -> Val -> Val -> Kappa -> Eff es Wasm.Expr
lowerBinOp op g x y (MkKappa [r] e) = do
let op' = S.Symbol op
let g' = g & #vars <>~ [r]
let n = succ $ length (g ^. #vars)
let reg = getArgRegister . fromIntegral $ n
x' <- lowerVal g x
y' <- lowerVal g y
e' <- lower' g' e
pure [expr|
##{x'}
(i31.get_s (ref.cast (ref i31)))
(i32.const 1)
i32.shr_u
##{y'}
(i31.get_s (ref.cast (ref i31)))
(i32.const 1)
i32.shr_u
#{op'}
##{makeSmallFixnum}
(global.set #{reg})
##{e'}
|]
emitRuntime :: GenMod :> es => Eff es ()
emitRuntime = mfix \runtime -> do
Wasm.defineFunctions [wats|
(import "gyehoek" "write" (func $gh-write (param (ref eq))))
(import "gyehoek" "truthy?" (func $gh-truthy? (param (ref eq))
(result i32)))
|]
-- cont stack
Wasm.defineTypes [wats|
(type $heap-object (sub (struct (field $hash (mut i32)))))
(type $cont-type (func (param i32)))
(type $cont-stack-type (array (mut (ref null $cont-type))))
(type $closure (sub $heap-object
(struct (field $hash (mut i32))
(field $code (ref $cont-type)))))
|]
Wasm.defineGlobals [wats|
(global $cont-stack-top (mut i32) (i32.const 0))
(global $cont-stack (ref $cont-stack-type)
(array.new_default $cont-stack-type (i32.const 128)))
|]
-- arg registers
Wasm.defineGlobals [wats|
(global $arg0 (mut (ref null eq)) (ref.null eq))
(global $arg1 (mut (ref null eq)) (ref.null eq))
(global $arg2 (mut (ref null eq)) (ref.null eq))
(global $arg3 (mut (ref null eq)) (ref.null eq))
(global $arg4 (mut (ref null eq)) (ref.null eq))
(global $arg5 (mut (ref null eq)) (ref.null eq))
(global $arg6 (mut (ref null eq)) (ref.null eq))
(global $arg7 (mut (ref null eq)) (ref.null eq))
(global $arg8 (mut (ref null eq)) (ref.null eq))
(global $arg9 (mut (ref null eq)) (ref.null eq))
(global $arg10 (mut (ref null eq)) (ref.null eq))
(global $arg11 (mut (ref null eq)) (ref.null eq))
(global $arg12 (mut (ref null eq)) (ref.null eq))
(global $arg13 (mut (ref null eq)) (ref.null eq))
(global $arg14 (mut (ref null eq)) (ref.null eq))
(global $arg15 (mut (ref null eq)) (ref.null eq))
|]
-- other things 😼
Wasm.defineGlobal [wat|
(global $result (mut (ref null eq))
(ref.null eq))
|]
-- procedures
let arg = popArg 0
Wasm.defineFunction [wat|
(func $halt (param i32)
##{arg}
(global.set $result))
|]
pure ()
lower :: Exp -> Eff es Text
lower e = fmap Wasm.renderModule . Wasm.execGenMod $ do
runtime <- emitRuntime
let g = MkEnv mempty mempty
e' <- lower' g e
Wasm.defineFunction [wat|
(func $scm-entry (param i32)
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
##{e'})
|]
Wasm.defineFunction [wat|
(func (export "main")
(call $scm-entry (i32.const 0))
(call $gh-write (ref.as_non_null (global.get $result))))
|]
lowerProgram :: Program -> Eff es Text
lowerProgram (MkProgram e) = lower e
+5 -16
View File
@@ -69,27 +69,15 @@ stackify g (ExpIf c t f) = do
pure . Tail $ Stk.If c' t' f' pure . Tail $ Stk.If c' t' f'
stackify g (ExpApply f xs ktail) = pure $ stackify g (ExpApply f xs ktail) = pure $
Code [ Stk.PushCont k ] $
Code [ Stk.Push (Stk.ValReg l) | l <- ls ] $ Code [ Stk.Push (Stk.ValReg l) | l <- ls ] $
Tail (Stk.TailCall (stackifyVal g f) (stackifyVal g <$> xs)) Tail (Stk.PushCall k (stackifyVal g f) (stackifyVal g <$> xs))
where where
k = var g ktail k = var g ktail
ls = fold $ (k ^? #ValImm . #ImmLabel) ls = fold $ (k ^? #ValImm . #ImmLabel)
>>= \klbl -> g ^. #liveness . at klbl >>= \klbl -> g ^. #liveness . at klbl
stackify g (ExpContinue k xs) = stackify g (ExpContinue k xs) =
-- return continuations require popping the stack. how do we know pure . Tail $ Stk.TailCall (stackifyVal g k) (stackifyVal g <$> xs)
-- when a continuation is a return continuation? is this a correct
-- test?
case elemIndex k g.contStack of
Nothing -> pure . Tail $ Stk.TailCall (Stk.ValLabel k) xs'
Just j -> do
ktail <- gensym' @Name $ k ^. _Wrapped'
pure $
Code (replicate j $ Stk.PopCont "_") $
Code [Stk.PopCont ktail] $
Tail (Stk.TailCall (Stk.ValReg ktail) xs')
where xs' = stackifyVal g <$> xs
stackify g (ExpPrim p (MkKappa [x] e)) = do stackify g (ExpPrim p (MkKappa [x] e)) = do
e' <- stackify (g & #bound . at x ?~ Stk.ValReg x) e e' <- stackify (g & #bound . at x ?~ Stk.ValReg x) e
@@ -132,8 +120,9 @@ emptyEnv = MkEnv mempty mempty ["halt"]
stackifyExp :: GenSym :> es => Name -> Exp -> Eff es Stk.Program stackifyExp :: GenSym :> es => Name -> Exp -> Eff es Stk.Program
stackifyExp lbl e = do stackifyExp lbl e = do
(code,p) <- runStackify $ stackify emptyEnv e let g = emptyEnv & #bound . at "main-ktail" ?~ Stk.ValReg "main-ktail"
pure $ p <> [ Stk.MkRoutine lbl [] (buildBlock code) ] (code,p) <- runStackify $ stackify g e
pure $ p <> [ Stk.MkRoutine lbl ["main-ktail"] (buildBlock code) ]
stackifyProgram :: GenSym :> es => Program -> Eff es Stk.Program stackifyProgram :: GenSym :> es => Program -> Eff es Stk.Program
stackifyProgram (MkProgram e) = stackifyExp "main" e stackifyProgram (MkProgram e) = stackifyExp "main" e
+4 -22
View File
@@ -102,7 +102,7 @@ pattern AbsLambda' xs e ktail = AbsLambda (MkLambda xs e ktail)
data Exp data Exp
= ExpPrim (Prim Val) Kappa = ExpPrim (Prim Val) Kappa
| ExpLetRec { binders :: List (Name, Abs), body :: Exp } | ExpLetRec { binders :: List (Name, Abs), body :: Exp }
| ExpContinue Name (List Val) | ExpContinue Val (List Val)
| ExpIf Val Exp Exp | ExpIf Val Exp Exp
| ExpApply | ExpApply
{ op :: Val { op :: Val
@@ -112,10 +112,10 @@ data Exp
deriving (Show, Generic, Data, Eq) deriving (Show, Generic, Data, Eq)
pattern Halt :: List Val -> Exp pattern Halt :: List Val -> Exp
pattern Halt xs = ExpContinue "halt" xs pattern Halt xs = ExpContinue (ValLabel "halt") xs
pattern Halt1 :: Val -> Exp pattern Halt1 :: Val -> Exp
pattern Halt1 x = ExpContinue "halt" [x] pattern Halt1 x = ExpContinue (ValLabel "halt") [x]
data Def = DefConstant Name Exp data Def = DefConstant Name Exp
deriving (Show, Generic, Data) deriving (Show, Generic, Data)
@@ -315,7 +315,7 @@ instance Free Exp where
foldMapOf (each . _2) (freeWithBound' bound') bs foldMapOf (each . _2) (freeWithBound' bound') bs
<> freeWithBound' bound' m <> freeWithBound' bound' m
where bound' = bound & insertFrom (bs ^.. each . _1) where bound' = bound & insertFrom (bs ^.. each . _1)
ExpContinue k xs -> filter (`notElem` bound) (k : xs ^.. each . #ValVar) ExpContinue k xs -> filter (`notElem` bound) ((k:xs) ^.. each . #ValVar)
ExpIf c t f -> ExpIf c t f ->
(c ^.. #ValVar . filtered (`notElem` bound)) (c ^.. #ValVar . filtered (`notElem` bound))
<> freeWithBound' bound t <> freeWithBound' bound f <> freeWithBound' bound t <> freeWithBound' bound f
@@ -330,21 +330,3 @@ instance Free Kappa where
instance Free Lambda where instance Free Lambda where
freeWithBound' bound (MkLambda xs k m) = freeWithBound' bound (MkLambda xs k m) =
freeWithBound' (bound & insertFrom (k:xs)) m freeWithBound' (bound & insertFrom (k:xs)) m
class Vars a where
-- | Traverse the immediate variables of an expression.
vars :: Traversal' a Name
instance Vars Val where
vars k (ValVar x) = ValVar <$> k x
vars _ x = pure x
instance Vars a => Vars (Prim a) where
vars k p = traverseOf (each . vars) k p
instance Vars Exp where
vars k (ExpPrim p kap) = ExpPrim <$> vars k p <*> pure kap
vars k (ExpContinue kname xs) = ExpContinue <$> k kname <*> pure xs
vars _ e = pure e
+8 -8
View File
@@ -1,7 +1,7 @@
module Gyehoek.Driver module Gyehoek.Driver
(main, lower_e2e, convert_e2e, parse_e2e, readScm, eval_e2e) (main, lower_e2e, convert_e2e, parse_e2e, readScm, eval_e2e)
where where
import Gyehoek.Options import Gyehoek.Options
import Prelude hiding (readFile) import Prelude hiding (readFile)
import Options.Applicative import Options.Applicative
@@ -17,7 +17,7 @@ import qualified Data.Text.Encoding as T
import System.IO (Handle) import System.IO (Handle)
import System.IO qualified as IO import System.IO qualified as IO
import Gyehoek.CPS.Convert import Gyehoek.CPS.Convert
import Gyehoek.CPS.Lower import Gyehoek.Stack.Lower
import Gyehoek.CPS.Eval qualified as CPS import Gyehoek.CPS.Eval qualified as CPS
import Control.Monad import Control.Monad
import Text.Pretty.Simple (pShowNoColor) import Text.Pretty.Simple (pShowNoColor)
@@ -35,14 +35,14 @@ import Control.Arrow ((>>>))
import Gyehoek.Prelude import Gyehoek.Prelude
import Gyehoek.Jalmot import Gyehoek.Jalmot
import qualified Gyehoek.Sexp as S import qualified Gyehoek.Sexp as S
main :: IO () main :: IO ()
main = do main = do
opts <- execParser $ info (helper <*> parser) fullDesc opts <- execParser $ info (helper <*> parser) fullDesc
runJalmotIO . runFileSystem . runGenSym . driver $ opts runJalmotIO . runFileSystem . runGenSym . driver $ opts
-- hPutStr :: FileSystem :> es => Handle -> Text -> Eff es () -- hPutStr :: FileSystem :> es => Handle -> Text -> Eff es ()
-- hPutStr h = FB.hPutStr h . T.encodeUtf8 -- hPutStr h = FB.hPutStr h . T.encodeUtf8
@@ -135,10 +135,10 @@ driver opts = do
& fmap writeObj & fmap writeObj
& T.unwords & T.unwords
& hPutStrLn FS.stdout & hPutStrLn FS.stdout
dumpOrRun opts.inspectWasm (rt_is #Wasm) -- dumpOrRun opts.inspectWasm (rt_is #Wasm)
(lowerProgram cps) -- (lowerProgram cps)
inspectWasm -- inspectWasm
(\wat -> withFile opts.output FS.WriteMode \h -> hPutStrLn h wat) -- (\wat -> withFile opts.output FS.WriteMode \h -> hPutStrLn h wat)
parse_e2e :: FilePath -> IO Scm.Program parse_e2e :: FilePath -> IO Scm.Program
parse_e2e = runJalmotIO . runFileSystem . readScm parse_e2e = runJalmotIO . runFileSystem . readScm
-11
View File
@@ -150,14 +150,3 @@ instance DatumIso a => DataIso (V.Vector a) where
instance (DatumIso a, DatumIso b) => DatumIso (a, b) where instance (DatumIso a, DatumIso b) => DatumIso (a, b) where
datumIso = with \tup2 -> list (el datumIso >>> el datumIso) >>> tup2 datumIso = with \tup2 -> list (el datumIso >>> el datumIso) >>> tup2
data Example = MkExample (List Int) Text
deriving (Generic, Show)
instance DataIso Example where
dataIso = with \g ->
flipped snoced
>>> onHead (traversed $ sealed int)
>>> onTail (onHead $ sealed symbol)
>>> swap
>>> g
+8 -1
View File
@@ -40,7 +40,7 @@ module Gyehoek.Sexp.Grammar.Base
, lambdaLike , lambdaLike
, lambdaKeyword , lambdaKeyword
, kappaKeyword , kappaKeyword
, beginLike , beginLike, headTagged2'
) where ) where
import Data.InvertibleGrammar import Data.InvertibleGrammar
@@ -325,6 +325,13 @@ headTagged2
-> G (Datum :- t) (b :- a :- t) -> G (Datum :- t) (b :- a :- t)
headTagged2 s g1 g2 = list $ el (symProcedure s) >>> el g1 >>> el g2 headTagged2 s g1 g2 = list $ el (symProcedure s) >>> el g1 >>> el g2
headTagged2'
:: Text
-> DatumGrammar a -> DatumGrammar b -> DatumGrammar c
-> G (Datum :- t) (List c :- b :- a :- t)
headTagged2' s g1 g2 gt =
list $ el (symProcedure s) >>> el g1 >>> el g2 >>> rest gt
ifLike ifLike
-- | keyword -- | keyword
:: Text :: Text
+29
View File
@@ -0,0 +1,29 @@
module Gyehoek.Stack.Lower
( lowerProgram
) where
import Gyehoek.Stack.Syntax
import Gyehoek.Wasm qualified as Wasm
import Gyehoek.Prelude
import Gyehoek.Wasm (wat, watM)
lowerRoutine :: Routine -> Wasm.Function
lowerRoutine rt = _
lowerBlock :: Block -> Wasm.Expr
lowerBlock = _
lowerInstr :: Instr -> Wasm.Expr
lowerInstr = \case
-- PopCont ktail -> [wat|
-- |]
lowerProgram :: Program -> Eff es Wasm.Module
lowerProgram p = pure [watM|
(module
##{rs})
|]
where
rs = p ^.. #routines . each . to lowerRoutine
+2 -4
View File
@@ -60,6 +60,7 @@ data Block = MkBlock
data Tail data Tail
= TailCall Val (List Val) = TailCall Val (List Val)
| PushCall Val Val (List Val)
| If Val Block Block | If Val Block Block
deriving stock (Show, Generic, Data) deriving stock (Show, Generic, Data)
deriving anyclass (NFData) deriving anyclass (NFData)
@@ -67,8 +68,6 @@ data Tail
data Instr data Instr
= Pop Name = Pop Name
| Push Val | Push Val
| PopCont Name
| PushCont Val
| Prim Name (Prim Val) | Prim Name (Prim Val)
deriving stock (Show, Generic, Data) deriving stock (Show, Generic, Data)
deriving anyclass (NFData) deriving anyclass (NFData)
@@ -91,8 +90,6 @@ instance S.DatumIso Instr where
datumIso = S.match datumIso = S.match
$ S.With (S.headTagged1 "pop!" regName >>>) $ S.With (S.headTagged1 "pop!" regName >>>)
$ S.With (S.headTagged1 "push!" S.datumIso >>>) $ S.With (S.headTagged1 "push!" S.datumIso >>>)
$ S.With (S.headTagged1 "pop-cont!" regName >>>)
$ S.With (S.headTagged1 "push-cont!" S.datumIso >>>)
$ S.With (S.headTagged2 "prim" regName S.datumIso >>>) $ S.With (S.headTagged2 "prim" regName S.datumIso >>>)
$ S.End $ S.End
where where
@@ -108,6 +105,7 @@ instance S.DataIso Block where
instance S.DatumIso Tail where instance S.DatumIso Tail where
datumIso = S.match datumIso = S.match
$ S.With (S.headTagged1' "tail-call" S.datumIso S.datumIso >>>) $ S.With (S.headTagged1' "tail-call" S.datumIso S.datumIso >>>)
$ S.With (S.headTagged2' "push-call" S.datumIso S.datumIso S.datumIso >>>)
$ S.With (if_ >>>) $ S.With (if_ >>>)
$ S.End $ S.End
where where
+4 -10
View File
@@ -17,7 +17,6 @@ import Gyehoek.Prelude
data VM = MkVM data VM = MkVM
{ stack :: List Obj { stack :: List Obj
, kstack :: List Name
, code :: List Instr , code :: List Instr
, tail :: Tail , tail :: Tail
, registers :: HashMap Name Obj , registers :: HashMap Name Obj
@@ -40,8 +39,6 @@ stepI :: Env -> VM -> Instr -> VM
stepI e vm (Push v) = vm & #stack %~ (evalVal e vm v :) stepI e vm (Push v) = vm & #stack %~ (evalVal e vm v :)
stepI e vm (PushCont k) = vm & #kstack %~ (evalToLabel e vm k :)
stepI e vm (Prim r p) = case evalVal e vm <$> p of stepI e vm (Prim r p) = case evalVal e vm <$> p of
PrimZeroP x -> case x of PrimZeroP x -> case x of
ObjImm (ImmInt n) -> ret . ObjImm . ImmBool $ n == 0 ObjImm (ImmInt n) -> ret . ObjImm . ImmBool $ n == 0
@@ -74,11 +71,6 @@ stepI e vm (Pop r) = case vm ^. #stack of
(x:xs) -> vm & #registers . at r ?~ x (x:xs) -> vm & #registers . at r ?~ x
& #stack .~ xs & #stack .~ xs
stepI e vm ins@(PopCont r) = case vm ^. #kstack of
[] -> error [i|empty cont stack: #{ins}|]
(x:xs) -> vm & #registers . at r ?~ ObjImm (ImmLabel x)
& #kstack .~ xs
stepI e vm ins = error [i|unimplemented instruction: #{ins}|] stepI e vm ins = error [i|unimplemented instruction: #{ins}|]
stepT :: Env -> VM -> Tail -> VM stepT :: Env -> VM -> Tail -> VM
@@ -95,6 +87,9 @@ stepT g vm (TailCall f xs) =
Nothing -> error [i|undefined label: #{l}|] Nothing -> error [i|undefined label: #{l}|]
Just x -> x Just x -> x
stepT g vm (PushCall k f xs) =
_
stepT g vm (If c t f) = vm & #code .~ branch.code & #tail .~ branch.tail stepT g vm (If c t f) = vm & #code .~ branch.code & #tail .~ branch.tail
where where
branch = case evalVal g vm c of branch = case evalVal g vm c of
@@ -116,9 +111,8 @@ evalVal e vm = \case
initialVM :: VM initialVM :: VM
initialVM = MkVM initialVM = MkVM
{ stack = [] { stack = []
, kstack = ["halt"]
, code = [] , code = []
, tail = TailCall (ValLabel "main") [] , tail = TailCall (ValLabel "main") [ValLabel "halt"]
, registers = mempty , registers = mempty
, stdout = "" , stdout = ""
, result = Nothing , result = Nothing
+18 -159
View File
@@ -6,182 +6,41 @@ module Gyehoek.Wasm
( (
-- * syntax -- * syntax
Module Module
, Idx , Program
, Function
, Expr , Expr
-- ** quasiquoters -- ** quasiquoters
, expr , watM
, S.sx
, S.sxs
-- * GenMod effect
, GenMod
, runGenMod
, execGenMod
, defineFunction
, defineType
, defineGlobal
, emit
, renderModule
, wat , wat
, wats
, defineFunctions
, defineTypes
, defineGlobals
) )
where where
import Data.List (List) import Data.List (List)
import GHC.Generics (Generic) import GHC.Generics (Generic)
import Data.Text (Text)
import Effectful
import Numeric.Natural (Natural)
import Effectful.Dispatch.Dynamic
import Effectful.State.Dynamic
import Control.Lens
import Data.Vector.Strict (Vector)
import qualified Data.Vector.Strict as V
import GHC.IsList (IsList(..))
import Language.Haskell.TH.Quote (QuasiQuoter) import Language.Haskell.TH.Quote (QuasiQuoter)
import Data.Data (Data)
import Gyehoek.Sexp qualified as S import Gyehoek.Sexp qualified as S
import Gyehoek.Sexp (Datum, sx, (>>>)) import Gyehoek.Sexp (Datum, (>>>))
import Data.Foldable (traverse_) import Data.Data (Data)
import Data.Coerce (coerce)
newtype Module = MkModule { inner :: Vector Datum } type Program = Module
deriving (Show, Generic) type Function = Datum
type Expr = List Datum
newtype Module = MkModule { inner :: List Datum }
deriving (Show, Generic, Data)
deriving newtype (Semigroup, Monoid) deriving newtype (Semigroup, Monoid)
newtype Expr = MkExpr { inner :: Vector Instr } instance S.DatumIso Module where
deriving (Show, Generic, Data, Eq) datumIso = S.with \g ->
deriving newtype (Semigroup, Monoid) S.list (S.el (S.sym "module") >>> S.rest S.datumIso)
>>> g
instance IsList Expr where
type Item Expr = Instr
fromList = MkExpr . V.fromList
toList = V.toList . view #inner
newtype Instr = MkInstr { inner :: Datum }
deriving (Show, Generic, Data, Eq)
newtype Idx = MkIdx { inner :: Natural }
deriving (Generic, Data)
deriving newtype (Show)
-- GenMod
-- | 'GenModState' is a 'Module' paired with the numbers of functions,
-- types, globals, etc. defined in the module.
data GenModState = MkGenModState
{ mod :: Module
, funcs :: Natural
, types :: Natural
, globals :: Natural
}
deriving (Show, Generic)
instance Semigroup GenModState where
m1 <> m2 = MkGenModState
{ mod = m1.mod <> m2.mod
, funcs = m1.funcs + m2.funcs
, types = m1.types + m2.types
, globals = m1.globals + m2.globals
}
instance Monoid GenModState where
mempty = MkGenModState
{ mod = mempty
, funcs = 0
, types = 0
, globals = 0
}
data GenMod :: Effect where
DefineFunction :: Datum -> GenMod m Idx
DefineType :: Datum -> GenMod m Idx
DefineGlobal :: Datum -> GenMod m Idx
Emit :: Datum -> GenMod m ()
type instance DispatchOf GenMod = Dynamic
defineFunction :: GenMod :> es => Datum -> Eff es Idx
defineFunction = send . DefineFunction
defineFunctions :: GenMod :> es => List Datum -> Eff es (List Idx)
defineFunctions = traverse (send . DefineFunction)
defineType :: GenMod :> es => Datum -> Eff es Idx
defineType = send . DefineType
defineTypes :: GenMod :> es => List Datum -> Eff es (List Idx)
defineTypes = traverse (send . DefineType)
defineGlobal :: GenMod :> es => Datum -> Eff es Idx
defineGlobal = send . DefineGlobal
defineGlobals :: GenMod :> es => List Datum -> Eff es (List Idx)
defineGlobals = traverse (send . DefineGlobal)
emit :: GenMod :> es => List Datum -> Eff es ()
emit = traverse_ (send . Emit)
appendAndIncrement
:: State GenModState :> es
=> LensLike' ((,) Natural) GenModState Natural
-> Datum
-> Eff es Idx
appendAndIncrement l s =
state \st -> st
& #mod . #inner <>~ V.singleton s
& l <<%~ succ
& _1 %~ MkIdx
runGenMod :: Eff (GenMod : es) a -> Eff es (a, Module)
runGenMod =
let run = (mapped . _2 %~ view #mod) . runStateLocal (mempty @GenModState)
in reinterpret run \cases
_ (DefineFunction s) -> appendAndIncrement #funcs s
_ (DefineType s) -> appendAndIncrement #types s
_ (DefineGlobal s) -> appendAndIncrement #globals s
_ (Emit s) -> #mod . #inner <>= V.singleton s
execGenMod :: Eff (GenMod : es) a -> Eff es Module
execGenMod = fmap snd . runGenMod
renderModule :: Module -> Text
renderModule (MkModule ss) = S.encodeWith' S.datumIso [sx|
(module ##{ss})
|]
-- DatumIso instances
instance S.DatumIso Idx where
datumIso = S.with \idx ->
S.integer >>> S.partialOsi f g
>>> idx
where
f n | n < 0 = Left $ S.unexpected "negative"
<> S.expected "natural"
| otherwise = Right $ fromIntegral n
g = fromIntegral
instance S.DatumIso Instr where
datumIso = S.with S.id
instance S.DataIso Expr where
dataIso = S.dataIso @(Vector Instr) >>> S.iso coerce coerce
-- quasiquoters -- quasiquoters
expr :: QuasiQuoter
expr = S.makeSxs
[|| MkExpr . V.fromList . fmap (S.fromDatumUnsafe $ S.datumIso @Instr) ||]
wat :: QuasiQuoter wat :: QuasiQuoter
wat = S.makeSx [|| id ||] wat = S.makeSxs [|| S.fromDataUnsafe (S.dataIso @(List Datum)) ||]
wats :: QuasiQuoter watM :: QuasiQuoter
wats = S.makeSxs [|| id ||] watM = S.makeSx [|| S.fromDatumUnsafe (S.datumIso @Module) ||]
+3 -3
View File
@@ -29,14 +29,14 @@ qq :: TestTree
qq = testGroup "parser" qq = testGroup "parser"
[ testCase "lambda" do [ testCase "lambda" do
assertEqual "" (Sut.MkLambda ["x","y"] "ktail" assertEqual "" (Sut.MkLambda ["x","y"] "ktail"
(Sut.ExpContinue "ktail" [Sut.ValVar "x"])) (Sut.ExpContinue (Sut.ValLabel "ktail") [Sut.ValVar "x"]))
[cps|(λ (x y ktail) (continue ktail x))|] [cps|(λ (x y ktail) (continue ktail x))|]
assertEqual "" (Sut.MkLambda [] "ktail" assertEqual "" (Sut.MkLambda [] "ktail"
(Sut.ExpContinue "ktail" [Sut.ValVar "x"])) (Sut.ExpContinue (Sut.ValLabel "ktail") [Sut.ValVar "x"]))
[cps|(λ (ktail) (continue ktail x))|] [cps|(λ (ktail) (continue ktail x))|]
, testCase "kappa" do , testCase "kappa" do
assertEqual "" (Sut.MkKappa ["x","y"] assertEqual "" (Sut.MkKappa ["x","y"]
(Sut.ExpContinue "k123" [Sut.ValVar "x", Sut.ValVar "y"])) (Sut.ExpContinue (Sut.ValLabel "k123") [Sut.ValVar "x", Sut.ValVar "y"]))
[cps|(κ (x y) (continue k123 x y))|] [cps|(κ (x y) (continue k123 x y))|]
, testCase "application" do , testCase "application" do
assertEqual "" (Sut.ExpApply (Sut.ValVar "f") assertEqual "" (Sut.ExpApply (Sut.ValVar "f")