packages feed

phino 0.0.0.57 → 0.0.0.58

raw patch · 18 files changed

+139/−854 lines, 18 filesdep +hlintdep ~aesondep ~arraydep ~base

Dependencies added: hlint

Dependency ranges changed: aeson, array, base, binary-ieee754, bytestring, containers, directory, filepath, hspec, hspec-core, megaparsec, optparse-applicative, process, random, regex-pcre-builtin, scientific, silently, text, transformers, utf8-string, vector, yaml

Files

README.md view
@@ -29,7 +29,7 @@  ```bash cabal update-cabal install --overwrite-policy=always phino-0.0.0.56+cabal install --overwrite-policy=always phino-0.0.0.57 phino --version ``` @@ -139,9 +139,9 @@ ```bash $ echo 'Q -> [[ @ -> QQ.io.stdout("hello") ]]' | phino rewrite Φ ↦ ⟦-  φ ↦ Φ.org.eolang.io.stdout(-    α0 ↦ Φ.org.eolang.string(-      α0 ↦ Φ.org.eolang.bytes(+  φ ↦ Φ.io.stdout(+    α0 ↦ Φ.string(+      α0 ↦ Φ.bytes(         α0 ↦ ⟦ Δ ⤍ 68-65-6C-6C-6F ⟧       )     )@@ -309,7 +309,7 @@ * `concat` - accepts bytes or dataizable expressions as arguments,   concatenates them into single sequence and convert it to expression   that can be pretty printed as human readable string:-  `Φ.org.eolang.string(Φ.org.eolang.bytes⟦ Δ ⤍ !d ⟧)`.+  `Φ.string(Φ.bytes⟦ Δ ⤍ !d ⟧)`. * `sed` - pattern replacer, works like unix `sed` function.   Accepts two arguments: target expression and pattern.   Pattern must start with `s/`, consists of three parts
phino.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: phino-version: 0.0.0.57+version: 0.0.0.58 license: MIT synopsis: Command-Line Manipulator of 𝜑-Calculus Expressions description: Please see the README on GitHub at <https://github.com/objectionary/phino#readme>@@ -73,27 +73,27 @@     Paths_phino    build-depends:-    aeson,-    array,+    aeson ^>=2.2.3.0,+    array ^>=0.5.8.0,     base >=4.18.3.0 && <5,-    binary-ieee754,-    bytestring,-    containers,-    directory,+    binary-ieee754 ^>=0.1.0.0,+    bytestring ^>=0.11.5.4,+    containers ^>=0.6.7,+    directory ^>=1.3.8.5,     file-embed ^>=0.0.16.0,-    filepath,-    megaparsec >=9.0,-    optparse-applicative,-    random,-    regex-pcre-builtin,-    scientific,-    text,+    filepath ^>=1.4.301.0,+    megaparsec ^>=9.7.0,+    optparse-applicative ^>=0.19.0.0,+    random >=1.2 && <1.4,+    regex-pcre-builtin ^>=0.95.2.3.8.44,+    scientific ^>=0.3.8.0,+    text ^>=2.0.2,     time ^>=1.12,-    transformers,-    utf8-string,-    vector,+    transformers ^>=0.6.1.0,+    utf8-string ^>=1.0.2,+    vector ^>=0.13.2.0,     xml-conduit ^>=1.10,-    yaml,+    yaml ^>=0.11.11.2,    default-language: Haskell2010 @@ -139,7 +139,6 @@     RewriterSpec     RuleSpec     Spec-    SugarSpec     XMIRSpec     YamlSpec @@ -150,22 +149,23 @@     ImportQualifiedPost    build-depends:-    aeson,-    base,-    bytestring,-    containers,-    directory,-    filepath,-    hspec,-    hspec-core,-    megaparsec,-    optparse-applicative,+    aeson ^>=2.2.3.0,+    base >=4.18.3.0 && <5,+    bytestring ^>=0.11.5.4,+    containers ^>=0.6.7,+    directory ^>=1.3.8.5,+    filepath ^>=1.4.301.0,+    hlint ^>=3.8,+    hspec ^>=2.11.16,+    hspec-core ^>=2.11.16,+    megaparsec ^>=9.7.0,+    optparse-applicative ^>=0.19.0.0,     phino,-    process,-    silently,-    text,+    process ^>=1.6.19.0,+    silently ^>=1.2.5.4,+    text ^>=2.0.2,     xml-conduit ^>=1.10,-    yaml,+    yaml ^>=0.11.11.2,    build-tool-depends:     hspec-discover:hspec-discover
src/CST.hs view
@@ -143,7 +143,6 @@  data EXPRESSION   = EX_GLOBAL {global :: GLOBAL}-  | EX_DEF_PACKAGE {pckg :: DEF_PACKAGE} -- sugar for Q.org.eolang   | EX_XI {xi :: XI}   | EX_ATTR {attr :: ATTRIBUTE} -- sugar for $.x -> just x   | EX_TERMINATION {termination :: TERMINATION}@@ -214,7 +213,6 @@       withoutLastVoidRho (bd : bds') = bd : withoutLastVoidRho bds'   toCST (DataString bts) tabs _ = EX_STRING (btsToStr bts) (TAB tabs) []   toCST (DataNumber bts) tabs _ = EX_NUMBER (btsToNum bts) (TAB tabs) []-  toCST (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang")) _ _ = EX_DEF_PACKAGE Φ̇   toCST (ExDispatch ExThis attr) tabs eol = EX_ATTR (toCST attr tabs eol)   toCST (ExDispatch expr attr) tabs eol = EX_DISPATCH (toCST expr tabs eol) (toCST attr tabs eol)   -- Since we convert AST to CST in sweet notation, here we're trying to get rid of unnecessary rho bindings
src/Dataize.hs view
@@ -99,7 +99,6 @@ -- Tail MUST start with dispatch, that's why most of the applications return Nothing withTail :: Expression -> DataizeContext -> IO (Maybe (Expression, String)) withTail (ExApplication (ExFormation _) _) _ = pure Nothing-withTail (ExApplication (ExDispatch ExGlobal _) _) _ = pure Nothing withTail (ExApplication expr tau) ctx = do   tailed <- withTail expr ctx   case tailed of@@ -111,10 +110,6 @@     Just (obj, rule) -> pure (Just (ExDispatch obj attr, rule))     _ -> pure Nothing withTail (ExFormation bds) ctx = formation bds ctx-withTail (ExDispatch (ExDispatch ExGlobal (AtLabel label)) attr) DataizeContext{_program = Program expr} =-  case phiDispatch label expr of-    Just (obj, rule) -> pure (Just (ExDispatch obj attr, rule))-    _ -> pure Nothing withTail (ExDispatch ExGlobal (AtLabel label)) DataizeContext{_program = Program expr} = pure (phiDispatch label expr) withTail (ExDispatch expr attr) ctx = do   tailed <- withTail expr ctx@@ -214,7 +209,7 @@ _dataize _ _ = throwIO (userError "Can't call _dataize from atoms with non-formation program")  atom :: String -> Expression -> DataizeContext -> IO Expression-atom "L_org_eolang_number_plus" self ctx = do+atom "L_number_plus" self ctx = do   left <- _dataize (ExDispatch self (AtLabel "x")) ctx   right <- _dataize (ExDispatch self AtRho) ctx   case (left, right) of@@ -224,7 +219,7 @@           sum = first + second       pure (DataNumber (numToBts sum))     _ -> pure ExTermination-atom "L_org_eolang_number_times" self ctx = do+atom "L_number_times" self ctx = do   left <- _dataize (ExDispatch self (AtLabel "x")) ctx   right <- _dataize (ExDispatch self AtRho) ctx   case (left, right) of@@ -234,7 +229,7 @@           sum = first * second       pure (DataNumber (numToBts sum))     _ -> pure ExTermination-atom "L_org_eolang_number_eq" self ctx = do+atom "L_number_eq" self ctx = do   x <- _dataize (ExDispatch self (AtLabel "x")) ctx   rho <- _dataize (ExDispatch self AtRho) ctx   case (x, rho) of
src/Encoding.hs view
@@ -23,7 +23,6 @@  instance ToASCII EXPRESSION where   toASCII EX_GLOBAL{} = EX_GLOBAL Q-  toASCII EX_DEF_PACKAGE{} = EX_DEF_PACKAGE QQ   toASCII EX_XI{} = EX_XI DOLLAR   toASCII EX_ATTR{..} = EX_ATTR (toASCII attr)   toASCII EX_TERMINATION{} = EX_TERMINATION T
src/LaTeX.hs view
@@ -137,7 +137,7 @@                 )                 rewrittens'             )-        , printf ".\n\\end{%s}" equation+        , printf "{.}\n\\end{%s}" equation         ]  programToLaTeX :: Program -> LatexContext -> String
src/Misc.hs view
@@ -76,30 +76,40 @@   show DirectoryDoesNotExist{..} = printf "Directory '%s' does not exist" _dir  matchBaseObject :: Expression -> Maybe String-matchBaseObject (ExDispatch (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang")) (AtLabel label)) = Just label+matchBaseObject (ExDispatch ExGlobal (AtLabel label)) = Just label matchBaseObject _ = Nothing  pattern BaseObject :: String -> Expression pattern BaseObject label <- (matchBaseObject -> Just label)   where-    BaseObject label = ExDispatch (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang")) (AtLabel label)+    BaseObject label = ExDispatch ExGlobal (AtLabel label)  -- Minimal matcher function (required for view pattern) matchDataObject :: Expression -> Maybe (String, Bytes)-matchDataObject-  ( ExApplication-      (BaseObject label)-      ( BiTau-          (AtAlpha 0)-          ( ExApplication-              (BaseObject "bytes")-              ( BiTau-                  (AtAlpha 0)-                  (ExFormation [BiDelta bts, BiVoid AtRho])-                )-            )-        )-    ) = Just (label, bts)+matchDataObject (ExApplication outer (BiTau (AtAlpha 0) inner)) = case (matchOuter outer, matchInner inner) of+  (Just label, Just bts) -> Just (label, bts)+  _ -> Nothing+  where+    matchOuter :: Expression -> Maybe String+    matchOuter (BaseObject label) = Just label+    matchOuter (ExPhiAgain _ _ (BaseObject label)) = Just label+    matchOuter _ = Nothing+    matchInner :: Expression -> Maybe Bytes+    matchInner (ExPhiAgain _ _ inner') = matchInner inner'+    matchInner inner' = matchInner' inner'+    matchInner' :: Expression -> Maybe Bytes+    matchInner' (ExApplication bytes (BiTau (AtAlpha 0) formation)) = case (matchesBytes bytes, matchFormation formation) of+      (True, Just bts) -> Just bts+      _ -> Nothing+    matchInner' _ = Nothing+    matchesBytes :: Expression -> Bool+    matchesBytes (BaseObject "bytes") = True+    matchesBytes (ExPhiAgain _ _ (BaseObject "bytes")) = True+    matchesBytes _ = False+    matchFormation :: Expression -> Maybe Bytes+    matchFormation (ExFormation [BiDelta bts, BiVoid AtRho]) = Just bts+    matchFormation (ExPhiAgain _ _ (ExFormation [BiDelta bts, BiVoid AtRho])) = Just bts+    matchFormation _ = Nothing matchDataObject _ = Nothing  pattern DataString :: Bytes -> Expression
src/Parser.hs view
@@ -373,9 +373,6 @@     , do         _ <- choice [symbol "$", symbol "ξ"]         return ExThis-    , try $ do-        _ <- choice [symbol "QQ", symbol "Φ̇"]-        return (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang"))     , do         _ <- global         return ExGlobal
src/Render.hs view
@@ -163,7 +163,6 @@  instance Render EXPRESSION where   render EX_GLOBAL{..} = render global-  render EX_DEF_PACKAGE{..} = render pckg   render EX_XI{..} = render xi   render EX_ATTR{..} = render attr   render EX_TERMINATION{..} = render termination
src/Sugar.hs view
@@ -43,7 +43,6 @@ --  | sugar                      | verbose version                                       | --  |----------------------------|-------------------------------------------------------| --  | {e}                        | Q -> e                                                |---  | QQ                         | Q.org.eolang                                          | --  | a1 -> a2                   | a1 ↦ $.a2                                             | --  | a -> 42                    | QQ.number(QQ.bytes([[ D> 40-45-00-00-00-00-00-00 ]])) | --  | a -> "Hey"                 | QQ.number(QQ.bytes([[ D> 48-65-79 ]]))                |@@ -60,7 +59,6 @@   toSalty prog = prog  instance ToSalty EXPRESSION where-  toSalty EX_DEF_PACKAGE{} = EX_DISPATCH (EX_DISPATCH (EX_GLOBAL Φ) (AT_LABEL "org")) (AT_LABEL "eolang")   toSalty EX_ATTR{..} = EX_DISPATCH (EX_XI XI) attr   toSalty EX_DISPATCH{..} = EX_DISPATCH (toSalty expr) attr   toSalty EX_FORMATION{lsb, binding = bd@BI_EMPTY{}, rsb} = EX_FORMATION lsb NO_EOL TAB' (toSalty (bdWithVoidRho bd)) NO_EOL TAB' rsb
src/XMIR.hs view
@@ -101,10 +101,10 @@ expression (DataNumber bytes) XmirContext{..} =   let bts =         object-          [("as", printAttribute (AtAlpha 0)), ("base", "Φ.org.eolang.bytes")]+          [("as", printAttribute (AtAlpha 0)), ("base", "Φ.bytes")]           [object [] [NodeContent (T.pack (printBytes bytes))]]    in pure-        ( "Φ.org.eolang.number"+        ( "Φ.number"         , if omitComments             then [bts]             else@@ -115,10 +115,10 @@ expression (DataString bytes) XmirContext{..} =   let bts =         object-          [("as", printAttribute (AtAlpha 0)), ("base", "Φ.org.eolang.bytes")]+          [("as", printAttribute (AtAlpha 0)), ("base", "Φ.bytes")]           [object [] [NodeContent (T.pack (printBytes bytes))]]    in pure-        ( "Φ.org.eolang.string"+        ( "Φ.string"         , if omitComments             then [bts]             else
test/CLISpec.hs view
@@ -261,11 +261,11 @@     it "desugares without any rules flag from file" $       testCLISucceeded         ["rewrite", resource "desugar.phi"]-        ["Φ ↦ ⟦\n  foo ↦ Φ.org.eolang,\n  ρ ↦ ∅\n⟧"]+        ["Φ ↦ ⟦\n  foo ↦ ξ.x,\n  ρ ↦ ∅\n⟧"]      it "desugares with without any rules flag from stdin" $-      withStdin "{[[foo ↦ QQ]]}" $-        testCLISucceeded ["rewrite"] ["Φ ↦ ⟦\n  foo ↦ Φ.org.eolang,\n  ρ ↦ ∅\n⟧"]+      withStdin "{[[foo ↦ x]]}" $+        testCLISucceeded ["rewrite"] ["Φ ↦ ⟦\n  foo ↦ ξ.x,\n  ρ ↦ ∅\n⟧"]      it "rewrites with single rule" $       withStdin "{T(x -> Q.y)}" $@@ -315,12 +315,12 @@           ["<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "<object", "  <o base=\"Φ.y\" name=\"x\"/>"]      it "rewrites as LaTeX" $-      withStdin "Q -> [[ x_o -> QQ.z(y -> 5), q$ -> T, w -> $, ^ -> Q, @ -> 1, y -> \"H$@^M\", L> Fu_nc ]]" $+      withStdin "Q -> [[ x_o -> Q.z(y -> 5), q$ -> T, w -> $, ^ -> Q, @ -> 1, y -> \"H$@^M\", L> Fu_nc ]]" $         testCLISucceeded           ["rewrite", "--output=latex", "--sweet"]           [ "\\begin{phiquation}"           , "\\Big\\{[[\n"-          , "  |x\\char95{}o| -> QQ.|z|( |y| -> 5 ),\n"+          , "  |x\\char95{}o| -> Q.|z|( |y| -> 5 ),\n"           , "  |q\\char36{}| -> T,\n"           , "  |w| -> $,\n"           , "  ^ -> Q,\n"@@ -345,7 +345,7 @@         testCLISucceeded           ["rewrite", "--output=latex", "--sweet", "--flat", "--expression=foo"]           [ "\\begin{phiquation}"-          , "\\phiExpression{foo} \\Big\\{[[ |x| -> 5 ]]\\Big\\}.\n"+          , "\\phiExpression{foo} \\Big\\{[[ |x| -> 5 ]]\\Big\\}{.}\n"           , "\\end{phiquation}"           ] @@ -354,7 +354,7 @@         testCLISucceeded           ["rewrite", "--output=latex", "--sweet", "--flat", "--label=foo"]           [ "\\begin{phiquation}\n\\label{foo}\n"-          , "\\Big\\{[[ |x| -> 5 ]]\\Big\\}.\n"+          , "\\Big\\{[[ |x| -> 5 ]]\\Big\\}{.}\n"           , "\\end{phiquation}"           ] @@ -419,7 +419,7 @@               [ "\\begin{phiquation}"               , "\\Big\\{[[ |x| -> \"foo\" ]]\\Big\\} \\leadsto_{\\nameref{r:first}}"               , "  \\leadsto \\Big\\{Q.|x|( |y| -> \"foo\" )\\Big\\} \\leadsto_{\\nameref{r:second}}"-              , "  \\leadsto \\Big\\{[[ |x| -> \"foo\" ]]\\Big\\}."+              , "  \\leadsto \\Big\\{[[ |x| -> \"foo\" ]]\\Big\\}{.}"               , "\\end{phiquation}"               ]           ]@@ -435,7 +435,7 @@               , "  \\leadsto \\Big\\{\\phiAgain{foo:1}.|x|( ^ -> \\phiAgain{foo:1} )\\Big\\} \\leadsto_{\\nameref{r:dot}}"               , "  \\leadsto \\Big\\{[[ D> 42- ]]( ^ -> \\phiAgain{foo:1}, ^ -> \\phiAgain{foo:1} )\\Big\\} \\leadsto_{\\nameref{r:copy}}"               , "  \\leadsto \\Big\\{[[ D> 42-, ^ -> \\phiAgain{foo:1} ]]( ^ -> \\phiAgain{foo:1} )\\Big\\} \\leadsto_{\\nameref{r:stay}}"-              , "  \\leadsto \\Big\\{[[ D> 42-, ^ -> \\phiAgain{foo:1} ]]\\Big\\}."+              , "  \\leadsto \\Big\\{[[ D> 42-, ^ -> \\phiAgain{foo:1} ]]\\Big\\}{.}"               , "\\end{phiquation}"               ]           ]@@ -451,7 +451,7 @@               , "  \\leadsto \\Big\\{\\phiAgain{1}.|x|( ^ -> \\phiAgain{1} )\\Big\\} \\leadsto_{\\nameref{r:dot}}"               , "  \\leadsto \\Big\\{[[ D> 42- ]]( ^ -> \\phiAgain{1}, ^ -> \\phiAgain{1} )\\Big\\} \\leadsto_{\\nameref{r:copy}}"               , "  \\leadsto \\Big\\{[[ D> 42-, ^ -> \\phiAgain{1} ]]( ^ -> \\phiAgain{1} )\\Big\\} \\leadsto_{\\nameref{r:stay}}"-              , "  \\leadsto \\Big\\{[[ D> 42-, ^ -> \\phiAgain{1} ]]\\Big\\}."+              , "  \\leadsto \\Big\\{[[ D> 42-, ^ -> \\phiAgain{1} ]]\\Big\\}{.}"               , "\\end{phiquation}"               ]           ]@@ -464,7 +464,7 @@               [ "\\begin{phiquation}"               , "\\Big\\{[[ |ex| -> [[ |x| -> [[ |y| -> ?, |k| -> \\phiMeet{1}{ [[ |t| -> 42 ]] } ]]( |y| -> \\phiAgain{1} ) ]].|i| ]]\\Big\\} \\leadsto_{\\nameref{r:copy}}"               , "  \\leadsto \\Big\\{[[ |ex| -> [[ |x| -> [[ |y| -> \\phiAgain{1}, |k| -> \\phiAgain{1} ]] ]].|i| ]]\\Big\\} \\leadsto_{\\nameref{r:stop}}"-              , "  \\leadsto \\Big\\{[[ |ex| -> T ]]\\Big\\}."+              , "  \\leadsto \\Big\\{[[ |ex| -> T ]]\\Big\\}{.}"               , "\\end{phiquation}"               ]           ]@@ -608,7 +608,7 @@           ["rewrite", "--log-level=debug", "--log-lines=4", "--normalize"]           [ intercalate               "\n"-              [ "[DEBUG]: Applied 'COPY' (28 nodes -> 25 nodes)"+              [ "[DEBUG]: Applied 'COPY' (20 nodes -> 17 nodes)"               , "⟦"               , "  x ↦ ⟦"               , "    y ↦ 5"@@ -652,7 +652,7 @@               , "  \\leadsto \\Big\\{[[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]].|x|\\Big\\} \\leadsto_{\\nameref{r:dot}}"               , "  \\leadsto \\Big\\{[[ D> 01-, |y| -> [[]] ]]( ^ -> [[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]] )\\Big\\} \\leadsto_{\\nameref{r:copy}}"               , "  \\leadsto \\Big\\{[[ D> 01-, |y| -> [[]], ^ -> [[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]] ]]\\Big\\} \\leadsto_{\\nameref{r:Mprim}}"-              , "  \\leadsto \\Big\\{[[ D> 01-, |y| -> [[]], ^ -> [[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]] ]]\\Big\\}."+              , "  \\leadsto \\Big\\{[[ D> 01-, |y| -> [[]], ^ -> [[ |x| -> [[ D> 01-, |y| -> [[]] ]] ]] ]]\\Big\\}{.}"               , "\\end{phiquation}"               , "01-"               ]@@ -743,7 +743,7 @@     it "merges single program" $       testCLISucceeded         ["merge", resource "desugar.phi", "--sweet", "--flat"]-        ["{⟦ foo ↦ Φ̇ ⟧}"]+        ["{⟦ foo ↦ x ⟧}"]      it "merges EO programs" $       testCLISucceeded
test/CSTSpec.hs view
@@ -6,6 +6,7 @@  module CSTSpec (spec) where +import AST import CST import Control.Monad (forM_) import Data.Aeson@@ -54,6 +55,26 @@           ast <- parseProgramThrows prog           programToCST ast `shouldBe` cst       )++  describe "build valid CST with wrapped phiAgain{} " $ do+    let number = BaseObject "number"+        again = ExPhiAgain Nothing 1+        bts = BaseObject "bytes"+        bt = BiTau (AtAlpha 0)+        app = ExApplication+        form = ExFormation [BiDelta (BtMany ["40", "18", "00", "00", "00", "00", "00", "00"]), BiVoid AtRho]+        isCSTNumber (EX_NUMBER{}) = True+        isCSTNumber _ = False+    forM_+      [ ("number(bytes(data))", app number (bt (app bts (bt form))))+      , ("again(number)(bytes(data))", app (again number) (bt (app bts (bt form))))+      , ("number(again(bytes(data)))", app number (bt (again (app bts (bt form)))))+      , ("number(again(bytes)(data))", app number (bt (app (again bts) (bt form))))+      , ("again(number)(again(bytes)(data))", app (again number) (bt (app (again bts) (bt form))))+      , ("number(bytes(again(data)))", app number (bt (app bts (bt (again form)))))+      , ("again(number)(again(bytes)(again(data)))", app (again number) (bt (app (again bts) (bt (again form)))))+      ]+      (\(desc, ex) -> it desc (toCST ex 0 EOL `shouldSatisfy` isCSTNumber))    describe "CST printing packs" $ do     let resources = "test-resources/cst/printing-packs"
test/DataizeSpec.hs view
@@ -108,19 +108,13 @@       , "Q"       , unlines           [ "Q -> [["-          , "  org -> [["-          , "    eolang -> [["-          , "      bytes -> [["-          , "        data -> ?,"-          , "        @ -> $.data"-          , "      ]],"-          , "      number -> [["-          , "        as-bytes -> ?,"-          , "        @ -> $.as-bytes,"-          , "        plus -> [[ x -> ?, L> L_org_eolang_number_plus ]]"-          , "      ]]"-          , "    ]]"+          , "  bytes(data) -> [["+          , "    @ -> $.data"           , "  ]],"+          , "  number(as-bytes) -> [["+          , "    @ -> $.as-bytes,"+          , "    plus(x) -> [[ L> L_number_plus ]]"+          , "  ]],"           , "  @ -> 5.plus(6)"           , "]]"           ]@@ -131,20 +125,16 @@       , "Q"       , unlines           [ "Q -> [["-          , "  org -> [["-          , "    eolang -> [["-          , "      bytes -> [["-          , "        data -> ?,"-          , "        @ -> $.data"-          , "      ]],"-          , "      number -> [["-          , "        as-bytes -> ?,"-          , "        @ -> $.as-bytes,"-          , "        plus -> [[ x -> ?, L> L_org_eolang_number_plus ]],"-          , "        times -> [[ x -> ?, L> L_org_eolang_number_times ]]"-          , "      ]]"-          , "    ]]"+          , "  bytes -> [["+          , "    data -> ?,"+          , "    @ -> $.data"           , "  ]],"+          , "  number -> [["+          , "    as-bytes -> ?,"+          , "    @ -> $.as-bytes,"+          , "    plus -> [[ x -> ?, L> L_number_plus ]],"+          , "    times -> [[ x -> ?, L> L_number_times ]]"+          , "  ]],"           , "  @ -> $.c.times(1.8).plus(32),"           , "  c -> 25"           , "]]"@@ -156,21 +146,17 @@       , "Q"       , unlines           [ "Q -> [["-          , "  org -> [["-          , "    eolang -> [["-          , "      bytes -> [["-          , "        data -> ?,"-          , "        @ -> $.data"-          , "      ]],"-          , "      number -> [["-          , "        as-bytes -> ?,"-          , "        @ -> $.as-bytes,"-          , "        times -> [[ x -> ?, L> L_org_eolang_number_times ]],"-          , "        plus -> [[ x -> ?, L> L_org_eolang_number_plus ]],"-          , "        eq -> [[ x -> ?, y -> ?, L> L_org_eolang_number_eq ]]"-          , "      ]]"-          , "    ]]"+          , "  bytes -> [["+          , "    data -> ?,"+          , "    @ -> $.data"           , "  ]],"+          , "  number -> [["+          , "    as-bytes -> ?,"+          , "    @ -> $.as-bytes,"+          , "    times -> [[ x -> ?, L> L_number_times ]],"+          , "    plus -> [[ x -> ?, L> L_number_plus ]],"+          , "    eq -> [[ x -> ?, y -> ?, L> L_number_eq ]]"+          , "  ]],"           , "  fac -> [["           , "    x -> ?,"           , "    @ -> $.x.eq("@@ -203,12 +189,8 @@       , "Q.x"       , unlines           [ "Q -> [["-          , "  org -> [["-          , "    eolang -> [["-          , "      number(as-bytes) -> [[ @ -> as-bytes ]],"-          , "      bytes(data) -> [[ @ -> data ]]"-          , "    ]]"-          , "  ]],"+          , "  number(as-bytes) -> [[ @ -> as-bytes ]],"+          , "  bytes(data) -> [[ @ -> data ]],"           , "  x -> 5"           , "]]"           ]
test/LaTeXSpec.hs view
@@ -3,24 +3,18 @@  {- | Tests for the LaTeX module that provides conversion of phi-calculus programs and rules to LaTeX format for academic documents.-Attention! Most of the tests are generated by LLM. Consider that when refactoring -} module LaTeXSpec where -import AST import Control.Monad (forM_)-import LaTeX (LatexContext (..), defaultLatexContext, explainRules, meetInProgram, programToLaTeX, rewrittensToLatex)-import LaTeX qualified as L-import Lining (LineFormat (MULTILINE, SINGLELINE))+import LaTeX (meetInProgram) import Parser (parseExpressionThrows, parseProgramThrows)-import Sugar (SugarType (SALTY, SWEET))-import Test.Hspec (Spec, describe, it, shouldBe, shouldContain, shouldNotContain)-import Yaml qualified as Y+import Test.Hspec (Spec, describe, it, shouldBe)  spec :: Spec-spec = do+spec =   describe "meet program in program" $-    forM_+    Control.Monad.forM_       [ ("Q.x.y", "{Q.x.y}", "{[[ x -> Q.x.y ]]}", ["Q.x.y"])       , ("Q.x.y twice", "{Q.x.y}", "{[[ x -> Q.x.y, y -> Q.x.y.z ]]}", ["Q.x.y", "Q.x.y"])       , ("Q.x.y.z.a and Q.x.y", "{Q.x.y.z.a}", "{[[ x -> Q.x.y, y -> Q.x.y.z ]]}", ["Q.x.y.z", "Q.x.y", "Q.x.y"])@@ -34,272 +28,3 @@           res <- traverse parseExpressionThrows exprs           meetInProgram ptn tgt `shouldBe` res       )--  describe "programToLaTeX with nonumber=True" $-    it "uses phiquation* environment" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "\\begin{phiquation*}"--  describe "programToLaTeX with nonumber=False" $-    it "uses phiquation environment" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = False}-          result = programToLaTeX prog ctx-      result `shouldContain` "\\begin{phiquation}"--  describe "programToLaTeX output structure" $-    it "contains begin and end tags" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "\\end{phiquation*}"--  describe "programToLaTeX with SWEET sugar" $-    it "renders sweet syntax with braces" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "\\Big\\{"--  describe "programToLaTeX with SALTY sugar" $-    it "renders salty syntax with arrow" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{sugar = SALTY, line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "->"--  describe "programToLaTeX with MULTILINE format" $-    it "renders multiline format" $ do-      prog <- parseProgramThrows "{[[ x -> Q ]]}"-      let ctx = defaultLatexContext{line = MULTILINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "|x|"--  describe "rewrittensToLatex with empty list" $-    it "generates valid latex structure" $ do-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = rewrittensToLatex [] ctx-      result `shouldContain` "\\begin{phiquation*}"--  describe "rewrittensToLatex with single program" $-    it "renders single program without rule" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = rewrittensToLatex [(prog, Nothing)] ctx-      result `shouldContain` "\\Big\\{"--  describe "rewrittensToLatex with rule name" $-    it "includes nameref for rule" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = rewrittensToLatex [(prog, Just "myrule")] ctx-      result `shouldContain` "\\nameref{r:myrule}"--  describe "rewrittensToLatex with label" $-    it "includes label command" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True, label = Just "myeq"}-          result = rewrittensToLatex [(prog, Nothing)] ctx-      result `shouldContain` "\\label{myeq}"--  describe "rewrittensToLatex without label" $-    it "excludes label command" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = rewrittensToLatex [(prog, Nothing)] ctx-      result `shouldNotContain` "\\label"--  describe "rewrittensToLatex with expression" $-    it "includes phiExpression command" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True, expression = Just "myexpr"}-          result = rewrittensToLatex [(prog, Nothing)] ctx-      result `shouldContain` "\\phiExpression{myexpr}"--  describe "rewrittensToLatex without expression" $-    it "excludes phiExpression command" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = rewrittensToLatex [(prog, Nothing)] ctx-      result `shouldNotContain` "\\phiExpression"--  describe "rewrittensToLatex with multiple programs" $-    it "joins with leadsto" $ do-      prog1 <- parseProgramThrows "{Q.x}"-      prog2 <- parseProgramThrows "{Q.y}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = rewrittensToLatex [(prog1, Nothing), (prog2, Nothing)] ctx-      result `shouldContain` "\\leadsto"--  describe "rewrittensToLatex ends with period" $-    it "adds period before end tag" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = rewrittensToLatex [(prog, Nothing)] ctx-      result `shouldContain` ".\n\\end"--  describe "rewrittensToLatex with nonumber=False" $-    it "uses phiquation without asterisk" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = False}-          result = rewrittensToLatex [(prog, Nothing)] ctx-      result `shouldContain` "\\begin{phiquation}"--  describe "escapeUnprintedChars escapes dollar" $-    it "replaces $ with char36 in label via AST" $ do-      let prog = Program (ExFormation [BiTau (AtLabel "$my") ExGlobal])-          ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "\\char36{}"--  describe "escapeUnprintedChars escapes at sign" $-    it "replaces @ with char64 in label via AST" $ do-      let prog = Program (ExFormation [BiTau (AtLabel "@my") ExGlobal])-          ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "\\char64{}"--  describe "escapeUnprintedChars escapes caret" $-    it "replaces ^ with char94 in label via AST" $ do-      let prog = Program (ExFormation [BiTau (AtLabel "^my") ExGlobal])-          ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "\\char94{}"--  describe "escapeUnprintedChars escapes underscore" $-    it "replaces _ in label with char95" $ do-      prog <- parseProgramThrows "{Q.my_label}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "\\char95{}"--  describe "escapeUnprintedChars preserves regular chars" $-    it "keeps alphanumeric chars unchanged" $ do-      prog <- parseProgramThrows "{Q.abc123}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "abc123"--  describe "explainRules with empty list" $-    it "generates document structure" $ do-      let result = explainRules []-      result `shouldContain` "\\documentclass{article}"--  describe "explainRules document has amsmath" $-    it "includes amsmath package" $ do-      let result = explainRules []-      result `shouldContain` "\\usepackage{amsmath}"--  describe "explainRules document structure" $-    it "has begin and end document" $ do-      let result = explainRules []-      result `shouldContain` "\\begin{document}"--  describe "explainRules document ends correctly" $-    it "has end document tag" $ do-      let result = explainRules []-      result `shouldContain` "\\end{document}"--  describe "explainRules with named rule" $-    it "includes rule name" $ do-      let rule = Y.Rule (Just "DOT") Nothing ExGlobal ExGlobal Nothing Nothing Nothing-          result = explainRules [rule]-      result `shouldContain` "\\rule{DOT}"--  describe "explainRules with unnamed rule" $-    it "uses unnamed as fallback" $ do-      let rule = Y.Rule Nothing Nothing ExGlobal ExGlobal Nothing Nothing Nothing-          result = explainRules [rule]-      result `shouldContain` "\\rule{unnamed}"--  describe "explainRules with multiple rules" $-    it "includes all rule names" $ do-      let rule1 = Y.Rule (Just "RULE1") Nothing ExGlobal ExGlobal Nothing Nothing Nothing-          rule2 = Y.Rule (Just "RULE2") Nothing ExGlobal ExGlobal Nothing Nothing Nothing-          result = explainRules [rule1, rule2]-      result `shouldContain` "\\rule{RULE1}"--  describe "explainRules with multiple rules second" $-    it "includes second rule name" $ do-      let rule1 = Y.Rule (Just "FIRST") Nothing ExGlobal ExGlobal Nothing Nothing Nothing-          rule2 = Y.Rule (Just "SECOND") Nothing ExGlobal ExGlobal Nothing Nothing Nothing-          result = explainRules [rule1, rule2]-      result `shouldContain` "\\rule{SECOND}"--  describe "LatexContext sugar field" $-    it "stores sugar type correctly" $ do-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = False}-      sugar ctx `shouldBe` SWEET--  describe "LatexContext line field" $-    it "stores line format correctly" $ do-      let ctx = defaultLatexContext{line = MULTILINE, nonumber = True}-      line ctx `shouldBe` MULTILINE--  describe "LatexContext nonumber field" $-    it "stores nonumber flag correctly" $ do-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = False}-      nonumber ctx `shouldBe` False--  describe "LatexContext expression field" $-    it "stores expression correctly" $ do-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True, expression = Just "expr"}-      L.expression ctx `shouldBe` Just "expr"--  describe "LatexContext label field" $-    it "stores label correctly" $ do-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True, label = Just "lbl"}-      L.label ctx `shouldBe` Just "lbl"--  describe "programToLaTeX handles formation" $-    it "renders formation with bindings" $ do-      prog <- parseProgramThrows "{[[ x -> Q, y -> $ ]]}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "|x|"--  describe "programToLaTeX handles dispatch" $-    it "renders dispatch expression" $ do-      prog <- parseProgramThrows "{Q.x.y.z}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "|z|"--  describe "programToLaTeX handles application" $-    it "renders application expression" $ do-      prog <- parseProgramThrows "{Q.f(x -> Q)}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "|f|"--  describe "programToLaTeX handles void binding" $-    it "renders void in formation" $ do-      prog <- parseProgramThrows "{[[ x -> ? ]]}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "|x|"--  describe "programToLaTeX handles nested formations" $-    it "renders nested structures" $ do-      prog <- parseProgramThrows "{[[ x -> [[ y -> Q ]] ]]}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = programToLaTeX prog ctx-      result `shouldContain` "|y|"--  describe "rewrittensToLatex with label and expression" $-    it "includes both label and expression" $ do-      prog <- parseProgramThrows "{Q}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True, expression = Just "expr", label = Just "lbl"}-          result = rewrittensToLatex [(prog, Nothing)] ctx-      result `shouldContain` "\\label{lbl}"--  describe "rewrittensToLatex with complex rewrite chain" $-    it "shows rewrite sequence" $ do-      prog1 <- parseProgramThrows "{Q.x}"-      prog2 <- parseProgramThrows "{Q.y}"-      prog3 <- parseProgramThrows "{Q.z}"-      let ctx = defaultLatexContext{line = SINGLELINE, nonumber = True}-          result = rewrittensToLatex [(prog1, Just "r1"), (prog2, Just "r2"), (prog3, Nothing)] ctx-      result `shouldContain` "\\nameref{r:r1}"
test/LiningSpec.hs view
@@ -105,7 +105,6 @@   describe "toSingleLine EXPRESSION leaves primitives unchanged" $     forM_       [ ("EX_GLOBAL", EX_GLOBAL Φ)-      , ("EX_DEF_PACKAGE", EX_DEF_PACKAGE Φ̇)       , ("EX_XI", EX_XI XI)       , ("EX_ATTR", EX_ATTR (AT_LABEL "attr"))       , ("EX_TERMINATION", EX_TERMINATION DEAD)
test/ParserSpec.hs view
@@ -34,7 +34,6 @@       , ("Q -> T(x -> Q)", Just (Program (ExApplication ExTermination (BiTau (AtLabel "x") ExGlobal))))       , ("Q -> Q.org.eolang", Just (Program (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang"))))       , ("Q -> [[x -> $, y -> ?]]", Just (Program (ExFormation [BiTau (AtLabel "x") ExThis, BiVoid (AtLabel "y"), BiVoid AtRho])))-      , ("{[[foo ↦ QQ]]}", Just (Program (ExFormation [BiTau (AtLabel "foo") (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang")), BiVoid AtRho])))       ]    describe "parse expression" $@@ -190,7 +189,6 @@     forM_       [ "[[x -> $, y -> ?]]"       , "[[x() -> [[]] ]]"-      , "[[x(^, @, y) -> [[q -> QQ]] ]]"       , "Q.x(y() -> [[]])"       , "Q.x(y(q) -> [[w -> !e]])"       , "Q.x(~1(^,@) -> [[]])"@@ -217,6 +215,7 @@       ( map           (\input -> (input, Nothing))           [ "Q.x()"+          , "[[x(^, @, y) -> [[q -> QQ]] ]]"           , "Q * !t1 * !t2"           , "Q(x -> [[]])"           , "$(x -> [[]])"@@ -424,7 +423,6 @@       [ ("ξ", Just ExThis)       , ("Φ", Just ExGlobal)       , ("⊥", Just ExTermination)-      , ("Φ̇", Just (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang")))       , ("⟦⟧", Just (ExFormation [BiVoid AtRho]))       , ("⟦ x ↦ ξ ⟧", Just (ExFormation [BiTau (AtLabel "x") ExThis, BiVoid AtRho]))       , ("ξ.ρ", Just (ExDispatch ExThis AtRho))
− test/SugarSpec.hs
@@ -1,436 +0,0 @@--- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com--- SPDX-License-Identifier: MIT--{- | Tests for the Sugar module that provides conversion between sweet-(sugared) and salty (desugared) syntax representations of phi-calculus programs.-Attention! Most of the tests are generated by LLM. Consider that when refactoring--}-module SugarSpec where--import CST-import Control.Monad (forM_)-import Parser (parseProgramThrows)-import Render (Render (render))-import Sugar (SugarType (..), toSalty, withSugarType)-import Test.Hspec (Spec, describe, it, shouldBe, shouldContain, shouldSatisfy)--spec :: Spec-spec = do-  describe "SugarType Eq instance compares types" $-    forM_-      [ ("sweet equals sweet", SWEET, SWEET, True)-      , ("salty equals salty", SALTY, SALTY, True)-      , ("sweet differs from salty", SWEET, SALTY, False)-      , ("salty differs from sweet", SALTY, SWEET, False)-      ]-      ( \(desc, lhs, rhs, expected) ->-          it desc $ (lhs == rhs) `shouldBe` expected-      )--  describe "SugarType Show instance renders types" $-    forM_-      [ ("shows sweet", SWEET, "SWEET")-      , ("shows salty", SALTY, "SALTY")-      ]-      ( \(desc, sugar, expected) ->-          it desc $ show sugar `shouldBe` expected-      )--  describe "withSugarType SWEET returns unchanged program" $-    it "preserves sweet CST" $ do-      prog <- parseProgramThrows "{Q}"-      let cst = programToCST prog-          result = withSugarType SWEET cst-      result `shouldBe` cst--  describe "withSugarType SALTY converts to salty" $-    it "transforms sweet CST to salty" $ do-      prog <- parseProgramThrows "{Q}"-      let cst = programToCST prog-          result = withSugarType SALTY cst-          isSalty PR_SALTY{} = True-          isSalty _ = False-      result `shouldSatisfy` isSalty--  describe "toSalty PROGRAM converts sweet to salty" $-    it "converts PR_SWEET to PR_SALTY" $ do-      prog <- parseProgramThrows "{Q}"-      let cst = programToCST prog-          salty = toSalty cst-          isSalty PR_SALTY{} = True-          isSalty _ = False-      salty `shouldSatisfy` isSalty--  describe "toSalty PROGRAM leaves salty unchanged" $-    it "preserves PR_SALTY" $ do-      prog <- parseProgramThrows "{Q}"-      let cst = programToCST prog-          salty = toSalty cst-          twice = toSalty salty-      twice `shouldBe` salty--  describe "toSalty EXPRESSION converts default package" $-    it "expands QQ to Q.org.eolang" $ do-      prog <- parseProgramThrows "{QQ}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "org"--  describe "toSalty EXPRESSION converts attribute sugar" $-    it "expands x to $.x" $ do-      prog <- parseProgramThrows "{[[ @ -> x ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "ξ"--  describe "toSalty EXPRESSION converts empty formation" $-    it "adds void rho to empty formation" $ do-      prog <- parseProgramThrows "{[[]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "ρ"--  describe "toSalty EXPRESSION converts formation with bindings" $-    it "adds void rho when missing" $ do-      prog <- parseProgramThrows "{[[ x -> Q ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "ρ"--  describe "toSalty EXPRESSION preserves existing rho void" $-    it "keeps void rho binding" $ do-      prog <- parseProgramThrows "{[[ ^ -> ?, x -> Q ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-          count = length (filter (== 'ρ') rendered)-      count `shouldBe` 1--  describe "toSalty EXPRESSION preserves existing rho tau" $-    it "keeps tau rho binding" $ do-      prog <- parseProgramThrows "{[[ ^ -> Q, x -> $ ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-          count = length (filter (== 'ρ') rendered)-      count `shouldBe` 1--  describe "toSalty EXPRESSION converts dispatch" $-    it "recursively processes dispatch expression" $ do-      prog <- parseProgramThrows "{QQ.x}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "org"--  describe "toSalty EXPRESSION converts application" $-    it "processes single application" $ do-      prog <- parseProgramThrows "{Q.x(y -> $)}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "y"--  describe "toSalty EXPRESSION converts multiple applications" $-    it "processes chained applications" $ do-      prog <- parseProgramThrows "{Q.x(a -> $, b -> Q)}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "a"--  describe "toSalty EXPRESSION converts expression arguments" $-    it "converts positional args to alpha bindings" $ do-      prog <- parseProgramThrows "{Q.x($, Q)}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "α0"--  describe "toSalty EXPRESSION converts number literal" $-    it "expands number to bytes" $ do-      prog <- parseProgramThrows "{[[ x -> 42 ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "number"--  describe "toSalty EXPRESSION converts string literal" $-    it "expands string to bytes" $ do-      prog <- parseProgramThrows "{[[ x -> \"hello\" ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "string"--  describe "toSalty EXPRESSION leaves global unchanged" $-    it "preserves Q" $ do-      let expr' = EX_GLOBAL Φ-          salty = toSalty expr'-      salty `shouldBe` expr'--  describe "toSalty EXPRESSION leaves xi unchanged" $-    it "preserves $" $ do-      let expr' = EX_XI XI-          salty = toSalty expr'-      salty `shouldBe` expr'--  describe "toSalty EXPRESSION leaves termination unchanged" $-    it "preserves T" $ do-      let expr' = EX_TERMINATION DEAD-          salty = toSalty expr'-      salty `shouldBe` expr'--  describe "toSalty EXPRESSION leaves meta unchanged" $-    it "preserves meta expression" $ do-      let expr' = EX_META (MT_EXPRESSION "e")-          salty = toSalty expr'-      salty `shouldBe` expr'--  describe "toSalty BINDING converts pair" $-    it "recursively processes binding pair" $ do-      prog <- parseProgramThrows "{[[ x -> QQ ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "org"--  describe "toSalty BINDING leaves empty unchanged" $-    it "preserves empty binding" $ do-      let bd = BI_EMPTY (TAB 0)-          salty = toSalty bd-      salty `shouldBe` bd--  describe "toSalty BINDINGS converts pair" $-    it "recursively processes bindings" $ do-      prog <- parseProgramThrows "{[[ x -> Q, y -> QQ ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "org"--  describe "toSalty BINDINGS leaves empty unchanged" $-    it "preserves empty bindings" $ do-      let bds = BDS_EMPTY (TAB 0)-          salty = toSalty bds-      salty `shouldBe` bds--  describe "toSalty PAIR converts tau" $-    it "recursively processes tau pair" $ do-      prog <- parseProgramThrows "{[[ x -> QQ ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "org"--  describe "toSalty PAIR converts formation with voids" $-    it "expands void parameters into formation" $ do-      prog <- parseProgramThrows "{[[ f(a, b) -> [[]] ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "a"--  describe "toSalty PAIR leaves void unchanged" $-    it "preserves void pair" $ do-      let pair' = PA_VOID (AT_LABEL "x") ARROW EMPTY-          salty = toSalty pair'-      salty `shouldBe` pair'--  describe "toSalty PAIR leaves lambda unchanged" $-    it "preserves lambda pair" $ do-      let pair' = PA_LAMBDA "Func"-          salty = toSalty pair'-      salty `shouldBe` pair'--  describe "toSalty PAIR leaves delta unchanged" $-    it "preserves delta pair" $ do-      let pair' = PA_DELTA BT_EMPTY-          salty = toSalty pair'-      salty `shouldBe` pair'--  describe "toSalty APP_BINDING converts pair" $-    it "recursively processes app binding" $ do-      prog <- parseProgramThrows "{Q.x(y -> QQ)}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "org"--  describe "toSalty handles nested formations" $-    it "adds rho to nested formations" $ do-      prog <- parseProgramThrows "{[[ x -> [[ y -> Q ]] ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-          count = length (filter (== 'ρ') rendered)-      count `shouldBe` 2--  describe "toSalty handles complex program" $-    it "processes fibonacci example" $ do-      prog <- parseProgramThrows "{[[ fac(n) -> [[ @ -> n.eq(1, n.times(^.fac(n.plus(-1)))) ]] ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "ρ"--  describe "toSalty handles mixed case identifiers" $-    it "preserves case in labels" $ do-      prog <- parseProgramThrows "{[[ myLabel -> Q ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "myLabel"--  describe "toSalty handles deep dispatch chain" $-    it "processes Q.a.b.c.d" $ do-      prog <- parseProgramThrows "{Q.a.b.c.d}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "d"--  describe "toSalty handles multiple expression arguments" $-    it "converts all positional args" $ do-      prog <- parseProgramThrows "{Q.f($, Q, $)}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "α2"--  describe "toSalty EXPRESSION converts EX_PHI_MEET" $-    it "recursively processes inner expression" $ do-      let inner = EX_DEF_PACKAGE Φ̇-          expr' = EX_PHI_MEET (Just "x") 1 inner-          salty = toSalty expr'-          isDispatch EX_DISPATCH{} = True-          isDispatch _ = False-      case salty of-        EX_PHI_MEET pref ix innerSalty -> do-          pref `shouldBe` Just "x"-          ix `shouldBe` 1-          innerSalty `shouldSatisfy` isDispatch-        _ -> fail "Expected EX_PHI_MEET but got different constructor"--  describe "toSalty EXPRESSION converts EX_PHI_AGAIN" $-    it "recursively processes inner expression" $ do-      let inner = EX_DEF_PACKAGE Φ̇-          expr' = EX_PHI_AGAIN Nothing 5 inner-          salty = toSalty expr'-          isDispatch EX_DISPATCH{} = True-          isDispatch _ = False-      case salty of-        EX_PHI_AGAIN pref ix innerSalty -> do-          pref `shouldBe` Nothing-          ix `shouldBe` 5-          innerSalty `shouldSatisfy` isDispatch-        _ -> fail "Expected EX_PHI_AGAIN but got different constructor"--  describe "toSalty handles BI_META binding" $-    it "preserves meta binding in formation" $ do-      prog <- parseProgramThrows "{[[ !B ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "𝐵"--  describe "toSalty handles BDS_META in nested bindings" $-    it "preserves meta bindings in sequence" $ do-      prog <- parseProgramThrows "{[[ x -> Q, !B ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "𝐵"--  describe "toSalty preserves rho tau in nested bindings" $-    it "keeps tau rho as first binding in sequence" $ do-      prog <- parseProgramThrows "{[[ ^ -> $, x -> Q, y -> $ ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-          count = length (filter (== 'ρ') rendered)-      count `shouldBe` 1--  describe "toSalty PAIR converts formation with empty inner binding" $-    it "expands void parameters into empty formation" $ do-      prog <- parseProgramThrows "{[[ f(a) -> [[]] ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "a"--  describe "toSalty handles floating point number" $-    it "expands float to bytes" $ do-      prog <- parseProgramThrows "{[[ x -> 3.14 ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "number"--  describe "toSalty handles negative number" $-    it "expands negative integer to bytes" $ do-      prog <- parseProgramThrows "{[[ x -> -42 ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "number"--  describe "toSalty handles single named application argument" $-    it "processes single tau binding correctly" $ do-      prog <- parseProgramThrows "{Q.x(y -> $)}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "y"--  describe "toSalty preserves rho tau as non-first binding" $-    it "keeps tau rho binding in sequence" $ do-      prog <- parseProgramThrows "{[[ x -> Q, ^ -> $ ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-          count = length (filter (== 'ρ') rendered)-      count `shouldBe` 1--  describe "toSalty handles single positional argument" $-    it "converts single arg to alpha binding" $ do-      prog <- parseProgramThrows "{Q.f($)}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "α0"--  describe "toSalty PAIR handles formation with multiple voids and empty body" $-    it "expands multiple void parameters into empty formation" $ do-      prog <- parseProgramThrows "{[[ g(a, b, c) -> [[]] ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "a"--  describe "toSalty handles unicode attribute in dispatch" $-    it "processes dispatch with decorated name" $ do-      prog <- parseProgramThrows "{Q.größe}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-      rendered `shouldContain` "größe"--  describe "toSalty handles empty string literal" $-    it "expands empty string to bytes" $ do-      prog <- parseProgramThrows "{[[ x -> \"\" ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "string"--  describe "toSalty handles scientific notation number" $-    it "expands scientific number to bytes" $ do-      prog <- parseProgramThrows "{[[ x -> 1e10 ]]}"-      let cst = programToCST prog-          salty = toSalty cst-      render salty `shouldContain` "number"--  describe "toSalty handles deeply nested formations" $-    it "adds rho to all nested levels" $ do-      prog <- parseProgramThrows "{[[ x -> [[ y -> [[ z -> Q ]] ]] ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-          count = length (filter (== 'ρ') rendered)-      count `shouldBe` 3--  describe "toSalty handles formation with only rho void" $-    it "preserves single rho void binding" $ do-      prog <- parseProgramThrows "{[[ ^ -> ? ]]}"-      let cst = programToCST prog-          salty = toSalty cst-          rendered = render salty-          count = length (filter (== 'ρ') rendered)-      count `shouldBe` 1