@@ -1,7 +1,9 @@
|
|||||||
{-# LANGUAGE DeriveGeneric #-}
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE OverloadedLabels #-}
|
{-# LANGUAGE OverloadedLabels #-}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
{-# LANGUAGE TypeOperators #-}
|
{-# LANGUAGE TypeOperators #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
{-# LANGUAGE PartialTypeSignatures #-}
|
{-# LANGUAGE PartialTypeSignatures #-}
|
||||||
{-# LANGUAGE DerivingStrategies #-}
|
{-# LANGUAGE DerivingStrategies #-}
|
||||||
{-# LANGUAGE OrPatterns #-}
|
{-# LANGUAGE OrPatterns #-}
|
||||||
@@ -17,6 +19,11 @@ module Gyehoek.Scheme.Syntax
|
|||||||
, CommandOrDef(..)
|
, CommandOrDef(..)
|
||||||
, primSexpIso
|
, primSexpIso
|
||||||
, pattern Void
|
, pattern Void
|
||||||
|
, free
|
||||||
|
, qexp
|
||||||
|
, qprog
|
||||||
|
, subst
|
||||||
|
, freeVariables
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -37,11 +44,17 @@ import Control.Lens
|
|||||||
import Data.String (IsString)
|
import Data.String (IsString)
|
||||||
import Data.Hashable (Hashable)
|
import Data.Hashable (Hashable)
|
||||||
import Control.Lens.Unsound (prismSum)
|
import Control.Lens.Unsound (prismSum)
|
||||||
|
import Data.Data (Data)
|
||||||
|
import Data.Functor.Foldable.TH (makeBaseFunctor)
|
||||||
|
import Data.Functor.Foldable hiding (fold)
|
||||||
|
import Data.HashSet (HashSet)
|
||||||
|
import qualified Data.HashSet as HS
|
||||||
|
import Data.Foldable (fold)
|
||||||
|
|
||||||
|
|
||||||
newtype Name = MkName { getName :: Text }
|
newtype Name = MkName { getName :: Text }
|
||||||
deriving newtype (Show, Eq, IsString, Gen, Hashable)
|
deriving newtype (Show, Eq, IsString, Gen, Hashable)
|
||||||
deriving stock (Generic)
|
deriving stock (Generic, Data)
|
||||||
|
|
||||||
data Prim e
|
data Prim e
|
||||||
= PrimAdd e e
|
= PrimAdd e e
|
||||||
@@ -57,7 +70,7 @@ data Prim e
|
|||||||
| PrimWrite e
|
| PrimWrite e
|
||||||
| PrimZeroP e
|
| PrimZeroP e
|
||||||
| PrimNewline
|
| PrimNewline
|
||||||
deriving (Show, Generic, Functor, Foldable, Traversable)
|
deriving (Show, Generic, Functor, Foldable, Traversable, Data)
|
||||||
|
|
||||||
instance Each (Prim e) (Prim e') e e'
|
instance Each (Prim e) (Prim e') e e'
|
||||||
|
|
||||||
@@ -67,7 +80,7 @@ data Lit
|
|||||||
| LitBool Bool
|
| LitBool Bool
|
||||||
| LitString Text
|
| LitString Text
|
||||||
| LitQuote Sexp
|
| LitQuote Sexp
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
pattern Void :: Lit
|
pattern Void :: Lit
|
||||||
pattern Void = LitNil
|
pattern Void = LitNil
|
||||||
@@ -75,7 +88,7 @@ pattern Void = LitNil
|
|||||||
data Def
|
data Def
|
||||||
= DefConstant Name Exp
|
= DefConstant Name Exp
|
||||||
| DefProcedure Name (List Name) (List Exp)
|
| DefProcedure Name (List Name) (List Exp)
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
data Exp
|
data Exp
|
||||||
= ExpLet (NonEmpty (Name, Exp)) Exp
|
= ExpLet (NonEmpty (Name, Exp)) Exp
|
||||||
@@ -86,24 +99,24 @@ data Exp
|
|||||||
| ExpLambda (List Name) Exp
|
| ExpLambda (List Name) Exp
|
||||||
| ExpVar Name
|
| ExpVar Name
|
||||||
| ExpApply Exp (List Exp)
|
| ExpApply Exp (List Exp)
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
data Sexp
|
data Sexp
|
||||||
= SexpCons Sexp Sexp
|
= SexpCons Sexp Sexp
|
||||||
| SexpSymbol Text
|
| SexpSymbol Text
|
||||||
| SexpLit Lit
|
| SexpLit Lit
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
data CommandOrDef
|
data CommandOrDef
|
||||||
= Command Exp
|
= Command Exp
|
||||||
| Definition Def
|
| Definition Def
|
||||||
| Begin (List CommandOrDef)
|
| Begin (List CommandOrDef)
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
data Program = MkProgram
|
data Program = MkProgram
|
||||||
{ commandsAndDefs :: List CommandOrDef
|
{ commandsAndDefs :: List CommandOrDef
|
||||||
}
|
}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
instance Each Program Program (Either Exp Def) (Either Exp Def) where
|
instance Each Program Program (Either Exp Def) (Either Exp Def) where
|
||||||
each = #commandsAndDefs . each . go
|
each = #commandsAndDefs . each . go
|
||||||
@@ -116,6 +129,8 @@ instance Each Program Program (Either Exp Def) (Either Exp Def) where
|
|||||||
go k (Definition d) = inj <$> k (Right d)
|
go k (Definition d) = inj <$> k (Right d)
|
||||||
go k (Begin xs) = Begin <$> traverse (go k) xs
|
go k (Begin xs) = Begin <$> traverse (go k) xs
|
||||||
|
|
||||||
|
makeBaseFunctor ''Exp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
instance SexpIso Name where
|
instance SexpIso Name where
|
||||||
@@ -211,3 +226,41 @@ instance SexpIso CommandOrDef where
|
|||||||
$ End
|
$ End
|
||||||
where
|
where
|
||||||
bgn = list $ el (sym "begin") >>> rest sexpIso
|
bgn = list $ el (sym "begin") >>> rest sexpIso
|
||||||
|
|
||||||
|
|
||||||
|
-- utilities
|
||||||
|
|
||||||
|
qexp = Gyehoek.Sexp.makeSx $ sexpIso @Exp
|
||||||
|
qprog = Gyehoek.Sexp.makeSxs (sexpIso @CommandOrDef) MkProgram
|
||||||
|
|
||||||
|
free :: Exp -> HashSet Name
|
||||||
|
free = cata \case
|
||||||
|
ExpVarF x -> HS.singleton x
|
||||||
|
ExpLetF bs e -> error "todo lol"
|
||||||
|
ExpLambdaF binders vs -> deleteFrom binders vs
|
||||||
|
e -> fold e
|
||||||
|
|
||||||
|
deleteFrom :: (Foldable f, Hashable a) => f a -> HashSet a -> HashSet a
|
||||||
|
deleteFrom = flip $ foldr HS.delete
|
||||||
|
|
||||||
|
insertFrom :: (Foldable f, Hashable a) => f a -> HashSet a -> HashSet a
|
||||||
|
insertFrom = flip $ foldr HS.insert
|
||||||
|
|
||||||
|
subst :: (Name -> Maybe Exp) -> Exp -> Exp
|
||||||
|
subst f = \e -> cata go e mempty where
|
||||||
|
go (ExpVarF x) bound
|
||||||
|
| not (x `HS.member` bound), Just e' <- f x = e'
|
||||||
|
| otherwise = ExpVar x
|
||||||
|
go (ExpLetF _ _) _ = error "todo lol"
|
||||||
|
go (ExpLambdaF bs e) bound = e $ insertFrom bs bound
|
||||||
|
go e bound = embed $ fmap ($ bound) e
|
||||||
|
|
||||||
|
-- | Unlawful!
|
||||||
|
freeVariables :: Traversal Exp Exp Name Exp
|
||||||
|
freeVariables k = \e -> cataA go e mempty where
|
||||||
|
go (ExpVarF x) bound
|
||||||
|
| not (x `HS.member` bound) = k x
|
||||||
|
| otherwise = pure $ ExpVar x
|
||||||
|
go (ExpLetF _ _) _ = error "todo lol"
|
||||||
|
go (ExpLambdaF bs e) bound = e $ insertFrom bs bound
|
||||||
|
go e bound = embed <$> traverse ($ bound) e
|
||||||
|
|||||||
+149
-4
@@ -4,6 +4,8 @@
|
|||||||
{-# LANGUAGE OverloadedLabels #-}
|
{-# LANGUAGE OverloadedLabels #-}
|
||||||
{-# LANGUAGE DerivingVia #-}
|
{-# LANGUAGE DerivingVia #-}
|
||||||
{-# LANGUAGE StandaloneDeriving #-}
|
{-# LANGUAGE StandaloneDeriving #-}
|
||||||
|
{-# LANGUAGE TemplateHaskellQuotes #-}
|
||||||
|
{-# LANGUAGE OrPatterns #-}
|
||||||
module Gyehoek.Sexp
|
module Gyehoek.Sexp
|
||||||
( let_
|
( let_
|
||||||
, sexp
|
, sexp
|
||||||
@@ -25,11 +27,18 @@ module Gyehoek.Sexp
|
|||||||
, encodePretty
|
, encodePretty
|
||||||
, UglySexpIso(..)
|
, UglySexpIso(..)
|
||||||
, AsSexpIso(..)
|
, AsSexpIso(..)
|
||||||
|
, parseSexpsWithPos
|
||||||
|
, parseSexpWithPos
|
||||||
|
, parseSexp
|
||||||
|
, sx
|
||||||
|
, sxs
|
||||||
|
, makeSx
|
||||||
|
, makeSxs
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Language.SexpGrammar as Sexp hiding (List, encode, decode, encodeWith, decodeWith, iso, encodePrettyWith, encodePretty)
|
import Language.SexpGrammar as Sexp hiding (toSexp, List, encode, decode, encodeWith, decodeWith, iso, encodePrettyWith, encodePretty)
|
||||||
import Language.SexpGrammar qualified as Sexp
|
import Language.SexpGrammar qualified as Sexp
|
||||||
import Language.Sexp qualified as S
|
import Language.Sexp qualified as S
|
||||||
import Language.SexpGrammar.Generic
|
import Language.SexpGrammar.Generic
|
||||||
@@ -37,7 +46,8 @@ import Data.InvertibleGrammar.Base qualified as IGB
|
|||||||
import Data.InvertibleGrammar qualified as IG
|
import Data.InvertibleGrammar qualified as IG
|
||||||
import Data.InvertibleGrammar.Base ((:-)((:-)))
|
import Data.InvertibleGrammar.Base ((:-)((:-)))
|
||||||
import Data.List.NonEmpty (NonEmpty ((:|)))
|
import Data.List.NonEmpty (NonEmpty ((:|)))
|
||||||
import Data.List (List)
|
import Data.List.NonEmpty qualified as NE
|
||||||
|
import Data.List (List, groupBy)
|
||||||
import Data.Text.Encoding
|
import Data.Text.Encoding
|
||||||
import Data.Either (either)
|
import Data.Either (either)
|
||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
@@ -47,10 +57,16 @@ import System.Process
|
|||||||
import GHC.IO.Unsafe (unsafePerformIO)
|
import GHC.IO.Unsafe (unsafePerformIO)
|
||||||
import qualified Data.Text.IO as TIO
|
import qualified Data.Text.IO as TIO
|
||||||
import Control.Monad (join)
|
import Control.Monad (join)
|
||||||
import qualified Language.Sexp.Located as SexpLoc
|
import qualified Language.Sexp.Located as SL
|
||||||
import Data.Void (absurd, Void)
|
import Data.Void (absurd, Void)
|
||||||
import Data.Coerce (coerce)
|
import Data.Coerce (coerce)
|
||||||
import qualified Data.Map
|
import qualified Data.Map
|
||||||
|
import Language.Haskell.TH.Quote
|
||||||
|
import Language.Haskell.TH (Quote, location, Loc (..), ExpQ, varE, mkName, listE, Exp, appE, conE)
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Control.Category
|
||||||
|
import Data.Data (Data, Typeable, cast)
|
||||||
|
import Language.Haskell.TH.Syntax (lift, Lift)
|
||||||
|
|
||||||
|
|
||||||
sexp :: SexpIso a => Iso' a Text
|
sexp :: SexpIso a => Iso' a Text
|
||||||
@@ -78,9 +94,23 @@ encodePrettyWith g =
|
|||||||
(_Right %~ decodeUtf8 . view strict) . Sexp.encodePrettyWith g
|
(_Right %~ decodeUtf8 . view strict) . Sexp.encodePrettyWith g
|
||||||
|
|
||||||
parseSexps :: SexpIso a => FilePath -> Text -> Either String (List a)
|
parseSexps :: SexpIso a => FilePath -> Text -> Either String (List a)
|
||||||
parseSexps f = marshal . SexpLoc.parseSexps f . view lazy . encodeUtf8
|
parseSexps f = marshal . SL.parseSexps f . view lazy . encodeUtf8
|
||||||
where marshal = join . traverseOf (_Right . each) (fromSexp sexpIso)
|
where marshal = join . traverseOf (_Right . each) (fromSexp sexpIso)
|
||||||
|
|
||||||
|
parseSexp :: SexpIso a => FilePath -> Text -> Either String a
|
||||||
|
parseSexp f = marshal . SL.parseSexp f . view lazy . encodeUtf8
|
||||||
|
where marshal = join . traverseOf _Right (fromSexp sexpIso)
|
||||||
|
|
||||||
|
parseSexpsWithPos :: SexpGrammar a -> Position -> Text -> Either String (List a)
|
||||||
|
parseSexpsWithPos g pos =
|
||||||
|
marshal . SL.parseSexpsWithPos pos . view lazy . encodeUtf8
|
||||||
|
where marshal = join . traverseOf (_Right . each) (fromSexp g)
|
||||||
|
|
||||||
|
parseSexpWithPos :: SexpGrammar a -> Position -> Text -> Either String a
|
||||||
|
parseSexpWithPos g pos =
|
||||||
|
marshal . SL.parseSexpWithPos pos . view lazy . encodeUtf8
|
||||||
|
where marshal = join . traverseOf _Right (fromSexp g)
|
||||||
|
|
||||||
nonEmptyGrammar :: Grammar p (NonEmpty x :- t) (List x :- x :- t)
|
nonEmptyGrammar :: Grammar p (NonEmpty x :- t) (List x :- x :- t)
|
||||||
nonEmptyGrammar = IGB.Iso
|
nonEmptyGrammar = IGB.Iso
|
||||||
(\((x:|xs) :- t) -> reverse xs :- x :- t)
|
(\((x:|xs) :- t) -> reverse xs :- x :- t)
|
||||||
@@ -183,3 +213,118 @@ instance UglySexpIso Int where uglySexpIso = sexpIso
|
|||||||
instance UglySexpIso Bool where uglySexpIso = sexpIso
|
instance UglySexpIso Bool where uglySexpIso = sexpIso
|
||||||
instance UglySexpIso Double where uglySexpIso = sexpIso
|
instance UglySexpIso Double where uglySexpIso = sexpIso
|
||||||
instance UglySexpIso () where uglySexpIso = sexpIso
|
instance UglySexpIso () where uglySexpIso = sexpIso
|
||||||
|
|
||||||
|
instance SexpIso Sexp where
|
||||||
|
sexpIso = Control.Category.id
|
||||||
|
|
||||||
|
-- evil ass orphan instances
|
||||||
|
deriving instance (Data a, Data e) => Data (SL.LocatedBy a e)
|
||||||
|
deriving instance Data SL.Atom
|
||||||
|
deriving instance Data SL.Prefix
|
||||||
|
deriving instance Data SL.Position
|
||||||
|
deriving instance (Data e) => Data (SL.SexpF e)
|
||||||
|
|
||||||
|
|
||||||
|
-- Quasiquoter
|
||||||
|
|
||||||
|
getPos = do
|
||||||
|
Loc {loc_filename,loc_start} <- location
|
||||||
|
pure $ SL.Position loc_filename (fst loc_start) (snd loc_start)
|
||||||
|
|
||||||
|
makeSxs :: Data b => SexpGrammar a -> (List a -> b) -> QuasiQuoter
|
||||||
|
makeSxs g f = QuasiQuoter
|
||||||
|
{ quoteExp = \str -> do
|
||||||
|
pos <- getPos
|
||||||
|
case parseSexpsWithPos g pos (T.pack str) of
|
||||||
|
Left e -> fail e
|
||||||
|
Right xs -> dataToExpQ (const Nothing) (f xs)
|
||||||
|
, quotePat = undefined
|
||||||
|
, quoteType = undefined
|
||||||
|
, quoteDec = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
toSexp :: SexpIso a => a -> Sexp
|
||||||
|
toSexp = either error id . Sexp.toSexp sexpIso
|
||||||
|
|
||||||
|
pattern Unquote x =
|
||||||
|
SL.Modified Hash (SL.BraceList [SL.Symbol x])
|
||||||
|
pattern UnquoteSplicing x =
|
||||||
|
SL.Modified Hash (SL.Modified Hash (SL.BraceList [SL.Symbol x]))
|
||||||
|
|
||||||
|
_UnquoteSplicing :: Prism' Sexp.Sexp Text
|
||||||
|
_UnquoteSplicing = prism'
|
||||||
|
UnquoteSplicing
|
||||||
|
(\case { UnquoteSplicing x -> Just x ; _ -> Nothing })
|
||||||
|
|
||||||
|
instance Each Sexp Sexp Sexp Sexp where
|
||||||
|
each k (SL.ParenList xs) = SL.ParenList <$> traverse k xs
|
||||||
|
each k (SL.BracketList xs) = SL.BracketList <$> traverse k xs
|
||||||
|
each k (SL.BraceList xs) = SL.BraceList <$> traverse k xs
|
||||||
|
each _ e@(SL.Atom _; SL.Modified _ _) = pure e
|
||||||
|
|
||||||
|
metaSexp :: Sexp.Sexp -> Maybe ExpQ
|
||||||
|
metaSexp (Unquote x) =
|
||||||
|
Just [| toSexp $(varE (mkName (T.unpack x))) |]
|
||||||
|
metaSexp (SL.ParenList xs)
|
||||||
|
| (_:_) <- xs ^.. each . _UnquoteSplicing
|
||||||
|
= Just [| SL.ParenList (mconcat $(listE spans)) |]
|
||||||
|
where
|
||||||
|
spans = xs
|
||||||
|
& groupBy \cases
|
||||||
|
(UnquoteSplicing _) _ -> False
|
||||||
|
_ (UnquoteSplicing _) -> False
|
||||||
|
_ _ -> True
|
||||||
|
& fmap \case
|
||||||
|
[UnquoteSplicing x] -> varE (mkName (T.unpack x))
|
||||||
|
x -> lift x
|
||||||
|
metaSexp _ = Nothing
|
||||||
|
|
||||||
|
-- 뻘짓뻘짓뻘짓뻘짓뻘짓
|
||||||
|
class Lift1 f where
|
||||||
|
liftLift :: Quote m => (a -> m Exp) -> f a -> m Exp
|
||||||
|
|
||||||
|
lift1 :: (Lift1 f, Lift a, Quote m) => f a -> m Exp
|
||||||
|
lift1 = liftLift lift
|
||||||
|
|
||||||
|
instance Lift1 f => Lift (SL.Fix f) where
|
||||||
|
lift (SL.Fix inner) = appE [|Fix|] (lift1 inner)
|
||||||
|
|
||||||
|
instance (Lift1 f, Lift1 g) => Lift1 (SL.Compose f g) where
|
||||||
|
liftLift l (SL.Compose fga) = [|Compose $(liftLift (liftLift l) fga)|]
|
||||||
|
|
||||||
|
instance Lift a => Lift1 (SL.LocatedBy a) where
|
||||||
|
liftLift l (a SL.:< e) = [|(SL.:<) $(lift a) $(l e)|]
|
||||||
|
|
||||||
|
instance Lift1 List where
|
||||||
|
liftLift l xs = listE $ l <$> xs
|
||||||
|
|
||||||
|
instance Lift1 SL.SexpF where
|
||||||
|
liftLift l = \case
|
||||||
|
SL.AtomF a -> [|SL.AtomF $(lift a)|]
|
||||||
|
SL.ParenListF es -> [|SL.ParenListF $(liftLift l es)|]
|
||||||
|
SL.BracketListF es -> [|SL.BracketListF $(liftLift l es)|]
|
||||||
|
SL.BraceListF es -> [|SL.BraceListF $(liftLift l es)|]
|
||||||
|
SL.ModifiedF p e -> [|SL.Modified $(lift p) $(l e)|]
|
||||||
|
|
||||||
|
-- deriving instance Lift a => Lift (SL.SexpF a)
|
||||||
|
deriving instance Lift SL.Atom
|
||||||
|
deriving instance Lift SL.Position
|
||||||
|
deriving instance Lift SL.Prefix
|
||||||
|
|
||||||
|
extQ :: (Typeable a, Typeable b) => (a -> r) -> (b -> r) -> a -> r
|
||||||
|
extQ f g a = maybe (f a) g (cast a)
|
||||||
|
|
||||||
|
makeSx :: Data a => SexpGrammar a -> QuasiQuoter
|
||||||
|
makeSx g = QuasiQuoter
|
||||||
|
{ quoteExp = \str -> do
|
||||||
|
pos <- getPos
|
||||||
|
case parseSexpWithPos g pos (T.pack str) of
|
||||||
|
Left e -> fail e
|
||||||
|
Right x -> dataToExpQ (const Nothing `extQ` metaSexp) x
|
||||||
|
, quotePat = undefined
|
||||||
|
, quoteType = undefined
|
||||||
|
, quoteDec = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
sxs = makeSxs (sexpIso @Sexp) id
|
||||||
|
sx = makeSx (sexpIso @Sexp)
|
||||||
|
|||||||
+19
-369
@@ -11,43 +11,7 @@
|
|||||||
{-# LANGUAGE ImpredicativeTypes #-}
|
{-# LANGUAGE ImpredicativeTypes #-}
|
||||||
{-# LANGUAGE DerivingVia #-}
|
{-# LANGUAGE DerivingVia #-}
|
||||||
module Gyehoek.Wasm
|
module Gyehoek.Wasm
|
||||||
( defun
|
( Module
|
||||||
, rec'
|
|
||||||
, start
|
|
||||||
, runGenMod
|
|
||||||
, execGenMod
|
|
||||||
, renderModule
|
|
||||||
, Module
|
|
||||||
, Function
|
|
||||||
, Type(..)
|
|
||||||
, Expr
|
|
||||||
, Instr
|
|
||||||
, GenMod
|
|
||||||
, Idx
|
|
||||||
, i32
|
|
||||||
, export
|
|
||||||
, ins
|
|
||||||
, sxp
|
|
||||||
, result
|
|
||||||
, param
|
|
||||||
, if'
|
|
||||||
, ref
|
|
||||||
, eq
|
|
||||||
, i31ref
|
|
||||||
, i31
|
|
||||||
, struct
|
|
||||||
, mut
|
|
||||||
, sub
|
|
||||||
, deftype
|
|
||||||
, namedType
|
|
||||||
, type'
|
|
||||||
, deftypeNamed
|
|
||||||
, defglobal
|
|
||||||
, array
|
|
||||||
, FromIdx(..)
|
|
||||||
, func
|
|
||||||
, refnull
|
|
||||||
, declareFuncref
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -83,344 +47,30 @@ import qualified Control.Category
|
|||||||
import Data.Functor (void)
|
import Data.Functor (void)
|
||||||
|
|
||||||
|
|
||||||
data Module = MkModule
|
newtype Module = MkModule { inner :: Vector Sexp }
|
||||||
{ types :: Vector RecType
|
|
||||||
, functions :: Vector Function
|
|
||||||
, funcrefs :: Vector Funcref
|
|
||||||
, start :: Maybe Idx
|
|
||||||
, exports :: Vector Export
|
|
||||||
, globals :: Vector Global
|
|
||||||
}
|
|
||||||
deriving (Show, Generic)
|
|
||||||
|
|
||||||
instance Semigroup Module where
|
|
||||||
m1 <> m2 = MkModule
|
|
||||||
{ types = m1.types <> m2.types
|
|
||||||
, functions = m1.functions <> m2.functions
|
|
||||||
, start = m2.start <|> m1.start
|
|
||||||
, exports = m1.exports <> m2.exports
|
|
||||||
, funcrefs = m1.funcrefs <> m2.funcrefs
|
|
||||||
, globals = m1.globals <> m2.globals
|
|
||||||
}
|
|
||||||
|
|
||||||
instance Monoid Module where
|
|
||||||
mempty = MkModule mempty mempty mempty Nothing mempty mempty
|
|
||||||
|
|
||||||
newtype Funcref = MkFuncref { inner :: Idx }
|
|
||||||
deriving (Show, Generic)
|
|
||||||
|
|
||||||
data Global = MkGlobal
|
|
||||||
{ ty :: Type
|
|
||||||
, body :: Expr
|
|
||||||
}
|
|
||||||
deriving (Show, Generic)
|
|
||||||
|
|
||||||
newtype RecType = MkRecType { inner :: Vector Type }
|
|
||||||
deriving (Show, Generic)
|
|
||||||
|
|
||||||
data Function = MkFunction
|
|
||||||
{ params :: List Type
|
|
||||||
, result :: List Type
|
|
||||||
, locals :: List Type
|
|
||||||
, body :: Expr
|
|
||||||
}
|
|
||||||
deriving (Show, Generic)
|
|
||||||
|
|
||||||
newtype Export = MkExport { inner :: Sexp }
|
|
||||||
deriving (Show, Generic)
|
|
||||||
|
|
||||||
newtype Expr = MkExpr { inner :: Vector Instr }
|
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
deriving newtype (Semigroup, Monoid)
|
deriving newtype (Semigroup, Monoid)
|
||||||
|
|
||||||
newtype Instr = MkInstr { inner :: Sexp }
|
newtype Expr = MkExpr { inner :: Vector Sexp }
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
|
deriving newtype (Semigroup, Monoid)
|
||||||
|
|
||||||
newtype Type = MkType { inner :: Sexp }
|
newtype Idx = MkIdx { inner :: Natural }
|
||||||
deriving (Show, Generic)
|
deriving (Generic)
|
||||||
|
deriving newtype (Show)
|
||||||
|
|
||||||
data Idx
|
|
||||||
= IdxNumeric Natural
|
-- GenMod
|
||||||
| IdxNamed Text
|
|
||||||
|
-- | '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
|
||||||
|
}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
|
|
||||||
data GenMod :: Effect where
|
data GenMod :: Effect where
|
||||||
DefRecType :: List Type -> GenMod m (List Idx)
|
DefineFunction :: Sexp -> GenMod m Idx
|
||||||
Defun :: List Type -> List Type -> List Type
|
DefineType :: Sexp -> GenMod m Idx
|
||||||
-> (Idx -> m Expr) -> GenMod m Idx
|
|
||||||
Start :: Idx -> GenMod m ()
|
|
||||||
Export :: Text -> Text -> Idx -> GenMod m ()
|
|
||||||
DefGlobal :: Type -> Expr -> GenMod m Idx
|
|
||||||
DeclareFuncref :: 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
|
|
||||||
|
|
||||||
rec' :: (GenMod :> es) => List Type -> Eff es (List Idx)
|
|
||||||
rec' = send . DefRecType
|
|
||||||
|
|
||||||
deftype :: (GenMod :> es) => Type -> Eff es Idx
|
|
||||||
deftype (MkType t) = send (DefRecType [type' t]) <&> \case
|
|
||||||
[x] -> x
|
|
||||||
x -> error $ "unreachable " <> show x
|
|
||||||
|
|
||||||
deftypeNamed :: (GenMod :> es) => Text -> Type -> Eff es ()
|
|
||||||
deftypeNamed name (MkType t) = void $ send (DefRecType [namedType name t])
|
|
||||||
|
|
||||||
defglobal :: (GenMod :> es) => Type -> Expr -> Eff es Idx
|
|
||||||
defglobal t e = send $ DefGlobal t e
|
|
||||||
|
|
||||||
defun
|
|
||||||
:: (GenMod :> es)
|
|
||||||
=> List Type -> List Type -> List Type
|
|
||||||
-> (Idx -> Eff es Expr)
|
|
||||||
-> Eff es Idx
|
|
||||||
defun params res locals code = send $ Defun params res locals code
|
|
||||||
|
|
||||||
declareFuncref :: GenMod :> es => Idx -> Eff es ()
|
|
||||||
declareFuncref = send . DeclareFuncref
|
|
||||||
|
|
||||||
-- 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 :: forall es a. Eff (GenMod : es) a -> Eff es (a, Module)
|
|
||||||
runGenMod =
|
|
||||||
reinterpret (runStateLocal (mempty :: Module)) \cases
|
|
||||||
_ (DefRecType ts) -> state \m ->
|
|
||||||
( let prev_n = sumOf (#types . each . #inner . to V.length) m
|
|
||||||
in IdxNumeric . fromIntegral <$> [prev_n .. prev_n + length ts - 1]
|
|
||||||
, m & #types <>~ V.singleton (MkRecType (V.fromList ts))
|
|
||||||
)
|
|
||||||
_ (Start idx) -> assign #start (Just idx)
|
|
||||||
_ (Export name ty idx) ->
|
|
||||||
#exports <>= V.singleton e
|
|
||||||
where e = MkExport $ ParenList
|
|
||||||
[ "export", sxp name, ParenList [ "func", sxp idx ] ]
|
|
||||||
env (Defun params result locals code) ->
|
|
||||||
localSeqUnlift env \unlift -> do
|
|
||||||
m <- get
|
|
||||||
-- the least unused function index, computed as the number
|
|
||||||
-- of currently allocated functions.
|
|
||||||
let idx = IdxNumeric . fromIntegral . length $ m.functions
|
|
||||||
-- the body is computed with access to the newly allocated
|
|
||||||
-- index `idx` for the sake of recursive occurences.
|
|
||||||
body <- unlift $ code idx
|
|
||||||
let func = MkFunction {params,result,locals,body}
|
|
||||||
#functions <>= V.singleton func
|
|
||||||
pure idx
|
|
||||||
_ (DefGlobal t e) -> state \m ->
|
|
||||||
let prev_n = IdxNumeric . fromIntegral . V.length $ m.globals
|
|
||||||
m' = m & #globals <>~ V.singleton (MkGlobal t e)
|
|
||||||
in (prev_n, m')
|
|
||||||
_ (DeclareFuncref idx) -> #funcrefs <>= V.singleton (MkFuncref idx)
|
|
||||||
|
|
||||||
execGenMod = fmap snd . runGenMod
|
|
||||||
|
|
||||||
renderModule :: Module -> Text
|
|
||||||
renderModule = (^?! _Right) . Gyehoek.Sexp.encodePretty
|
|
||||||
|
|
||||||
ref :: Type -> Type
|
|
||||||
ref (MkType x) = MkType . ParenList $ [Symbol "ref", x]
|
|
||||||
|
|
||||||
refnull :: Type -> Type
|
|
||||||
refnull (MkType x) = MkType . ParenList $ ["ref", "null", x]
|
|
||||||
|
|
||||||
sub :: List Idx -> Type -> Type
|
|
||||||
sub supers (MkType x) = MkType . ParenList $
|
|
||||||
Symbol "sub" : (sxp <$> supers) ++ [x]
|
|
||||||
|
|
||||||
array :: Type -> Type
|
|
||||||
array (MkType x) = MkType . ParenList $ [Symbol "array", x]
|
|
||||||
|
|
||||||
mut :: Type -> Type
|
|
||||||
mut (MkType x) = MkType . ParenList $ [Symbol "mut", x]
|
|
||||||
|
|
||||||
struct :: List Type -> Type
|
|
||||||
struct xs = MkType . ParenList $
|
|
||||||
Symbol "struct" : (xs ^.. each . #inner . to field)
|
|
||||||
where field x = ParenList [Symbol "field", x]
|
|
||||||
|
|
||||||
func :: List Type -> List Type -> Type
|
|
||||||
func params results =
|
|
||||||
MkType . ParenList $
|
|
||||||
[ Symbol "func"
|
|
||||||
, wrap "param" params
|
|
||||||
, wrap "result" results
|
|
||||||
]
|
|
||||||
where
|
|
||||||
wrap s xs = ParenList $ Symbol s : xs ^.. each . #inner
|
|
||||||
|
|
||||||
i32, i31ref, eq, i31 :: Type
|
|
||||||
i32 = MkType $ Symbol "i32"
|
|
||||||
i31ref = MkType $ Symbol "i31ref"
|
|
||||||
eq = MkType $ Symbol "eq"
|
|
||||||
i31 = MkType $ Symbol "i31"
|
|
||||||
|
|
||||||
class FromIdx a where
|
|
||||||
fromIdx :: Idx -> a
|
|
||||||
|
|
||||||
instance FromIdx Type where
|
|
||||||
fromIdx (IdxNumeric n) = MkType . Symbol . T.pack . show $ n
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
instance SexpIso Idx where
|
|
||||||
sexpIso = match
|
|
||||||
$ With (\numeric -> num >>> numeric)
|
|
||||||
$ With (\named -> name >>> named)
|
|
||||||
$ End
|
|
||||||
where
|
|
||||||
num = Sexp.integer >>> Sexp.partialOsi f g
|
|
||||||
where
|
|
||||||
f n | n < 0 = Left $ Sexp.unexpected "negative"
|
|
||||||
<> Sexp.expected "natural"
|
|
||||||
| otherwise = Right $ fromIntegral n
|
|
||||||
g n = fromIntegral n
|
|
||||||
l :: Prism' Text Text
|
|
||||||
l = prefixed "$"
|
|
||||||
name = Sexp.symbol >>> Sexp.partialOsi
|
|
||||||
(maybe (Left $ Sexp.expected "$-prefixed sym") Right . preview l)
|
|
||||||
(review l)
|
|
||||||
|
|
||||||
instance SexpIso RecType where
|
|
||||||
sexpIso = with \rectype ->
|
|
||||||
Sexp.coproduct
|
|
||||||
[ sexpIso @Type >>> Sexp.partialIso
|
|
||||||
(\x -> [x])
|
|
||||||
(\case [x] -> Right x
|
|
||||||
_ -> Left $ Sexp.expected "a single type")
|
|
||||||
, list (el (sym "rec") >>> rest sexpIso)
|
|
||||||
]
|
|
||||||
>>> Sexp.iso V.fromList V.toList
|
|
||||||
>>> rectype
|
|
||||||
-- where
|
|
||||||
-- typedef
|
|
||||||
-- :: forall a t. Sexp.Grammar Position (Sexp :- t) (a :- t)
|
|
||||||
-- -> Sexp.Grammar Position (Sexp :- t) (a :- t)
|
|
||||||
-- typedef x = list (el (sym "type") >>> el x)
|
|
||||||
|
|
||||||
type' :: Sexp -> Type
|
|
||||||
type' e = MkType . ParenList $ [ "type", e ]
|
|
||||||
|
|
||||||
namedType :: Text -> Sexp -> Type
|
|
||||||
namedType name e = MkType . ParenList $ [ "type", Symbol name, e ]
|
|
||||||
|
|
||||||
instance SexpIso Global where
|
|
||||||
sexpIso = with \glob ->
|
|
||||||
list ( el (sym "global")
|
|
||||||
>>> el (sexpIso @Type)
|
|
||||||
>>> restCode
|
|
||||||
)
|
|
||||||
>>> glob
|
|
||||||
|
|
||||||
instance SexpIso Instr where
|
|
||||||
sexpIso = Sexp.iso coerce coerce
|
|
||||||
|
|
||||||
instance SexpIso Type where
|
|
||||||
sexpIso = Sexp.iso coerce coerce
|
|
||||||
|
|
||||||
instance SexpIso Export where
|
|
||||||
sexpIso = Sexp.iso coerce coerce
|
|
||||||
|
|
||||||
restCode :: Sexp.Grammar Position (Sexp.List :- t) (Sexp.List :- (Expr :- t))
|
|
||||||
restCode =
|
|
||||||
rest (sexpIso @Instr)
|
|
||||||
>>> Sexp.onTail
|
|
||||||
(Sexp.iso
|
|
||||||
(view instrsExpr)
|
|
||||||
(review instrsExpr))
|
|
||||||
where
|
|
||||||
instrsExpr :: Iso' (List Instr) Expr
|
|
||||||
instrsExpr = vector . coerced
|
|
||||||
|
|
||||||
instance SexpIso Function where
|
|
||||||
sexpIso = with \func ->
|
|
||||||
list ( el (sym "func")
|
|
||||||
>>> el (list $ el (sym "param") >>> rest (sexpIso @Type))
|
|
||||||
>>> el (list $ el (sym "result") >>> rest (sexpIso @Type))
|
|
||||||
>>> el (list $ el (sym "local") >>> rest (sexpIso @Type))
|
|
||||||
>>> restCode
|
|
||||||
)
|
|
||||||
>>> func
|
|
||||||
|
|
||||||
instance SexpIso Module where
|
|
||||||
sexpIso = Sexp.partialOsi (const $ Left mempty) \m ->
|
|
||||||
ParenList $
|
|
||||||
[ Symbol "module" ]
|
|
||||||
<> (m ^.. #types . each . to sxp)
|
|
||||||
<> (m ^.. #globals . each . to sxp)
|
|
||||||
<> (m ^.. #funcrefs . each . to sxp)
|
|
||||||
<> (m ^.. #functions . each . to sxp)
|
|
||||||
<> (m ^.. #exports . each . to sxp)
|
|
||||||
|
|
||||||
instance SexpIso Funcref where
|
|
||||||
sexpIso = with \funcref ->
|
|
||||||
list ( el (sym "elem")
|
|
||||||
>>> el (sym "declare")
|
|
||||||
>>> el (sym "funcref")
|
|
||||||
>>> el (list $ el (sym "ref.func") >>> el (sexpIso @Idx))
|
|
||||||
)
|
|
||||||
>>> funcref
|
|
||||||
|
|
||||||
instance SexpIso Sexp where
|
|
||||||
sexpIso = Control.Category.id
|
|
||||||
|
|
||||||
instance Each Expr Expr Instr Instr where
|
|
||||||
each = #MkExpr . each
|
|
||||||
|
|
||||||
sxp :: HasCallStack => SexpIso a => a -> Sexp
|
|
||||||
sxp e = either error id . Sexp.toSexp sexpIso $ e
|
|
||||||
|
|
||||||
ins :: Text -> List Sexp -> Expr
|
|
||||||
ins op [] = [ MkInstr $ Symbol op ]
|
|
||||||
ins op xs = [ MkInstr . ParenList $ Symbol op : xs ]
|
|
||||||
|
|
||||||
instance IsString Sexp where
|
|
||||||
fromString = Symbol . T.pack
|
|
||||||
|
|
||||||
instance IsList Expr where
|
|
||||||
type Item Expr = Instr
|
|
||||||
fromList = MkExpr . V.fromList
|
|
||||||
toList e = V.toList e.inner
|
|
||||||
|
|
||||||
data ResultType = MkResultType
|
|
||||||
{ params :: List Type
|
|
||||||
, result :: List Type
|
|
||||||
}
|
|
||||||
deriving stock (Generic)
|
|
||||||
deriving (Semigroup, Monoid)
|
|
||||||
via Generically ResultType
|
|
||||||
|
|
||||||
param :: List Type -> ResultType
|
|
||||||
param ts = MkResultType ts mempty
|
|
||||||
|
|
||||||
result :: List Type -> ResultType
|
|
||||||
result ts = MkResultType mempty ts
|
|
||||||
|
|
||||||
resultTypeSexp :: ResultType -> List Sexp
|
|
||||||
resultTypeSexp rt =
|
|
||||||
f "param" (coerce <$> rt.params) <> f "result" (coerce <$> rt.result)
|
|
||||||
where
|
|
||||||
f :: Text -> List Sexp -> List Sexp
|
|
||||||
f _ [] = []
|
|
||||||
f kw s = [ ParenList $ Symbol kw : s ]
|
|
||||||
|
|
||||||
-- resultSexp :: ResultType -> Sexp
|
|
||||||
-- resultSexp rt = ParenList $ Symbol "param" : (coerce <$> rt.result)
|
|
||||||
|
|
||||||
if' :: ResultType -> Expr -> Expr -> Expr
|
|
||||||
if' rt t f = MkExpr . V.singleton . MkInstr . ParenList $
|
|
||||||
[ Symbol "if" ]
|
|
||||||
<> resultTypeSexp rt
|
|
||||||
<> [ ParenList $ Symbol "then" : (t ^.. each . to sxp) ]
|
|
||||||
<> [ ParenList $ Symbol "else" : (f ^.. each . to sxp) ]
|
|
||||||
|
|||||||
Reference in New Issue
Block a user