packages feed

phino 0.0.82 → 0.0.83

raw patch · 20 files changed

+92/−71 lines, 20 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- CST: ETA :: META_HEAD
- CST: ETA' :: META_HEAD
- CST: H :: META_HEAD
- CST: INDEX :: ATTRIBUTE -> NUMBER
- CST: alphaToCST :: Alpha -> ATTRIBUTE
- Matcher: MvAlpha :: Alpha -> MetaValue
- Yaml: Index :: Alpha -> Number
+ CST: AT_ALPHA_META :: ALPHA -> META -> ATTRIBUTE
+ CST: I :: META_HEAD
+ CST: I' :: META_HEAD
+ CST: IDX_META :: META -> NUMBER
+ Matcher: MvIndex :: Int -> MetaValue
+ Parser: [_indexMeta] :: PhiParser -> Parser Text
+ Parser: parseIndexMeta :: String -> Either String Text
+ Yaml: MetaIndex :: Text -> Number
- Parser: PhiParser :: Parser Attribute -> Parser Alpha -> Parser Binding -> Parser Expression -> Parser String -> PhiParser
+ Parser: PhiParser :: Parser Attribute -> Parser Alpha -> Parser Text -> Parser Binding -> Parser Expression -> Parser String -> PhiParser

Files

README.md view
@@ -214,9 +214,9 @@ $ phino explain --normalize \begin{tabular}{rl} \trrule{alpha}-  { [[ B_1, \tau_1 -> ?, B_2 ]] ( \eta -> e ) }-  { [[ B_1, \tau_1 -> ?, B_2 ]] ( \tau_1 -> e ) }-  { if $ \indexof{ \eta } = \vert \overline{ B_1 } \vert $ }+  { [[ B_1, \tau -> ?, B_2 ]] ( \alpha_{i} -> e ) }+  { [[ B_1, \tau -> ?, B_2 ]] ( \tau -> e ) }+  { if $ i = \vert \overline{ B_1 } \vert $ }   { } \trrule{dc}   { T ( \tau -> e ) }@@ -318,7 +318,7 @@  Number:                  # comparable number   = Integer              # just regular integer-  | index: Alpha'        # calculate index of alpha+  | IndexMeta'           # 𝑖 (or !i), the index captured by an α𝑖 argument   | length: BiMeta'      # calculate length of bindings by given meta binding  Extension:               # substitutions extension used to introduce new meta variables@@ -377,7 +377,8 @@ This is the list of supported meta variables:  * `!a` || `𝜏` - attribute-* `!h` || `𝜂` - alpha, the positional index of an application argument+* `!i` || `𝑖` - the index of a positional (α) application argument,+                captured by writing `α𝑖` * `!e` || `𝑒` - any expression * `!n` || `𝑛` - any expression that is already in normal form (behaves like                 `!e`/`𝑒`, but only binds a sub-expression in NF, so no explicit
phino.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: phino-version: 0.0.82+version: 0.0.83 license: MIT synopsis: Command-Line Manipulator of 𝜑-Calculus Expressions description: Please see the README on GitHub at <https://github.com/objectionary/phino#readme>
resources/morphing.yaml view
@@ -50,8 +50,8 @@       normalize: '𝑒1(𝜏 ↦ 𝑒)'  - name: applicationa-  description: '𝕄(n(η ↦ e)) ⟿ 𝕄(𝒩(𝕄(n)(η ↦ e)))'-  match: '𝑛(𝜂 ↦ 𝑒)'+  description: '𝕄(n(α_i ↦ e)) ⟿ 𝕄(𝒩(𝕄(n)(α_i ↦ e)))'+  match: '𝑛(α𝑖 ↦ 𝑒)'   where:     - meta: 𝑒1       function: morph@@ -59,7 +59,7 @@         - 𝑛   then:     morph:-      normalize: '𝑒1(𝜂 ↦ 𝑒)'+      normalize: '𝑒1(α𝑖 ↦ 𝑒)'  - name: root   description: '𝕄(Φ) ⟿ 𝕄(𝒩(e)) where e := global(), unless e is Φ'
resources/normalize/alpha.yaml view
@@ -2,9 +2,9 @@ # SPDX-License-Identifier: MIT --- name: alpha-pattern: ⟦𝐵1, 𝜏1 ↦ ∅, 𝐵2⟧(𝜂 ↦ 𝑒)-result: ⟦𝐵1, 𝜏1 ↦ ∅, 𝐵2⟧(𝜏1 ↦ 𝑒)+pattern: ⟦𝐵1, 𝜏 ↦ ∅, 𝐵2⟧(α𝑖 ↦ 𝑒)+result: ⟦𝐵1, 𝜏 ↦ ∅, 𝐵2⟧(𝜏 ↦ 𝑒) when:   eq:-    - index: 𝜂+    - 𝑖     - domain: 𝐵1
resources/normalize/dca.yaml view
@@ -2,5 +2,5 @@ # SPDX-License-Identifier: MIT --- name: dca-pattern: ⊥(𝜂 ↦ 𝑒)+pattern: ⊥(α𝑖 ↦ 𝑒) result: ⊥
src/AST.hs view
@@ -77,7 +77,7 @@  instance Show Alpha where   show (Alpha idx) = 'α' : show idx-  show (AlMeta meta) = '!' : T.unpack meta+  show (AlMeta meta) = 'α' : '!' : T.unpack meta  -- A cheap, fixed-size digest of an expression, used for fast (dirty) equality -- checks during loop detection. Equal expressions always produce the same
src/Builder.hs view
@@ -71,7 +71,7 @@  buildAlpha :: Alpha -> Subst -> Built Alpha buildAlpha (AlMeta meta) (Subst mp) = case Map.lookup meta mp of-  Just (MvAlpha alpha) -> Right alpha+  Just (MvIndex idx) -> Right (Alpha idx)   _ -> Left (metaMsg meta) buildAlpha a _ = Right a 
src/CST.hs view
@@ -86,9 +86,8 @@   | A -- a   | TAU -- 𝜏   | TAU' -- \tau-  | ETA -- 𝜂-  | ETA' -- \eta-  | H -- h+  | I -- 𝑖+  | I' -- i   | B -- 𝐵   | B' -- B   | D -- δ@@ -175,6 +174,7 @@ data ATTRIBUTE   = AT_LABEL {label :: T.Text}   | AT_ALPHA {alpha :: ALPHA, idx :: Int}+  | AT_ALPHA_META {alpha :: ALPHA, meta :: META}   | AT_RHO {rho :: RHO}   | AT_PHI {phi :: PHI}   | AT_LAMBDA {lambda :: LAMBDA}@@ -204,7 +204,7 @@   deriving (Eq, Show)  data NUMBER-  = INDEX {attr :: ATTRIBUTE}+  = IDX_META {meta :: META}   | LENGTH {binding :: BINDING}   | DOMAIN {binding :: BINDING}   | LITERAL {num :: Int}@@ -262,9 +262,6 @@ attributeToCST :: Attribute -> ATTRIBUTE attributeToCST = toCST' -alphaToCST :: Alpha -> ATTRIBUTE-alphaToCST = toCST'- bindingsToCST :: [Binding] -> BINDING bindingsToCST = toCST' @@ -514,7 +511,7 @@  instance ToCST Alpha ATTRIBUTE where   toCST (Alpha idx) _ = AT_ALPHA ALPHA idx-  toCST (AlMeta mt) _ = AT_META (META NO_EXCL ETA (metaTail mt))+  toCST (AlMeta mt) _ = AT_ALPHA_META ALPHA (META NO_EXCL I (metaTail mt))  instance ToCST Y.Condition CONDITION where   toCST (Y.Not (Y.In attr binding)) _ = CO_BELONGS (attributeToCST attr) NOT_IN (ST_BINDING (bindingsToCST [binding]))@@ -541,7 +538,7 @@   toCST (Y.CmpNum num) _ = CMP_NUM (numberToCST num)  instance ToCST Y.Number NUMBER where-  toCST (Y.Index alpha) _ = INDEX (alphaToCST alpha)+  toCST (Y.MetaIndex mt) _ = IDX_META (META NO_EXCL I (metaTail mt))   toCST (Y.Length binding) _ = LENGTH (bindingsToCST [binding])   toCST (Y.Domain binding) _ = DOMAIN (bindingsToCST [binding])   toCST (Y.Literal num) _ = LITERAL num
src/Condition.hs view
@@ -49,11 +49,6 @@ number =   choice     [ do-        _ <- symbol "index" >> lparen-        alpha <- _alpha phiParser-        _ <- rparen-        return (Y.Index alpha)-    , do         _ <- symbol "length" >> lparen         bd <- _binding phiParser         _ <- rparen@@ -63,6 +58,7 @@         bd <- _binding phiParser         _ <- rparen         return (Y.Domain bd)+    , Y.MetaIndex <$> _indexMeta phiParser     , do         sign <- optional (choice [char '-', char '+'])         unsigned <- lexeme L.decimal
src/Encoding.hs view
@@ -70,9 +70,9 @@  instance ToASCII ATTRIBUTE where   toASCII AT_ALPHA{..} = AT_ALPHA ALPHA' idx+  toASCII AT_ALPHA_META{..} = AT_ALPHA_META ALPHA' (META EXCL I' (rest meta))   toASCII AT_PHI{} = AT_PHI AT   toASCII AT_RHO{} = AT_RHO CARET-  toASCII AT_META{meta = META{hd = ETA, ..}} = AT_META (META EXCL H rest)   toASCII AT_META{..} = AT_META (META EXCL A (rest meta))   toASCII attr = attr @@ -81,7 +81,7 @@   toASCII ST_ATTRIBUTES{..} = ST_ATTRIBUTES (map toASCII attrs)  instance ToASCII NUMBER where-  toASCII INDEX{..} = INDEX (toASCII attr)+  toASCII IDX_META{..} = IDX_META (META EXCL I' (rest meta))   toASCII LENGTH{..} = LENGTH (toASCII binding)   toASCII DOMAIN{..} = DOMAIN (toASCII binding)   toASCII literal@LITERAL{} = literal
src/LaTeX.hs view
@@ -167,6 +167,17 @@   let (progs, rules) = unzip rewrittens    in if _compress then zip (meetInPrograms progs ctx) rules else rewrittens +-- Compress a sequence of focused sub-expressions the way 'compressedRewrittens'+-- compresses whole programs: each expression is wrapped as a program so the+-- meet machinery factors recurring sub-expressions out across the sequence.+-- Focusing happens before this, so the meet never replaces a program root the+-- focus must still descend through.+compressedExpressions :: [Expression] -> LatexContext -> [Expression]+compressedExpressions exprs ctx@LatexContext{..} =+  if _compress then map unwrap (meetInPrograms (map Program exprs) ctx) else exprs+  where+    unwrap (Program expr) = expr+ rewrittensToLatex :: Rewrittens' -> LatexContext -> IO String rewrittensToLatex (rewrittens, exceeded) ctx@LatexContext{_focus = ExRoot} =   pure@@ -177,12 +188,12 @@         ]     ) rewrittensToLatex (rewrittens, exceeded) ctx@LatexContext{..} = do-  let (progs, rules) = unzip (compressedRewrittens rewrittens ctx)-  exprs <- mapM (locatedExpression _focus) progs+  let (progs, rules) = unzip rewrittens+  focused <- mapM (locatedExpression _focus) progs   pure     ( concat         [ preamble ctx-        , body (zip exprs rules) (\expr -> renderToLatex (expressionToCST expr) ctx)+        , body (zip (compressedExpressions focused ctx) rules) (\expr -> renderToLatex (expressionToCST expr) ctx)         , ending exceeded ctx         ]     )@@ -227,6 +238,7 @@  instance ToLaTeX ATTRIBUTE where   toLaTeX AT_LABEL{..} = AT_LABEL (piped label)+  toLaTeX AT_ALPHA_META{..} = AT_LABEL ("\\alpha_{" <> render (hd meta) <> rest meta <> "}")   toLaTeX AT_META{..} = AT_META (toLaTeX meta)   toLaTeX AT_LAMBDA{} = AT_LAMBDA LAMBDA'   toLaTeX AT_DELTA{} = AT_DELTA DELTA'@@ -271,8 +283,6 @@   toLaTeX K = K'   toLaTeX A = TAU'   toLaTeX TAU = TAU'-  toLaTeX ETA = ETA'-  toLaTeX H = ETA'   toLaTeX B = B'   toLaTeX D = D'   toLaTeX mh = mh@@ -302,7 +312,7 @@   toLaTeX ST_ATTRIBUTES{..} = ST_ATTRIBUTES (map toLaTeX attrs)  instance ToLaTeX NUMBER where-  toLaTeX INDEX{..} = INDEX (toLaTeX attr)+  toLaTeX IDX_META{..} = IDX_META (toLaTeX meta)   toLaTeX LENGTH{..} = LENGTH (toLaTeX binding)   toLaTeX DOMAIN{..} = DOMAIN (toLaTeX binding)   toLaTeX literal@LITERAL{} = literal
src/Matcher.hs view
@@ -15,7 +15,7 @@ -- The right part of substitution data MetaValue   = MvAttribute Attribute -- !a-  | MvAlpha Alpha -- !h+  | MvIndex Int -- α𝑖   | MvBytes Bytes -- !b   | MvBindings [Binding] -- !B   | MvFunction Text -- !F@@ -62,7 +62,7 @@   | otherwise = []  matchAlpha :: Alpha -> Alpha -> [Subst]-matchAlpha (AlMeta meta) tgt = [substSingle meta (MvAlpha tgt)]+matchAlpha (AlMeta meta) (Alpha idx) = [substSingle meta (MvIndex idx)] matchAlpha ptn tgt   | ptn == tgt = [substEmpty]   | otherwise = []
src/Parser.hs view
@@ -13,6 +13,7 @@   , parseAttribute   , parseAttributeThrows   , parseAlpha+  , parseIndexMeta   , parseNumber   , parseNumberThrows   , parseBinding@@ -49,13 +50,14 @@ data PhiParser = PhiParser   { _attribute :: Parser Attribute   , _alpha :: Parser Alpha+  , _indexMeta :: Parser T.Text   , _binding :: Parser Binding   , _expression :: Parser Expression   , _string :: Parser String   }  phiParser :: PhiParser-phiParser = PhiParser attribute alpha binding expression quotedStr+phiParser = PhiParser attribute alpha indexMeta binding expression quotedStr  instance Show ParserException where   show CouldNotParseProgram{..} = printf "Couldn't parse given phi program, cause: %s" message@@ -132,7 +134,7 @@   choice     [ meta ch     , do-        _ <- symbol uni+        _ <- string uni         suf <- metaSuffix         return (T.pack (ch : suf))     ]@@ -330,16 +332,19 @@     ]     <?> "attribute" +-- index meta: !i, 𝑖+indexMeta :: Parser T.Text+indexMeta = meta' 'i' "𝑖"+ -- alpha -- 1. index: ~0, α0--- 2. meta: !h, 𝜂+-- 2. meta: α𝑖, ~!i alpha :: Parser Alpha-alpha =+alpha = do+  _ <- choice [symbol "~", symbol "α"]   choice-    [ do-        _ <- choice [symbol "~", symbol "α"]-        Alpha <$> lexeme L.decimal-    , AlMeta <$> meta' 'h' "𝜂"+    [ Alpha <$> lexeme L.decimal+    , AlMeta <$> indexMeta     ]     <?> "alpha" @@ -498,6 +503,9 @@  parseAlpha :: String -> Either String Alpha parseAlpha = parse' "alpha" alpha++parseIndexMeta :: String -> Either String T.Text+parseIndexMeta = parse' "index meta" indexMeta  parseAttributeThrows :: String -> IO Attribute parseAttributeThrows attr = case parseAttribute attr of
src/Printer.hs view
@@ -91,7 +91,7 @@  printMetaValue :: MetaValue -> PrintConfig -> String printMetaValue (MvAttribute att) (_, encoding, _, _) = printAttribute' att encoding-printMetaValue (MvAlpha index) (_, encoding, _, _) = printAlpha' index encoding+printMetaValue (MvIndex index) _ = show index printMetaValue (MvExpression ex) config = printExpression' ex config printMetaValue (MvBytes bts) _ = printBytes bts printMetaValue (MvBindings bds) config = printExpression' (ExFormation bds) config
src/Render.hs view
@@ -120,9 +120,8 @@   render A = "a"   render TAU = "𝜏"   render TAU' = "\\tau"-  render ETA = "𝜂"-  render ETA' = "\\eta"-  render H = "h"+  render I = "𝑖"+  render I' = "i"   render B = "𝐵"   render B' = "B"   render D = "δ"@@ -207,6 +206,7 @@ instance Render ATTRIBUTE where   render AT_LABEL{..} = render label   render AT_ALPHA{..} = render alpha <> render idx+  render AT_ALPHA_META{..} = render alpha <> render meta   render AT_RHO{..} = render rho   render AT_PHI{..} = render phi   render AT_LAMBDA{..} = render lambda@@ -227,7 +227,7 @@   render OR = "\\;\\text{or}\\;"  instance Render NUMBER where-  render INDEX{..} = "\\indexof{ " <> render attr <> " }"+  render IDX_META{..} = render meta   render LENGTH{..} = "\\vert " <> render binding <> " \\vert"   render DOMAIN{..} = "\\vert \\overline{ " <> render binding <> " } \\vert"   render LITERAL{..} = T.pack (show num)
src/Rule.hs view
@@ -117,10 +117,9 @@   where     -- Convert Number to Int     numToInt :: Y.Number -> Subst -> Maybe Int-    numToInt (Y.Index (AlMeta meta)) (Subst mp) = case M.lookup meta mp of-      Just (MvAlpha (Alpha idx)) -> Just idx+    numToInt (Y.MetaIndex meta) (Subst mp) = case M.lookup meta mp of+      Just (MvIndex idx) -> Just idx       _ -> Nothing-    numToInt (Y.Index (Alpha idx)) _ = Just idx     numToInt (Y.Length (BiMeta meta)) (Subst mp) = case M.lookup meta mp of       Just (MvBindings bds) -> Just (length bds)       _ -> Nothing
src/Yaml.hs view
@@ -15,7 +15,7 @@ import Data.Aeson import qualified Data.ByteString as BS import Data.FileEmbed (embedDir, embedFile)-import Data.Text (unpack)+import Data.Text (Text, unpack) import Data.Yaml (Parser) import qualified Data.Yaml as Yaml import GHC.Generics (Generic)@@ -58,15 +58,17 @@ instance FromJSON Number where   parseJSON v = case v of     Object o -> do-      validateYamlObject o ["index", "length", "domain"]+      validateYamlObject o ["length", "domain"]       asum-        [ Index <$> o .: "index"-        , Length <$> o .: "length"+        [ Length <$> o .: "length"         , Domain <$> o .: "domain"         ]     Number num -> pure (Literal (round num))+    String txt -> case parseIndexMeta (unpack txt) of+      Right mt -> pure (MetaIndex mt)+      Left err -> fail err     _ ->-      fail "Expected a numerable expression (object or number)"+      fail "Expected a numerable expression (object, number or index meta)"  instance FromJSON Comparable where   parseJSON v =@@ -149,7 +151,7 @@         }  data Number-  = Index Alpha+  = MetaIndex Text   | Length Binding   | Domain Binding   | Literal Int
test/CLISpec.hs view
@@ -874,6 +874,12 @@               ]           ] +    it "focuses a compressed sequence whose meet replaces a step root" $+      withStdin "{[[ @ -> [[ @ -> $.c.plus( 32.0 ), c -> 25.0 ]], bytes(data) -> [[ @ -> $.data ]], number(as-bytes) -> [[ @ -> $.as-bytes, plus -> [[ x -> ?, L> L_number_plus ]] ]] ]]}" $+        testCLISucceeded+          ["dataize", "--output=latex", "--sweet", "--nonumber", "--compress", "--canonize", "--meet-prefix=dataization", "--sequence", "--flat", "--quiet", "--hide=Q.bytes", "--hide=Q.number", "--locator=Q.@", "--focus=Q.@", "--meet-length=5", "--meet-popularity=1"]+          ["\\phiMeet{dataization:1}{ [[ @ -> |c| . |plus| ( 32 ), |c| -> 25 ]] } \\leadsto_{\\nameref{r:contextualize}}"]+     it "dataizes with --locator" $       withStdin "{[[ ex -> [[ @ -> Q.x ]], x -> [[ D> 42- ]] ]]}" $         testCLISucceeded ["dataize", "--locator=Q.ex"] ["42-"]@@ -945,9 +951,9 @@         [ unlines             [ "\\begin{tabular}{rl}"             , "\\trrule{alpha}"-            , "  { [[ B_1, \\tau_1 -> ?, B_2 ]] ( \\eta -> e ) }"-            , "  { [[ B_1, \\tau_1 -> ?, B_2 ]] ( \\tau_1 -> e ) }"-            , "  { if $ \\indexof{ \\eta } = \\vert \\overline{ B_1 } \\vert $ }"+            , "  { [[ B_1, \\tau -> ?, B_2 ]] ( \\alpha_{i} -> e ) }"+            , "  { [[ B_1, \\tau -> ?, B_2 ]] ( \\tau -> e ) }"+            , "  { if $ i = \\vert \\overline{ B_1 } \\vert $ }"             , "  { }"             , "\\trrule{copy}"             , "  { [[ B_1, \\tau -> ?, B_2 ]] ( \\tau -> k ) }"@@ -960,7 +966,7 @@             , "  { }"             , "  { }"             , "\\trrule{dca}"-            , "  { T ( \\eta -> e ) }"+            , "  { T ( \\alpha_{i} -> e ) }"             , "  { T }"             , "  { }"             , "  { }"@@ -1034,8 +1040,8 @@             , "  { }"             , "  { where $ e_1 \\coloneqq morph( n ) $ }"             , "\\trrule{applicationa}"-            , "  { \\mathbb{M}( n ( \\eta -> e ) ) }"-            , "  { \\mathbb{M}( \\mathcal{N}( e_1 ( \\eta -> e ) ) ) }"+            , "  { \\mathbb{M}( n ( \\alpha_{i} -> e ) ) }"+            , "  { \\mathbb{M}( \\mathcal{N}( e_1 ( \\alpha_{i} -> e ) ) ) }"             , "  { }"             , "  { where $ e_1 \\coloneqq morph( n ) $ }"             , "\\trrule{root}"
test/ConditionSpec.hs view
@@ -5,7 +5,7 @@  module ConditionSpec where -import AST (Alpha (AlMeta, Alpha), Attribute (AtLabel, AtMeta), Binding (BiMeta), Expression (ExDispatch, ExMeta, ExRoot))+import AST (Attribute (AtLabel, AtMeta), Binding (BiMeta), Expression (ExDispatch, ExMeta, ExRoot)) import Condition import Control.Monad (forM_) import Data.Either (isLeft, isRight)@@ -19,7 +19,7 @@       [ "in (!a, !B)"       , " not   (in (!a1,   !B))   "       , "eq(1, 1)"-      , "or(eq(index(~0),1),eq(length(!B),-2),eq(!e1,!e2),eq(!a1,x),eq(Q.org.eolang,[[ x -> 2 ]]))"+      , "or(eq(!i,1),eq(length(!B),-2),eq(!e1,!e2),eq(!a1,x),eq(Q.org.eolang,[[ x -> 2 ]]))"       , "nf([[ x -> !e ]].x)"       , "absolute(!e1)"       , "matches(\"hello(\\\"\\u0000)\", !e)"@@ -32,8 +32,8 @@       [ ("in(!a, !B)", Y.In (AtMeta "a") (BiMeta "B"))       , ("not(in(!a,!B))", Y.Not (Y.In (AtMeta "a") (BiMeta "B")))       , ("eq(1,-2)", Y.Eq (Y.CmpNum (Y.Literal 1)) (Y.CmpNum (Y.Literal (-2))))-      , ("eq(index(α0),length(!B1))", Y.Eq (Y.CmpNum (Y.Index (Alpha 0))) (Y.CmpNum (Y.Length (BiMeta "B1"))))-      , ("eq(index(!h),domain(!B1))", Y.Eq (Y.CmpNum (Y.Index (AlMeta "h"))) (Y.CmpNum (Y.Domain (BiMeta "B1"))))+      , ("eq(!i,length(!B1))", Y.Eq (Y.CmpNum (Y.MetaIndex "i")) (Y.CmpNum (Y.Length (BiMeta "B1"))))+      , ("eq(!i2,domain(!B1))", Y.Eq (Y.CmpNum (Y.MetaIndex "i2")) (Y.CmpNum (Y.Domain (BiMeta "B1"))))       , ("eq(!a1, !e2)", Y.Eq (Y.CmpAttr (AtMeta "a1")) (Y.CmpExpr (ExMeta "e2")))       , ("or(absolute(!e1), nf(Q.x))", Y.Or [Y.Absolute (ExMeta "e1"), Y.NF (ExDispatch ExRoot (AtLabel "x"))])       , ("and(matches(\"hi\", !e),part-of(!e, !B))", Y.And [Y.Matches "hi" (ExMeta "e"), Y.PartOf (ExMeta "e") (BiMeta "B")])
test/ParserSpec.hs view
@@ -207,6 +207,8 @@       , "[[ x -> \"\\uD835\\uDF11\"]]"       , "[[ x ↦ \"This plugin has \\x01\\x01\" ]]"       , "[[ !afoo -> !e1Some, !a-BAR -> !e_123someW, !Bhi123 ]]"+      , "[[ !B ]](α𝑖 -> !e)"+      , "[[ 𝜏 -> !e, 𝐵 ]]"       ]       (\expr -> it expr (parseExpression expr `shouldSatisfy` isRight))