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 +5/−5
- phino.cabal +33/−33
- src/CST.hs +0/−2
- src/Dataize.hs +3/−8
- src/Encoding.hs +0/−1
- src/LaTeX.hs +1/−1
- src/Misc.hs +26/−16
- src/Parser.hs +0/−3
- src/Render.hs +0/−1
- src/Sugar.hs +0/−2
- src/XMIR.hs +4/−4
- test/CLISpec.hs +14/−14
- test/CSTSpec.hs +21/−0
- test/DataizeSpec.hs +27/−45
- test/LaTeXSpec.hs +4/−279
- test/LiningSpec.hs +0/−1
- test/ParserSpec.hs +1/−3
- test/SugarSpec.hs +0/−436
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