swarm-0.7.0.0: src/swarm-lang/Swarm/Language/Parser/QQ.hs
-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- A quasiquoter for Swarm polytypes + untyped terms.
module Swarm.Language.Parser.QQ (tyQ, astQ) where
import Data.Generics
import Language.Haskell.TH qualified as TH
import Language.Haskell.TH.Quote
import Swarm.Language.Parser.Core (runParserTH)
import Swarm.Language.Parser.Lex (sc)
import Swarm.Language.Parser.Term (parseTerm)
import Swarm.Language.Parser.Type (parsePolytype)
import Swarm.Language.Parser.Util (fully)
import Swarm.Language.Syntax
import Swarm.Util (liftText)
import Witch (from)
------------------------------------------------------------
-- Quasiquoters
------------------------------------------------------------
-- | A quasiquoter for Swarm polytypes, so we can conveniently write them
-- down using concrete syntax and have them parsed into abstract
-- syntax at compile time. This is used, for example, in writing down
-- the concrete types of constants (see "Swarm.Language.Typecheck").
tyQ :: QuasiQuoter
tyQ =
QuasiQuoter
{ quoteExp = quoteTypeExp
, -- Using `error` is OK here since a quasiquoter will only ever run
-- at compile time; hence it can only make compilation fail, not
-- crash the game at runtime.
quotePat = error "quotePat not implemented for polytypes"
, quoteType = error "quoteType not implemented for polytypes"
, quoteDec = error "quoteDec not implemented for polytypes"
}
quoteTypeExp :: String -> TH.ExpQ
quoteTypeExp s = do
loc <- TH.location
parsed <- runParserTH loc (fully sc parsePolytype) s
dataToExpQ (fmap liftText . cast) parsed
astQ :: QuasiQuoter
astQ =
QuasiQuoter
{ quoteExp = quoteASTExp
, quotePat = error "quotePat not implemented for ASTs"
, quoteType = error "quoteType not implemented for ASTs"
, quoteDec = error "quoteDec not implemented for ASTs"
}
quoteASTExp :: String -> TH.ExpQ
quoteASTExp s = do
loc <- TH.location
parsed <- runParserTH loc (fully sc parseTerm) s
dataToExpQ ((fmap liftText . cast) `extQ` antiASTExp) parsed
antiASTExp :: Syntax -> Maybe TH.ExpQ
antiASTExp (STerm (TAntiSyn v)) = Just $ TH.varE (TH.mkName (from v))
antiASTExp _ = Nothing