From 85d34883a6247f5f67580029688f02e831ce7b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Madeleine=20Sydney=20=C5=9Alaga?= Date: Fri, 17 Jul 2026 01:27:13 -0600 Subject: [PATCH] beautiful --- src/Gyehoek/CPS/Lower.hs | 221 ++++++++++++++++++++++----------------- src/Gyehoek/Sexp.hs | 4 + src/Gyehoek/Wasm.hs | 12 +++ 3 files changed, 142 insertions(+), 95 deletions(-) diff --git a/src/Gyehoek/CPS/Lower.hs b/src/Gyehoek/CPS/Lower.hs index 11ba71e..28b3060 100644 --- a/src/Gyehoek/CPS/Lower.hs +++ b/src/Gyehoek/CPS/Lower.hs @@ -42,8 +42,7 @@ import Data.Functor.Foldable (cata) data Env = MkEnv - { runtime :: Runtime - , vars :: Vector Name + { vars :: Vector Name , kvars :: Vector Name } deriving (Show, Generic) @@ -54,17 +53,17 @@ type instance IxValue Env = Name instance Ixed Env where ix i = #vars . ix (fromIntegral i) -data Runtime = MkRuntime - { argArrayType :: Idx - , argArray :: Idx - , contType :: Idx - , contStackType :: Idx - , contStackTop :: Idx - , contStack :: Idx - , result :: Idx - , halt :: Idx - } - deriving (Show, Generic) +-- data Runtime = MkRuntime +-- { argArrayType :: Idx +-- , argArray :: Idx +-- , contType :: Idx +-- , contStackType :: Idx +-- , contStackTop :: Idx +-- , contStack :: Idx +-- , result :: Idx +-- , halt :: Idx +-- } +-- deriving (Show, Generic) @@ -80,59 +79,58 @@ makeSmallFixnum = [expr| -- | 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 :: Runtime -> Natural -> Wasm.Expr -> Wasm.Expr -pushArg (MkRuntime {argArrayType,argArray}) n e = [expr| - (global.get #{argArray}) +pushArg :: Natural -> Wasm.Expr -> Wasm.Expr +pushArg n e = [expr| + (global.get $arg-array) (global.get #{n}) ##{e} - (array.set #{argArrayType}) + (array.set $arg-array-type) |] - -- [ ins "global.get" [sxp argArray] - -- , ins "i32.const" [sxp n] - -- , e - -- , ins "array.set" [sxp argArrayType] - -- ] -- | Pop the nth arg from the arg-passing array onto the stack. --- popArg :: Runtime -> Int -> Wasm.Expr --- popArg (MkRuntime {argArrayType,argArray}) n = mconcat --- [ ins "global.get" [sxp argArray] --- , ins "i32.const" [sxp n] --- , ins "array.get" [sxp argArrayType] --- , ins "ref.as_non_null" [] --- ] +popArg :: Int -> Wasm.Expr +popArg n = [expr| + (global.get $arg-array) + (i32.const #{n}) + (array.get $arg-array-type) + ref.as_non_null +|] --- lowerVal :: Env -> Val -> Wasm.Expr +lowerVal :: Env -> Val -> Wasm.Expr --- lowerVal g (ValLit l) = --- case l of --- LitInt n -> --- ins "i32.const" [sxp n] --- <> makeSmallFixnum --- LitBool b -> --- ins "i32.const" [sxp @Int $ if b then 1 else 0] --- <> ins "ref.i31" [] --- _ -> _ +lowerVal g (ValLit l) = + case l of + LitInt n -> [expr| + (i32.const #{n}) + ##{makeSmallFixnum} + |] + LitBool b -> [expr| + (i32.const #{b'}) + ref.i31 + |] + where b' :: Int = if b then 1 else 0 + _ -> _ --- lowerVal g (ValVar x) = ins "local.get" [sxp (1+l)] --- where --- l = V.elemIndex x g.vars ^?! _Just +lowerVal g (ValVar x) = [expr|(local.get #{l})|] + where + l = succ $ V.elemIndex x g.vars ^?! _Just --- lower' :: (GenMod :> es) => Env -> Exp -> Eff es Wasm.Expr +lower' :: (GenMod :> es) => Env -> Exp -> Eff es Wasm.Expr --- lower' g (Halt [v]) = pure . mconcat $ --- [ pushArg g.runtime 0 (lowerVal g v) --- , ins "return_call" [sxp @Int 1] --- ] +lower' g (Halt [v]) = pure [expr| + ##{arg} + (return_call $halt) +|] + where arg = pushArg 0 (lowerVal g v) --- lower' g (ExpPrim p rs e) = --- case p of --- PrimAdd x y -> lowerBinOp "i32.add" g x y r e --- PrimMul x y -> lowerBinOp "i32.mul" g x y r e --- where --- r = head rs +lower' g (ExpPrim p rs e) = + case p of + PrimAdd x y -> lowerBinOp "i32.add" g x y r e + PrimMul x y -> lowerBinOp "i32.mul" g x y r e + where + r = head rs -- lower' g (ExpIf c t f) = do -- t' <- lower' g t @@ -181,26 +179,23 @@ pushArg (MkRuntime {argArrayType,argArray}) n e = [expr| -- lower' g e = error . show $ e --- lowerBinOp --- :: (GenMod :> es) --- => Text -> Env -> Val -> Val -> Name -> Exp -> Eff es Wasm.Expr --- lowerBinOp op g x y r e = do --- e' <- lower' g' e --- pure . mconcat $ --- [ lowerVal g x --- , ins "ref.cast" [sxp $ ref i31] --- , ins "i31.get_s" [] --- , lowerVal g y --- , ins "ref.cast" [sxp $ ref i31] --- , ins "i31.get_s" [] --- , ins op [] --- , ins "ref.i31" [] --- , ins "local.set" [sxp (1+n)] --- , e' --- ] --- where --- g' = g & #vars <>~ [r] --- n = length (g ^. #vars) +lowerBinOp + :: (GenMod :> es) + => Text -> Env -> Val -> Val -> Name -> Exp -> Eff es Wasm.Expr +lowerBinOp op g x y r e = do + let g' = g & #vars <>~ [r] + let n = succ $ length (g ^. #vars) + let x' = lowerVal g x + let y' = lowerVal g y + e' <- lower' g' e + pure [expr| + ##{x'} + (i31.get_s (ref.cast (ref i31))) + ##{y'} + (i31.get_s (ref.cast (ref i31))) + (local.set #{n} (ref.i31 #{op})) + ##{e'} + |] @@ -237,29 +232,65 @@ pushArg (MkRuntime {argArrayType,argArray}) n e = [expr| -- ,result,halt} -- -- pure $ error "todo" --- lower :: Exp -> Eff es Text --- lower e = fmap Wasm.renderModule . Wasm.execGenMod $ do --- runtime <- emitRuntime --- let g = MkEnv runtime mempty mempty --- scm_entry <- Wasm.defun [i32] [] (replicate 5 scm) \_ -> --- lower' g e --- main <- Wasm.defun [] [scm] [scm, scm, scm, scm, scm] \_ -> --- pure . mconcat $ --- -- push return cont --- [-- ins "ref.func" [sxp halt] --- -- make call --- ins "i32.const" [sxp @Int 0] --- , ins "call" [sxp scm_entry] --- , ins "global.get" [sxp runtime.result] --- , ins "ref.as_non_null" [] --- ] --- Wasm.export "main" "func" main +emitRuntime :: GenMod :> es => Eff es () +emitRuntime = mfix \runtime -> do + -- cont stack + Wasm.defineType [wat| + (type $heap-object (sub (struct (field $hash (mut i32))))) + |] + Wasm.defineType [wat| + (type $cont-type (func (param i32))) + |] + Wasm.defineType [wat| + (type $cont-stack-type (array (mut (ref null $cont-type)))) + |] + Wasm.defineGlobal [wat| + (global $cont-stack-top (mut i32) (i32.const 0)) + |] + Wasm.defineGlobal [wat| + (global $cont-stack (ref $cont-stack-type) + (array.new_default $cont-stack-type (i32.const 128))) + |] + -- arg array + Wasm.defineType [wat| + (type $arg-array-type (array (mut (ref null eq)))) + |] + Wasm.defineGlobal [wat| + (global $arg-array (ref $arg-array-type) + (array.new_default $arg-array-type) (i32.const 32)) + |] + -- 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 () --- lowerProgram :: Program -> Eff es Text --- lowerProgram (MkProgram e) = lower e - -lower = _ -lowerProgram = _ +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") (result (ref eq)) + (call $scm-entry (i32.const 0)) + (ref.as_non_null (global.get $result))) + |] + +lowerProgram :: Program -> Eff es Text +lowerProgram (MkProgram e) = lower e antiquote_example = let diff --git a/src/Gyehoek/Sexp.hs b/src/Gyehoek/Sexp.hs index cc1f13c..699f319 100644 --- a/src/Gyehoek/Sexp.hs +++ b/src/Gyehoek/Sexp.hs @@ -38,6 +38,7 @@ module Gyehoek.Sexp , toSexp , fromSexp , stripLocation + , format ) where @@ -87,6 +88,9 @@ sexp = iso (either error id . encode) (either error id . decode) +format :: Sexp -> Text +format = decodeUtf8 . view strict . SL.format + encode :: SexpIso a => a -> Either String Text encode = encodeWith sexpIso diff --git a/src/Gyehoek/Wasm.hs b/src/Gyehoek/Wasm.hs index 6c57aa0..b2bb0f3 100644 --- a/src/Gyehoek/Wasm.hs +++ b/src/Gyehoek/Wasm.hs @@ -29,6 +29,8 @@ module Gyehoek.Wasm , defineType , defineGlobal , declare + , renderModule + , wat ) where @@ -65,6 +67,8 @@ import Data.Functor (void) import Language.Haskell.TH.Quote (QuasiQuoter) import Data.Data (Data) import Data.Functor.Foldable (cata) +import Gyehoek.Sexp (sx) +import qualified Language.Sexp as SL newtype Module = MkModule { inner :: Vector Sexp } @@ -159,6 +163,11 @@ runGenMod = execGenMod :: Eff (GenMod : es) a -> Eff es Module execGenMod = fmap snd . runGenMod +renderModule :: Module -> Text +renderModule (MkModule ss) = Gyehoek.Sexp.format [sx| + (module ##{ss}) +|] + -- SexpIso instances @@ -185,3 +194,6 @@ expr :: QuasiQuoter expr = Gyehoek.Sexp.makeSxs [||MkExpr . V.fromList . (each . #inner %~ Gyehoek.Sexp.stripLocation) . fmap (Gyehoek.Sexp.fromSexp @Instr) ||] + +wat :: QuasiQuoter +wat = Gyehoek.Sexp.makeSx [|| id ||]