This commit is contained in:
@@ -62,6 +62,7 @@ library
|
|||||||
Gyehoek.GenSym
|
Gyehoek.GenSym
|
||||||
Gyehoek.Jalmot
|
Gyehoek.Jalmot
|
||||||
Gyehoek.Language
|
Gyehoek.Language
|
||||||
|
Gyehoek.Lift1
|
||||||
Gyehoek.Options
|
Gyehoek.Options
|
||||||
Gyehoek.Prelude
|
Gyehoek.Prelude
|
||||||
Gyehoek.Scheme.Syntax
|
Gyehoek.Scheme.Syntax
|
||||||
@@ -69,6 +70,7 @@ library
|
|||||||
Gyehoek.Sexp.Grammar
|
Gyehoek.Sexp.Grammar
|
||||||
Gyehoek.Sexp.Grammar.Base
|
Gyehoek.Sexp.Grammar.Base
|
||||||
Gyehoek.Sexp.Print
|
Gyehoek.Sexp.Print
|
||||||
|
Gyehoek.Sexp.QQ
|
||||||
Gyehoek.Sexp.Read
|
Gyehoek.Sexp.Read
|
||||||
Gyehoek.Sexp.Syntax
|
Gyehoek.Sexp.Syntax
|
||||||
Gyehoek.Stack.Syntax
|
Gyehoek.Stack.Syntax
|
||||||
@@ -131,6 +133,7 @@ test-suite test
|
|||||||
Gyehoek.Test.Scheme.Syntax
|
Gyehoek.Test.Scheme.Syntax
|
||||||
Gyehoek.Test.Sexp
|
Gyehoek.Test.Sexp
|
||||||
Gyehoek.Test.Sexp.Print
|
Gyehoek.Test.Sexp.Print
|
||||||
|
Gyehoek.Test.Sexp.QQ
|
||||||
Gyehoek.Test.Sexp.Read
|
Gyehoek.Test.Sexp.Read
|
||||||
Gyehoek.Test.Stack.VM
|
Gyehoek.Test.Stack.VM
|
||||||
Gyehoek.TestUtil
|
Gyehoek.TestUtil
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
module Gyehoek.Lift1
|
||||||
|
( Lift1(..)
|
||||||
|
, lift1
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Gyehoek.Prelude hiding ((:<))
|
||||||
|
import Language.Haskell.TH (Quote, Exp, listE)
|
||||||
|
import Language.Haskell.TH.Syntax (Lift (..))
|
||||||
|
import Control.Comonad.Cofree (Cofree(..))
|
||||||
|
|
||||||
|
|
||||||
|
-- 뻘짓뻘짓뻘짓뻘짓뻘짓
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
--- instances
|
||||||
|
|
||||||
|
instance Lift1 f => Lift1 (Cofree f) where
|
||||||
|
liftLift l (a :< e) = [|(:<) $(l a) $(liftLift (liftLift l) e)|]
|
||||||
|
|
||||||
|
instance Lift1 List where
|
||||||
|
liftLift l xs = listE $ l <$> xs
|
||||||
|
|
||||||
|
instance Lift1 NonEmpty where
|
||||||
|
liftLift l (x :| xs) = [|(:|) $(l x) $(liftLift l xs)|]
|
||||||
@@ -21,7 +21,7 @@ module Gyehoek.Prelude
|
|||||||
, (<=<)
|
, (<=<)
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Lens hiding (List)
|
import Control.Lens hiding (List, (:<))
|
||||||
import Data.List (List)
|
import Data.List (List)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Effectful
|
import Effectful
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ module Gyehoek.Sexp.Grammar
|
|||||||
where
|
where
|
||||||
|
|
||||||
import Gyehoek.Sexp.Grammar.Base
|
import Gyehoek.Sexp.Grammar.Base
|
||||||
import Gyehoek.Prelude
|
import Gyehoek.Prelude hiding (traversed, iso)
|
||||||
import Data.InvertibleGrammar (backward, sealed, forward, runGrammar)
|
import Data.InvertibleGrammar (backward, sealed, forward, runGrammar)
|
||||||
import Gyehoek.Sexp.Print (printDatum, printDatum', printData)
|
import Gyehoek.Sexp.Print (printDatum, printDatum', printData)
|
||||||
import Gyehoek.Jalmot
|
import Gyehoek.Jalmot
|
||||||
@@ -31,6 +31,7 @@ import qualified Gyehoek.Sexp.Read as Read
|
|||||||
import qualified Data.Text.IO as TIO
|
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
|
||||||
|
|
||||||
|
|
||||||
toDatum :: Jalmot :> es => DatumGrammar a -> a -> Eff es Datum
|
toDatum :: Jalmot :> es => DatumGrammar a -> a -> Eff es Datum
|
||||||
@@ -95,3 +96,8 @@ instance DatumIso a => DatumIso (List a) where
|
|||||||
instance DatumIso Bool where datumIso = boolean
|
instance DatumIso Bool where datumIso = boolean
|
||||||
|
|
||||||
instance DatumIso Int where datumIso = int
|
instance DatumIso Int where datumIso = int
|
||||||
|
|
||||||
|
instance DatumIso Datum where datumIso = Control.Category.id
|
||||||
|
|
||||||
|
instance DatumIso a => DataIso (List a) where
|
||||||
|
dataIso = onHead . traversed . sealed $ datumIso @a
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ prettyDatum depth datum = case datum of
|
|||||||
Ordinary; NSpecial _ -> pparen depth $
|
Ordinary; NSpecial _ -> pparen depth $
|
||||||
group . align . vsep $
|
group . align . vsep $
|
||||||
prettyDatum (depth+1) <$> xs
|
prettyDatum (depth+1) <$> xs
|
||||||
|
_ -> error [i|unimplemented: #{datum}|]
|
||||||
|
|
||||||
pparen depth = enclose (delim depth "(") (delim depth ")")
|
pparen depth = enclose (delim depth "(") (delim depth ")")
|
||||||
delim depth = annotate (SynParen depth)
|
delim depth = annotate (SynParen depth)
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
module Gyehoek.Sexp.QQ
|
||||||
|
( makeSxs
|
||||||
|
, makeSx
|
||||||
|
, makeSx'
|
||||||
|
, sx
|
||||||
|
, sxs
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Data (Typeable, cast)
|
||||||
|
import Gyehoek.Prelude
|
||||||
|
import Gyehoek.Sexp.Syntax
|
||||||
|
import Language.Haskell.TH
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import Data.List (groupBy)
|
||||||
|
import Language.Haskell.TH.Syntax (liftData, Lift (lift))
|
||||||
|
import Gyehoek.Jalmot
|
||||||
|
import Gyehoek.Sexp.Grammar
|
||||||
|
import Control.Exception (throw)
|
||||||
|
import Language.Haskell.TH.Quote (QuasiQuoter(..))
|
||||||
|
import Language.Haskell.TH.Syntax (dataToExpQ)
|
||||||
|
import qualified Gyehoek.Sexp.Read as Read
|
||||||
|
import Text.Megaparsec.Pos (mkPos)
|
||||||
|
import Gyehoek.Lift1
|
||||||
|
import Data.Foldable (toList)
|
||||||
|
|
||||||
|
|
||||||
|
extQ :: (Typeable a, Typeable b) => (a -> r) -> (b -> r) -> a -> r
|
||||||
|
extQ f g a = maybe (f a) g (cast a)
|
||||||
|
|
||||||
|
spliceMeta :: (HasCallStack, DataIso a) => a -> List Datum
|
||||||
|
spliceMeta x =
|
||||||
|
case runPureEff . runJalmot . toData dataIso $ x of
|
||||||
|
Left (cs,e) -> throw $ MkAJalmotCS cs e
|
||||||
|
Right xs -> xs
|
||||||
|
|
||||||
|
meta :: (HasCallStack, DatumIso a) => a -> Datum
|
||||||
|
meta x =
|
||||||
|
case runPureEff . runJalmot . toDatum datumIso $ x of
|
||||||
|
Left (cs,e) -> throw $ MkAJalmotCS cs e
|
||||||
|
Right xs -> xs
|
||||||
|
|
||||||
|
unquoteSplicingRecursive :: List Datum -> ExpQ
|
||||||
|
unquoteSplicingRecursive xs = [| mconcat $(spans) |]
|
||||||
|
where
|
||||||
|
spans = xs
|
||||||
|
& groupBy \cases
|
||||||
|
(MetaSplice _) _ -> False
|
||||||
|
_ (MetaSplice _) -> False
|
||||||
|
_ _ -> True
|
||||||
|
& fmap \case
|
||||||
|
[MetaSplice x] ->
|
||||||
|
[| spliceMeta $(varE (mkName (T.unpack x))) |]
|
||||||
|
es -> listE $ unquoteRecursive <$> es
|
||||||
|
& listE
|
||||||
|
|
||||||
|
unquoteRecursive :: Datum -> ExpQ
|
||||||
|
unquoteRecursive = \case
|
||||||
|
Meta x -> [| meta $(varE (mkName (T.unpack x))) |]
|
||||||
|
a :< CompoundF x -> [| $(liftData a) :< CompoundF $c|]
|
||||||
|
where
|
||||||
|
c = case x of
|
||||||
|
ListF ind xs ->
|
||||||
|
[| ListF $(lift ind) $(unquoteSplicingRecursive xs) |]
|
||||||
|
VectorF xs ->
|
||||||
|
[| VectorF $(unquoteSplicingRecursive xs) |]
|
||||||
|
DotListF xs t ->
|
||||||
|
[| DotListF $(liftLift unquoteRecursive xs) $(unquoteRecursive t) |]
|
||||||
|
AbbrevF p t ->
|
||||||
|
[| AbbrevF $(lift p) $(unquoteRecursive t) |]
|
||||||
|
e -> liftData e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
getPos :: Q SourcePos
|
||||||
|
getPos = do
|
||||||
|
Loc {loc_filename,loc_start} <- location
|
||||||
|
pure $ SourcePos
|
||||||
|
{ sourceName = loc_filename
|
||||||
|
, sourceLine = mkPos $ fst loc_start
|
||||||
|
, sourceColumn = mkPos $ snd loc_start
|
||||||
|
}
|
||||||
|
|
||||||
|
readq
|
||||||
|
:: (SourcePos -> Text -> Eff '[Jalmot, IOE] a)
|
||||||
|
-> String -> Q a
|
||||||
|
readq f s = do
|
||||||
|
pos <- getPos
|
||||||
|
liftIO . runJalmotIO . f pos . T.pack $ s
|
||||||
|
|
||||||
|
makeSxs :: Data r => Code Q (List Datum -> r) -> QuasiQuoter
|
||||||
|
makeSxs f = QuasiQuoter
|
||||||
|
{ quoteExp = \str -> do
|
||||||
|
xs <- readq Read.readStringWithPos str
|
||||||
|
let e = dataToExpQ
|
||||||
|
(const Nothing
|
||||||
|
`extQ` (Just . unquoteRecursive)
|
||||||
|
`extQ` (Just . unquoteSplicingRecursive))
|
||||||
|
xs
|
||||||
|
[| $(unTypeCode f) $e |]
|
||||||
|
, 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
|
||||||
|
x <- readq Read.readStringWithPos1 str
|
||||||
|
let e = dataToExpQ
|
||||||
|
(const Nothing
|
||||||
|
`extQ` (Just . unquoteRecursive)
|
||||||
|
`extQ` (Just . unquoteSplicingRecursive))
|
||||||
|
x
|
||||||
|
[| $f $e |]
|
||||||
|
, quotePat = undefined
|
||||||
|
, quoteType = undefined
|
||||||
|
, quoteDec = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
makeSx :: Data r => Code Q (Datum -> r) -> QuasiQuoter
|
||||||
|
makeSx = makeSx' . unTypeCode
|
||||||
|
|
||||||
|
sx, sxs :: QuasiQuoter
|
||||||
|
sxs = makeSxs [|| id @(List Datum) ||]
|
||||||
|
sx = makeSx [|| id @Datum ||]
|
||||||
@@ -2,6 +2,9 @@ module Gyehoek.Sexp.Read
|
|||||||
( readFile
|
( readFile
|
||||||
, readString
|
, readString
|
||||||
, readString1
|
, readString1
|
||||||
|
, SourcePos(..)
|
||||||
|
, readStringWithPos
|
||||||
|
, readStringWithPos1
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Text.Megaparsec
|
import Text.Megaparsec
|
||||||
@@ -34,10 +37,48 @@ readString s =
|
|||||||
|
|
||||||
readString1 :: Jalmot :> es => Text -> Eff es Datum
|
readString1 :: Jalmot :> es => Text -> Eff es Datum
|
||||||
readString1 s =
|
readString1 s =
|
||||||
case runParser (sc *> datum <* eof) "<none>" s of
|
case runParser file1 "<none>" s of
|
||||||
Right x -> pure x
|
Right x -> pure x
|
||||||
Left eb -> throwError . ReaderError $ eb
|
Left eb -> throwError . ReaderError $ eb
|
||||||
|
|
||||||
|
initialStateFromSourcePos :: SourcePos -> s -> State s e
|
||||||
|
initialStateFromSourcePos pos s = State
|
||||||
|
{ stateInput = s
|
||||||
|
, stateOffset = 0
|
||||||
|
, stateParseErrors = []
|
||||||
|
, statePosState = PosState
|
||||||
|
{ pstateInput = s
|
||||||
|
, pstateOffset = 0
|
||||||
|
, pstateSourcePos = pos
|
||||||
|
, pstateTabWidth = defaultTabWidth
|
||||||
|
, pstateLinePrefix = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readStringWithPos1
|
||||||
|
:: Jalmot :> es
|
||||||
|
=> SourcePos
|
||||||
|
-> Text
|
||||||
|
-> Eff es Datum
|
||||||
|
readStringWithPos1 pos s =
|
||||||
|
case snd $ runParser' file1 st of
|
||||||
|
Right x -> pure x
|
||||||
|
Left eb -> throwError . ReaderError $ eb
|
||||||
|
where
|
||||||
|
st = initialStateFromSourcePos pos s
|
||||||
|
|
||||||
|
readStringWithPos
|
||||||
|
:: Jalmot :> es
|
||||||
|
=> SourcePos
|
||||||
|
-> Text
|
||||||
|
-> Eff es (List Datum)
|
||||||
|
readStringWithPos pos s =
|
||||||
|
case snd $ runParser' file st of
|
||||||
|
Right x -> pure x
|
||||||
|
Left eb -> throwError . ReaderError $ eb
|
||||||
|
where
|
||||||
|
st = initialStateFromSourcePos pos s
|
||||||
|
|
||||||
type P = Parsec Void Text
|
type P = Parsec Void Text
|
||||||
|
|
||||||
|
|
||||||
@@ -134,16 +175,19 @@ string = label "string" . lexeme $
|
|||||||
|
|
||||||
metaSplice :: P Text
|
metaSplice :: P Text
|
||||||
metaSplice = label "splicing meta" . lexeme . between "##{" "}" $
|
metaSplice = label "splicing meta" . lexeme . between "##{" "}" $
|
||||||
takeWhileP Nothing (/= '}')
|
takeWhile1P Nothing (/= '}')
|
||||||
|
|
||||||
meta :: P Text
|
meta :: P Text
|
||||||
meta = label "meta" . lexeme . between "#{" "}" $
|
meta = label "meta" . lexeme . between "#{" "}" $
|
||||||
takeWhileP Nothing (/= '}')
|
takeWhile1P Nothing (/= '}')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
file :: P (List Datum)
|
file :: P (List Datum)
|
||||||
file = many datum <* eof
|
file = sc *> many datum <* eof
|
||||||
|
|
||||||
|
file1 :: P Datum
|
||||||
|
file1 = sc *> datum <* eof
|
||||||
|
|
||||||
datum :: P Datum
|
datum :: P Datum
|
||||||
datum = do
|
datum = do
|
||||||
@@ -153,6 +197,8 @@ datum = do
|
|||||||
, Simple <$> simpleDatum
|
, Simple <$> simpleDatum
|
||||||
-- , labeled
|
-- , labeled
|
||||||
-- , labelRef
|
-- , labelRef
|
||||||
|
, MetaSplice <$> metaSplice
|
||||||
|
, Meta <$> meta
|
||||||
]
|
]
|
||||||
|
|
||||||
simpleDatum :: P Simple
|
simpleDatum :: P Simple
|
||||||
@@ -163,8 +209,6 @@ simpleDatum = choice
|
|||||||
, SimpleString <$> string
|
, SimpleString <$> string
|
||||||
, SimpleSymbol <$> symbol
|
, SimpleSymbol <$> symbol
|
||||||
-- , SimpleBytevector <$> bytevector
|
-- , SimpleBytevector <$> bytevector
|
||||||
, SimpleMetaSplice <$> metaSplice
|
|
||||||
, SimpleMeta <$> meta
|
|
||||||
]
|
]
|
||||||
|
|
||||||
compoundDatum :: P Compound
|
compoundDatum :: P Compound
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ module Gyehoek.Sexp.Syntax
|
|||||||
, pattern Compound
|
, pattern Compound
|
||||||
, pattern Labeled
|
, pattern Labeled
|
||||||
, pattern LabelRef
|
, pattern LabelRef
|
||||||
|
, pattern Meta
|
||||||
|
, pattern MetaSplice
|
||||||
, pattern Abbrev
|
, pattern Abbrev
|
||||||
, pattern Vector
|
, pattern Vector
|
||||||
, pattern DotList
|
, pattern DotList
|
||||||
@@ -38,19 +40,26 @@ module Gyehoek.Sexp.Syntax
|
|||||||
, ann
|
, ann
|
||||||
, pattern List'
|
, pattern List'
|
||||||
, position
|
, position
|
||||||
|
, stripAnn
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Language.Haskell.TH.Syntax (Lift)
|
import Language.Haskell.TH.Syntax (Lift (lift), liftData)
|
||||||
import Data.Scientific (Scientific)
|
import Data.Scientific (Scientific)
|
||||||
import Data.ByteString (ByteString)
|
import Data.ByteString (ByteString)
|
||||||
import Gyehoek.Prelude hiding ((:<), Simple)
|
import Gyehoek.Prelude hiding ((:<), Simple)
|
||||||
import Text.Megaparsec.Pos (SourcePos(..), sourcePosPretty)
|
import Text.Megaparsec.Pos (SourcePos(..), sourcePosPretty)
|
||||||
import Control.Comonad.Cofree (Cofree((:<)), _extract)
|
import Control.Comonad.Cofree (Cofree((:<)), _extract, _unwrap)
|
||||||
import Data.Fix (Fix (..))
|
import Data.Fix (Fix (..))
|
||||||
import Data.Functor.Foldable
|
import Data.Functor.Foldable
|
||||||
import Text.Show.Deriving (deriveShow1)
|
import Text.Show.Deriving (deriveShow1)
|
||||||
|
import Data.Eq.Deriving (deriveEq1)
|
||||||
import qualified Control.Comonad.Trans.Cofree as F
|
import qualified Control.Comonad.Trans.Cofree as F
|
||||||
import Prettyprinter (Pretty (pretty), viaShow)
|
import Prettyprinter (Pretty (pretty), viaShow)
|
||||||
|
import Gyehoek.Lift1 (Lift1 (liftLift))
|
||||||
|
import Data.Data (Typeable, cast)
|
||||||
|
import Language.Haskell.TH
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import Control.Comonad.Trans.Cofree (tailF)
|
||||||
|
|
||||||
|
|
||||||
data DatumF a
|
data DatumF a
|
||||||
@@ -58,6 +67,8 @@ data DatumF a
|
|||||||
| CompoundF (CompoundF a)
|
| CompoundF (CompoundF a)
|
||||||
| LabeledF Label a
|
| LabeledF Label a
|
||||||
| LabelRefF Label
|
| LabelRefF Label
|
||||||
|
| MetaF Text
|
||||||
|
| MetaSpliceF Text
|
||||||
deriving stock (Show, Eq, Data, Generic, Lift, Functor, Foldable, Traversable)
|
deriving stock (Show, Eq, Data, Generic, Lift, Functor, Foldable, Traversable)
|
||||||
deriving anyclass (NFData)
|
deriving anyclass (NFData)
|
||||||
|
|
||||||
@@ -68,8 +79,6 @@ data Simple
|
|||||||
| SimpleString Text
|
| SimpleString Text
|
||||||
| SimpleSymbol Text
|
| SimpleSymbol Text
|
||||||
| SimpleBytevector ByteString
|
| SimpleBytevector ByteString
|
||||||
| SimpleMeta Text
|
|
||||||
| SimpleMetaSplice Text
|
|
||||||
deriving stock (Show, Eq, Data, Generic, Lift)
|
deriving stock (Show, Eq, Data, Generic, Lift)
|
||||||
deriving anyclass (NFData)
|
deriving anyclass (NFData)
|
||||||
|
|
||||||
@@ -135,10 +144,13 @@ noAnn = MkAnn
|
|||||||
instance Pretty Ann where
|
instance Pretty Ann where
|
||||||
pretty = pretty . maybe "<unknown>" sourcePosPretty . view #position
|
pretty = pretty . maybe "<unknown>" sourcePosPretty . view #position
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
deriveShow1 ''CompoundF
|
deriveShow1 ''CompoundF
|
||||||
|
deriveEq1 ''CompoundF
|
||||||
deriveShow1 ''DatumF
|
deriveShow1 ''DatumF
|
||||||
|
deriveEq1 ''DatumF
|
||||||
|
|
||||||
|
|
||||||
|
--- modification and extraction of annotations
|
||||||
|
|
||||||
ann :: Lens' Datum Ann
|
ann :: Lens' Datum Ann
|
||||||
ann = _extract
|
ann = _extract
|
||||||
@@ -161,6 +173,12 @@ adorn = set syntax
|
|||||||
indentWith :: Indentation -> Datum -> Datum
|
indentWith :: Indentation -> Datum -> Datum
|
||||||
indentWith = set indentation
|
indentWith = set indentation
|
||||||
|
|
||||||
|
stripAnn :: Datum -> Fix DatumF
|
||||||
|
stripAnn = hoist tailF
|
||||||
|
|
||||||
|
|
||||||
|
--- pattern synonyms
|
||||||
|
|
||||||
pattern Simple :: Simple -> Datum
|
pattern Simple :: Simple -> Datum
|
||||||
pattern Simple a <- _ :< SimpleF a
|
pattern Simple a <- _ :< SimpleF a
|
||||||
where Simple a = noAnn :< SimpleF a
|
where Simple a = noAnn :< SimpleF a
|
||||||
@@ -177,6 +195,14 @@ pattern LabelRef :: Label -> Datum
|
|||||||
pattern LabelRef l <- _ :< LabelRefF l
|
pattern LabelRef l <- _ :< LabelRefF l
|
||||||
where LabelRef l = noAnn :< LabelRefF l
|
where LabelRef l = noAnn :< LabelRefF l
|
||||||
|
|
||||||
|
pattern MetaSplice :: Text -> Datum
|
||||||
|
pattern MetaSplice x <- _ :< MetaSpliceF x
|
||||||
|
where MetaSplice x = noAnn :< MetaSpliceF x
|
||||||
|
|
||||||
|
pattern Meta :: Text -> Datum
|
||||||
|
pattern Meta x <- _ :< MetaF x
|
||||||
|
where Meta x = noAnn :< MetaF x
|
||||||
|
|
||||||
pattern List :: List Datum -> Datum
|
pattern List :: List Datum -> Datum
|
||||||
pattern List a <- _ :< CompoundF (ListF _ a)
|
pattern List a <- _ :< CompoundF (ListF _ a)
|
||||||
where List a = noAnn :< CompoundF (ListF Ordinary a)
|
where List a = noAnn :< CompoundF (ListF Ordinary a)
|
||||||
@@ -203,3 +229,22 @@ pattern Character a = Simple (SimpleCharacter a)
|
|||||||
pattern String a = Simple (SimpleString a)
|
pattern String a = Simple (SimpleString a)
|
||||||
pattern Symbol a = Simple (SimpleSymbol a)
|
pattern Symbol a = Simple (SimpleSymbol a)
|
||||||
pattern Bytevector a = Simple (SimpleBytevector a)
|
pattern Bytevector a = Simple (SimpleBytevector a)
|
||||||
|
|
||||||
|
|
||||||
|
--- Lift1 instances
|
||||||
|
|
||||||
|
instance Lift1 DatumF where
|
||||||
|
liftLift l = \case
|
||||||
|
SimpleF s -> [|SimpleF $(lift s)|]
|
||||||
|
CompoundF c -> [|CompoundF $(liftLift l c)|]
|
||||||
|
LabeledF lbl x -> [|LabeledF $(lift lbl) $(l x)|]
|
||||||
|
LabelRefF lbl -> [|LabelRefF $(lift lbl)|]
|
||||||
|
MetaF x -> [|MetaF $(lift x)|]
|
||||||
|
MetaSpliceF x -> [|MetaSpliceF $(lift x)|]
|
||||||
|
|
||||||
|
instance Lift1 CompoundF where
|
||||||
|
liftLift l = \case
|
||||||
|
ListF ind xs -> [|ListF $(lift ind) $(liftLift l xs)|]
|
||||||
|
DotListF xs t -> [|DotListF $(liftLift l xs) $(l t)|]
|
||||||
|
VectorF xs -> [|VectorF $(liftLift l xs)|]
|
||||||
|
AbbrevF p x -> [|AbbrevF $(lift p) $(l x)|]
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
module Gyehoek.Test.Sexp.QQ where
|
||||||
|
|
||||||
|
import Test.Tasty (TestTree, testGroup)
|
||||||
|
import Test.Tasty.HUnit
|
||||||
|
import Gyehoek.Sexp.QQ (sx)
|
||||||
|
import Data.Function (on)
|
||||||
|
import Gyehoek.Sexp.Syntax
|
||||||
|
import Data.Coerce (coerce)
|
||||||
|
|
||||||
|
|
||||||
|
newtype EquivDatum = MkEquiv Datum
|
||||||
|
deriving newtype (Show)
|
||||||
|
|
||||||
|
instance Eq EquivDatum where
|
||||||
|
(==) = (==) `on` (stripAnn . coerce)
|
||||||
|
|
||||||
|
assertEquiv
|
||||||
|
:: HasCallStack
|
||||||
|
=> String -> Datum -> Datum -> Assertion
|
||||||
|
assertEquiv prefix = assertEqual prefix `on` MkEquiv
|
||||||
|
|
||||||
|
equivto :: HasCallStack => Datum -> Datum -> Assertion
|
||||||
|
equivto = assertEquiv ""
|
||||||
|
|
||||||
|
test_qq :: TestTree
|
||||||
|
test_qq = testGroup "sexp quasiquoter"
|
||||||
|
[ testCase "quotation" do
|
||||||
|
equivto (Symbol "abc") [sx|abc|]
|
||||||
|
equivto (List [Symbol "a", 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 simple" do
|
||||||
|
equivto [sx|(a b c d e f g)|]
|
||||||
|
let metas = Symbol <$> ["c","d","e"]
|
||||||
|
in [sx|(a b ##{metas} f g)|]
|
||||||
|
, testCase "splicing multiple" do
|
||||||
|
equivto [sx|(a (b c d) e f g)|]
|
||||||
|
let
|
||||||
|
e1 = Symbol "c"
|
||||||
|
e2 = Symbol <$> ["e","f"]
|
||||||
|
in [sx|(a (b #{e1} d) ##{e2} g)|]
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user