Compare commits
1
Commits
cps
...
b630cddb83
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b630cddb83 |
+18
-16
@@ -1,4 +1,5 @@
|
|||||||
{-# LANGUAGE OverloadedLists #-}
|
{-# LANGUAGE OverloadedLists #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
{-# LANGUAGE OverloadedRecordDot #-}
|
{-# LANGUAGE OverloadedRecordDot #-}
|
||||||
{-# LANGUAGE OverloadedLabels #-}
|
{-# LANGUAGE OverloadedLabels #-}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
@@ -28,6 +29,9 @@ import Text.Printf
|
|||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Vector.Strict as V
|
import qualified Data.Vector.Strict as V
|
||||||
import Data.IntMap.Strict (IntMap)
|
import Data.IntMap.Strict (IntMap)
|
||||||
|
import Data.String.Interpolate
|
||||||
|
import Gyehoek.Wasm qualified as Wasm
|
||||||
|
import Gyehoek.Wasm (i32)
|
||||||
|
|
||||||
|
|
||||||
data Env = MkEnv { vars :: Vector Name }
|
data Env = MkEnv { vars :: Vector Name }
|
||||||
@@ -49,18 +53,18 @@ tshow = T.pack . show
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
lowerVal :: Env -> Val -> Vector Text
|
lowerVal :: Env -> Val -> Wasm.Expr
|
||||||
|
|
||||||
lowerVal g (ValLit l) =
|
lowerVal g (ValLit l) =
|
||||||
case l of
|
case l of
|
||||||
LitInt n -> [ "i32.const " <> tshow n ]
|
LitInt n -> [i|i32.const #{n}|]
|
||||||
_ -> _
|
_ -> _
|
||||||
|
|
||||||
lowerVal g (ValVar x) = [ "local.get " <> tshow i ]
|
lowerVal g (ValVar x) = [i|local.get #{l}|]
|
||||||
where
|
where
|
||||||
i = V.elemIndex x g.vars ^?! _Just
|
l = V.elemIndex x g.vars ^?! _Just
|
||||||
|
|
||||||
lower' :: Env -> Exp -> Vector Text
|
lower' :: Env -> Exp -> Wasm.Expr
|
||||||
|
|
||||||
lower' g (Halt [e]) = lowerVal g e
|
lower' g (Halt [e]) = lowerVal g e
|
||||||
|
|
||||||
@@ -71,10 +75,14 @@ lower' g (ExpPrim p rs e) =
|
|||||||
where
|
where
|
||||||
r = head rs
|
r = head rs
|
||||||
|
|
||||||
|
lowerBinOp
|
||||||
|
:: _
|
||||||
|
-> _ -> _ -> _ -> _ -> _ -> Wasm.Expr
|
||||||
lowerBinOp op g x y r e =
|
lowerBinOp op g x y r e =
|
||||||
lowerVal g x
|
lowerVal g x
|
||||||
<> lowerVal g y
|
<> lowerVal g y
|
||||||
<> [ op, "local.set " <> tshow n ]
|
<> op
|
||||||
|
<> [i|local.set #{n}|]
|
||||||
<> lower' g' e
|
<> lower' g' e
|
||||||
where
|
where
|
||||||
g' = g & #vars <>~ [r]
|
g' = g & #vars <>~ [r]
|
||||||
@@ -82,14 +90,8 @@ lowerBinOp op g x y r e =
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
makeFunc :: Vector Text -> Text
|
|
||||||
makeFunc = (preamble<>) . (<>postamble) . T.unlines . toList . fmap indent
|
|
||||||
where
|
|
||||||
indent = (" "<>)
|
|
||||||
preamble = "(module\n\
|
|
||||||
\ (func (export \"main\") (result i32)\n\
|
|
||||||
\ (local i32 i32 i32 i32 i32 i32)\n"
|
|
||||||
postamble = " ))"
|
|
||||||
|
|
||||||
lower :: Exp -> Eff es Text
|
lower :: Exp -> Eff es Text
|
||||||
lower = pure . makeFunc . lower' emptyEnv
|
lower e = fmap Wasm.renderModule . Wasm.execGenMod $ do
|
||||||
|
idx <- Wasm.defun [] [i32] [i32, i32, i32, i32, i32] \_ ->
|
||||||
|
lower' emptyEnv e
|
||||||
|
Wasm.export "main" "func" idx
|
||||||
|
|||||||
@@ -35,3 +35,11 @@ runGenSym = reinterpret (evalStateLocal (0 :: Natural)) \cases
|
|||||||
instance Gen Text where
|
instance Gen Text where
|
||||||
gen = fromString . ('x':) . show
|
gen = fromString . ('x':) . show
|
||||||
gen' s = (s <>) . fromString . show
|
gen' s = (s <>) . fromString . show
|
||||||
|
|
||||||
|
instance Gen Natural where
|
||||||
|
gen = id
|
||||||
|
gen' = const id
|
||||||
|
|
||||||
|
instance Gen Int where
|
||||||
|
gen = fromIntegral
|
||||||
|
gen' _ = fromIntegral
|
||||||
|
|||||||
+168
-6
@@ -1,19 +1,62 @@
|
|||||||
{- HLINT ignore "Use newtype instead of data" -}
|
{- HLINT ignore "Use newtype instead of data" -}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
{-# LANGUAGE NoFieldSelectors #-}
|
||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
{-# LANGUAGE OverloadedLabels #-}
|
||||||
module Gyehoek.Wasm
|
module Gyehoek.Wasm
|
||||||
()
|
( defun
|
||||||
|
, deftype
|
||||||
|
, start
|
||||||
|
, runGenMod
|
||||||
|
, execGenMod
|
||||||
|
, renderModule
|
||||||
|
, Module
|
||||||
|
, Function
|
||||||
|
, Expr
|
||||||
|
, Instr
|
||||||
|
, GenMod
|
||||||
|
, i32
|
||||||
|
, export
|
||||||
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Data.List (List)
|
import Data.List (List)
|
||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
|
import Data.Text (Text)
|
||||||
|
import Data.String (IsString (fromString))
|
||||||
|
import Text.Printf
|
||||||
|
import Effectful
|
||||||
|
import Numeric.Natural (Natural)
|
||||||
|
import Effectful.Dispatch.Dynamic
|
||||||
|
import Effectful.State.Dynamic
|
||||||
|
import Control.Lens
|
||||||
|
import Data.Generics.Labels
|
||||||
|
import Data.Vector (Vector)
|
||||||
|
import Data.String.Interpolate
|
||||||
|
import qualified Data.Vector as V
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import Effectful.Writer.Dynamic
|
||||||
|
import Control.Applicative (Alternative((<|>)))
|
||||||
|
|
||||||
|
|
||||||
data Module = MkModule
|
data Module = MkModule
|
||||||
{ typeSection :: List Type
|
{ types :: Vector Type
|
||||||
|
, functions :: Vector Function
|
||||||
|
, start :: Maybe Idx
|
||||||
|
, exports :: Vector Export
|
||||||
}
|
}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
|
|
||||||
data Type
|
instance Semigroup Module where
|
||||||
deriving (Show, Generic)
|
m1 <> m2 = MkModule
|
||||||
|
{ types = m1.types <> m2.types
|
||||||
|
, functions = m1.functions <> m2.functions
|
||||||
|
, start = m2.start <|> m1.start
|
||||||
|
, exports = m1.exports <> m2.exports
|
||||||
|
}
|
||||||
|
|
||||||
|
instance Monoid Module where
|
||||||
|
mempty = MkModule mempty mempty Nothing mempty
|
||||||
|
|
||||||
data Function = MkFunction
|
data Function = MkFunction
|
||||||
{ params :: List Type
|
{ params :: List Type
|
||||||
@@ -23,6 +66,125 @@ data Function = MkFunction
|
|||||||
}
|
}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
|
|
||||||
type Expr = List Instr
|
newtype Export = MkExport { getExport :: Text }
|
||||||
|
deriving (Generic)
|
||||||
|
deriving newtype (Show, IsString)
|
||||||
|
|
||||||
type Instr = ByteString
|
newtype Expr = MkExpr { getExpr :: Vector Instr }
|
||||||
|
deriving (Generic)
|
||||||
|
deriving newtype (Semigroup, Monoid)
|
||||||
|
|
||||||
|
instance IsString Expr where
|
||||||
|
fromString s = MkExpr . V.fromList $ fromString <$> lines s
|
||||||
|
|
||||||
|
instance Show Expr where
|
||||||
|
show e = unlines . fmap show . V.toList $ e.getExpr
|
||||||
|
|
||||||
|
newtype Instr = MkInstr { getInstr :: Text }
|
||||||
|
deriving (Generic)
|
||||||
|
deriving newtype (IsString)
|
||||||
|
|
||||||
|
instance Show Instr where
|
||||||
|
show e = T.unpack e.getInstr
|
||||||
|
|
||||||
|
newtype Type = MkType { getType :: Text }
|
||||||
|
deriving (Generic)
|
||||||
|
deriving newtype (Show, IsString)
|
||||||
|
|
||||||
|
newtype Idx = MkIdx { getIdx :: Natural }
|
||||||
|
deriving newtype (Show)
|
||||||
|
|
||||||
|
data GenMod :: Effect where
|
||||||
|
DefType :: Type -> GenMod m Idx
|
||||||
|
Defun :: List Type -> List Type -> List Type -> (Idx -> Expr) -> GenMod m Idx
|
||||||
|
Start :: Idx -> GenMod m ()
|
||||||
|
Export :: Text -> Text -> Idx -> GenMod m ()
|
||||||
|
|
||||||
|
type instance DispatchOf GenMod = Dynamic
|
||||||
|
|
||||||
|
export :: (GenMod :> es) => Text -> Text -> Idx -> Eff es ()
|
||||||
|
export name ty idx = send $ Export name ty idx
|
||||||
|
|
||||||
|
start :: (GenMod :> es) => Idx -> Eff es ()
|
||||||
|
start = send . Start
|
||||||
|
|
||||||
|
deftype :: (GenMod :> es) => Type -> Eff es Idx
|
||||||
|
deftype = send . DefType
|
||||||
|
|
||||||
|
defun
|
||||||
|
:: (GenMod :> es)
|
||||||
|
=> List Type -> List Type -> List Type
|
||||||
|
-> (Idx -> Expr)
|
||||||
|
-> Eff es Idx
|
||||||
|
defun params result locals code = send $ Defun params result locals code
|
||||||
|
|
||||||
|
-- defun
|
||||||
|
-- :: (GenMod :> es)
|
||||||
|
-- => List Type -> List Type -> List Type
|
||||||
|
-- -> (Idx -> Eff '[GenExp] a)
|
||||||
|
-- -> Eff es Idx
|
||||||
|
-- defun params result locals code =
|
||||||
|
-- send $ Defun params result locals (runPureEff . execWriterLocal . code)
|
||||||
|
|
||||||
|
runGenMod :: Eff (GenMod : es) a -> Eff es (a, Module)
|
||||||
|
runGenMod =
|
||||||
|
reinterpret (runStateLocal (mempty :: Module)) \cases
|
||||||
|
_ (DefType t) -> state \m ->
|
||||||
|
( MkIdx . fromIntegral . length $ m.types
|
||||||
|
, m & #types <>~ V.singleton t
|
||||||
|
)
|
||||||
|
_ (Start idx) -> assign #start (Just idx)
|
||||||
|
_ (Export name ty idx) ->
|
||||||
|
#exports <>= V.singleton [i|(export #{show name} (#{ty} #{idx}))|]
|
||||||
|
_ (Defun params result locals code) -> state \m ->
|
||||||
|
let idx = MkIdx . fromIntegral . length $ m.functions
|
||||||
|
in ( idx
|
||||||
|
, m & #functions <>~ V.singleton
|
||||||
|
(MkFunction params result locals (code idx))
|
||||||
|
)
|
||||||
|
|
||||||
|
execGenMod = fmap snd . runGenMod
|
||||||
|
|
||||||
|
indent n = (T.replicate n " " <>)
|
||||||
|
|
||||||
|
unlines' :: Foldable f => f Text -> Text
|
||||||
|
unlines' = foldr f ""
|
||||||
|
where
|
||||||
|
f a "" = a
|
||||||
|
f a b = a <> "\n" <> b
|
||||||
|
|
||||||
|
renderModule :: Module -> Text
|
||||||
|
renderModule m = [__i|
|
||||||
|
(module
|
||||||
|
#{types}
|
||||||
|
#{functions}
|
||||||
|
#{strt}
|
||||||
|
#{exports})
|
||||||
|
|]
|
||||||
|
where
|
||||||
|
strt :: Text
|
||||||
|
strt = case m.start of
|
||||||
|
Just x -> [i|(start #{x})|]
|
||||||
|
Nothing -> ""
|
||||||
|
exports = unlines' $ view #getExport <$> m.exports
|
||||||
|
types = foldMapOf (#types . each . #getType) (indent 2) m
|
||||||
|
functions = unlines' $
|
||||||
|
indent 2 . showfunc <$> m.functions
|
||||||
|
showtypes ts = T.unwords $ fmap (\x -> x.getType) ts
|
||||||
|
showfunc :: Function -> Text
|
||||||
|
showfunc func = [__i|
|
||||||
|
(func (param #{params})
|
||||||
|
(result #{result})
|
||||||
|
(local #{locals})
|
||||||
|
#{body})
|
||||||
|
|]
|
||||||
|
where
|
||||||
|
params = showtypes func.params
|
||||||
|
result = showtypes func.result
|
||||||
|
locals = showtypes func.locals
|
||||||
|
body = unlines' $ indent 4 . view #getInstr <$> func.body.getExpr
|
||||||
|
|
||||||
|
type GenExp = Writer Expr
|
||||||
|
|
||||||
|
i32 :: Type
|
||||||
|
i32 = "i32"
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ common ghcstuffs
|
|||||||
OverloadedStrings
|
OverloadedStrings
|
||||||
PartialTypeSignatures
|
PartialTypeSignatures
|
||||||
PatternSynonyms
|
PatternSynonyms
|
||||||
|
QuasiQuotes
|
||||||
|
|
||||||
executable gyehoek
|
executable gyehoek
|
||||||
import: ghcstuffs, ghcstuffs-dev
|
import: ghcstuffs, ghcstuffs-dev
|
||||||
@@ -70,6 +71,7 @@ executable gyehoek
|
|||||||
, text-short
|
, text-short
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
, vector
|
, vector
|
||||||
|
, string-interpolate
|
||||||
|
|
||||||
hs-source-dirs: app
|
hs-source-dirs: app
|
||||||
default-language: GHC2024
|
default-language: GHC2024
|
||||||
|
|||||||
Reference in New Issue
Block a user