@@ -7,6 +7,5 @@
|
|||||||
, sourceColumn = Pos 1
|
, sourceColumn = Pos 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} :< SimpleF
|
} :< MetaF "aHaskellVariable + abc * 2"
|
||||||
( SimpleMeta "aHaskellVariable + abc * 2" )
|
|
||||||
]
|
]
|
||||||
@@ -7,6 +7,5 @@
|
|||||||
, sourceColumn = Pos 1
|
, sourceColumn = Pos 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} :< SimpleF
|
} :< MetaSpliceF "takeWhile (\x -> even x) aHaskellList"
|
||||||
( SimpleMetaSplice "takeWhile (\x -> even x) aHaskellList" )
|
|
||||||
]
|
]
|
||||||
@@ -7,6 +7,5 @@
|
|||||||
, sourceColumn = Pos 1
|
, sourceColumn = Pos 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} :< SimpleF
|
} :< MetaSpliceF "aHaskellList"
|
||||||
( SimpleMetaSplice "aHaskellList" )
|
|
||||||
]
|
]
|
||||||
@@ -7,6 +7,5 @@
|
|||||||
, sourceColumn = Pos 1
|
, sourceColumn = Pos 1
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} :< SimpleF
|
} :< MetaF "aHaskellVariable"
|
||||||
( SimpleMeta "aHaskellVariable" )
|
|
||||||
]
|
]
|
||||||
@@ -131,7 +131,6 @@ test-suite test
|
|||||||
Gyehoek.Test.CPS.Syntax
|
Gyehoek.Test.CPS.Syntax
|
||||||
Gyehoek.Test.Golden
|
Gyehoek.Test.Golden
|
||||||
Gyehoek.Test.Scheme.Syntax
|
Gyehoek.Test.Scheme.Syntax
|
||||||
Gyehoek.Test.Sexp
|
|
||||||
Gyehoek.Test.Sexp.Print
|
Gyehoek.Test.Sexp.Print
|
||||||
Gyehoek.Test.Sexp.QQ
|
Gyehoek.Test.Sexp.QQ
|
||||||
Gyehoek.Test.Sexp.Read
|
Gyehoek.Test.Sexp.Read
|
||||||
|
|||||||
@@ -17,12 +17,11 @@ import Numeric.Natural
|
|||||||
import qualified Data.Vector.Strict as V
|
import qualified Data.Vector.Strict as V
|
||||||
import Gyehoek.Wasm qualified as Wasm
|
import Gyehoek.Wasm qualified as Wasm
|
||||||
import Gyehoek.Wasm hiding (Expr)
|
import Gyehoek.Wasm hiding (Expr)
|
||||||
import Language.Sexp.Located qualified as SL
|
|
||||||
import Control.Monad.Fix
|
import Control.Monad.Fix
|
||||||
import qualified Gyehoek.Sexp
|
|
||||||
import Data.Text qualified as T
|
import Data.Text qualified as T
|
||||||
import Data.Foldable (fold)
|
import Data.Foldable (fold)
|
||||||
import Gyehoek.Sexp (encodeOrShow)
|
import Gyehoek.Jalmot
|
||||||
|
import Gyehoek.Sexp qualified as S
|
||||||
import Gyehoek.Prelude
|
import Gyehoek.Prelude
|
||||||
|
|
||||||
|
|
||||||
@@ -53,8 +52,8 @@ makeSmallFixnum = [expr|
|
|||||||
ref.i31
|
ref.i31
|
||||||
|]
|
|]
|
||||||
|
|
||||||
getArgRegister :: Natural -> SL.Sexp
|
getArgRegister :: Natural -> S.Datum
|
||||||
getArgRegister n = SL.Symbol [i|$arg#{n}|]
|
getArgRegister n = S.Symbol [i|$arg#{n}|]
|
||||||
|
|
||||||
-- | Given an expression @e@ leaving a @ref eq@ atop the stack,
|
-- | 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
|
-- @pushArg rt n e@ sets the nth slot of the arg-passing array to the
|
||||||
@@ -110,11 +109,9 @@ lower' g (Halt [v]) = do
|
|||||||
|]
|
|]
|
||||||
|
|
||||||
lower' g e@(ExpPrim p k) =
|
lower' g e@(ExpPrim p k) =
|
||||||
([expr|(@gyehoek :origin #{origin})|]<>)
|
case p of
|
||||||
<$> case p of
|
|
||||||
PrimAdd x y -> lowerBinOp "i32.add" g x y k
|
PrimAdd x y -> lowerBinOp "i32.add" g x y k
|
||||||
PrimMul x y -> lowerBinOp "i32.mul" g x y k
|
PrimMul x y -> lowerBinOp "i32.mul" g x y k
|
||||||
where origin = encodeOrShow @_ @Text e
|
|
||||||
|
|
||||||
lower' g (ExpIf c t f) = do
|
lower' g (ExpIf c t f) = do
|
||||||
c' <- lowerVal g c
|
c' <- lowerVal g c
|
||||||
@@ -131,9 +128,7 @@ lower' g (ExpLetRec [(r,AbsKappa kap)] e) = do
|
|||||||
idx <- lowerKappa g kap
|
idx <- lowerKappa g kap
|
||||||
let g' = g & #kvars <>~ [r]
|
let g' = g & #kvars <>~ [r]
|
||||||
e' <- lower' g' e
|
e' <- lower' g' e
|
||||||
let origin = encodeOrShow @_ @Text e
|
|
||||||
pure [expr|
|
pure [expr|
|
||||||
(@gyehoek :origin #{origin})
|
|
||||||
(@gyehoek "push cont" :idx #{idx})
|
(@gyehoek "push cont" :idx #{idx})
|
||||||
(array.set $cont-stack-type
|
(array.set $cont-stack-type
|
||||||
(global.get $cont-stack)
|
(global.get $cont-stack)
|
||||||
@@ -165,9 +160,7 @@ lower' g e@(ExpApply f xs ktail) = do
|
|||||||
let l = succ $ V.elemIndex ktail g.kvars ^?! _Just
|
let l = succ $ V.elemIndex ktail g.kvars ^?! _Just
|
||||||
args <- fold <$>
|
args <- fold <$>
|
||||||
itraverse (\i -> fmap (pushArg $ tonat i) . lowerVal g) xs
|
itraverse (\i -> fmap (pushArg $ tonat i) . lowerVal g) xs
|
||||||
let origin = encodeOrShow @_ @Text e
|
|
||||||
pure [expr|
|
pure [expr|
|
||||||
(@gyehoek :origin #{origin})
|
|
||||||
(@gyehoek "load args")
|
(@gyehoek "load args")
|
||||||
##{args}
|
##{args}
|
||||||
(i32.const 1)
|
(i32.const 1)
|
||||||
@@ -184,9 +177,7 @@ lower' g e@(ExpContinue k xs) = do
|
|||||||
let nargs = length xs
|
let nargs = length xs
|
||||||
args <- fold <$>
|
args <- fold <$>
|
||||||
itraverse (\i -> fmap (pushArg $ tonat i) . lowerVal g) xs
|
itraverse (\i -> fmap (pushArg $ tonat i) . lowerVal g) xs
|
||||||
let origin = encodeOrShow @_ @Text e
|
|
||||||
pure [expr|
|
pure [expr|
|
||||||
(@gyehoek :origin #{origin})
|
|
||||||
(@gyehoek "push args")
|
(@gyehoek "push args")
|
||||||
##{args}
|
##{args}
|
||||||
(@gyehoek "nargs")
|
(@gyehoek "nargs")
|
||||||
@@ -205,18 +196,14 @@ lower' g e@(ExpContinue k xs) = do
|
|||||||
where
|
where
|
||||||
l = succ $ V.elemIndex k g.kvars ^?! _Just
|
l = succ $ V.elemIndex k g.kvars ^?! _Just
|
||||||
|
|
||||||
lower' g e = error $ case Gyehoek.Sexp.encode e of
|
lower' g e = error . S.encodeOrShow' S.datumIso $ e
|
||||||
Left _ -> show e
|
|
||||||
Right x -> T.unpack x
|
|
||||||
|
|
||||||
lowerKappa :: GenMod :> es => Env -> Kappa -> Eff es Idx
|
lowerKappa :: GenMod :> es => Env -> Kappa -> Eff es Idx
|
||||||
lowerKappa g e@(MkKappa xs m) = do
|
lowerKappa g e@(MkKappa xs m) = do
|
||||||
let g' = g & #vars <>~ V.fromList xs
|
let g' = g & #vars <>~ V.fromList xs
|
||||||
m' <- lower' g' m
|
m' <- lower' g' m
|
||||||
let origin = encodeOrShow @_ @Text e
|
|
||||||
idx <- Wasm.defineFunction [wat|
|
idx <- Wasm.defineFunction [wat|
|
||||||
(func (param i32)
|
(func (param i32)
|
||||||
(@gyehoek :origin #{origin})
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
##{m'})
|
##{m'})
|
||||||
|]
|
|]
|
||||||
@@ -228,10 +215,8 @@ lowerLambda g e@(MkLambda xs ktail m) = do
|
|||||||
let g' = g & #vars .~ V.fromList xs
|
let g' = g & #vars .~ V.fromList xs
|
||||||
& #kvars <>~ [ktail]
|
& #kvars <>~ [ktail]
|
||||||
m' <- lower' g' m
|
m' <- lower' g' m
|
||||||
let origin = encodeOrShow @_ @Text e
|
|
||||||
idx <- Wasm.defineFunction [wat|
|
idx <- Wasm.defineFunction [wat|
|
||||||
(func (param i32)
|
(func (param i32)
|
||||||
(@gyehoek :origin #{origin})
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
##{m'})
|
##{m'})
|
||||||
|]
|
|]
|
||||||
@@ -242,7 +227,7 @@ lowerBinOp
|
|||||||
:: (GenMod :> es)
|
:: (GenMod :> es)
|
||||||
=> Text -> Env -> Val -> Val -> Kappa -> Eff es Wasm.Expr
|
=> Text -> Env -> Val -> Val -> Kappa -> Eff es Wasm.Expr
|
||||||
lowerBinOp op g x y (MkKappa [r] e) = do
|
lowerBinOp op g x y (MkKappa [r] e) = do
|
||||||
let op' = SL.Symbol op
|
let op' = S.Symbol op
|
||||||
let g' = g & #vars <>~ [r]
|
let g' = g & #vars <>~ [r]
|
||||||
let n = succ $ length (g ^. #vars)
|
let n = succ $ length (g ^. #vars)
|
||||||
let reg = getArgRegister . fromIntegral $ n
|
let reg = getArgRegister . fromIntegral $ n
|
||||||
@@ -325,10 +310,8 @@ lower e = fmap Wasm.renderModule . Wasm.execGenMod $ do
|
|||||||
runtime <- emitRuntime
|
runtime <- emitRuntime
|
||||||
let g = MkEnv mempty mempty
|
let g = MkEnv mempty mempty
|
||||||
e' <- lower' g e
|
e' <- lower' g e
|
||||||
let origin = encodeOrShow @_ @Text e
|
|
||||||
Wasm.defineFunction [wat|
|
Wasm.defineFunction [wat|
|
||||||
(func $scm-entry (param i32)
|
(func $scm-entry (param i32)
|
||||||
(@gyehoek :origin #{origin})
|
|
||||||
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
(local (ref eq) (ref eq) (ref eq) (ref eq) (ref eq))
|
||||||
##{e'})
|
##{e'})
|
||||||
|]
|
|]
|
||||||
|
|||||||
+81
-102
@@ -40,23 +40,18 @@ module Gyehoek.CPS.Syntax
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Language.SexpGrammar qualified as S
|
|
||||||
import Gyehoek.Sexp qualified
|
|
||||||
import Gyehoek.Scheme.Syntax (Name (..), Prim(..), primDatumIso, Lit(..))
|
import Gyehoek.Scheme.Syntax (Name (..), Prim(..), primDatumIso, Lit(..))
|
||||||
import Language.SexpGrammar.Generic
|
import Gyehoek.Sexp qualified as S
|
||||||
import Control.Category
|
import Control.Category
|
||||||
import Prelude hiding ((.), id)
|
import Prelude hiding ((.), id)
|
||||||
import Language.Haskell.TH.Quote (QuasiQuoter)
|
|
||||||
import Language.Sexp.Located (Sexp)
|
|
||||||
import qualified Data.InvertibleGrammar.Base as IG
|
|
||||||
import Data.InvertibleGrammar.Base (type (:-)((:-)))
|
|
||||||
import qualified Data.HashSet as HS
|
import qualified Data.HashSet as HS
|
||||||
import Data.Monoid (Endo)
|
import Data.Monoid (Endo)
|
||||||
import Data.Functor.Foldable.TH
|
import Data.Functor.Foldable.TH
|
||||||
import qualified Gyehoek.Sexp as GS
|
|
||||||
import qualified Language.Sexp.Located as SL
|
|
||||||
import Data.Data.Lens (uniplate)
|
import Data.Data.Lens (uniplate)
|
||||||
import Gyehoek.Prelude hiding (op)
|
import Gyehoek.Prelude hiding (op)
|
||||||
|
import Gyehoek.Sexp (Datum)
|
||||||
|
import Gyehoek.Sexp (G, (:-)(..))
|
||||||
|
import qualified Data.InvertibleGrammar.Base as IG
|
||||||
|
|
||||||
-- Data types
|
-- Data types
|
||||||
|
|
||||||
@@ -131,13 +126,7 @@ data Program = MkProgram
|
|||||||
deriving (Show, Generic, Data)
|
deriving (Show, Generic, Data)
|
||||||
|
|
||||||
makePrisms ''Kappa
|
makePrisms ''Kappa
|
||||||
-- makeLenses ''Kappa
|
|
||||||
makePrisms ''Exp
|
makePrisms ''Exp
|
||||||
-- makeLenses ''Exp
|
|
||||||
-- makeFieldsNoPrefix ''Exp
|
|
||||||
-- makeFieldsNoPrefix ''Kappa
|
|
||||||
-- makeLensesWith abbreviatedFields ''Exp
|
|
||||||
-- makeLensesFor [("binders", "_binders"), ("body", "_body")] ''Exp
|
|
||||||
makeFieldsId ''Exp
|
makeFieldsId ''Exp
|
||||||
makeFieldsId ''Kappa
|
makeFieldsId ''Kappa
|
||||||
makeFieldsId ''Lambda
|
makeFieldsId ''Lambda
|
||||||
@@ -157,69 +146,61 @@ _AbsLambda' = prism'
|
|||||||
(\case AbsLambda' bs ktail e -> Just (bs,ktail,e)
|
(\case AbsLambda' bs ktail e -> Just (bs,ktail,e)
|
||||||
_ -> Nothing)
|
_ -> Nothing)
|
||||||
|
|
||||||
instance Plated Exp where
|
instance Plated Exp where plate = uniplate
|
||||||
plate = uniplate
|
|
||||||
-- plate k = \case
|
|
||||||
-- ExpPrim p kap -> ExpPrim p <$> body k kap
|
|
||||||
-- ExpLetRec bs e -> ExpLetRec <$> (each . _2 . body) k bs <*> k e
|
|
||||||
-- ExpContinue c xs -> pure $ ExpContinue c xs
|
|
||||||
-- ExpIf c t f -> ExpIf c <$> k t <*> k f
|
|
||||||
-- ExpApply f xs ktail -> pure $ ExpApply f xs ktail
|
|
||||||
|
|
||||||
|
|
||||||
-- SexpIso instances
|
-- DatumIso instances
|
||||||
|
|
||||||
instance S.SexpIso Val where
|
instance S.DatumIso Val where
|
||||||
sexpIso = match
|
datumIso = S.match
|
||||||
$ With (\imm -> imm . S.sexpIso)
|
$ S.With (\imm -> imm . S.datumIso)
|
||||||
$ With (\var -> var . S.sexpIso)
|
$ S.With (\var -> var . S.datumIso)
|
||||||
$ End
|
$ S.End
|
||||||
|
|
||||||
instance S.SexpIso Obj where
|
instance S.DatumIso Obj where
|
||||||
sexpIso = match
|
datumIso = S.match
|
||||||
$ With (\imm -> imm . S.sexpIso)
|
$ S.With (\imm -> imm . S.datumIso)
|
||||||
$ With (\hob -> hob . S.sexpIso)
|
$ S.With (\hob -> hob . S.datumIso)
|
||||||
$ End
|
$ S.End
|
||||||
|
|
||||||
instance S.SexpIso Imm where
|
instance S.DatumIso Imm where
|
||||||
sexpIso = match
|
datumIso = S.match
|
||||||
$ With (. S.int)
|
$ S.With (. S.int)
|
||||||
$ With (. GS.schemeBool)
|
$ S.With (. S.datumIso)
|
||||||
$ With (. labelName)
|
$ S.With (. labelName)
|
||||||
$ End
|
$ S.End
|
||||||
|
|
||||||
labelName :: S.SexpGrammar Name
|
labelName :: S.DatumGrammar Name
|
||||||
labelName = S.coproduct
|
labelName = S.coproduct
|
||||||
[ S.sexpIso @Name >>> Gyehoek.Sexp.prismIso
|
[ S.datumIso @Name >>> S.prismIso
|
||||||
(S.expected "label")
|
(S.expected "label")
|
||||||
(prefixed @Name "$")
|
(prefixed @Name "$")
|
||||||
, S.list $ S.el (S.sym "$") >>> S.el (S.sexpIso @Name)
|
, S.list $ S.el (S.sym "$") >>> S.el (S.datumIso @Name)
|
||||||
]
|
]
|
||||||
|
|
||||||
instance S.SexpIso Hob where
|
instance S.DatumIso Hob where
|
||||||
sexpIso = match
|
datumIso = S.match
|
||||||
$ With (. closure)
|
$ S.With (. closure)
|
||||||
$ End
|
$ S.End
|
||||||
where
|
where
|
||||||
-- closures can be printed, but not parsed.
|
-- closures can be printed, but not parsed.
|
||||||
closure :: S.Grammar S.Position (Sexp :- t) (List Obj :- Name :- t)
|
closure :: G (Datum :- t) (List Obj :- Name :- t)
|
||||||
closure = IG.Flip $ IG.PartialIso
|
closure = IG.Flip $ IG.PartialIso
|
||||||
(\(env:-code:-t) -> SL.Modified SL.Hash [GS.sx|(#{code} ##{env})|] :- t)
|
(\(env:-code:-t) -> [S.sx|(<closure> #{code} ##{env})|] :- t)
|
||||||
(const . Left $ mempty)
|
(const . Left $ mempty)
|
||||||
|
|
||||||
instance S.SexpIso Lambda where
|
instance S.DatumIso Lambda where
|
||||||
sexpIso = match
|
datumIso = S.match
|
||||||
$ With (. lambda)
|
$ S.With (. lambda)
|
||||||
$ End
|
$ S.End
|
||||||
where
|
where
|
||||||
lambda = S.list $
|
lambda = S.list $
|
||||||
S.el Gyehoek.Sexp.lambdaKeyword
|
S.el S.lambdaKeyword
|
||||||
>>> S.el binders
|
>>> S.el binders
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.datumIso
|
||||||
binders :: forall t.
|
binders :: forall t. G (Datum :- t) (Name :- List Name :- t)
|
||||||
IG.Grammar S.Position (Sexp :- t) (Name :- List Name :- t)
|
|
||||||
binders = S.list $
|
binders = S.list $
|
||||||
S.rest (S.sexpIso @Name)
|
S.rest (S.datumIso @Name)
|
||||||
>>> S.onTail (S.flipped $ IG.PartialIso
|
>>> S.onTail (S.flipped $ IG.PartialIso
|
||||||
(\(ktail:-args:-t) -> (args ++ [ktail]) :- t)
|
(\(ktail:-args:-t) -> (args ++ [ktail]) :- t)
|
||||||
(\(args:-t) -> case args ^? _Snoc of
|
(\(args:-t) -> case args ^? _Snoc of
|
||||||
@@ -227,43 +208,43 @@ instance S.SexpIso Lambda where
|
|||||||
Nothing -> Left $ S.expected "cont param")
|
Nothing -> Left $ S.expected "cont param")
|
||||||
)
|
)
|
||||||
|
|
||||||
instance S.SexpIso Kappa where
|
instance S.DatumIso Kappa where
|
||||||
sexpIso = match
|
datumIso = S.match
|
||||||
$ With (. kappa)
|
$ S.With (. kappa)
|
||||||
$ End
|
$ S.End
|
||||||
where
|
where
|
||||||
kappa = S.list $
|
kappa = S.list $
|
||||||
S.el Gyehoek.Sexp.kappaKeyword
|
S.el S.kappaKeyword
|
||||||
>>> S.el (S.list $ S.rest S.sexpIso)
|
>>> S.el (S.list $ S.rest S.datumIso)
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.datumIso
|
||||||
|
|
||||||
instance S.SexpIso Abs where
|
instance S.DatumIso Abs where
|
||||||
sexpIso = match
|
datumIso = S.match
|
||||||
$ With (\lambda -> lambda . S.sexpIso)
|
$ S.With (\lambda -> lambda . S.datumIso)
|
||||||
$ With (\kappa -> kappa . S.sexpIso)
|
$ S.With (\kappa -> kappa . S.datumIso)
|
||||||
$ End
|
$ S.End
|
||||||
|
|
||||||
instance S.SexpIso Exp where
|
instance S.DatumIso Exp where
|
||||||
sexpIso = match
|
datumIso = S.match
|
||||||
$ With (. prim)
|
$ S.With (. prim)
|
||||||
$ With (. letrec)
|
$ S.With (. letrec)
|
||||||
$ With (. continue)
|
$ S.With (. continue)
|
||||||
$ With (. if_)
|
$ S.With (. if_)
|
||||||
$ With (. app)
|
$ S.With (. app)
|
||||||
$ End
|
$ S.End
|
||||||
where
|
where
|
||||||
continue = S.list $
|
continue = S.list $
|
||||||
S.el (S.sym "continue")
|
S.el (S.sym "continue")
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.datumIso
|
||||||
>>> S.rest S.sexpIso
|
>>> S.rest S.datumIso
|
||||||
letrec = Gyehoek.Sexp.let_ "letrec" S.sexpIso S.sexpIso S.sexpIso
|
letrec = S.letLike "letrec" S.datumIso S.datumIso S.datumIso
|
||||||
if_ = S.list $ S.el (S.sym "if")
|
if_ = S.ifLike "if"
|
||||||
>>> S.el S.sexpIso >>> S.el S.sexpIso >>> S.el S.sexpIso
|
S.datumIso S.datumIso S.datumIso
|
||||||
app :: forall t.
|
app :: forall t.
|
||||||
IG.Grammar S.Position (Sexp :- t) (Name :- ([Val] :- (Val :- t)))
|
G (Datum :- t) (Name :- ([Val] :- (Val :- t)))
|
||||||
app = S.list $ S.el (S.sexpIso @Val)
|
app = S.list $ S.el (S.datumIso @Val)
|
||||||
-- >>> S.flipped Gyehoek.Sexp.nonEmptyGrammar
|
-- >>> S.flipped Gyehoek.Datum.nonEmptyGrammar
|
||||||
>>> S.rest (S.sexpIso @Val)
|
>>> S.rest (S.datumIso @Val)
|
||||||
-- >>> _
|
-- >>> _
|
||||||
>>> S.onTail (S.flipped $ IG.PartialIso
|
>>> S.onTail (S.flipped $ IG.PartialIso
|
||||||
(\(karg :- args :- op :- t) ->
|
(\(karg :- args :- op :- t) ->
|
||||||
@@ -273,31 +254,29 @@ instance S.SexpIso Exp where
|
|||||||
Right $ karg:- args :- op :- t
|
Right $ karg:- args :- op :- t
|
||||||
_ -> Left $ S.expected "continuation arg"
|
_ -> Left $ S.expected "continuation arg"
|
||||||
))
|
))
|
||||||
where
|
|
||||||
_ = S.flipped $ Gyehoek.Sexp.nonEmptyGrammar @S.Position @Val
|
|
||||||
prim = S.list $
|
prim = S.list $
|
||||||
S.el (S.sym "prim")
|
S.el (S.sym "prim")
|
||||||
>>> S.el (primSexpIso id (S.sexpIso @Val))
|
>>> S.el (primDatumIso id (S.datumIso @Val))
|
||||||
>>> S.el S.sexpIso
|
>>> S.el S.datumIso
|
||||||
|
|
||||||
instance S.SexpIso Program where
|
instance S.DatumIso Program where
|
||||||
sexpIso = with \prog -> S.sexpIso @Exp >>> prog
|
datumIso = S.with \prog -> S.datumIso @Exp >>> prog
|
||||||
|
|
||||||
|
|
||||||
-- quasiquoters
|
-- quasiquoters
|
||||||
|
|
||||||
class Data a => CPS a where
|
class Data a => CPS a where
|
||||||
toCPS :: Sexp -> a
|
toCPS :: Datum -> a
|
||||||
|
|
||||||
instance CPS Exp where toCPS = Gyehoek.Sexp.fromSexp
|
instance CPS Exp where toCPS = S.fromDatumUnsafe S.datumIso
|
||||||
instance CPS Val where toCPS = Gyehoek.Sexp.fromSexp
|
instance CPS Val where toCPS = S.fromDatumUnsafe S.datumIso
|
||||||
instance CPS Kappa where toCPS = Gyehoek.Sexp.fromSexp
|
instance CPS Kappa where toCPS = S.fromDatumUnsafe S.datumIso
|
||||||
instance CPS Lambda where toCPS = Gyehoek.Sexp.fromSexp
|
instance CPS Lambda where toCPS = S.fromDatumUnsafe S.datumIso
|
||||||
instance CPS Abs where toCPS = Gyehoek.Sexp.fromSexp
|
instance CPS Abs where toCPS = S.fromDatumUnsafe S.datumIso
|
||||||
instance CPS Program where toCPS = Gyehoek.Sexp.fromSexp
|
instance CPS Program where toCPS = S.fromDatumUnsafe S.datumIso
|
||||||
|
|
||||||
cps :: QuasiQuoter
|
cps :: S.QuasiQuoter
|
||||||
cps = Gyehoek.Sexp.makeSx' [| toCPS |]
|
cps = S.makeSx' [| toCPS |]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+14
-11
@@ -33,12 +33,14 @@ import Gyehoek.CPS.Close (closeProgram)
|
|||||||
import Control.Lens.Extras (is)
|
import Control.Lens.Extras (is)
|
||||||
import Control.Arrow ((>>>))
|
import Control.Arrow ((>>>))
|
||||||
import Gyehoek.Prelude
|
import Gyehoek.Prelude
|
||||||
|
import Gyehoek.Jalmot
|
||||||
|
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
|
||||||
runEff . runFileSystem . runGenSym . driver $ opts
|
runJalmotIO . runFileSystem . runGenSym . driver $ opts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -65,11 +67,12 @@ fileName :: FilePath -> FilePath
|
|||||||
fileName "-" = "<interactive>"
|
fileName "-" = "<interactive>"
|
||||||
fileName e = e
|
fileName e = e
|
||||||
|
|
||||||
readScm :: FileSystem :> es => FilePath -> Eff es Scm.Program
|
readScm
|
||||||
|
:: forall es. (Jalmot :> es, FileSystem :> es)
|
||||||
|
=> FilePath -> Eff es Scm.Program
|
||||||
readScm f =
|
readScm f =
|
||||||
withFile f FS.ReadMode $ \h ->
|
withFile f FS.ReadMode $ \h ->
|
||||||
Sexp.parseSexps @Scm.CommandOrDef (fileName f) <$> hGetContents h
|
S.decodeDataWith @es S.dataIso =<< hGetContents h
|
||||||
>>= either error (pure . Scm.MkProgram)
|
|
||||||
|
|
||||||
inspectWasm :: IOE :> es => Text -> Eff es ()
|
inspectWasm :: IOE :> es => Text -> Eff es ()
|
||||||
inspectWasm wat = do
|
inspectWasm wat = do
|
||||||
@@ -107,7 +110,7 @@ dumpOrRun dump run acquire do_dump do_run =
|
|||||||
when run (do_run x)
|
when run (do_run x)
|
||||||
|
|
||||||
driver
|
driver
|
||||||
:: (GenSym :> es, FileSystem :> es, IOE :> es)
|
:: (GenSym :> es, FileSystem :> es, Jalmot :> es, IOE :> es)
|
||||||
=> Options -> Eff es ()
|
=> Options -> Eff es ()
|
||||||
driver opts = do
|
driver opts = do
|
||||||
scm <- readScm opts.sourceFile
|
scm <- readScm opts.sourceFile
|
||||||
@@ -115,10 +118,10 @@ driver opts = do
|
|||||||
hPutStrLn FS.stdout . view strict . pShowNoColor $ scm
|
hPutStrLn FS.stdout . view strict . pShowNoColor $ scm
|
||||||
cps <- convertProgram scm
|
cps <- convertProgram scm
|
||||||
when opts.dumpCPS do
|
when opts.dumpCPS do
|
||||||
hPutStrLn FS.stdout $ Sexp.encodePretty cps ^?! _Right
|
hPutStrLn FS.stdout =<< S.encodeWith S.datumIso cps
|
||||||
closedCps <- closeProgram cps
|
closedCps <- closeProgram cps
|
||||||
when opts.dumpClosed do
|
when opts.dumpClosed do
|
||||||
hPutStrLn FS.stdout $ Sexp.encodePretty closedCps ^?! _Right
|
hPutStrLn FS.stdout =<< S.encodeWith S.datumIso closedCps
|
||||||
let rt_is p = is (_Just . p) opts.runtime
|
let rt_is p = is (_Just . p) opts.runtime
|
||||||
dumpOrRun opts.dumpStackified (rt_is #Stackify)
|
dumpOrRun opts.dumpStackified (rt_is #Stackify)
|
||||||
(stackifyProgram closedCps)
|
(stackifyProgram closedCps)
|
||||||
@@ -138,18 +141,18 @@ driver opts = do
|
|||||||
(\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 = runEff . runFileSystem . readScm
|
parse_e2e = runJalmotIO . runFileSystem . readScm
|
||||||
|
|
||||||
convert_e2e :: FilePath -> IO CPS.Program
|
convert_e2e :: FilePath -> IO CPS.Program
|
||||||
convert_e2e = runEff . runFileSystem . runGenSym
|
convert_e2e = runJalmotIO . runFileSystem . runGenSym
|
||||||
. (closeProgram <=< convertProgram <=< readScm)
|
. (closeProgram <=< convertProgram <=< readScm)
|
||||||
|
|
||||||
lower_e2e :: FilePath -> IO Text
|
lower_e2e :: FilePath -> IO Text
|
||||||
lower_e2e =
|
lower_e2e =
|
||||||
runEff . runFileSystem . runGenSym
|
runJalmotIO . runFileSystem . runGenSym
|
||||||
. (lowerProgram <=< closeProgram <=< convertProgram <=< readScm)
|
. (lowerProgram <=< closeProgram <=< convertProgram <=< readScm)
|
||||||
|
|
||||||
eval_e2e :: FilePath -> IO (List Obj)
|
eval_e2e :: FilePath -> IO (List Obj)
|
||||||
eval_e2e fp = runEff . runFileSystem . runGenSym $ do
|
eval_e2e fp = runJalmotIO . runFileSystem . runGenSym $ do
|
||||||
stk <- stackifyProgram <=< closeProgram <=< convertProgram <=< readScm $ fp
|
stk <- stackifyProgram <=< closeProgram <=< convertProgram <=< readScm $ fp
|
||||||
pure . eval $ stk
|
pure . eval $ stk
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ module Gyehoek.Jalmot
|
|||||||
, runJalmot
|
, runJalmot
|
||||||
, runJalmotIO
|
, runJalmotIO
|
||||||
, runJalmotIOE
|
, runJalmotIOE
|
||||||
|
, runJalmotUnsafe
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ import qualified Data.InvertibleGrammar as Grammar
|
|||||||
import Gyehoek.Sexp.Syntax (Ann)
|
import Gyehoek.Sexp.Syntax (Ann)
|
||||||
import Prettyprinter (defaultLayoutOptions, layoutPretty, pretty)
|
import Prettyprinter (defaultLayoutOptions, layoutPretty, pretty)
|
||||||
import Prettyprinter.Render.String (renderString)
|
import Prettyprinter.Render.String (renderString)
|
||||||
|
import Control.Exception.Base (throw)
|
||||||
|
|
||||||
|
|
||||||
deriving instance Show p => Show (Grammar.ErrorMessage p)
|
deriving instance Show p => Show (Grammar.ErrorMessage p)
|
||||||
@@ -46,6 +48,11 @@ runJalmotIOE eff =
|
|||||||
runJalmotIO :: Eff '[Jalmot, IOE] a -> IO a
|
runJalmotIO :: Eff '[Jalmot, IOE] a -> IO a
|
||||||
runJalmotIO = runEff . runJalmotIOE
|
runJalmotIO = runEff . runJalmotIOE
|
||||||
|
|
||||||
|
runJalmotUnsafe :: Eff '[Jalmot] a -> a
|
||||||
|
runJalmotUnsafe m = case runPureEff . runJalmot $ m of
|
||||||
|
Left (cs,e) -> throw $ MkAJalmotCS cs e
|
||||||
|
Right x -> x
|
||||||
|
|
||||||
instance Exception AJalmot where
|
instance Exception AJalmot where
|
||||||
displayException = \case
|
displayException = \case
|
||||||
ReaderError eb -> errorBundlePretty eb
|
ReaderError eb -> errorBundlePretty eb
|
||||||
|
|||||||
@@ -24,12 +24,9 @@ module Gyehoek.Scheme.Syntax
|
|||||||
, subst
|
, subst
|
||||||
, getName
|
, getName
|
||||||
, scm
|
, scm
|
||||||
, readExp
|
|
||||||
, readProgram
|
|
||||||
, free'
|
, free'
|
||||||
, freeWithBound'
|
, freeWithBound'
|
||||||
, freeO
|
, freeO
|
||||||
, encodeProgram
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -54,7 +51,7 @@ import qualified Effectful.FileSystem.IO.ByteString as FB
|
|||||||
import qualified Data.Set.Ordered as O
|
import qualified Data.Set.Ordered as O
|
||||||
import Gyehoek.Sexp.Grammar qualified as Sexp
|
import Gyehoek.Sexp.Grammar qualified as Sexp
|
||||||
import Gyehoek.Sexp.Grammar qualified as S
|
import Gyehoek.Sexp.Grammar qualified as S
|
||||||
import Gyehoek.Sexp.Grammar (DatumIso)
|
import Gyehoek.Sexp.Grammar (DatumIso, DataIso)
|
||||||
import Gyehoek.Prelude
|
import Gyehoek.Prelude
|
||||||
|
|
||||||
|
|
||||||
@@ -125,7 +122,7 @@ data CommandOrDef
|
|||||||
deriving stock (Show, Generic, Data)
|
deriving stock (Show, Generic, Data)
|
||||||
deriving anyclass (NFData)
|
deriving anyclass (NFData)
|
||||||
|
|
||||||
data Program = MkProgram
|
newtype Program = MkProgram
|
||||||
{ commandsAndDefs :: List CommandOrDef
|
{ commandsAndDefs :: List CommandOrDef
|
||||||
}
|
}
|
||||||
deriving stock (Show, Generic, Data)
|
deriving stock (Show, Generic, Data)
|
||||||
@@ -221,11 +218,14 @@ instance DatumIso CommandOrDef where
|
|||||||
$ S.With (\_Begin -> _Begin . S.beginLike "begin" S.datumIso)
|
$ S.With (\_Begin -> _Begin . S.beginLike "begin" S.datumIso)
|
||||||
$ S.End
|
$ S.End
|
||||||
|
|
||||||
|
instance DataIso Program where
|
||||||
|
dataIso = S.dataIso @(List CommandOrDef) >>> S.iso coerce coerce
|
||||||
|
|
||||||
|
|
||||||
-- utilities
|
-- utilities
|
||||||
|
|
||||||
scm :: QuasiQuoter
|
scm :: QuasiQuoter
|
||||||
scm = GS.makeSx [|| GS.fromSexp @Exp ||]
|
scm = GS.makeSx [|| S.fromDatumUnsafe S.datumIso ||]
|
||||||
|
|
||||||
freeWithBound' :: Foldable f => f Name -> Exp -> List Name
|
freeWithBound' :: Foldable f => f Name -> Exp -> List Name
|
||||||
freeWithBound' bound = filter (`elem` bound) . free'
|
freeWithBound' bound = filter (`elem` bound) . free'
|
||||||
@@ -280,27 +280,3 @@ subst f = \e -> cata go e mempty where
|
|||||||
go (ExpLetF _ _) _ = error "todo lol"
|
go (ExpLetF _ _) _ = error "todo lol"
|
||||||
go (ExpLambdaF bs e) bound = e $ insertFrom bs bound
|
go (ExpLambdaF bs e) bound = e $ insertFrom bs bound
|
||||||
go e bound = embed $ fmap ($ bound) e
|
go e bound = embed $ fmap ($ bound) e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fileName :: FilePath -> FilePath
|
|
||||||
fileName "-" = "<interactive>"
|
|
||||||
fileName e = e
|
|
||||||
|
|
||||||
hGetContents :: FS.FileSystem :> es => FS.Handle -> Eff es Text
|
|
||||||
hGetContents h = T.decodeUtf8 <$> FB.hGetContents h
|
|
||||||
|
|
||||||
readProgram :: IOE :> es => FilePath -> Eff es Program
|
|
||||||
readProgram fp = runFileSystem $
|
|
||||||
FS.withFile fp FS.ReadMode $ \h ->
|
|
||||||
GS.parseSexps @CommandOrDef (fileName fp) <$> hGetContents h
|
|
||||||
>>= either error (pure . MkProgram)
|
|
||||||
|
|
||||||
readExp :: IOE :> es => FilePath -> Eff es Exp
|
|
||||||
readExp fp = readProgram fp <&> (^?! #commandsAndDefs . _head . #Command)
|
|
||||||
|
|
||||||
encodeProgram :: Program -> Text
|
|
||||||
encodeProgram p = p.commandsAndDefs
|
|
||||||
& fmap ((^?! _Right) . GS.encodePretty)
|
|
||||||
& intersperse "\n\n"
|
|
||||||
& mconcat
|
|
||||||
|
|||||||
+6
-448
@@ -1,453 +1,11 @@
|
|||||||
{-# LANGUAGE PartialTypeSignatures #-}
|
|
||||||
{-# LANGUAGE TypeOperators #-}
|
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
|
||||||
{-# LANGUAGE OverloadedLabels #-}
|
|
||||||
{-# LANGUAGE DerivingVia #-}
|
|
||||||
{-# LANGUAGE StandaloneDeriving #-}
|
|
||||||
{-# LANGUAGE TemplateHaskellQuotes #-}
|
|
||||||
{-# LANGUAGE OrPatterns #-}
|
|
||||||
module Gyehoek.Sexp
|
module Gyehoek.Sexp
|
||||||
( let_
|
( module Gyehoek.Sexp.QQ
|
||||||
, sexp
|
, module Gyehoek.Sexp.Syntax
|
||||||
, nonempty
|
, module Gyehoek.Sexp.Grammar
|
||||||
, nonEmptyGrammar
|
|
||||||
, encode
|
|
||||||
, decode
|
|
||||||
, parseSexps
|
|
||||||
, prefixSugar
|
|
||||||
, todo
|
|
||||||
, isoIso
|
|
||||||
, encodeWith
|
|
||||||
, decodeWith
|
|
||||||
, kappa
|
|
||||||
, lambda
|
|
||||||
, kappaKeyword
|
|
||||||
, lambdaKeyword
|
|
||||||
, encodePrettyWith
|
|
||||||
, encodePretty
|
|
||||||
, SpliceSexp(..)
|
|
||||||
, Position(..)
|
|
||||||
, parseSexpsWithPos
|
|
||||||
, parseSexpWithPos
|
|
||||||
, parseSexp
|
|
||||||
, sx
|
|
||||||
, sxs
|
|
||||||
, makeSx
|
|
||||||
, makeSxs
|
|
||||||
, makeSx'
|
|
||||||
, toSexp
|
|
||||||
, fromSexp
|
|
||||||
, fromSexp'
|
|
||||||
, stripLocation
|
|
||||||
, format
|
|
||||||
, equivalent
|
|
||||||
, encodeOrShow
|
|
||||||
, readSxs
|
|
||||||
, prismIso
|
|
||||||
, schemeBool
|
|
||||||
, headTagged1'
|
|
||||||
, headTagged1
|
|
||||||
, headTagged2
|
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Data.Text (Text)
|
import Gyehoek.Sexp.QQ
|
||||||
import Language.SexpGrammar as Sexp hiding (toSexp, List, encode, decode, encodeWith, decodeWith, iso, encodePrettyWith, encodePretty, fromSexp)
|
import Gyehoek.Sexp.Syntax
|
||||||
import Language.SexpGrammar qualified as Sexp
|
import Gyehoek.Sexp.Grammar
|
||||||
import Language.Sexp qualified as S
|
|
||||||
import Data.InvertibleGrammar.Base qualified as IGB
|
|
||||||
import Data.InvertibleGrammar qualified as IG
|
|
||||||
import Data.InvertibleGrammar.Base ((:-)((:-)))
|
|
||||||
import Data.List.NonEmpty (NonEmpty ((:|)))
|
|
||||||
import Data.List (List, groupBy)
|
|
||||||
import Data.Text.Encoding
|
|
||||||
import GHC.Generics (Generic)
|
|
||||||
import Control.Lens hiding (para)
|
|
||||||
import Control.Monad (join)
|
|
||||||
import qualified Language.Sexp.Located as SL
|
|
||||||
import Data.Void (absurd)
|
|
||||||
import Language.Haskell.TH.Quote
|
|
||||||
import Language.Haskell.TH (Quote, location, Loc (..), ExpQ, varE, mkName, listE, Exp, appE, Q, Code, unTypeCode)
|
|
||||||
import qualified Data.Text as T
|
|
||||||
import qualified Control.Category
|
|
||||||
import Data.Data (Data (..), Typeable, cast)
|
|
||||||
import Language.Haskell.TH.Syntax (lift, Lift, liftData)
|
|
||||||
import Data.Functor.Foldable (cata)
|
|
||||||
import Data.Vector (Vector)
|
|
||||||
import Numeric.Natural (Natural)
|
|
||||||
import qualified Data.Vector.Strict
|
|
||||||
import Data.Function (on)
|
|
||||||
import Data.String (IsString (fromString))
|
|
||||||
import Effectful
|
|
||||||
import qualified Effectful.FileSystem.IO as FS
|
|
||||||
import qualified Effectful.FileSystem.IO.ByteString as FB
|
|
||||||
import qualified Data.Text.Encoding as T
|
|
||||||
|
|
||||||
|
|
||||||
sexp :: SexpIso a => Iso' a Text
|
|
||||||
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
|
|
||||||
|
|
||||||
decode :: SexpIso a => Text -> Either String a
|
|
||||||
decode = decodeWith sexpIso
|
|
||||||
|
|
||||||
encodeWith :: SexpGrammar a -> a -> Either String Text
|
|
||||||
encodeWith g = (_Right %~ decodeUtf8 . view strict) . Sexp.encodeWith g
|
|
||||||
|
|
||||||
encodePretty :: SexpIso a => a -> Either String Text
|
|
||||||
encodePretty = encodePrettyWith sexpIso
|
|
||||||
|
|
||||||
decodeWith :: SexpGrammar a -> Text -> Either String a
|
|
||||||
decodeWith g = Sexp.decodeWith g "FILE" . view lazy . encodeUtf8
|
|
||||||
|
|
||||||
encodePrettyWith :: SexpGrammar a -> a -> Either String Text
|
|
||||||
encodePrettyWith g =
|
|
||||||
(_Right %~ decodeUtf8 . view strict) . Sexp.encodePrettyWith g
|
|
||||||
|
|
||||||
parseSexps :: SexpIso a => FilePath -> Text -> Either String (List a)
|
|
||||||
parseSexps f = marshal . SL.parseSexps f . view lazy . encodeUtf8
|
|
||||||
where marshal = join . traverseOf (_Right . each) (Sexp.fromSexp sexpIso)
|
|
||||||
|
|
||||||
parseSexpsWith :: SexpGrammar a -> FilePath -> Text -> Either String (List a)
|
|
||||||
parseSexpsWith g f = marshal . SL.parseSexps f . view lazy . encodeUtf8
|
|
||||||
where marshal = join . traverseOf (_Right . each) (Sexp.fromSexp g)
|
|
||||||
|
|
||||||
parseSexp :: SexpIso a => FilePath -> Text -> Either String a
|
|
||||||
parseSexp f = marshal . SL.parseSexp f . view lazy . encodeUtf8
|
|
||||||
where marshal = join . traverseOf _Right (Sexp.fromSexp sexpIso)
|
|
||||||
|
|
||||||
readSexpWithPos :: Position -> Text -> Either String Sexp
|
|
||||||
readSexpWithPos pos = SL.parseSexpWithPos pos . view lazy . encodeUtf8
|
|
||||||
|
|
||||||
readSexpsWithPos :: Position -> Text -> Either String (List Sexp)
|
|
||||||
readSexpsWithPos pos = SL.parseSexpsWithPos pos . view lazy . encodeUtf8
|
|
||||||
|
|
||||||
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) (Sexp.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 (Sexp.fromSexp g)
|
|
||||||
|
|
||||||
fileName :: FilePath -> FilePath
|
|
||||||
fileName "-" = "<interactive>"
|
|
||||||
fileName e = e
|
|
||||||
|
|
||||||
hGetContents :: FS.FileSystem :> es => FS.Handle -> Eff es Text
|
|
||||||
hGetContents h = T.decodeUtf8 <$> FB.hGetContents h
|
|
||||||
|
|
||||||
readSxs
|
|
||||||
:: IOE :> es
|
|
||||||
=> SexpGrammar a
|
|
||||||
-> FilePath -> Eff es (List a)
|
|
||||||
readSxs g fp = FS.runFileSystem $
|
|
||||||
FS.withFile fp FS.ReadMode $ \h ->
|
|
||||||
parseSexpsWith g (fileName fp) <$> hGetContents h
|
|
||||||
>>= either error pure
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
nonEmptyGrammar :: Grammar p (NonEmpty x :- t) (List x :- x :- t)
|
|
||||||
nonEmptyGrammar = IGB.Iso
|
|
||||||
(\((x:|xs) :- t) -> reverse xs :- x :- t)
|
|
||||||
(\(xs :- x :- t) -> (x :| reverse xs) :- t)
|
|
||||||
|
|
||||||
nonempty :: SexpGrammar a -> SexpGrammar (NonEmpty a)
|
|
||||||
nonempty a =
|
|
||||||
list (el a >>> rest a) >>>
|
|
||||||
IG.flipped nonEmptyGrammar
|
|
||||||
|
|
||||||
let_
|
|
||||||
:: Text
|
|
||||||
-> (forall t. Grammar Position (Sexp :- t) (a :- t))
|
|
||||||
-> (forall t. Grammar Position (Sexp :- t) (b :- t))
|
|
||||||
-> Grammar Position (Sexp :- (List (a, b) :- t1)) t2
|
|
||||||
-> Grammar Position (Sexp :- t1) t2
|
|
||||||
let_ kw name rhs e = list (el (sym kw) >>> el bindings >>> el e)
|
|
||||||
where
|
|
||||||
-- bindings :: Grammar Position (Sexp :- _) (List (_, _) :- _)
|
|
||||||
bindings = list $ rest binding
|
|
||||||
binding :: Grammar Position (Sexp :- t) ((_, _) :- t)
|
|
||||||
binding = list (el name >>> el rhs) >>> pair
|
|
||||||
|
|
||||||
data DotList a = MkDotList (NonEmpty a) a
|
|
||||||
deriving (Show, Generic)
|
|
||||||
|
|
||||||
-- | Define a sexp representation as either (⟨name⟩ ⟨e⟩) or '⟨e⟩.
|
|
||||||
prefixSugar
|
|
||||||
:: Text -> Prefix
|
|
||||||
-> Grammar Position (Sexp :- t') a
|
|
||||||
-> Grammar Position (Sexp :- t') a
|
|
||||||
prefixSugar name prefix e = coproduct
|
|
||||||
-- 'something
|
|
||||||
[ Sexp.prefixed prefix e
|
|
||||||
-- (quote something)
|
|
||||||
, list $ el (sym name) >>> el e
|
|
||||||
]
|
|
||||||
|
|
||||||
todo :: Grammar p (Sexp :- t) t'
|
|
||||||
todo = IGB.Flip (IGB.PartialIso absurd f) >>> IGB.PartialIso absurd g
|
|
||||||
where
|
|
||||||
f _ = Left $ unexpected "todo"
|
|
||||||
g _ = Left $ unexpected "todo"
|
|
||||||
|
|
||||||
kappa
|
|
||||||
:: (forall t. Grammar Position (Sexp :- t) (a :- t))
|
|
||||||
-> Grammar Position (Sexp :- List a :- t1) t2
|
|
||||||
-> Grammar Position (Sexp :- t1) t2
|
|
||||||
kappa name e = list $
|
|
||||||
el kappaKeyword
|
|
||||||
>>> el (list $ rest name)
|
|
||||||
>>> el e
|
|
||||||
|
|
||||||
lambda
|
|
||||||
:: (forall t. Grammar Position (Sexp :- t) (a :- t))
|
|
||||||
-> Grammar Position (Sexp :- List a :- t1) t2
|
|
||||||
-> Grammar Position (Sexp :- t1) t2
|
|
||||||
lambda name e = list $
|
|
||||||
el lambdaKeyword
|
|
||||||
>>> el (list $ rest name)
|
|
||||||
>>> el e
|
|
||||||
|
|
||||||
isoIso :: Iso' s a -> Grammar p (s :- t) (a :- t)
|
|
||||||
isoIso l = Sexp.iso (view l) (review l)
|
|
||||||
|
|
||||||
prismIso :: Mismatch -> Prism' s a -> Grammar p (s :- t) (a :- t)
|
|
||||||
prismIso mm p = Sexp.partialOsi
|
|
||||||
(maybe (Left mm) Right . preview p)
|
|
||||||
(review p)
|
|
||||||
|
|
||||||
kappaKeyword :: Grammar Position (Sexp :- t) t
|
|
||||||
kappaKeyword = coproduct [ sym "κ", sym "kappa" ]
|
|
||||||
|
|
||||||
lambdaKeyword :: Grammar Position (Sexp :- t) t
|
|
||||||
lambdaKeyword = coproduct [ sym "λ", sym "lambda" ]
|
|
||||||
|
|
||||||
schemeBool :: SexpGrammar Bool
|
|
||||||
schemeBool = Sexp.hashed $ Sexp.partialOsi f g
|
|
||||||
where
|
|
||||||
f (SL.Symbol ("t";"true")) = Right True
|
|
||||||
f (SL.Symbol ("f";"false")) = Right False
|
|
||||||
f _ = Left $ Sexp.expected "bool"
|
|
||||||
g True = SL.Symbol "true"
|
|
||||||
g False = SL.Symbol "false"
|
|
||||||
|
|
||||||
headTagged1 :: Text -> SexpGrammar a -> Grammar Position (Sexp :- t) (a :- t)
|
|
||||||
headTagged1 s g1 = list $ el (sym s) >>> el g1
|
|
||||||
|
|
||||||
headTagged1'
|
|
||||||
:: Text
|
|
||||||
-> SexpGrammar a -> SexpGrammar b
|
|
||||||
-> Grammar Position (Sexp :- t) (List b :- a :- t)
|
|
||||||
headTagged1' s g1 gt = list $ el (sym s) >>> el g1 >>> rest gt
|
|
||||||
|
|
||||||
headTagged2
|
|
||||||
:: Text
|
|
||||||
-> SexpGrammar a -> SexpGrammar b
|
|
||||||
-> Grammar Position (Sexp :- t) (b :- a :- t)
|
|
||||||
headTagged2 s g1 g2 = list $ el (sym s) >>> el g1 >>> el g2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
fromSexp :: SexpIso a => Sexp -> a
|
|
||||||
fromSexp = either error id . Sexp.fromSexp sexpIso
|
|
||||||
|
|
||||||
fromSexp' :: SexpGrammar a -> Sexp -> a
|
|
||||||
fromSexp' g = either error id . Sexp.fromSexp g
|
|
||||||
|
|
||||||
toSexp :: SexpIso a => a -> Sexp
|
|
||||||
toSexp = either error id . Sexp.toSexp sexpIso
|
|
||||||
|
|
||||||
toSexps :: (Foldable f, SexpIso a) => f a -> List Sexp
|
|
||||||
toSexps = foldMap \x -> [toSexp x]
|
|
||||||
|
|
||||||
pattern Unquote :: Text -> Sexp
|
|
||||||
pattern Unquote x =
|
|
||||||
SL.Modified Hash (SL.BraceList [SL.Symbol x])
|
|
||||||
|
|
||||||
pattern UnquoteSplicing :: Text -> Sexp
|
|
||||||
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 k (SL.Modified m e) = SL.Modified m <$> each k e
|
|
||||||
each _ e@(SL.Atom _; SL.Modified _ _) = pure e
|
|
||||||
|
|
||||||
stripLocation :: Sexp -> Sexp
|
|
||||||
stripLocation = cata \case
|
|
||||||
SL.Compose (a SL.:< e) ->
|
|
||||||
SL.Fix . SL.Compose $ SL.dummyPos SL.:< e
|
|
||||||
|
|
||||||
-- | @('==')@ for 'Sexp's modulo source location — return true if the
|
|
||||||
-- two sexps are equal in all but 'Position' fields.
|
|
||||||
equivalent :: Sexp -> Sexp -> Bool
|
|
||||||
equivalent = (==) `on` stripLocation
|
|
||||||
|
|
||||||
instance SexpIso Natural where
|
|
||||||
sexpIso = 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
|
|
||||||
|
|
||||||
class SpliceSexp a where
|
|
||||||
spliceSexp :: a -> List Sexp
|
|
||||||
|
|
||||||
instance SexpIso a => SpliceSexp (Data.Vector.Strict.Vector a) where
|
|
||||||
spliceSexp = toSexps
|
|
||||||
|
|
||||||
instance SexpIso a => SpliceSexp (Vector a) where
|
|
||||||
spliceSexp = toSexps
|
|
||||||
|
|
||||||
instance SexpIso a => SpliceSexp (List a) where
|
|
||||||
spliceSexp = toSexps
|
|
||||||
|
|
||||||
instance SpliceSexp Sexp where
|
|
||||||
spliceSexp = toListOf each
|
|
||||||
|
|
||||||
unquoteSplicingRecursive :: List Sexp.Sexp -> ExpQ
|
|
||||||
unquoteSplicingRecursive xs = [| mconcat $(spans) |]
|
|
||||||
where
|
|
||||||
spans = xs
|
|
||||||
& groupBy \cases
|
|
||||||
(UnquoteSplicing _) _ -> False
|
|
||||||
_ (UnquoteSplicing _) -> False
|
|
||||||
_ _ -> True
|
|
||||||
& fmap \case
|
|
||||||
[UnquoteSplicing x] ->
|
|
||||||
[| spliceSexp $(varE (mkName (T.unpack x))) |]
|
|
||||||
es -> listE $ unquoteRecursive <$> es
|
|
||||||
& listE
|
|
||||||
|
|
||||||
unquoteRecursive :: Sexp.Sexp -> ExpQ
|
|
||||||
unquoteRecursive = \case
|
|
||||||
Unquote x -> [| toSexp $(varE (mkName (T.unpack x))) |]
|
|
||||||
SL.ParenList xs -> [|SL.ParenList $(unquoteSplicingRecursive xs)|]
|
|
||||||
e -> liftData e
|
|
||||||
|
|
||||||
_ParenList :: Prism' Sexp (List Sexp)
|
|
||||||
_ParenList = prism' SL.ParenList \case
|
|
||||||
SL.ParenList xs -> Just xs
|
|
||||||
_ -> Nothing
|
|
||||||
|
|
||||||
metaSexps :: List Sexp.Sexp -> Maybe ExpQ
|
|
||||||
metaSexps = Just . unquoteSplicingRecursive
|
|
||||||
|
|
||||||
metaSexp :: Sexp.Sexp -> Maybe ExpQ
|
|
||||||
metaSexp = Just . unquoteRecursive
|
|
||||||
|
|
||||||
-- 뻘짓뻘짓뻘짓뻘짓뻘짓
|
|
||||||
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 [|SL.Fix|] (lift1 inner)
|
|
||||||
|
|
||||||
instance (Lift1 f, Lift1 g) => Lift1 (SL.Compose f g) where
|
|
||||||
liftLift l (SL.Compose fga) = [|SL.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.ModifiedF $(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
|
|
||||||
|
|
||||||
encodeOrShow :: (SexpIso a, Show a, IsString s) => a -> s
|
|
||||||
encodeOrShow a = fromString case encode a of
|
|
||||||
Left _ -> show a
|
|
||||||
Right e -> T.unpack e
|
|
||||||
|
|
||||||
extQ :: (Typeable a, Typeable b) => (a -> r) -> (b -> r) -> a -> r
|
|
||||||
extQ f g a = maybe (f a) g (cast a)
|
|
||||||
|
|
||||||
makeSxs :: Data r => Code Q (List Sexp -> r) -> QuasiQuoter
|
|
||||||
makeSxs f = QuasiQuoter
|
|
||||||
{ quoteExp = \str -> do
|
|
||||||
pos <- getPos
|
|
||||||
case readSexpsWithPos pos (T.pack str) of
|
|
||||||
Left e -> fail e
|
|
||||||
Right xs -> [| $(unTypeCode f) $e |]
|
|
||||||
where
|
|
||||||
e = dataToExpQ
|
|
||||||
(const Nothing `extQ` metaSexp `extQ` metaSexps)
|
|
||||||
xs
|
|
||||||
, quotePat = undefined
|
|
||||||
, quoteType = undefined
|
|
||||||
, quoteDec = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
-- | An untyped variant of 'makeSx', useful when the user function is
|
|
||||||
-- polymorphic in its return value.
|
|
||||||
makeSx' :: ExpQ -> QuasiQuoter
|
|
||||||
makeSx' f = QuasiQuoter
|
|
||||||
{ quoteExp = \str -> do
|
|
||||||
pos <- getPos
|
|
||||||
case readSexpWithPos pos (T.pack str) of
|
|
||||||
Left e -> fail e
|
|
||||||
Right x -> [| $f $e |]
|
|
||||||
where
|
|
||||||
e = dataToExpQ
|
|
||||||
(const Nothing `extQ` metaSexp `extQ` metaSexps)
|
|
||||||
x
|
|
||||||
, quotePat = undefined
|
|
||||||
, quoteType = undefined
|
|
||||||
, quoteDec = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
makeSx :: Data r => Code Q (Sexp -> r) -> QuasiQuoter
|
|
||||||
makeSx = makeSx' . unTypeCode
|
|
||||||
|
|
||||||
sxs = makeSxs [||id||]
|
|
||||||
sx = makeSx [||id||]
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ module Gyehoek.Sexp.Grammar
|
|||||||
, toData
|
, toData
|
||||||
, fromData
|
, fromData
|
||||||
, encodeWith
|
, encodeWith
|
||||||
|
, encodeWith'
|
||||||
, encodeDataWith
|
, encodeDataWith
|
||||||
, decodeWith
|
, decodeWith
|
||||||
, encodeTest
|
, encodeTest
|
||||||
@@ -18,6 +19,10 @@ module Gyehoek.Sexp.Grammar
|
|||||||
, with
|
, with
|
||||||
, match
|
, match
|
||||||
, Coproduct (..)
|
, Coproduct (..)
|
||||||
|
, fromDatumUnsafe
|
||||||
|
, Control.Category.id
|
||||||
|
, encodeOrShow'
|
||||||
|
, decodeDataWith
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
@@ -32,6 +37,9 @@ import qualified Data.Text.IO as TIO
|
|||||||
import Text.Pretty.Simple (pPrintNoColor)
|
import Text.Pretty.Simple (pPrintNoColor)
|
||||||
import Data.InvertibleGrammar.Generic
|
import Data.InvertibleGrammar.Generic
|
||||||
import qualified Control.Category
|
import qualified Control.Category
|
||||||
|
import qualified Data.Vector as V
|
||||||
|
import Data.String (IsString (fromString))
|
||||||
|
import qualified Data.Text as T
|
||||||
|
|
||||||
|
|
||||||
toDatum :: Jalmot :> es => DatumGrammar a -> a -> Eff es Datum
|
toDatum :: Jalmot :> es => DatumGrammar a -> a -> Eff es Datum
|
||||||
@@ -52,6 +60,9 @@ fromDatum g =
|
|||||||
>>> runGrammar noAnn
|
>>> runGrammar noAnn
|
||||||
>>> either (throwError . GrammarError) pure
|
>>> either (throwError . GrammarError) pure
|
||||||
|
|
||||||
|
fromDatumUnsafe :: DatumGrammar a -> Datum -> a
|
||||||
|
fromDatumUnsafe g = runJalmotUnsafe . fromDatum g
|
||||||
|
|
||||||
fromData :: Jalmot :> es => DataGrammar a -> List Datum -> Eff es a
|
fromData :: Jalmot :> es => DataGrammar a -> List Datum -> Eff es a
|
||||||
fromData g =
|
fromData g =
|
||||||
forward (sealed g)
|
forward (sealed g)
|
||||||
@@ -70,6 +81,10 @@ encodeWith' g = toDatum g >>> fmap printDatum'
|
|||||||
decodeWith :: forall es a. Jalmot :> es => DatumGrammar a -> Text -> Eff es a
|
decodeWith :: forall es a. Jalmot :> es => DatumGrammar a -> Text -> Eff es a
|
||||||
decodeWith g = Read.readString1 @es >=> fromDatum g
|
decodeWith g = Read.readString1 @es >=> fromDatum g
|
||||||
|
|
||||||
|
decodeDataWith
|
||||||
|
:: forall es a. Jalmot :> es => DataGrammar a -> Text -> Eff es a
|
||||||
|
decodeDataWith g = Read.readString @es >=> fromData g
|
||||||
|
|
||||||
-- | run a grammar, quick and dirty.
|
-- | run a grammar, quick and dirty.
|
||||||
decodeTest :: Show a => DatumGrammar a -> Text -> IO ()
|
decodeTest :: Show a => DatumGrammar a -> Text -> IO ()
|
||||||
decodeTest g = pPrintNoColor <=< (runJalmotIO . decodeWith g)
|
decodeTest g = pPrintNoColor <=< (runJalmotIO . decodeWith g)
|
||||||
@@ -82,6 +97,12 @@ encodeTest g = TIO.putStrLn <=< (runJalmotIO . encodeWith' g)
|
|||||||
encodeTestColour :: DatumGrammar a -> a -> IO ()
|
encodeTestColour :: DatumGrammar a -> a -> IO ()
|
||||||
encodeTestColour g = TIO.putStrLn <=< (runJalmotIO . encodeWith g)
|
encodeTestColour g = TIO.putStrLn <=< (runJalmotIO . encodeWith g)
|
||||||
|
|
||||||
|
encodeOrShow' :: (IsString s, Show a) => DatumGrammar a -> a -> s
|
||||||
|
encodeOrShow' g x = fromString $
|
||||||
|
case runPureEff . runJalmot . encodeWith' g $ x of
|
||||||
|
Left _ -> show x
|
||||||
|
Right t -> T.unpack t
|
||||||
|
|
||||||
class DatumIso a where
|
class DatumIso a where
|
||||||
datumIso :: DatumGrammar a
|
datumIso :: DatumGrammar a
|
||||||
|
|
||||||
@@ -101,3 +122,10 @@ instance DatumIso Datum where datumIso = Control.Category.id
|
|||||||
|
|
||||||
instance DatumIso a => DataIso (List a) where
|
instance DatumIso a => DataIso (List a) where
|
||||||
dataIso = onHead . traversed . sealed $ datumIso @a
|
dataIso = onHead . traversed . sealed $ datumIso @a
|
||||||
|
|
||||||
|
instance DatumIso a => DataIso (V.Vector a) where
|
||||||
|
dataIso = iso fromList V.toList
|
||||||
|
>>> (onHead . traversed . sealed $ datumIso @a)
|
||||||
|
|
||||||
|
instance (DatumIso a, DatumIso b) => DatumIso (a, b) where
|
||||||
|
datumIso = with \tup2 -> list (el datumIso >>> el datumIso) >>> tup2
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
-- | cribbed from sexp-grammar:Language.SexpGrammar.Base
|
-- | cribbed from sexp-grammar:Language.SexpGrammar.Base
|
||||||
module Gyehoek.Sexp.Grammar.Base
|
module Gyehoek.Sexp.Grammar.Base
|
||||||
( module Gyehoek.Sexp.Syntax
|
( module Gyehoek.Sexp.Syntax
|
||||||
|
, module Data.InvertibleGrammar.Combinators
|
||||||
|
, expected, unexpected
|
||||||
-- * types
|
-- * types
|
||||||
, G
|
, G
|
||||||
, Grammar
|
, Grammar
|
||||||
@@ -31,15 +33,17 @@ module Gyehoek.Sexp.Grammar.Base
|
|||||||
, headTagged0
|
, headTagged0
|
||||||
, lambdaLike
|
, lambdaLike
|
||||||
, lambdaKeyword
|
, lambdaKeyword
|
||||||
|
, kappaKeyword
|
||||||
, beginLike
|
, beginLike
|
||||||
|
, prismIso
|
||||||
|
, isoIso
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.InvertibleGrammar
|
import Data.InvertibleGrammar
|
||||||
import Data.InvertibleGrammar.Base
|
import Data.InvertibleGrammar.Base
|
||||||
|
import Data.InvertibleGrammar.Combinators
|
||||||
import Gyehoek.Prelude hiding (iso, cons, coerced, Iso, Simple, simple)
|
import Gyehoek.Prelude hiding (iso, cons, coerced, Iso, Simple, simple)
|
||||||
import Gyehoek.Sexp.Syntax hiding (position)
|
import Gyehoek.Sexp.Syntax hiding (position)
|
||||||
import Gyehoek.Sexp qualified as GS
|
|
||||||
import qualified Gyehoek.Sexp as GS
|
|
||||||
import Gyehoek.Sexp.Print (printDatum')
|
import Gyehoek.Sexp.Print (printDatum')
|
||||||
import Data.Scientific (Scientific)
|
import Data.Scientific (Scientific)
|
||||||
import qualified Data.Scientific as Sci
|
import qualified Data.Scientific as Sci
|
||||||
@@ -249,10 +253,10 @@ ifLike
|
|||||||
-- | condition
|
-- | condition
|
||||||
-> DatumGrammar a
|
-> DatumGrammar a
|
||||||
-- | consequent (then-branch)
|
-- | consequent (then-branch)
|
||||||
-> DatumGrammar a
|
-> DatumGrammar b
|
||||||
-- | alternative (else-branch)
|
-- | alternative (else-branch)
|
||||||
-> DatumGrammar a
|
-> DatumGrammar c
|
||||||
-> G (Datum :- t) (a :- a :- a :- t)
|
-> G (Datum :- t) (c :- b :- a :- t)
|
||||||
ifLike kw c t f = list $ el (symBuiltin kw) >>> el c >>> el t >>> el f
|
ifLike kw c t f = list $ el (symBuiltin kw) >>> el c >>> el t >>> el f
|
||||||
|
|
||||||
symBuiltin :: Text -> G (Datum :- t) t
|
symBuiltin :: Text -> G (Datum :- t) t
|
||||||
@@ -282,7 +286,10 @@ lambdaLike kw formals body = listWithIndentation (NSpecial 1) $
|
|||||||
>>> body
|
>>> body
|
||||||
|
|
||||||
lambdaKeyword :: G (Datum :- t) t
|
lambdaKeyword :: G (Datum :- t) t
|
||||||
lambdaKeyword = coproduct [ sym "lambda", sym "λ" ]
|
lambdaKeyword = coproduct [ sym "λ", sym "lambda" ]
|
||||||
|
|
||||||
|
kappaKeyword :: G (Datum :- t) t
|
||||||
|
kappaKeyword = coproduct [ sym "κ", sym "kappa" ]
|
||||||
|
|
||||||
beginLike
|
beginLike
|
||||||
:: Text
|
:: Text
|
||||||
@@ -291,3 +298,11 @@ beginLike
|
|||||||
beginLike kw g =
|
beginLike kw g =
|
||||||
listWithIndentation (NSpecial 0) $
|
listWithIndentation (NSpecial 0) $
|
||||||
el (symBuiltin kw) >>> rest g
|
el (symBuiltin kw) >>> rest g
|
||||||
|
|
||||||
|
isoIso :: Iso' s a -> Grammar p (s :- t) (a :- t)
|
||||||
|
isoIso l = iso (view l) (review l)
|
||||||
|
|
||||||
|
prismIso :: Mismatch -> Prism' s a -> Grammar p (s :- t) (a :- t)
|
||||||
|
prismIso mm p = partialOsi
|
||||||
|
(maybe (Left mm) Right . preview p)
|
||||||
|
(review p)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ module Gyehoek.Sexp.QQ
|
|||||||
, makeSx'
|
, makeSx'
|
||||||
, sx
|
, sx
|
||||||
, sxs
|
, sxs
|
||||||
|
, QuasiQuoter
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.Data (Typeable, cast)
|
import Data.Data (Typeable, cast)
|
||||||
@@ -124,5 +125,5 @@ makeSx :: Data r => Code Q (Datum -> r) -> QuasiQuoter
|
|||||||
makeSx = makeSx' . unTypeCode
|
makeSx = makeSx' . unTypeCode
|
||||||
|
|
||||||
sx, sxs :: QuasiQuoter
|
sx, sxs :: QuasiQuoter
|
||||||
sxs = makeSxs [|| id @(List Datum) ||]
|
sxs = makeSxs [|| Prelude.id @(List Datum) ||]
|
||||||
sx = makeSx [|| id @Datum ||]
|
sx = makeSx [|| Prelude.id @Datum ||]
|
||||||
|
|||||||
+34
-39
@@ -10,8 +10,8 @@ module Gyehoek.Wasm
|
|||||||
, Expr
|
, Expr
|
||||||
-- ** quasiquoters
|
-- ** quasiquoters
|
||||||
, expr
|
, expr
|
||||||
, Gyehoek.Sexp.sx
|
, S.sx
|
||||||
, Gyehoek.Sexp.sxs
|
, S.sxs
|
||||||
-- * GenMod effect
|
-- * GenMod effect
|
||||||
, GenMod
|
, GenMod
|
||||||
, runGenMod
|
, runGenMod
|
||||||
@@ -29,10 +29,6 @@ module Gyehoek.Wasm
|
|||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
|
||||||
import Language.SexpGrammar
|
|
||||||
( SexpIso(..), (>>>) )
|
|
||||||
import Language.SexpGrammar qualified as Sexp
|
|
||||||
import Language.SexpGrammar.Generic
|
|
||||||
import Data.List (List)
|
import Data.List (List)
|
||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
@@ -43,16 +39,16 @@ import Effectful.State.Dynamic
|
|||||||
import Control.Lens
|
import Control.Lens
|
||||||
import Data.Vector.Strict (Vector)
|
import Data.Vector.Strict (Vector)
|
||||||
import qualified Data.Vector.Strict as V
|
import qualified Data.Vector.Strict as V
|
||||||
import Language.Sexp.Located
|
|
||||||
import qualified Gyehoek.Sexp
|
|
||||||
import GHC.IsList (IsList(..))
|
import GHC.IsList (IsList(..))
|
||||||
import Language.Haskell.TH.Quote (QuasiQuoter)
|
import Language.Haskell.TH.Quote (QuasiQuoter)
|
||||||
import Data.Data (Data)
|
import Data.Data (Data)
|
||||||
import Gyehoek.Sexp (sx)
|
import Gyehoek.Sexp qualified as S
|
||||||
|
import Gyehoek.Sexp (Datum, sx, (>>>))
|
||||||
import Data.Foldable (traverse_)
|
import Data.Foldable (traverse_)
|
||||||
|
import Data.Coerce (coerce)
|
||||||
|
|
||||||
|
|
||||||
newtype Module = MkModule { inner :: Vector Sexp }
|
newtype Module = MkModule { inner :: Vector Datum }
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
deriving newtype (Semigroup, Monoid)
|
deriving newtype (Semigroup, Monoid)
|
||||||
|
|
||||||
@@ -65,7 +61,7 @@ instance IsList Expr where
|
|||||||
fromList = MkExpr . V.fromList
|
fromList = MkExpr . V.fromList
|
||||||
toList = V.toList . view #inner
|
toList = V.toList . view #inner
|
||||||
|
|
||||||
newtype Instr = MkInstr { inner :: Sexp }
|
newtype Instr = MkInstr { inner :: Datum }
|
||||||
deriving (Show, Generic, Data, Eq)
|
deriving (Show, Generic, Data, Eq)
|
||||||
|
|
||||||
newtype Idx = MkIdx { inner :: Natural }
|
newtype Idx = MkIdx { inner :: Natural }
|
||||||
@@ -102,38 +98,38 @@ instance Monoid GenModState where
|
|||||||
}
|
}
|
||||||
|
|
||||||
data GenMod :: Effect where
|
data GenMod :: Effect where
|
||||||
DefineFunction :: Sexp -> GenMod m Idx
|
DefineFunction :: Datum -> GenMod m Idx
|
||||||
DefineType :: Sexp -> GenMod m Idx
|
DefineType :: Datum -> GenMod m Idx
|
||||||
DefineGlobal :: Sexp -> GenMod m Idx
|
DefineGlobal :: Datum -> GenMod m Idx
|
||||||
Emit :: Sexp -> GenMod m ()
|
Emit :: Datum -> GenMod m ()
|
||||||
|
|
||||||
type instance DispatchOf GenMod = Dynamic
|
type instance DispatchOf GenMod = Dynamic
|
||||||
|
|
||||||
defineFunction :: GenMod :> es => Sexp -> Eff es Idx
|
defineFunction :: GenMod :> es => Datum -> Eff es Idx
|
||||||
defineFunction = send . DefineFunction
|
defineFunction = send . DefineFunction
|
||||||
|
|
||||||
defineFunctions :: GenMod :> es => List Sexp -> Eff es (List Idx)
|
defineFunctions :: GenMod :> es => List Datum -> Eff es (List Idx)
|
||||||
defineFunctions = traverse (send . DefineFunction)
|
defineFunctions = traverse (send . DefineFunction)
|
||||||
|
|
||||||
defineType :: GenMod :> es => Sexp -> Eff es Idx
|
defineType :: GenMod :> es => Datum -> Eff es Idx
|
||||||
defineType = send . DefineType
|
defineType = send . DefineType
|
||||||
|
|
||||||
defineTypes :: GenMod :> es => List Sexp -> Eff es (List Idx)
|
defineTypes :: GenMod :> es => List Datum -> Eff es (List Idx)
|
||||||
defineTypes = traverse (send . DefineType)
|
defineTypes = traverse (send . DefineType)
|
||||||
|
|
||||||
defineGlobal :: GenMod :> es => Sexp -> Eff es Idx
|
defineGlobal :: GenMod :> es => Datum -> Eff es Idx
|
||||||
defineGlobal = send . DefineGlobal
|
defineGlobal = send . DefineGlobal
|
||||||
|
|
||||||
defineGlobals :: GenMod :> es => List Sexp -> Eff es (List Idx)
|
defineGlobals :: GenMod :> es => List Datum -> Eff es (List Idx)
|
||||||
defineGlobals = traverse (send . DefineGlobal)
|
defineGlobals = traverse (send . DefineGlobal)
|
||||||
|
|
||||||
emit :: GenMod :> es => List Sexp -> Eff es ()
|
emit :: GenMod :> es => List Datum -> Eff es ()
|
||||||
emit = traverse_ (send . Emit)
|
emit = traverse_ (send . Emit)
|
||||||
|
|
||||||
appendAndIncrement
|
appendAndIncrement
|
||||||
:: State GenModState :> es
|
:: State GenModState :> es
|
||||||
=> LensLike' ((,) Natural) GenModState Natural
|
=> LensLike' ((,) Natural) GenModState Natural
|
||||||
-> Sexp
|
-> Datum
|
||||||
-> Eff es Idx
|
-> Eff es Idx
|
||||||
appendAndIncrement l s =
|
appendAndIncrement l s =
|
||||||
state \st -> st
|
state \st -> st
|
||||||
@@ -154,39 +150,38 @@ execGenMod :: Eff (GenMod : es) a -> Eff es Module
|
|||||||
execGenMod = fmap snd . runGenMod
|
execGenMod = fmap snd . runGenMod
|
||||||
|
|
||||||
renderModule :: Module -> Text
|
renderModule :: Module -> Text
|
||||||
renderModule (MkModule ss) = Gyehoek.Sexp.format [sx|
|
renderModule (MkModule ss) = S.encodeWith' S.datumIso [sx|
|
||||||
(module ##{ss})
|
(module ##{ss})
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
|
||||||
-- SexpIso instances
|
-- DatumIso instances
|
||||||
|
|
||||||
instance SexpIso Idx where
|
instance S.DatumIso Idx where
|
||||||
sexpIso = with \idx ->
|
datumIso = S.with \idx ->
|
||||||
Sexp.integer >>> Sexp.partialOsi f g
|
S.integer >>> S.partialOsi f g
|
||||||
>>> idx
|
>>> idx
|
||||||
where
|
where
|
||||||
f n | n < 0 = Left $ Sexp.unexpected "negative"
|
f n | n < 0 = Left $ S.unexpected "negative"
|
||||||
<> Sexp.expected "natural"
|
<> S.expected "natural"
|
||||||
| otherwise = Right $ fromIntegral n
|
| otherwise = Right $ fromIntegral n
|
||||||
g = fromIntegral
|
g = fromIntegral
|
||||||
|
|
||||||
instance SexpIso Instr where
|
instance S.DatumIso Instr where
|
||||||
sexpIso = with id
|
datumIso = S.with S.id
|
||||||
|
|
||||||
instance Gyehoek.Sexp.SpliceSexp Expr where
|
instance S.DataIso Expr where
|
||||||
spliceSexp = toListOf $ #inner . each . #inner
|
dataIso = S.dataIso @(Vector Instr) >>> S.iso coerce coerce
|
||||||
|
|
||||||
|
|
||||||
-- quasiquoters
|
-- quasiquoters
|
||||||
|
|
||||||
expr :: QuasiQuoter
|
expr :: QuasiQuoter
|
||||||
expr = Gyehoek.Sexp.makeSxs
|
expr = S.makeSxs
|
||||||
[||MkExpr . V.fromList . (each . #inner %~ Gyehoek.Sexp.stripLocation)
|
[|| MkExpr . V.fromList . fmap (S.fromDatumUnsafe $ S.datumIso @Instr) ||]
|
||||||
. fmap (Gyehoek.Sexp.fromSexp @Instr) ||]
|
|
||||||
|
|
||||||
wat :: QuasiQuoter
|
wat :: QuasiQuoter
|
||||||
wat = Gyehoek.Sexp.makeSx [|| id ||]
|
wat = S.makeSx [|| id ||]
|
||||||
|
|
||||||
wats :: QuasiQuoter
|
wats :: QuasiQuoter
|
||||||
wats = Gyehoek.Sexp.makeSxs [|| id ||]
|
wats = S.makeSxs [|| id ||]
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
module Gyehoek.Test.Sexp where
|
|
||||||
|
|
||||||
import Test.Tasty (TestTree, testGroup)
|
|
||||||
import Test.Tasty.HUnit
|
|
||||||
import Language.Sexp.Located qualified as SL
|
|
||||||
import Language.SexpGrammar ()
|
|
||||||
import Gyehoek.Sexp (sx, equivalent)
|
|
||||||
import Data.Function (on)
|
|
||||||
|
|
||||||
|
|
||||||
test_root = testGroup "sexp" $
|
|
||||||
[ sxTree
|
|
||||||
]
|
|
||||||
|
|
||||||
newtype EquivSexp = MkEquiv SL.Sexp
|
|
||||||
deriving newtype (Show)
|
|
||||||
|
|
||||||
instance Eq EquivSexp where
|
|
||||||
MkEquiv x == MkEquiv y = equivalent x y
|
|
||||||
|
|
||||||
assertEquiv
|
|
||||||
:: HasCallStack
|
|
||||||
=> String -> SL.Sexp -> SL.Sexp -> Assertion
|
|
||||||
assertEquiv prefix = assertEqual prefix `on` MkEquiv
|
|
||||||
|
|
||||||
equivto = assertEquiv ""
|
|
||||||
|
|
||||||
sxTree :: TestTree
|
|
||||||
sxTree = testGroup "sx"
|
|
||||||
[ testCase "quotation" do
|
|
||||||
equivto (SL.Symbol "abc") [sx|abc|]
|
|
||||||
equivto (SL.ParenList [SL.Symbol "a", SL.Symbol "b"]) [sx|(a b)|]
|
|
||||||
, testCase "antiquotation" do
|
|
||||||
equivto [sx|123|]
|
|
||||||
let meta = 123 :: Int
|
|
||||||
in [sx|#{meta}|]
|
|
||||||
equivto [sx|(blah (blah blah) blah)|]
|
|
||||||
let meta = [sx|blah|]
|
|
||||||
in [sx|(#{meta} (#{meta} #{meta}) #{meta})|]
|
|
||||||
, testCase "splicing" do
|
|
||||||
equivto [sx|(a b c d e f g)|]
|
|
||||||
let metas = SL.Symbol <$> ["c","d","e"]
|
|
||||||
in [sx|(a b ##{metas} f g)|]
|
|
||||||
equivto [sx|(a (b c d) e f g)|]
|
|
||||||
let
|
|
||||||
e1 = SL.Symbol "c"
|
|
||||||
e2 = SL.Symbol <$> ["e","f"]
|
|
||||||
in [sx|(a (b #{e1} d) ##{e2} g)|]
|
|
||||||
]
|
|
||||||
Reference in New Issue
Block a user