phino 0.0.0.67 → 0.0.0.68
raw patch · 35 files changed
+743/−366 lines, 35 filesdep ~basedep ~timePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: base, time
API changes (from Hackage documentation)
- LaTeX: instance LaTeX.ToLaTeX GHC.Base.String
- Render: instance Render.Render GHC.Num.Integer.Integer
- Render: instance Render.Render GHC.Types.Double
+ CLI.Parsers: cliArgsParser :: Parser CliArgs
+ CLI.Parsers: optPin :: Parser (Maybe String)
+ CLI.Types: CliArgs :: Maybe String -> Command -> CliArgs
+ CLI.Types: VersionMismatch :: String -> String -> CmdException
+ CLI.Types: [_command] :: CliArgs -> Command
+ CLI.Types: [_pin] :: CliArgs -> Maybe String
+ CLI.Types: [_update] :: OptsRewrite -> Bool
+ CLI.Types: data CliArgs
+ LaTeX: instance LaTeX.ToLaTeX Data.Text.Internal.Text
+ Render: instance Render.Render Data.Text.Internal.Text
- AST: AtLabel :: String -> Attribute
+ AST: AtLabel :: Text -> Attribute
- AST: AtMeta :: String -> Attribute
+ AST: AtMeta :: Text -> Attribute
- AST: BiLambda :: String -> Binding
+ AST: BiLambda :: Text -> Binding
- AST: BiMeta :: String -> Binding
+ AST: BiMeta :: Text -> Binding
- AST: BiMetaLambda :: String -> Binding
+ AST: BiMetaLambda :: Text -> Binding
- AST: BtMeta :: String -> Bytes
+ AST: BtMeta :: Text -> Bytes
- AST: ExMeta :: String -> Expression
+ AST: ExMeta :: Text -> Expression
- AST: ExMetaTail :: Expression -> String -> Expression
+ AST: ExMetaTail :: Expression -> Text -> Expression
- CLI.Parsers: parserInfo :: ParserInfo Command
+ CLI.Parsers: parserInfo :: ParserInfo CliArgs
- CLI.Types: OptsRewrite :: LogLevel -> Int -> IOFormat -> IOFormat -> SugarType -> LineFormat -> Must -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Int -> Int -> Int -> Maybe Int -> Maybe Int -> [FilePath] -> [String] -> [String] -> String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe FilePath -> Maybe FilePath -> Maybe FilePath -> OptsRewrite
+ CLI.Types: OptsRewrite :: LogLevel -> Int -> IOFormat -> IOFormat -> SugarType -> LineFormat -> Must -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Int -> Int -> Int -> Maybe Int -> Maybe Int -> [FilePath] -> [String] -> [String] -> String -> String -> Maybe String -> Maybe String -> Maybe String -> Maybe String -> Maybe FilePath -> Maybe FilePath -> Maybe FilePath -> OptsRewrite
- CST: AT_LABEL :: String -> ATTRIBUTE
+ CST: AT_LABEL :: Text -> ATTRIBUTE
- CST: META :: EXCLAMATION -> META_HEAD -> String -> META
+ CST: META :: EXCLAMATION -> META_HEAD -> Text -> META
- CST: PA_LAMBDA :: String -> PAIR
+ CST: PA_LAMBDA :: Text -> PAIR
- CST: PA_LAMBDA' :: String -> PAIR
+ CST: PA_LAMBDA' :: Text -> PAIR
- CST: [label] :: ATTRIBUTE -> String
+ CST: [label] :: ATTRIBUTE -> Text
- CST: [rest] :: META -> String
+ CST: [rest] :: META -> Text
- CST: metaTail :: String -> String
+ CST: metaTail :: Text -> Text
- Matcher: MvFunction :: String -> MetaValue
+ Matcher: MvFunction :: Text -> MetaValue
- Matcher: Subst :: Map String MetaValue -> Subst
+ Matcher: Subst :: Map Text MetaValue -> Subst
- Matcher: substSingle :: String -> MetaValue -> Subst
+ Matcher: substSingle :: Text -> MetaValue -> Subst
- Misc: matchDataObject :: Expression -> Maybe (String, Bytes)
+ Misc: matchDataObject :: Expression -> Maybe (Text, Bytes)
- Misc: pattern BaseObject :: String -> Expression
+ Misc: pattern BaseObject :: Text -> Expression
- Misc: pattern DataObject :: String -> Bytes -> Expression
+ Misc: pattern DataObject :: Text -> Bytes -> Expression
- Render: render :: Render a => a -> String
+ Render: render :: Render a => a -> Text
- Render: renderFunc :: Render a => String -> a -> String
+ Render: renderFunc :: Render a => Text -> a -> Text
Files
- README.md +95/−1
- benchmark/Main.hs +102/−0
- phino.cabal +16/−3
- src/AST.hs +12/−10
- src/Builder.hs +4/−2
- src/CLI.hs +15/−4
- src/CLI/Parsers.hs +16/−2
- src/CLI/Runners.hs +16/−0
- src/CLI/Types.hs +9/−0
- src/CST.hs +10/−8
- src/Canonizer.hs +2/−1
- src/Dataize.hs +5/−3
- src/Functions.hs +6/−5
- src/LaTeX.hs +17/−18
- src/Margin.hs +5/−4
- src/Matcher.hs +5/−4
- src/Misc.hs +31/−17
- src/Parser.hs +11/−8
- src/Printer.hs +7/−6
- src/Render.hs +50/−44
- src/Sugar.hs +1/−0
- src/XMIR.hs +10/−10
- test/ASTSpec.hs +1/−0
- test/BuilderSpec.hs +4/−1
- test/CLISpec.hs +70/−1
- test/CSTSpec.hs +3/−1
- test/ConditionSpec.hs +2/−0
- test/DataizeSpec.hs +2/−0
- test/FunctionsSpec.hs +2/−0
- test/MatcherSpec.hs +206/−213
- test/MiscSpec.hs +2/−0
- test/ParserSpec.hs +1/−0
- test/PrinterSpec.hs +2/−0
- test/ReplacerSpec.hs +2/−0
- test/RuleSpec.hs +1/−0
README.md view
@@ -1,3 +1,8 @@+<!--+SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com+SPDX-License-Identifier: MIT+-->+ # Command-Line Manipulator of 𝜑-Calculus Expressions [](https://www.rultor.com/p/objectionary/phino)@@ -29,7 +34,7 @@ ```bash cabal update-cabal install --overwrite-policy=always phino-0.0.0.66+cabal install --overwrite-policy=always phino-0.0.0.67 phino --version ``` @@ -78,6 +83,14 @@ 0.0.0.0 ``` +You can ensure scripts are run with a specific version of `phino` using+the `--pin` global option. It exits with an error when the version supplied+doesn't match the installed one:++```bash+phino --pin=0.0.0.67 dataize hello.phi+```+ ## Dataize Then, you dataize the program:@@ -339,6 +352,81 @@ Incorrect usage of meta variables in 𝜑-expression patterns leads to parsing errors. +## Benchmark++To run performance benchmarks, you need [Java 8+][java] and [curl][curl].+Maven is downloaded automatically on first run via `benchmark/mvnw`.++The benchmark uses the compiled [`Native`][jna-native] class from+[JNA][jna] — a large real-world Java class — as its test input.+On first run, `make bench` downloads the class, disassembles it to+[XMIR][xmir] via [jeo-maven-plugin][jeo], converts it to 𝜑 using+`phino rewrite`, and caches the results in `benchmark/tmp/`.+Subsequent runs skip straight to the benchmarks.++```bash+make bench+```++<!-- benchmark_begin -->++```text+=== parse/phi ===+ warmup: 3 iterations+ batches: 10 x 1+ total: 1031210.405 μs+ avg: 103121.040 μs+ min: 93623.015 μs+ max: 126930.202 μs+ std dev: 13077.810 μs+=== parse/xmir ===+ warmup: 3 iterations+ batches: 10 x 1+ total: 6217322.833 μs+ avg: 621732.283 μs+ min: 554694.491 μs+ max: 755833.179 μs+ std dev: 55468.859 μs+=== rewrite/normalize ===+ warmup: 3 iterations+ batches: 10 x 1+ total: 312902.089 μs+ avg: 31290.209 μs+ min: 29879.534 μs+ max: 34353.613 μs+ std dev: 1360.426 μs+=== print/sweet/multiline ===+ warmup: 3 iterations+ batches: 10 x 1+ total: 3650499.458 μs+ avg: 365049.946 μs+ min: 336866.083 μs+ max: 392609.052 μs+ std dev: 14447.496 μs+=== print/sweet/flat ===+ warmup: 3 iterations+ batches: 10 x 1+ total: 3666297.385 μs+ avg: 366629.738 μs+ min: 342205.526 μs+ max: 380537.332 μs+ std dev: 10914.667 μs+=== print/salty/multiline ===+ warmup: 3 iterations+ batches: 10 x 1+ total: 11397878.380 μs+ avg: 1139787.838 μs+ min: 1105293.829 μs+ max: 1179067.130 μs+ std dev: 23579.734 μs+```++The results were calculated in [this GHA job][benchmark-gha]+on 2026-05-17 at 21:49,+on Linux with 4 CPUs.++<!-- benchmark_end -->+ ## How to Contribute Fork repository, make changes, then send us a [pull request][guidelines].@@ -365,3 +453,9 @@ [guidelines]: https://www.yegor256.com/2014/04/15/github-guidelines.html [xmir]: https://news.eolang.org/2022-11-25-xmir-guide.html [latex]: https://en.wikipedia.org/wiki/LaTeX+[java]: https://www.java.com/en/download/+[curl]: https://curl.se/+[jna]: https://github.com/java-native-access/jna+[jna-native]: https://github.com/java-native-access/jna/blob/master/src/com/sun/jna/Native.java+[jeo]: https://github.com/objectionary/jeo-maven-plugin+[benchmark-gha]: https://github.com/objectionary/phino/actions/runs/26003582110
+ benchmark/Main.hs view
@@ -0,0 +1,102 @@+-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com+-- SPDX-License-Identifier: MIT++module Main where++import AST (Expression (ExGlobal))+import Control.Exception (evaluate)+import Control.Monad (replicateM, replicateM_)+import Data.Time.Clock+import Deps (dontSaveStep)+import Encoding (Encoding (UNICODE))+import Functions (buildTerm)+import Lining (LineFormat (MULTILINE, SINGLELINE))+import Margin (defaultMargin)+import Must (Must (MtDisabled))+import Parser (parseProgramThrows)+import Printer (printProgram')+import Rewriter (RewriteContext (RewriteContext), rewrite)+import Sugar (SugarType (SALTY, SWEET))+import Text.Printf (printf)+import XMIR (parseXMIRThrows, xmirToPhi)+import Yaml (normalizationRules)++warmups :: Int+warmups = 3++iterations :: Int+iterations = 10++targetBatchMs :: Double+targetBatchMs = 20.0++rewriteCtx :: RewriteContext+rewriteCtx =+ RewriteContext+ ExGlobal+ 100+ 100+ False+ buildTerm+ MtDisabled+ Nothing+ dontSaveStep++timeAction :: IO a -> IO Double+timeAction action = do+ start <- getCurrentTime+ _ <- evaluate =<< action+ end <- getCurrentTime+ pure (realToFrac (diffUTCTime end start) * 1e6)++timeBatch :: Int -> IO a -> IO Double+timeBatch batch action = do+ start <- getCurrentTime+ replicateM_ batch (evaluate =<< action)+ end <- getCurrentTime+ pure (realToFrac (diffUTCTime end start) * 1e6 / fromIntegral batch)++calibrate :: IO a -> IO Int+calibrate action = do+ t <- timeAction action+ pure (max 1 (round (targetBatchMs * 1000.0 / t)))++stdDev :: [Double] -> Double -> Double+stdDev xs avg = sqrt (sum (map (\x -> (x - avg) ^ (2 :: Int)) xs) / fromIntegral (length xs))++runBench :: String -> IO a -> IO ()+runBench name action = do+ replicateM_ warmups action+ batch <- calibrate action+ times <- replicateM iterations (timeBatch batch action)+ let total = sum times * fromIntegral batch+ avg = sum times / fromIntegral iterations+ mn = minimum times+ mx = maximum times+ sd = stdDev times avg+ putStrLn $ "=== " ++ name ++ " ==="+ putStrLn $ printf " warmup: %d iterations" warmups+ putStrLn $ printf " batches: %d x %d" iterations batch+ putStrLn $ printf " total: %.3f μs" total+ putStrLn $ printf " avg: %.3f μs" avg+ putStrLn $ printf " min: %.3f μs" mn+ putStrLn $ printf " max: %.3f μs" mx+ putStrLn $ printf " std dev: %.3f μs" sd++main :: IO ()+main = do+ src <- readFile "benchmark/tmp/native.phi"+ xsrc <- readFile "benchmark/tmp/Native.xmir"+ prog <- parseProgramThrows src+ runBench "parse/phi" (parseProgramThrows src)+ runBench "parse/xmir" (parseXMIRThrows xsrc >>= xmirToPhi)+ runBench "rewrite/normalize" (rewrite prog normalizationRules rewriteCtx)+ runBench+ "print/sweet/multiline"+ (evaluate (length (printProgram' prog (SWEET, UNICODE, MULTILINE, defaultMargin))))+ runBench+ "print/sweet/flat"+ (evaluate (length (printProgram' prog (SWEET, UNICODE, SINGLELINE, defaultMargin))))+ runBench+ "print/salty/multiline"+ (evaluate (length (printProgram' prog (SALTY, UNICODE, MULTILINE, defaultMargin))))
phino.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: phino-version: 0.0.0.67+version: 0.0.0.68 license: MIT synopsis: Command-Line Manipulator of 𝜑-Calculus Expressions description: Please see the README on GitHub at <https://github.com/objectionary/phino#readme>@@ -93,7 +93,7 @@ regex-pcre-builtin >=0.95.2 && <0.96, scientific >=0.3.7 && <0.4, text >=2.0.2 && <2.2,- time >=1.12 && <1.16,+ time >=1.12 && <1.17, utf8-string >=1.0.2 && <1.1, vector >=0.13.0 && <0.14, xml-conduit >=1.9 && <1.11,@@ -166,11 +166,24 @@ process >=1.6.17 && <1.7, silently >=1.2.5 && <1.3, text >=2.0.2 && <2.2,- time >=1.12 && <1.16,+ time >=1.12 && <1.17, xml-conduit >=1.9 && <1.11, yaml >=0.11.8 && <0.12, build-tool-depends: hspec-discover:hspec-discover >=2.11.0 && <2.12++ default-language: Haskell2010++-- Benchmark suite+benchmark bench+ import: warnings+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs: benchmark+ build-depends:+ base >=4.18.3.0 && <5,+ phino,+ time >=1.12 && <1.17, default-language: Haskell2010
src/AST.hs view
@@ -6,6 +6,8 @@ -- This module represents AST tree for parsed phi-calculus program module AST where +import Data.Text (Text)+import qualified Data.Text as T import GHC.Generics (Generic) newtype Program = Program Expression@@ -18,8 +20,8 @@ | ExTermination | ExApplication Expression Binding | ExDispatch Expression Attribute- | ExMeta String- | ExMetaTail Expression String+ | ExMeta Text+ | ExMetaTail Expression Text | ExPhiMeet (Maybe String) Int Expression | ExPhiAgain (Maybe String) Int Expression deriving (Eq, Ord, Show, Generic)@@ -28,36 +30,36 @@ = BiTau Attribute Expression | BiDelta Bytes | BiVoid Attribute- | BiLambda String- | BiMeta String- | BiMetaLambda String+ | BiLambda Text+ | BiMeta Text+ | BiMetaLambda Text deriving (Eq, Ord, Show, Generic) data Bytes = BtEmpty | BtOne String | BtMany [String]- | BtMeta String+ | BtMeta Text deriving (Eq, Ord, Show, Generic) data Attribute- = AtLabel String+ = AtLabel Text | AtAlpha Int | AtPhi | AtRho | AtLambda | AtDelta- | AtMeta String+ | AtMeta Text deriving (Eq, Generic, Ord) instance Show Attribute where- show (AtLabel label) = label+ show (AtLabel label) = T.unpack label show (AtAlpha idx) = 'α' : show idx show AtRho = "ρ" show AtPhi = "φ" show AtDelta = "Δ" show AtLambda = "λ"- show (AtMeta meta) = '!' : meta+ show (AtMeta meta) = '!' : T.unpack meta countNodes :: Expression -> Int countNodes (ExFormation bds) = 1 + sum (map nodesInBinding bds) + length bds
src/Builder.hs view
@@ -26,6 +26,8 @@ import Control.Exception (Exception, throwIO) import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.Map.Strict as Map+import Data.Text (Text)+import qualified Data.Text as T import Matcher import Misc (uniqueBindings) import Printer@@ -38,8 +40,8 @@ | CouldNotBuildBytes {_bts :: Bytes, _msg :: String} deriving (Exception) -metaMsg :: String -> String-metaMsg = printf "meta '%s' is either does not exist or refers to an inappropriate term"+metaMsg :: Text -> String+metaMsg = printf "meta '%s' is either does not exist or refers to an inappropriate term" . T.unpack type Built a = Either String a
src/CLI.hs view
@@ -10,9 +10,11 @@ import CLI.Parsers import CLI.Runners import CLI.Types-import Control.Exception.Base (Exception (displayException), SomeException, fromException, handle)+import Control.Exception.Base (Exception (displayException), SomeException, fromException, handle, throwIO)+import Data.Version (showVersion) import Logger import Options.Applicative+import Paths_phino (version) import System.Exit (ExitCode (..), exitFailure) handler :: SomeException -> IO ()@@ -32,11 +34,20 @@ CmdMatch OptsMatch{_logLevel, _logLines} -> (_logLevel, _logLines) in setLogConfig level lns +checkPin :: Maybe String -> IO ()+checkPin Nothing = pure ()+checkPin (Just expected)+ | expected == actual = pure ()+ | otherwise = throwIO (VersionMismatch expected actual)+ where+ actual = showVersion version+ runCLI :: [String] -> IO () runCLI args = handle handler $ do- cmd <- handleParseResult (execParserPure defaultPrefs parserInfo args)- setLogger cmd- case cmd of+ CliArgs{_pin, _command} <- handleParseResult (execParserPure defaultPrefs parserInfo args)+ checkPin _pin+ setLogger _command+ case _command of CmdRewrite opts -> runRewrite opts CmdDataize opts -> runDataize opts CmdExplain opts -> runExplain opts
src/CLI/Parsers.hs view
@@ -282,6 +282,7 @@ <*> optDepthSensitive <*> optNonumber <*> switch (long "in-place" <> help "Edit file in-place instead of printing to output")+ <*> switch (long "update" <> help "Skip rewriting if --target file is newer than the input file") <*> optSequence <*> optCanonize <*> optCompress@@ -344,8 +345,21 @@ <> command "match" (info matchParser (progDesc "Match 𝜑-program against provided pattern and build matched substitutions")) ) -parserInfo :: ParserInfo Command+optPin :: Parser (Maybe String)+optPin =+ optional+ ( strOption+ ( long "pin"+ <> metavar "VERSION"+ <> help "Fail if this version doesn't match the version of phino"+ )+ )++cliArgsParser :: Parser CliArgs+cliArgsParser = CliArgs <$> optPin <*> commandParser++parserInfo :: ParserInfo CliArgs parserInfo = info- (commandParser <**> helper <**> simpleVersioner (showVersion version))+ (cliArgsParser <**> helper <**> simpleVersioner (showVersion version)) (fullDesc <> header "Phino - CLI Manipulator of 𝜑-Calculus Expressions")
src/CLI/Runners.hs view
@@ -29,6 +29,8 @@ import qualified Printer as P import Rewriter import Rule (RuleContext (..), matchProgramWithRule)+import System.Directory (doesFileExist, getModificationTime)+import System.Exit (exitSuccess) import Text.Printf (printf) import XMIR import qualified Yaml as Y@@ -36,6 +38,7 @@ runRewrite :: OptsRewrite -> IO () runRewrite OptsRewrite{..} = do validateOpts+ checkUpdate excluded <- validatedDispatches "hide" _hide included <- validatedDispatches "show" _show [loc] <- validatedDispatches "locator" [_locator]@@ -64,6 +67,9 @@ validateOpts = do when (_inPlace && isNothing _inputFile) (invalidCLIArguments "The option --in-place requires an input file") when (_inPlace && isJust _targetFile) (invalidCLIArguments "The options --in-place and --target cannot be used together")+ when (_update && _inPlace) (invalidCLIArguments "The options --update and --in-place cannot be used together")+ when (_update && isNothing _targetFile) (invalidCLIArguments "The option --update requires --target")+ when (_update && isNothing _inputFile) (invalidCLIArguments "The option --update requires an input file") when (length _show > 1) (invalidCLIArguments "The option --show can be used only once") validateLatexOptions _outputFormat@@ -72,6 +78,16 @@ [(_meetPopularity, "meet-popularity"), (_meetLength, "meet-length")] validateMust' _must validateXmirOptions _outputFormat [(_omitListing, "omit-listing"), (_omitComments, "omit-comments")] _focus+ checkUpdate :: IO ()+ checkUpdate = case (_update, _inputFile, _targetFile) of+ (True, Just src, Just tgt) -> do+ exists <- doesFileExist tgt+ when exists $ do+ newer <- (>) <$> getModificationTime tgt <*> getModificationTime src+ when newer $ do+ logDebug (printf "Target '%s' is newer than source '%s', skipping rewriting (--update)" tgt src)+ exitSuccess+ _ -> pure () validateBreakpoint :: Maybe String -> [Y.Rule] -> IO () validateBreakpoint Nothing _ = pure () validateBreakpoint (Just rule) rules =
src/CLI/Types.hs view
@@ -38,6 +38,7 @@ | CouldNotDataize | CouldNotPrintExpressionInXMIR | EmptySubstsOnMatch+ | VersionMismatch String String deriving (Exception) instance Show CmdException where@@ -46,6 +47,8 @@ show CouldNotDataize = "Could not dataize given program" show CouldNotPrintExpressionInXMIR = "Could not print expression with --output=xmir, only program printing is allowed" show EmptySubstsOnMatch = "Provided pattern was not matched, no substitutions are built"+ show (VersionMismatch expected actual) =+ printf "Version mismatch: --pin requires '%s', but this is phino %s" expected actual data Command = CmdRewrite OptsRewrite@@ -54,6 +57,11 @@ | CmdMerge OptsMerge | CmdMatch OptsMatch +data CliArgs = CliArgs+ { _pin :: Maybe String+ , _command :: Command+ }+ data IOFormat = XMIR | PHI | LATEX deriving (Eq) @@ -117,6 +125,7 @@ , _depthSensitive :: Bool , _nonumber :: Bool , _inPlace :: Bool+ , _update :: Bool , _sequence :: Bool , _canonize :: Bool , _compress :: Bool
src/CST.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -Wno-partial-fields -Wno-name-shadowing #-} @@ -11,6 +12,7 @@ import AST import Data.Maybe (isJust)+import qualified Data.Text as T import Misc import qualified Yaml as Y @@ -92,7 +94,7 @@ data EXCLAMATION = EXCL | NO_EXCL deriving (Eq, Show) -data META = META {excl :: EXCLAMATION, hd :: META_HEAD, rest :: String}+data META = META {excl :: EXCLAMATION, hd :: META_HEAD, rest :: T.Text} deriving (Eq, Show) data TAB@@ -113,8 +115,8 @@ = PA_TAU {attr :: ATTRIBUTE, arrow :: ARROW, expr :: EXPRESSION} | PA_FORMATION {attr :: ATTRIBUTE, voids :: [ATTRIBUTE], arrow :: ARROW, expr :: EXPRESSION} | PA_VOID {attr :: ATTRIBUTE, arrow :: ARROW, void :: VOID}- | PA_LAMBDA {func :: String}- | PA_LAMBDA' {func :: String} -- ASCII version of PA_LAMBDA+ | PA_LAMBDA {func :: T.Text}+ | PA_LAMBDA' {func :: T.Text} -- ASCII version of PA_LAMBDA | PA_META_LAMBDA {meta :: META} | PA_META_LAMBDA' {meta :: META} -- ASCII version of PA_META_LAMBDA' | PA_DELTA {bytes :: BYTES}@@ -167,7 +169,7 @@ deriving (Eq, Show) data ATTRIBUTE- = AT_LABEL {label :: String}+ = AT_LABEL {label :: T.Text} | AT_ALPHA {alpha :: ALPHA, idx :: Int} | AT_RHO {rho :: RHO} | AT_PHI {phi :: PHI}@@ -257,8 +259,8 @@ toCST' :: ToCST a b => a -> b toCST' = (`toCST` (0, EOL)) -metaTail :: String -> String-metaTail = drop 1+metaTail :: T.Text -> T.Text+metaTail = T.drop 1 -- This class is used to convert AST to CST -- CST is created with sugar and unicode@@ -340,7 +342,7 @@ (TAB tabs) next where- primitives :: [String]+ primitives :: [T.Text] primitives = ["number", "string"] withoutRhosInPrimitives :: Expression -> [Binding] -> ([Binding], [Binding]) withoutRhosInPrimitives _ [] = ([], [])@@ -437,7 +439,7 @@ toCST (BiDelta bts) ctx = PA_DELTA (toCST bts ctx) toCST (BiLambda func) _ = PA_LAMBDA func toCST (BiMetaLambda mt) _ = PA_META_LAMBDA (META EXCL F (metaTail mt))- toCST (BiMeta mt) _ = error $ "BiMeta binding " ++ mt ++ " cannot be converted to PAIR"+ toCST (BiMeta mt) _ = error $ "BiMeta binding " ++ T.unpack mt ++ " cannot be converted to PAIR" instance ToCST Binding APP_BINDING where toCST bd@(BiTau _ _) ctx = APP_BINDING (toCST bd ctx :: PAIR)
src/Canonizer.hs view
@@ -7,13 +7,14 @@ module Canonizer (canonize) where import AST+import qualified Data.Text as T import Rewriter (Rewritten) canonizeBindings :: [Binding] -> Int -> ([Binding], Int) canonizeBindings [] idx = ([], idx) canonizeBindings ((BiLambda _) : rest) idx = let (bds', idx') = canonizeBindings rest (idx + 1)- in (BiLambda ('F' : show idx) : bds', idx')+ in (BiLambda (T.pack ('F' : show idx)) : bds', idx') canonizeBindings (BiTau attr expr : rest) idx = let (expr', idx') = canonizeExpression expr idx (bds', idx'') = canonizeBindings rest idx'
src/Dataize.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -Wno-name-shadowing #-} {-# OPTIONS_GHC -Wno-unused-record-wildcards #-}@@ -15,6 +16,7 @@ import Data.List (partition) import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE+import qualified Data.Text as T import Deps (BuildTermFunc, SaveStepFunc, Term (TeAttribute)) import Locator (locatedExpression, withLocatedExpression) import Matcher (substEmpty)@@ -87,7 +89,7 @@ -- and expr is expression which program refers to. -- If Q refers to formation which contains binding with attribute == tau - -- the expression from this binding is returned.-phiDispatch :: String -> Expression -> Maybe (Expression, String)+phiDispatch :: T.Text -> Expression -> Maybe (Expression, String) phiDispatch tau expr = case expr of ExFormation bds -> boundExpr bds _ -> Nothing@@ -213,7 +215,7 @@ pure bts _dataize _ _ = throwIO (userError "Can't call _dataize from atoms with non-formation program") -atom :: String -> Expression -> DataizeContext -> IO Expression+atom :: T.Text -> Expression -> DataizeContext -> IO Expression atom "L_number_plus" self ctx = do left <- _dataize (ExDispatch self (AtLabel "x")) ctx right <- _dataize (ExDispatch self AtRho) ctx@@ -245,4 +247,4 @@ then pure (DataNumber (numToBts first)) else pure (ExDispatch self (AtLabel "y")) _ -> pure ExTermination-atom func _ _ = throwIO (userError (printf "Atom '%s' does not exist" func))+atom func _ _ = throwIO (userError (printf "Atom '%s' does not exist" (T.unpack func)))
src/Functions.hs view
@@ -12,6 +12,7 @@ import qualified Data.ByteString.Char8 as B import Data.Functor import qualified Data.Set as Set+import qualified Data.Text as T import Deps import GHC.IO (unsafePerformIO) import Logger (logDebug)@@ -75,7 +76,7 @@ _randomTau args subst = do attrs <- argsToAttrs args tau <- randomTau attrs- pure (TeAttribute (AtLabel tau))+ pure (TeAttribute (AtLabel (T.pack tau))) where argsToAttrs :: [Y.ExtraArgument] -> IO [String] argsToAttrs [] = pure []@@ -186,7 +187,7 @@ throwIO ( userError ( printf- "Couldn't convert given expression to 'Φ̇.string' object, only 'Φ̇.number' or 'Φ̇.string' are allowed\n%s"+ "Couldn't convert given expression to 'Φ.string' object, only 'Φ.number' or 'Φ.string' are allowed\n%s" (printExpression ex) ) )@@ -194,7 +195,7 @@ _string [Y.ArgAttribute attr] subst = do attr' <- buildAttributeThrows attr subst pure (TeExpression (DataString (strToBts (printAttribute attr'))))-_string _ _ = throwIO (userError "Function string() requires exactly 1 argument as attribute or data expression (Φ̇.number or Φ̇.string)")+_string _ _ = throwIO (userError "Function string() requires exactly 1 argument as attribute or data expression (Φ.number or Φ.string)") _number :: BuildTermMethod _number [Y.ArgExpression expr] subst = do@@ -203,8 +204,8 @@ DataString bts -> do num <- parseNumberThrows (btsToUnescapedStr bts) pure (TeExpression num)- _ -> throwIO (userError (printf "Function number() expects expression to be 'Φ̇.string', but got:\n%s" (printExpression expr')))-_number _ _ = throwIO (userError "Function number() requires exactly 1 argument as 'Φ̇.string'")+ _ -> throwIO (userError (printf "Function number() expects expression to be 'Φ.string', but got:\n%s" (printExpression expr')))+_number _ _ = throwIO (userError "Function number() requires exactly 1 argument as 'Φ.string'") _sum :: BuildTermMethod _sum args subst = do
src/LaTeX.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com@@ -23,6 +24,7 @@ import CST import Data.List (intercalate, nub) import Data.Maybe (isJust)+import qualified Data.Text as T import Encoding import Lining import Locator (locatedExpression)@@ -124,7 +126,7 @@ popularity = toDouble _meetPopularity / 100.0 renderToLatex :: (ToSalty a, ToASCII a, ToSingleLine a, ToLaTeX a, WithMargin a, Render a) => a -> LatexContext -> String-renderToLatex renderable LatexContext{..} = render (toLaTeX $ withLineFormat _line $ withMargin _margin $ withEncoding ASCII $ withSugarType _sugar renderable)+renderToLatex renderable LatexContext{..} = T.unpack $ render (toLaTeX $ withLineFormat _line $ withMargin _margin $ withEncoding ASCII $ withSugarType _sugar renderable) phiquation :: LatexContext -> String phiquation LatexContext{_nonumber = True} = "phiquation*"@@ -195,8 +197,8 @@ , ending False ctx ] -piped :: String -> String-piped str = "|" <> str <> "|"+piped :: T.Text -> T.Text+piped str = "|" <> toLaTeX str <> "|" class ToLaTeX a where toLaTeX :: a -> a@@ -218,7 +220,7 @@ toLaTeX expr = expr instance ToLaTeX ATTRIBUTE where- toLaTeX AT_LABEL{..} = AT_LABEL (piped (toLaTeX label))+ toLaTeX AT_LABEL{..} = AT_LABEL (piped label) toLaTeX AT_META{..} = AT_META (toLaTeX meta) toLaTeX AT_LAMBDA{} = AT_LAMBDA LAMBDA' toLaTeX AT_REST{} = AT_REST DOTS'@@ -239,8 +241,8 @@ instance ToLaTeX PAIR where toLaTeX PA_DELTA{..} = PA_DELTA' bytes- toLaTeX PA_LAMBDA{..} = PA_LAMBDA' (piped (toLaTeX func))- toLaTeX PA_LAMBDA'{..} = PA_LAMBDA' (piped (toLaTeX func))+ toLaTeX PA_LAMBDA{..} = PA_LAMBDA' (piped func)+ toLaTeX PA_LAMBDA'{..} = PA_LAMBDA' (piped func) toLaTeX PA_VOID{..} = PA_VOID (toLaTeX attr) arrow void toLaTeX PA_TAU{..} = PA_TAU (toLaTeX attr) arrow (toLaTeX expr) toLaTeX PA_FORMATION{..} = PA_FORMATION (toLaTeX attr) (map toLaTeX voids) arrow (toLaTeX expr)@@ -252,8 +254,8 @@ instance ToLaTeX META where toLaTeX META{..} =- let idx = readMaybe rest :: Maybe Int- rest' = if not (null rest) && length rest <= 2 && isJust idx then '_' : rest else rest+ let idx = readMaybe (T.unpack rest) :: Maybe Int+ rest' = if not (T.null rest) && T.length rest <= 2 && isJust idx then T.cons '_' rest else rest in META NO_EXCL (toLaTeX hd) rest' instance ToLaTeX META_HEAD where@@ -271,17 +273,14 @@ toLaTeX AAS_EXPR{..} = AAS_EXPR eol tab (toLaTeX expr) (toLaTeX args) toLaTeX args = args -instance ToLaTeX String where- toLaTeX = escapeUnprintedChars+instance ToLaTeX T.Text where+ toLaTeX = T.concatMap escape where- escapeUnprintedChars :: String -> String- escapeUnprintedChars [] = []- escapeUnprintedChars (ch : rest) = case ch of- '$' -> "\\char36{}" <> escapeUnprintedChars rest- '@' -> "\\char64{}" <> escapeUnprintedChars rest- '^' -> "\\char94{}" <> escapeUnprintedChars rest- '_' -> "\\char95{}" <> escapeUnprintedChars rest- _ -> ch : escapeUnprintedChars rest+ escape '$' = "\\char36{}"+ escape '@' = "\\char64{}"+ escape '^' = "\\char94{}"+ escape '_' = "\\char95{}"+ escape ch = T.singleton ch instance ToLaTeX SET where toLaTeX ST_BINDING{..} = ST_BINDING (toLaTeX binding)
src/Margin.hs view
@@ -8,6 +8,7 @@ module Margin (defaultMargin, withMargin, WithMargin) where import CST+import qualified Data.Text as T import Lining (ToSingleLine (..)) import Render (Render (..)) @@ -42,7 +43,7 @@ let single = toSingleLine ex main = withMargin' cfg expr singleMain = toSingleLine main- extra' = length (last (lines (render main))) + 4 -- 2 spaces + 2 braces around argument+ extra' = T.length (last (T.lines (render main))) + 4 -- 2 spaces + 2 braces around argument arg = withMargin' (indt, margin) tau singleArg = toSingleLine arg in if@@ -54,7 +55,7 @@ let single = toSingleLine ex main = withMargin' cfg expr singleMain = toSingleLine main- extra' = length (last (lines (render main))) + 4 -- 2 spaces + 2 braces around arguments+ extra' = T.length (last (T.lines (render main))) + 4 -- 2 spaces + 2 braces around arguments exprs = withMargin' (indt, margin) args singleExprs = toSingleLine exprs in if@@ -66,7 +67,7 @@ let single = toSingleLine ex main = withMargin' cfg expr singleMain = toSingleLine main- extra' = length (last (lines (render main))) + 4 -- 2 spaces + 2 braces around arguments+ extra' = T.length (last (T.lines (render main))) + 4 -- 2 spaces + 2 braces around arguments taus' = withMargin' (indt, margin) taus singleTaus = toSingleLine taus' in if@@ -118,4 +119,4 @@ withMargin' _ = id lengthOf :: Render a => a -> Int-lengthOf renderable = length (render renderable)+lengthOf renderable = T.length (render renderable)
src/Matcher.hs view
@@ -11,6 +11,7 @@ import Data.Map.Strict (Map) import qualified Data.Map.Strict as Map import Data.Maybe (catMaybes)+import Data.Text (Text) -- Meta value -- The right part of substitution@@ -18,7 +19,7 @@ = MvAttribute Attribute -- !a | MvBytes Bytes -- !b | MvBindings [Binding] -- !B- | MvFunction String -- !F+ | MvFunction Text -- !F | MvExpression Expression Expression -- !e, the second expression is scope, which is closest formation | MvTail [Tail] -- !t deriving (Eq, Show)@@ -32,7 +33,7 @@ -- Substitution -- Shows the match of meta name to meta value-newtype Subst = Subst (Map String MetaValue)+newtype Subst = Subst (Map Text MetaValue) deriving (Eq, Show) -- Empty substitution@@ -40,7 +41,7 @@ substEmpty = Subst Map.empty -- Singleton substitution with one (key -> value) pair-substSingle :: String -> MetaValue -> Subst+substSingle :: Text -> MetaValue -> Subst substSingle key value = Subst (Map.singleton key value) defaultScope :: Expression@@ -51,7 +52,7 @@ combine :: Subst -> Subst -> Maybe Subst combine (Subst a) (Subst b) = combine' (Map.toList b) a where- combine' :: [(String, MetaValue)] -> Map String MetaValue -> Maybe Subst+ combine' :: [(Text, MetaValue)] -> Map Text MetaValue -> Maybe Subst combine' [] acc = Just (Subst acc) combine' ((key, MvExpression tgt scope) : rest) acc = case Map.lookup key acc of Just (MvExpression expr' _)
src/Misc.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT@@ -42,12 +43,12 @@ import qualified Data.Aeson.Key as Key import qualified Data.Aeson.KeyMap as KeyMap import Data.Binary.IEEE754-import Data.Bits (Bits (shiftL), (.|.))+import Data.Bits (Bits (shiftL, shiftR), (.&.), (.|.)) import qualified Data.ByteString as B import Data.ByteString.Builder (toLazyByteString, word64BE) import Data.ByteString.Lazy (unpack) import qualified Data.ByteString.Lazy.UTF8 as U-import Data.Char (isPrint, ord)+import Data.Char (chr, isDigit, isPrint, ord) import Data.List (intercalate) import Data.Maybe (catMaybes) import qualified Data.Set as Set@@ -75,22 +76,22 @@ show FileDoesNotExist{..} = printf "File '%s' does not exist" _file show DirectoryDoesNotExist{..} = printf "Directory '%s' does not exist" _dir -matchBaseObject :: Expression -> Maybe String+matchBaseObject :: Expression -> Maybe T.Text matchBaseObject (ExDispatch ExGlobal (AtLabel label)) = Just label matchBaseObject _ = Nothing -pattern BaseObject :: String -> Expression+pattern BaseObject :: T.Text -> Expression pattern BaseObject label <- (matchBaseObject -> Just label) where BaseObject label = ExDispatch ExGlobal (AtLabel label) -- Minimal matcher function (required for view pattern)-matchDataObject :: Expression -> Maybe (String, Bytes)+matchDataObject :: Expression -> Maybe (T.Text, Bytes) 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 :: Expression -> Maybe T.Text matchOuter (BaseObject label) = Just label matchOuter (ExPhiAgain _ _ (BaseObject label)) = Just label matchOuter _ = Nothing@@ -118,7 +119,7 @@ pattern DataNumber :: Bytes -> Expression pattern DataNumber bts = DataObject "number" bts -pattern DataObject :: String -> Bytes -> Expression+pattern DataObject :: T.Text -> Bytes -> Expression pattern DataObject label bts <- (matchDataObject -> Just (label, bts)) where DataObject label bts =@@ -250,22 +251,35 @@ -- [64,20,0,0,0,0,0,0] btsToWord8 :: Bytes -> [Word8] btsToWord8 BtEmpty = []-btsToWord8 (BtOne bt) = case readHex bt of- [(hex, "")] -> [fromIntegral (hex :: Integer)]+btsToWord8 (BtOne bt) = [hexByte bt]+btsToWord8 (BtMany bts) = map hexByte bts+btsToWord8 (BtMeta mt) = error $ "Cannot convert meta bytes to Word8; " ++ T.unpack mt++hexByte :: String -> Word8+hexByte [hi, lo] = (nibble hi `shiftL` 4) .|. nibble lo+ where+ nibble c+ | isDigit c = fromIntegral (ord c - ord '0')+ | c >= 'A' && c <= 'F' = fromIntegral (ord c - ord 'A' + 10)+ | c >= 'a' && c <= 'f' = fromIntegral (ord c - ord 'a' + 10)+ | otherwise = error ("Invalid hex digit: " ++ [c])+hexByte bt = case readHex bt of+ [(hex, "")] -> fromIntegral (hex :: Integer) _ -> error $ "Invalid hex byte; " ++ bt-btsToWord8 (BtMany []) = []-btsToWord8 (BtMany (bt : bts)) =- case btsToWord8 (BtOne bt) of- [byte] -> byte : btsToWord8 (BtMany bts)- _ -> error $ "Invalid hex byte; " ++ bt-btsToWord8 (BtMeta mt) = error $ "Cannot convert meta bytes to Word8; " ++ mt -- >>> word8ToBytes [64, 20, 0] -- BtMany ["40","14","00"] word8ToBytes :: [Word8] -> Bytes word8ToBytes [] = BtEmpty-word8ToBytes [w8] = BtOne (printf "%02X" w8)-word8ToBytes bts = BtMany (map (printf "%02X") bts)+word8ToBytes [w8] = BtOne (toHex w8)+word8ToBytes bts = BtMany (map toHex bts)++toHex :: Word8 -> String+toHex w = [digit (w `shiftR` 4), digit (w .&. 0x0F)]+ where+ digit n+ | n < 10 = chr (fromIntegral n + ord '0')+ | otherwise = chr (fromIntegral n + ord 'A' - 10) -- Convert Bytes back to Double -- >>> btsToNum (BtMany ["40", "14", "00", "00", "00", "00", "00", "00"])
src/Parser.hs view
@@ -26,6 +26,7 @@ import Control.Monad (guard) import Data.Char (isAsciiLower, isDigit) import Data.Scientific (toRealFloat)+import qualified Data.Text as T import Data.Void import GHC.Char import Misc@@ -58,7 +59,7 @@ show CouldNotParseProgram{..} = printf "Couldn't parse given phi program, cause: %s" message show CouldNotParseExpression{..} = printf "Couldn't parse given phi expression, cause: %s" message show CouldNotParseAttribute{..} = printf "Couldn't parse given attribute, cause: %s" message- show CouldNotParseNumber{..} = printf "Couldn't parse given number to 'Φ̇.number', cause: %s" message+ show CouldNotParseNumber{..} = printf "Couldn't parse given number to 'Φ.number', cause: %s" message -- White space consumer whiteSpace :: Parser ()@@ -72,11 +73,12 @@ symbol :: String -> Parser String symbol = L.symbol whiteSpace -label' :: Parser String+-- Parsed as String then packed to Text once; BiLambda keeps String so function stays String+label' :: Parser T.Text label' = lexeme $ do first <- oneOf ['a' .. 'z'] rest <- many (satisfy (`notElem` " \r\n\t,.|':;!?][}{)(⟧⟦") <?> "allowed character")- return (first : rest)+ return (T.pack (first : rest)) function :: Parser String function = lexeme $ do@@ -115,21 +117,22 @@ metaSuffix :: Parser String metaSuffix = lexeme (many (oneOf ('_' : '-' : ['0' .. '9'] ++ ['a' .. 'z'] ++ ['A' .. 'Z']) <?> "meta suffix")) -meta :: Char -> Parser String+-- Meta variable names are packed to Text once here; all AST meta fields are Text+meta :: Char -> Parser T.Text meta ch = do _ <- char '!' c <- char ch suf <- metaSuffix- return (c : suf)+ return (T.pack (c : suf)) -meta' :: Char -> String -> Parser String+meta' :: Char -> String -> Parser T.Text meta' ch uni = choice [ meta ch , do _ <- symbol uni suf <- metaSuffix- return (ch : suf)+ return (T.pack (ch : suf)) ] byte :: Parser String@@ -286,7 +289,7 @@ , try metaBinding , try $ do _ <- lambda- BiLambda <$> function+ BiLambda . T.pack <$> function , do _ <- lambda BiMetaLambda <$> meta 'F'
src/Printer.hs view
@@ -24,6 +24,7 @@ import CST import Data.List (intercalate) import qualified Data.Map.Strict as Map+import qualified Data.Text as T import Encoding import Lining import Margin (defaultMargin, withMargin)@@ -42,19 +43,19 @@ logPrintConfig = (SWEET, UNICODE, SINGLELINE, defaultMargin) printProgram' :: Program -> PrintConfig -> String-printProgram' prog (sugar, encoding, line, margin) = render (withLineFormat line $ withMargin margin $ withEncoding encoding $ withSugarType sugar $ programToCST prog)+printProgram' prog (sugar, encoding, line, margin) = T.unpack $ render (withLineFormat line $ withMargin margin $ withEncoding encoding $ withSugarType sugar $ programToCST prog) printProgram :: Program -> String printProgram prog = printProgram' prog defaultPrintConfig printExpression' :: Expression -> PrintConfig -> String-printExpression' ex (sugar, encoding, line, margin) = render (withLineFormat line $ withMargin margin $ withEncoding encoding $ withSugarType sugar $ expressionToCST ex)+printExpression' ex (sugar, encoding, line, margin) = T.unpack $ render (withLineFormat line $ withMargin margin $ withEncoding encoding $ withSugarType sugar $ expressionToCST ex) printExpression :: Expression -> String printExpression ex = printExpression' ex defaultPrintConfig printAttribute' :: Attribute -> Encoding -> String-printAttribute' att encoding = render (withEncoding encoding (toCST att (0, NO_EOL) :: ATTRIBUTE))+printAttribute' att encoding = T.unpack $ render (withEncoding encoding (toCST att (0, NO_EOL) :: ATTRIBUTE)) printAttribute :: Attribute -> String printAttribute att =@@ -68,7 +69,7 @@ printBinding bd = printBinding' bd defaultPrintConfig printBytes :: Bytes -> String-printBytes bts = render (toCST bts (0, NO_EOL) :: BYTES)+printBytes bts = T.unpack $ render (toCST bts (0, NO_EOL) :: BYTES) printExtraArg' :: ExtraArgument -> PrintConfig -> String printExtraArg' (ArgAttribute att) (_, encoding, _, _) = printAttribute' att encoding@@ -88,14 +89,14 @@ printMetaValue (MvExpression ex _) config = printExpression' ex config printMetaValue (MvBytes bts) _ = printBytes bts printMetaValue (MvBindings bds) config = printExpression' (ExFormation bds) config-printMetaValue (MvFunction fun) _ = fun+printMetaValue (MvFunction fun) _ = T.unpack fun printMetaValue (MvTail tails) config = intercalate "," (map (`printTail` config) tails) printSubst :: Subst -> PrintConfig -> String printSubst (Subst mp) config = intercalate "\n"- (map (\(key, value) -> key <> " >> " <> printMetaValue value config) (Map.toList mp))+ (map (\(key, value) -> T.unpack key <> " >> " <> printMetaValue value config) (Map.toList mp)) printSubsts' :: [Subst] -> PrintConfig -> String printSubsts' [] _ = "------"
src/Render.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com@@ -8,26 +9,25 @@ module Render where import CST-import Data.List (intercalate)-import Text.Printf (printf)+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TLB class Render a where- render :: a -> String+ render :: a -> Text instance Render String where- render str = str+ render = T.pack -instance Render Integer where- render = show+instance Render Text where+ render = id instance Render Int where- render = show--instance Render Double where- render = show+ render = T.pack . show instance Render Char where- render ch = [ch]+ render = T.singleton instance Render LCB where render LCB = "{"@@ -102,7 +102,7 @@ instance Render BYTES where render BT_EMPTY = "--" render (BT_ONE bte) = render bte <> "-"- render (BT_MANY bts) = intercalate "-" bts+ render (BT_MANY bts) = T.intercalate "-" (map render bts) render (BT_META mt) = render mt instance Render EXCLAMATION where@@ -130,7 +130,7 @@ render ALPHA' = "~" instance Render TAB where- render TAB{..} = concat (replicate indent " ")+ render TAB{..} = T.replicate indent " " render TAB' = " " render NO_TAB = "" @@ -143,19 +143,22 @@ render PA_FORMATION{voids = [], attr, arrow, expr} = render (PA_TAU attr arrow expr) render PA_FORMATION{..} = render attr <> "(" <> render voids <> ")" <> render SPACE <> render arrow <> render SPACE <> render expr render PA_LAMBDA{..} = render LAMBDA <> render SPACE <> render DASHED_ARROW <> render SPACE <> render func- render PA_LAMBDA'{..} = "L> " <> func+ render PA_LAMBDA'{..} = "L> " <> render func render PA_VOID{..} = render attr <> render SPACE <> render arrow <> render SPACE <> render void render PA_DELTA{..} = render DELTA <> render SPACE <> render DASHED_ARROW <> render SPACE <> render bytes render PA_DELTA'{..} = "D> " <> render bytes render PA_META_LAMBDA{..} = render LAMBDA <> render SPACE <> render DASHED_ARROW <> render SPACE <> render meta- render PA_META_LAMBDA'{..} = render "L> " <> render meta+ render PA_META_LAMBDA'{..} = "L> " <> render meta render PA_META_DELTA{..} = render DELTA <> render SPACE <> render DASHED_ARROW <> render SPACE <> render meta- render PA_META_DELTA'{..} = render "D> " <> render meta+ render PA_META_DELTA'{..} = "D> " <> render meta instance Render BINDINGS where- render BDS_EMPTY{} = ""- render BDS_PAIR{..} = render COMMA <> render eol <> render tab <> render pair <> render bindings- render BDS_META{..} = render COMMA <> render eol <> render tab <> render meta <> render bindings+ render = TL.toStrict . TLB.toLazyText . binds+ where+ binds :: BINDINGS -> TLB.Builder+ binds BDS_EMPTY{} = mempty+ binds BDS_PAIR{..} = TLB.fromText (render COMMA <> render eol <> render tab <> render pair) <> binds bindings+ binds BDS_META{..} = TLB.fromText (render COMMA <> render eol <> render tab <> render meta) <> binds bindings instance Render APP_BINDING where render APP_BINDING{..} = render pair@@ -169,8 +172,11 @@ render APP_ARG{..} = render expr <> render args instance Render APP_ARGS where- render AAS_EMPTY = ""- render AAS_EXPR{..} = render COMMA <> render eol <> render tab <> render expr <> render args+ render = TL.toStrict . TLB.toLazyText . arguments+ where+ arguments :: APP_ARGS -> TLB.Builder+ arguments AAS_EMPTY = mempty+ arguments AAS_EXPR{..} = TLB.fromText (render COMMA <> render eol <> render tab <> render expr) <> arguments args instance Render EXPRESSION where render EX_GLOBAL{..} = render global@@ -182,18 +188,18 @@ render EX_APPLICATION{..} = render expr <> render space <> "(" <> render eol <> render tab <> render tau <> render eol' <> render tab' <> ")" render EX_APPLICATION_TAUS{..} = render expr <> render space <> "(" <> render eol <> render tab <> render taus <> render eol' <> render tab' <> ")" render EX_APPLICATION_EXPRS{..} = render expr <> render space <> "(" <> render eol <> render tab <> render args <> render eol' <> render tab' <> ")"- render EX_STRING{..} = '"' : render str <> "\""- render EX_NUMBER{..} = either show show num+ render EX_STRING{..} = "\"" <> render str <> "\""+ render EX_NUMBER{..} = either (T.pack . show) (T.pack . show) num render EX_META{..} = render meta render EX_META_TAIL{..} = render expr <> " * " <> render meta- render EX_PHI_MEET{..} = "\\phiMeet{" <> maybe "" (++ ":") prefix <> render idx <> "}{ " <> render expr <> " }"- render EX_PHI_AGAIN{..} = "\\phiAgain{" <> maybe "" (++ ":") prefix <> render idx <> "}"+ render EX_PHI_MEET{..} = "\\phiMeet{" <> maybe "" (\p -> T.pack p <> ":") prefix <> render idx <> "}{ " <> render expr <> " }"+ render EX_PHI_AGAIN{..} = "\\phiAgain{" <> maybe "" (\p -> T.pack p <> ":") prefix <> render idx <> "}" instance Render [ATTRIBUTE] where- render attrs = intercalate ", " (map render attrs)+ render attrs = T.intercalate ", " (map render attrs) instance Render ATTRIBUTE where- render AT_LABEL{..} = label+ render AT_LABEL{..} = render label render AT_ALPHA{..} = render alpha <> render idx render AT_RHO{..} = render rho render AT_PHI{..} = render phi@@ -208,16 +214,16 @@ instance Render SET where render ST_BINDING{..} = render binding- render ST_ATTRIBUTES{..} = printf "[ %s ]" (intercalate ", " (map render attrs))+ render ST_ATTRIBUTES{..} = "[ " <> T.intercalate ", " (map render attrs) <> " ]" instance Render LOGIC_OPERATOR where render AND = "\\;\\text{and}\\;" render OR = "\\;\\text{or}\\;" instance Render NUMBER where- render INDEX{..} = printf "\\indexof{ %s }" (render attr)- render LENGTH{..} = printf "\\vert %s \\vert" (render binding)- render LITERAL{..} = show num+ render INDEX{..} = "\\indexof{ " <> render attr <> " }"+ render LENGTH{..} = "\\vert " <> render binding <> " \\vert"+ render LITERAL{..} = T.pack (show num) instance Render COMPARABLE where render CMP_ATTR{..} = render attr@@ -229,23 +235,23 @@ render NOT_EQUAL = "\\not=" instance Render CONDITION where- render CO_BELONGS{..} = render attr <> render SPACE <> render belongs <> render SPACE <> render set+ render CO_BELONGS{..} = render attr <> " " <> render belongs <> " " <> render set render CO_LOGIC{conditions = [cond]} = render cond- render CO_LOGIC{..} = intercalate (printf " %s " (render operator)) (map renderWrapped conditions)+ render CO_LOGIC{..} = T.intercalate (" " <> render operator <> " ") (map renderWrapped conditions) where- renderWrapped :: CONDITION -> String+ renderWrapped :: CONDITION -> Text renderWrapped CO_LOGIC{conditions = [cond]} = render cond- renderWrapped cond@CO_LOGIC{} = printf "( %s )" (render cond)+ renderWrapped cond@CO_LOGIC{} = "( " <> render cond <> " )" renderWrapped cond = render cond- render CO_NF{..} = printf "\\isnormal{ %s }" (render expr)+ render CO_NF{..} = "\\isnormal{ " <> render expr <> " }" render CO_NOT{..} = renderFunc "not" condition- render CO_COMPARE{..} = render left <> render SPACE <> render equal <> render SPACE <> render right- render CO_MATCHES{..} = printf "matches( %s, %s )" regex (render expr)- render CO_PART_OF{..} = printf "part-of( %s, %s )" (render expr) (render binding)+ render CO_COMPARE{..} = render left <> " " <> render equal <> " " <> render right+ render CO_MATCHES{..} = "matches( " <> T.pack regex <> ", " <> render expr <> " )"+ render CO_PART_OF{..} = "part-of( " <> render expr <> ", " <> render binding <> " )" render CO_EMPTY = "" -renderFunc :: Render a => String -> a -> String-renderFunc func renderable = printf "%s( %s )" func (render renderable)+renderFunc :: Render a => Text -> a -> Text+renderFunc func renderable = func <> "( " <> render renderable <> " )" instance Render EXTRA_ARG where render ARG_ATTR{..} = render attr@@ -254,6 +260,6 @@ render ARG_BYTES{..} = render bytes instance Render EXTRA where- render EXTRA{func = "contextualize", args = arg : rest, ..} = printf "$ %s \\coloneqq \\ctx{ %s }{ %s } $" (render meta) (render arg) (intercalate ", " (map render rest))- render EXTRA{func = "scope", args = arg : _, ..} = printf "$ %s \\coloneqq \\scopeof{ %s } $" (render meta) (render arg)- render EXTRA{..} = printf "$ %s \\coloneqq %s( %s ) $" (render meta) func (intercalate ", " (map render args))+ render EXTRA{func = "contextualize", args = arg : rest, ..} = "$ " <> render meta <> " \\coloneqq \\ctx{ " <> render arg <> " }{ " <> T.intercalate ", " (map render rest) <> " } $"+ render EXTRA{func = "scope", args = arg : _, ..} = "$ " <> render meta <> " \\coloneqq \\scopeof{ " <> render arg <> " } $"+ render EXTRA{..} = "$ " <> render meta <> " \\coloneqq " <> T.pack func <> "( " <> T.intercalate ", " (map render args) <> " ) $"
src/Sugar.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -Wno-name-shadowing #-}
src/XMIR.hs view
@@ -142,10 +142,10 @@ formationBinding :: Binding -> XmirContext -> IO (Maybe Node) formationBinding (BiTau (AtLabel label) (ExFormation bds)) ctx = do inners <- nestedBindings bds ctx- pure (Just (object [("name", label)] inners))+ pure (Just (object [("name", T.unpack label)] inners)) formationBinding (BiTau (AtLabel label) expr) ctx = do (base, children) <- expression expr ctx- pure (Just (object [("name", label), ("base", base)] children))+ pure (Just (object [("name", T.unpack label), ("base", base)] children)) formationBinding (BiTau AtPhi expr) ctx = do (base, children) <- expression expr ctx pure (Just (object [("name", show AtPhi), ("base", base)] children))@@ -154,7 +154,7 @@ formationBinding (BiLambda _) _ = pure (Just (object [("name", show AtLambda)] [])) formationBinding (BiVoid AtRho) _ = pure Nothing formationBinding (BiVoid AtPhi) _ = pure (Just (object [("name", show AtPhi), ("base", "∅")] []))-formationBinding (BiVoid (AtLabel label)) _ = pure (Just (object [("name", label), ("base", "∅")] []))+formationBinding (BiVoid (AtLabel label)) _ = pure (Just (object [("name", T.unpack label), ("base", "∅")] [])) formationBinding binding _ = throwIO (UnsupportedBinding binding) nestedBindings :: [Binding] -> XmirContext -> IO [Node]@@ -207,10 +207,10 @@ getPackage :: Expression -> IO ([String], Expression) getPackage (ExFormation [BiTau (AtLabel label) (ExFormation [bd, BiLambda "Package", BiVoid AtRho]), BiVoid AtRho]) = do (pckg, expr') <- getPackage (ExFormation [bd, BiLambda "Package", BiVoid AtRho])- pure (label : pckg, expr')+ pure (T.unpack label : pckg, expr') getPackage (ExFormation [BiTau (AtLabel label) (ExFormation [bd, BiLambda "Package", BiVoid AtRho]), BiLambda "Package", BiVoid AtRho]) = do (pckg, expr') <- getPackage (ExFormation [bd, BiLambda "Package", BiVoid AtRho])- pure (label : pckg, expr')+ pure (T.unpack label : pckg, expr') getPackage (ExFormation [BiTau at ex, BiLambda "Package", BiVoid AtRho]) = pure ([], ExFormation [BiTau at ex, BiVoid AtRho]) getPackage (ExFormation [bd, BiVoid AtRho]) = pure ([], ExFormation [bd, BiVoid AtRho]) getPackage ex = throwIO (userError (printf "Can't extract package from given expression:\n %s" (printExpression ex)))@@ -378,7 +378,7 @@ if null pckg then pure (Program (ExFormation [obj, BiVoid AtRho])) else- let bd = foldr (\part acc -> BiTau (AtLabel part) (ExFormation [acc, BiLambda "Package", BiVoid AtRho])) obj pckg+ let bd = foldr (\part acc -> BiTau (AtLabel (T.pack part)) (ExFormation [acc, BiLambda "Package", BiVoid AtRho])) obj pckg in pure (Program (ExFormation [bd, BiVoid AtRho])) | otherwise -> throwIO (InvalidXMIRFormat "Expected single <object> element" doc) _ -> throwIO (InvalidXMIRFormat "NodeElement is expected as root element" doc)@@ -390,17 +390,17 @@ name <- getAttr "name" cur bds <- mapM (`xmirToFormationBinding` (name : fqn)) (cur C.$/ C.element (toName "o")) >>= uniqueBindings' case name of- "λ" -> pure (BiLambda (intercalate "_" ("L" : reverse fqn)))+ "λ" -> pure (BiLambda (T.pack (intercalate "_" ("L" : reverse fqn)))) ('α' : _) -> throwIO (InvalidXMIRFormat "Formation child @name can't start with α" cur) "φ" -> pure (BiTau AtPhi (ExFormation (withVoidRho bds)))- _ -> pure (BiTau (AtLabel name) (ExFormation (withVoidRho bds)))+ _ -> pure (BiTau (AtLabel (T.pack name)) (ExFormation (withVoidRho bds))) | otherwise = do name <- getAttr "name" cur base <- getAttr "base" cur attr <- case name of "φ" -> pure AtPhi ('α' : _) -> throwIO (InvalidXMIRFormat "Formation child @name can't start with α" cur)- _ -> pure (AtLabel name)+ _ -> pure (AtLabel (T.pack name)) case base of "∅" -> pure (BiVoid attr) _ -> do@@ -496,7 +496,7 @@ ch : _ | ch `notElem` ['a' .. 'z'] -> throwIO (InvalidXMIRFormat (printf "The attribute '%s' must start with ['a'..'z']" attr) cur) | '.' `elem` attr -> throwIO (InvalidXMIRFormat "Attribute can't contain dots" cur)- | otherwise -> pure (AtLabel attr)+ | otherwise -> pure (AtLabel (T.pack attr)) _ -> throwIO (InvalidXMIRFormat (printf "Invalid attribute given: %s" attr) cur) hasAttr :: String -> C.Cursor -> Bool
test/ASTSpec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
test/BuilderSpec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT @@ -8,10 +10,11 @@ import Control.Monad import Data.Either (isLeft) import Data.Map.Strict qualified as Map+import Data.Text qualified as T import Matcher import Test.Hspec (Example (Arg), Expectation, Spec, SpecWith, anyException, describe, it, shouldBe, shouldSatisfy, shouldThrow) -test :: (Show a, Eq a) => (a -> Subst -> Either String (a, a)) -> [(String, a, [(String, MetaValue)], Either String (a, a))] -> SpecWith (Arg Expectation)+test :: (Show a, Eq a) => (a -> Subst -> Either String (a, a)) -> [(String, a, [(T.Text, MetaValue)], Either String (a, a))] -> SpecWith (Arg Expectation) test function useCases = forM_ useCases $ \(desc, expr, mp, res) -> it desc $ function expr (Subst (Map.fromList mp)) `shouldBe` res
test/CLISpec.hs view
@@ -10,11 +10,12 @@ import Control.Exception import Control.Monad (forM_, unless, when) import Data.List (intercalate, isInfixOf)+import Data.Time.Clock (addUTCTime, getCurrentTime) import Data.Time.Clock.POSIX (getPOSIXTime) import Data.Version (showVersion) import GHC.IO.Handle import Paths_phino (version)-import System.Directory (createDirectoryIfMissing, doesDirectoryExist, doesFileExist, getTemporaryDirectory, listDirectory, removeDirectoryRecursive, removeFile)+import System.Directory (createDirectoryIfMissing, doesDirectoryExist, doesFileExist, getTemporaryDirectory, listDirectory, removeDirectoryRecursive, removeFile, setModificationTime) import System.Exit (ExitCode (ExitFailure)) import System.FilePath ((</>)) import System.IO@@ -71,6 +72,13 @@ (openTempFile "." pattern) (\(path, _) -> removeFile path) +withTempFileContent :: String -> String -> (FilePath -> IO a) -> IO a+withTempFileContent pattern content action =+ withTempFile pattern $ \(path, h) -> do+ hPutStr h content+ hClose h+ action path+ testCLI' :: [String] -> [String] -> Either ExitCode () -> Expectation testCLI' args outputs exit = do (out, result) <- withStdout (try (runCLI args) :: IO (Either ExitCode ()))@@ -110,6 +118,25 @@ ["--help"] ["Phino - CLI Manipulator of 𝜑-Calculus Expressions", "Usage:"] + describe "--pin" $ do+ it "succeeds when --pin matches actual version" $+ withStdin "Q -> [[ ]]" $+ testCLISucceeded+ ["--pin=" ++ showVersion version, "rewrite", "--sweet"]+ ["{⟦⟧}"]++ it "fails when --pin doesn't match actual version" $+ withStdin "Q -> [[ ]]" $+ testCLIFailed+ ["--pin=9.9.9.9", "rewrite"]+ ["Version mismatch: --pin requires '9.9.9.9', but this is phino " ++ showVersion version]++ it "fails when --pin is empty" $+ withStdin "Q -> [[ ]]" $+ testCLIFailed+ ["--pin=", "rewrite"]+ ["Version mismatch: --pin requires ''"]+ it "prints debug info with --log-level=DEBUG" $ withStdin "{[[]]}" $ testCLISucceeded ["rewrite", "--log-level=DEBUG"] ["[DEBUG]:"]@@ -154,6 +181,24 @@ ["rewrite", "--in-place", "--target=output.phi", path] ["--in-place and --target cannot be used together"] + it "when --update is used without --target" $+ withStdin "Q -> [[ ]]" $+ testCLIFailed+ ["rewrite", "--update"]+ ["--update requires --target"]++ it "when --update is used without an input file" $+ withStdin "Q -> [[ ]]" $+ testCLIFailed+ ["rewrite", "--update", "--target=output.phi"]+ ["--update requires an input file"]++ it "when --update is used with --in-place" $+ withStdin "Q -> [[ ]]" $+ testCLIFailed+ ["rewrite", "--update", "--in-place", "input.phi"]+ ["--update and --in-place cannot be used together"]+ it "with --depth-sensitive" $ withStdin "Q -> [[ x -> \"x\"]]" $ testCLIFailed@@ -693,6 +738,30 @@ testCLISucceeded ["rewrite", rule "simple.yaml", "--in-place", "--sweet", path] [] content <- readFile path content `shouldBe` "{⟦ x ↦ \"bar\" ⟧}"++ it "skips rewriting with --update when target is newer than source" $+ withTempFileContent "src-XXXXXX.phi" "Q -> [[ x -> \"foo\" ]]" $ \src ->+ withTempFileContent "tgt-XXXXXX.phi" "ORIGINAL" $ \tgt -> do+ now <- getCurrentTime+ setModificationTime src (addUTCTime (-60) now)+ setModificationTime tgt now+ testCLISucceeded+ ["rewrite", rule "simple.yaml", "--update", "--sweet", "--target=" ++ tgt, src]+ []+ content <- readFile tgt+ content `shouldBe` "ORIGINAL"++ it "rewrites with --update when source is newer than target" $+ withTempFileContent "src-XXXXXX.phi" "Q -> [[ x -> \"foo\" ]]" $ \src ->+ withTempFileContent "tgt-XXXXXX.phi" "ORIGINAL" $ \tgt -> do+ now <- getCurrentTime+ setModificationTime tgt (addUTCTime (-60) now)+ setModificationTime src now+ testCLISucceeded+ ["rewrite", rule "simple.yaml", "--update", "--sweet", "--target=" ++ tgt, src]+ []+ content <- readFile tgt+ content `shouldBe` "{⟦ x ↦ \"bar\" ⟧}" it "rewrites with cycles" $ withStdin "Q -> [[ x -> \"x\" ]]" $
test/CSTSpec.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-} -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT@@ -10,6 +11,7 @@ import CST import Control.Monad (forM_) import Data.Aeson+import Data.Text qualified as T import Data.Yaml qualified as Yaml import Encoding (Encoding (ASCII), withEncoding) import GHC.Generics (Generic)@@ -24,7 +26,7 @@ data CSTPack = CSTPack { program :: String- , result :: String+ , result :: T.Text } deriving (Generic, Show, FromJSON)
test/ConditionSpec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT
test/DataizeSpec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT
test/FunctionsSpec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT
test/MatcherSpec.hs view
@@ -1,6 +1,4 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE OverloadedStrings #-} -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT@@ -11,16 +9,12 @@ import Control.Monad (forM_) import Data.Map.Strict qualified as Map import Data.Maybe (fromMaybe)+import Data.Text qualified as T import Matcher import Test.Hspec (Example (Arg), Expectation, Spec, SpecWith, describe, it, shouldBe) -class Expected e where- type ExpectedResult e- toExpected :: e -> ExpectedResult e--instance Expected [[(String, MetaValue)]] where- type ExpectedResult [[(String, MetaValue)]] = [Subst]- toExpected = map (Subst . Map.fromList)+substs :: [[(T.Text, MetaValue)]] -> [Subst]+substs = map (Subst . Map.fromList) maybeCombined :: Subst -> Subst -> Subst maybeCombined first second =@@ -29,13 +23,12 @@ (combine first second) test ::- (Expected e, ExpectedResult e ~ r, Eq r, Show r) =>- (a -> a -> b -> r) ->- [(String, a, a, b, e)] ->+ (a -> a -> b -> [Subst]) ->+ [(String, a, a, b, [Subst])] -> SpecWith (Arg Expectation) test function useCases =- forM_ useCases $ \(desc, ptn, tgt, scope, mp) ->- it desc $ function ptn tgt scope `shouldBe` toExpected mp+ forM_ useCases $ \(desc, ptn, tgt, scope, expected) ->+ it desc $ function ptn tgt scope `shouldBe` expected spec :: Spec spec = do@@ -47,7 +40,7 @@ , ExGlobal , ExFormation [BiTau AtPhi ExGlobal, BiTau AtRho ExGlobal] , defaultScope- , [[], []]+ , substs [[], []] ) , ( "Q.!a => [[ @ -> Q.y, ^ -> [[ a -> Q.w ]], @ -> Q.y ]] => [(a >> y), (a >> w), (a >> y)]"@@ -58,7 +51,7 @@ , BiTau AtPhi (ExDispatch ExGlobal (AtLabel "y")) ] , defaultScope- , [[("a", MvAttribute (AtLabel "y"))], [("a", MvAttribute (AtLabel "w"))], [("a", MvAttribute (AtLabel "y"))]]+ , substs [[("a", MvAttribute (AtLabel "y"))], [("a", MvAttribute (AtLabel "w"))], [("a", MvAttribute (AtLabel "y"))]] ) , ( "[[!a -> Q.org.!a]] => [[f -> [[x -> Q.org.x]], t -> [[y -> Q.org.y]] => [(!a >> x), (!a >> y)]"@@ -68,27 +61,27 @@ , BiTau (AtLabel "t") (ExFormation [BiTau (AtLabel "y") (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "y"))]) ] , defaultScope- , [[("a", MvAttribute (AtLabel "x"))], [("a", MvAttribute (AtLabel "y"))]]+ , substs [[("a", MvAttribute (AtLabel "x"))], [("a", MvAttribute (AtLabel "y"))]] ) , ( "!e => [[x -> Q]] => [(!e >> [[x -> Q]] ), (!e >> Q)]" , ExMeta "e" , ExFormation [BiTau (AtLabel "x") ExGlobal] , defaultScope- ,- [ [("e", MvExpression (ExFormation [BiTau (AtLabel "x") ExGlobal]) defaultScope)]- , [("e", MvExpression ExGlobal (ExFormation [BiTau (AtLabel "x") ExGlobal]))]- ]+ , substs+ [ [("e", MvExpression (ExFormation [BiTau (AtLabel "x") ExGlobal]) defaultScope)]+ , [("e", MvExpression ExGlobal (ExFormation [BiTau (AtLabel "x") ExGlobal]))]+ ] ) , ( "!e.!a => Q.org.eolang => [(!e >> Q.org, !a >> eolang), (!e >> Q, !a >> org)]" , ExDispatch (ExMeta "e") (AtMeta "a") , ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang") , defaultScope- ,- [ [("e", MvExpression (ExDispatch ExGlobal (AtLabel "org")) defaultScope), ("a", MvAttribute (AtLabel "eolang"))]- , [("e", MvExpression ExGlobal defaultScope), ("a", MvAttribute (AtLabel "org"))]- ]+ , substs+ [ [("e", MvExpression (ExDispatch ExGlobal (AtLabel "org")) defaultScope), ("a", MvAttribute (AtLabel "eolang"))]+ , [("e", MvExpression ExGlobal defaultScope), ("a", MvAttribute (AtLabel "org"))]+ ] ) , ( "⟦!B1, !a ↦ ∅, !B2⟧.!a => ⟦ x ↦ ξ.t, t ↦ ∅ ⟧.t(ρ ↦ ⟦ x ↦ ξ.t, t ↦ ∅ ⟧) => [(!B1 >> ⟦x ↦ ξ.t⟧, !a >> t, !B2 >> ⟦⟧ )]"@@ -111,13 +104,13 @@ ) ) , defaultScope- ,- [- [ ("B1", MvBindings [BiTau (AtLabel "x") (ExDispatch ExThis (AtLabel "t"))])- , ("a", MvAttribute (AtLabel "t"))- , ("B2", MvBindings [])+ , substs+ [+ [ ("B1", MvBindings [BiTau (AtLabel "x") (ExDispatch ExThis (AtLabel "t"))])+ , ("a", MvAttribute (AtLabel "t"))+ , ("B2", MvBindings [])+ ] ]- ] ) , ( "somebody"@@ -154,52 +147,52 @@ ) ] , defaultScope- ,- [+ , substs [- ( "e0"- , MvExpression- ExGlobal- ( ExFormation- [ BiTau (AtLabel "a") ExGlobal- , BiTau (AtLabel "b") ExThis- ]- )- )- ,- ( "e-first"- , MvExpression- ExThis- ( ExFormation- [ BiTau (AtLabel "a") ExGlobal- , BiTau (AtLabel "b") ExThis- ]- )- )- ,- ( "e-second"- , MvExpression- (ExFormation [BiVoid AtPhi])- ( ExFormation- [ BiTau (AtLabel "a") ExGlobal- , BiTau (AtLabel "b") (ExFormation [BiVoid AtPhi])- ]- )- )+ [+ ( "e0"+ , MvExpression+ ExGlobal+ ( ExFormation+ [ BiTau (AtLabel "a") ExGlobal+ , BiTau (AtLabel "b") ExThis+ ]+ )+ )+ ,+ ( "e-first"+ , MvExpression+ ExThis+ ( ExFormation+ [ BiTau (AtLabel "a") ExGlobal+ , BiTau (AtLabel "b") ExThis+ ]+ )+ )+ ,+ ( "e-second"+ , MvExpression+ (ExFormation [BiVoid AtPhi])+ ( ExFormation+ [ BiTau (AtLabel "a") ExGlobal+ , BiTau (AtLabel "b") (ExFormation [BiVoid AtPhi])+ ]+ )+ )+ ] ]- ] ) ] describe "matchAttribute: attribute => attribute => substitution" $ forM_- [ ("~1 => ~1 => [()]", AtAlpha 1, AtAlpha 1, [[]])- , ("!a => ^ => [(!a >> ^)]", AtMeta "a", AtRho, [[("a", MvAttribute AtRho)]])- , ("!a => @ => [(!a >> @)]", AtMeta "a", AtPhi, [[("a", MvAttribute AtPhi)]])- , ("~0 => [] => [()]", AtAlpha 0, AtLabel "x", [])+ [ ("~1 => ~1 => [()]", AtAlpha 1, AtAlpha 1, substs [[]])+ , ("!a => ^ => [(!a >> ^)]", AtMeta "a", AtRho, substs [[("a", MvAttribute AtRho)]])+ , ("!a => @ => [(!a >> @)]", AtMeta "a", AtPhi, substs [[("a", MvAttribute AtPhi)]])+ , ("~0 => [] => [()]", AtAlpha 0, AtLabel "x", substs []) ]- ( \(desc, ptn, tgt, mp) ->- it desc $ matchAttribute ptn tgt `shouldBe` toExpected mp+ ( \(desc, ptn, tgt, expected) ->+ it desc $ matchAttribute ptn tgt `shouldBe` expected ) describe "matchBindings: [binding] => [binding] => substitution" $@@ -210,114 +203,114 @@ , [] , [] , defaultScope- , [[]]+ , substs [[]] ) , ( "[[!B]] => T:[[x -> ?, D> 01-, L> Func]] => (!B >> T)" , [BiMeta "B"] , [BiVoid (AtLabel "x"), BiDelta (BtOne "01"), BiLambda "Func"] , defaultScope- , [[("B", MvBindings [BiVoid (AtLabel "x"), BiDelta (BtOne "01"), BiLambda "Func"])]]+ , substs [[("B", MvBindings [BiVoid (AtLabel "x"), BiDelta (BtOne "01"), BiLambda "Func"])]] ) , ( "[[D> 00-]] => [[D> 00-, L> Func]] => []" , [BiDelta (BtOne "00")] , [BiDelta (BtOne "00"), BiLambda "Func"] , defaultScope- , []+ , substs [] ) , ( "[[y -> ?, !a -> ?]] => [[y -> ?, x -> ?]] => (!a >> x)" , [BiVoid (AtLabel "y"), BiVoid (AtMeta "a")] , [BiVoid (AtLabel "y"), BiVoid (AtLabel "x")] , defaultScope- , [[("a", MvAttribute (AtLabel "x"))]]+ , substs [[("a", MvAttribute (AtLabel "x"))]] ) , ( "[[!B, x -> ?]] => [[x -> ?]] => (!B >> [[]])" , [BiMeta "B", BiVoid (AtLabel "x")] , [BiVoid (AtLabel "x")] , defaultScope- , [[("B", MvBindings [])]]+ , substs [[("B", MvBindings [])]] ) , ( "[[!B1, x -> ?, !B2]] => [[x -> ?, y -> ?]] => (!B1 >> [[]], !B2 >> [[y -> ?]])" , [BiMeta "B1", BiVoid (AtLabel "x"), BiMeta "B2"] , [BiVoid (AtLabel "x"), BiVoid (AtLabel "y")] , defaultScope- , [[("B1", MvBindings []), ("B2", MvBindings [BiVoid (AtLabel "y")])]]+ , substs [[("B1", MvBindings []), ("B2", MvBindings [BiVoid (AtLabel "y")])]] ) , ( "[[!B1, !x -> ?, !B2]] => [[y -> ?, D> -> 00-, L> Func]] => (!x >> y, !B1 >> [[]], !B2 >> [[D> -> 00-, L> Func]])" , [BiMeta "B1", BiVoid (AtMeta "x"), BiMeta "B2"] , [BiVoid (AtLabel "y"), BiDelta (BtOne "00"), BiLambda "Func"] , defaultScope- , [[("B1", MvBindings []), ("B2", MvBindings [BiDelta (BtOne "00"), BiLambda "Func"]), ("x", MvAttribute (AtLabel "y"))]]+ , substs [[("B1", MvBindings []), ("B2", MvBindings [BiDelta (BtOne "00"), BiLambda "Func"]), ("x", MvAttribute (AtLabel "y"))]] ) , ( "[[!x -> ?, !y -> ?]] => [[a -> ?, b -> ?]] => (!x >> a, !y >> b)" , [BiVoid (AtMeta "x"), BiVoid (AtMeta "y")] , [BiVoid (AtLabel "a"), BiVoid (AtLabel "b")] , defaultScope- , [[("x", MvAttribute (AtLabel "a")), ("y", MvAttribute (AtLabel "b"))]]+ , substs [[("x", MvAttribute (AtLabel "a")), ("y", MvAttribute (AtLabel "b"))]] ) , ( "[[t -> ?, !B]] => [[t -> ?, x -> Q, y -> $]] => (!B >> [[x -> Q, y -> $]])" , [BiVoid (AtLabel "t"), BiMeta "B"] , [BiVoid (AtLabel "t"), BiTau (AtLabel "x") ExGlobal, BiTau (AtLabel "y") ExThis] , defaultScope- , [[("B", MvBindings [BiTau (AtLabel "x") ExGlobal, BiTau (AtLabel "y") ExThis])]]+ , substs [[("B", MvBindings [BiTau (AtLabel "x") ExGlobal, BiTau (AtLabel "y") ExThis])]] ) , ( "[[!B, z -> Q]] => [[x -> Q, y -> $, z -> Q]] => (!B >> [[x -> Q, y -> $]])" , [BiMeta "B", BiTau (AtLabel "z") ExGlobal] , [BiTau (AtLabel "x") ExGlobal, BiTau (AtLabel "y") ExThis, BiTau (AtLabel "z") ExGlobal] , defaultScope- , [[("B", MvBindings [BiTau (AtLabel "x") ExGlobal, BiTau (AtLabel "y") ExThis])]]+ , substs [[("B", MvBindings [BiTau (AtLabel "x") ExGlobal, BiTau (AtLabel "y") ExThis])]] ) , ( "[[L> Func, D> 00-]] => [[D> 00-, L> Func]] => []" , [BiLambda "Func", BiDelta (BtOne "00")] , [BiDelta (BtOne "00"), BiLambda "Func"] , defaultScope- , []+ , substs [] ) , ( "[[t -> ?, !B]] => [[x -> ?, t -> ?]] => []" , [BiVoid (AtLabel "t"), BiMeta "B"] , [BiVoid (AtLabel "x"), BiVoid (AtLabel "t")] , defaultScope- , []+ , substs [] ) , ( "[[!B, !a -> ?]] => [[x -> ?, y -> ?]] => (!a >> y, !B >> [[ x -> ? ]] )" , [BiMeta "B", BiVoid (AtMeta "a")] , [BiVoid (AtLabel "x"), BiVoid (AtLabel "y")] , defaultScope- , [[("a", MvAttribute (AtLabel "y")), ("B", MvBindings [BiVoid (AtLabel "x")])]]+ , substs [[("a", MvAttribute (AtLabel "y")), ("B", MvBindings [BiVoid (AtLabel "x")])]] ) , ( "[[!B1, !a -> ?, !B2]] => [[ x -> ?, y -> ?, z -> ? ]] => [(!B1 >> [[]], !a >> x, !B2 >> [[ y -> ?, z -> ? ]]), (...), (...)]" , [BiMeta "B1", BiVoid (AtMeta "a"), BiMeta "B2"] , [BiVoid (AtLabel "x"), BiVoid (AtLabel "y"), BiVoid (AtLabel "z")] , defaultScope- ,- [- [ ("B1", MvBindings [])- , ("a", MvAttribute (AtLabel "x"))- , ("B2", MvBindings [BiVoid (AtLabel "y"), BiVoid (AtLabel "z")])- ]- ,- [ ("B1", MvBindings [BiVoid (AtLabel "x")])- , ("a", MvAttribute (AtLabel "y"))- , ("B2", MvBindings [BiVoid (AtLabel "z")])- ]- ,- [ ("B1", MvBindings [BiVoid (AtLabel "x"), BiVoid (AtLabel "y")])- , ("a", MvAttribute (AtLabel "z"))- , ("B2", MvBindings [])+ , substs+ [+ [ ("B1", MvBindings [])+ , ("a", MvAttribute (AtLabel "x"))+ , ("B2", MvBindings [BiVoid (AtLabel "y"), BiVoid (AtLabel "z")])+ ]+ ,+ [ ("B1", MvBindings [BiVoid (AtLabel "x")])+ , ("a", MvAttribute (AtLabel "y"))+ , ("B2", MvBindings [BiVoid (AtLabel "z")])+ ]+ ,+ [ ("B1", MvBindings [BiVoid (AtLabel "x"), BiVoid (AtLabel "y")])+ , ("a", MvAttribute (AtLabel "z"))+ , ("B2", MvBindings [])+ ] ]- ] ) , ( "[[!B1, !a1 -> ?, !B2, !a2 -> ?, !B3]] => [[ a -> ?, b -> ?, x -> ?, y -> ?, z -> ? ]] => [10 substs]"@@ -330,113 +323,113 @@ , BiVoid (AtLabel "z") ] , defaultScope- ,- [- [ ("B1", MvBindings [])- , ("a1", MvAttribute (AtLabel "a"))- , ("B2", MvBindings [])- , ("a2", MvAttribute (AtLabel "b"))- , ("B3", MvBindings [BiVoid (AtLabel "x"), BiVoid (AtLabel "y"), BiVoid (AtLabel "z")])- ]- ,- [ ("B1", MvBindings [])- , ("a1", MvAttribute (AtLabel "a"))- , ("B2", MvBindings [BiVoid (AtLabel "b")])- , ("a2", MvAttribute (AtLabel "x"))- , ("B3", MvBindings [BiVoid (AtLabel "y"), BiVoid (AtLabel "z")])- ]- ,- [ ("B1", MvBindings [])- , ("a1", MvAttribute (AtLabel "a"))- , ("B2", MvBindings [BiVoid (AtLabel "b"), BiVoid (AtLabel "x")])- , ("a2", MvAttribute (AtLabel "y"))- , ("B3", MvBindings [BiVoid (AtLabel "z")])- ]- ,- [ ("B1", MvBindings [])- , ("a1", MvAttribute (AtLabel "a"))- , ("B2", MvBindings [BiVoid (AtLabel "b"), BiVoid (AtLabel "x"), BiVoid (AtLabel "y")])- , ("a2", MvAttribute (AtLabel "z"))- , ("B3", MvBindings [])- ]- ,- [ ("B1", MvBindings [BiVoid (AtLabel "a")])- , ("a1", MvAttribute (AtLabel "b"))- , ("B2", MvBindings [])- , ("a2", MvAttribute (AtLabel "x"))- , ("B3", MvBindings [BiVoid (AtLabel "y"), BiVoid (AtLabel "z")])- ]- ,- [ ("B1", MvBindings [BiVoid (AtLabel "a")])- , ("a1", MvAttribute (AtLabel "b"))- , ("B2", MvBindings [BiVoid (AtLabel "x")])- , ("a2", MvAttribute (AtLabel "y"))- , ("B3", MvBindings [BiVoid (AtLabel "z")])- ]- ,- [ ("B1", MvBindings [BiVoid (AtLabel "a")])- , ("a1", MvAttribute (AtLabel "b"))- , ("B2", MvBindings [BiVoid (AtLabel "x"), BiVoid (AtLabel "y")])- , ("a2", MvAttribute (AtLabel "z"))- , ("B3", MvBindings [])- ]- ,- [ ("B1", MvBindings [BiVoid (AtLabel "a"), BiVoid (AtLabel "b")])- , ("a1", MvAttribute (AtLabel "x"))- , ("B2", MvBindings [])- , ("a2", MvAttribute (AtLabel "y"))- , ("B3", MvBindings [BiVoid (AtLabel "z")])- ]- ,- [ ("B1", MvBindings [BiVoid (AtLabel "a"), BiVoid (AtLabel "b")])- , ("a1", MvAttribute (AtLabel "x"))- , ("B2", MvBindings [BiVoid (AtLabel "y")])- , ("a2", MvAttribute (AtLabel "z"))- , ("B3", MvBindings [])- ]- ,- [ ("B1", MvBindings [BiVoid (AtLabel "a"), BiVoid (AtLabel "b"), BiVoid (AtLabel "x")])- , ("a1", MvAttribute (AtLabel "y"))- , ("B2", MvBindings [])- , ("a2", MvAttribute (AtLabel "z"))- , ("B3", MvBindings [])+ , substs+ [+ [ ("B1", MvBindings [])+ , ("a1", MvAttribute (AtLabel "a"))+ , ("B2", MvBindings [])+ , ("a2", MvAttribute (AtLabel "b"))+ , ("B3", MvBindings [BiVoid (AtLabel "x"), BiVoid (AtLabel "y"), BiVoid (AtLabel "z")])+ ]+ ,+ [ ("B1", MvBindings [])+ , ("a1", MvAttribute (AtLabel "a"))+ , ("B2", MvBindings [BiVoid (AtLabel "b")])+ , ("a2", MvAttribute (AtLabel "x"))+ , ("B3", MvBindings [BiVoid (AtLabel "y"), BiVoid (AtLabel "z")])+ ]+ ,+ [ ("B1", MvBindings [])+ , ("a1", MvAttribute (AtLabel "a"))+ , ("B2", MvBindings [BiVoid (AtLabel "b"), BiVoid (AtLabel "x")])+ , ("a2", MvAttribute (AtLabel "y"))+ , ("B3", MvBindings [BiVoid (AtLabel "z")])+ ]+ ,+ [ ("B1", MvBindings [])+ , ("a1", MvAttribute (AtLabel "a"))+ , ("B2", MvBindings [BiVoid (AtLabel "b"), BiVoid (AtLabel "x"), BiVoid (AtLabel "y")])+ , ("a2", MvAttribute (AtLabel "z"))+ , ("B3", MvBindings [])+ ]+ ,+ [ ("B1", MvBindings [BiVoid (AtLabel "a")])+ , ("a1", MvAttribute (AtLabel "b"))+ , ("B2", MvBindings [])+ , ("a2", MvAttribute (AtLabel "x"))+ , ("B3", MvBindings [BiVoid (AtLabel "y"), BiVoid (AtLabel "z")])+ ]+ ,+ [ ("B1", MvBindings [BiVoid (AtLabel "a")])+ , ("a1", MvAttribute (AtLabel "b"))+ , ("B2", MvBindings [BiVoid (AtLabel "x")])+ , ("a2", MvAttribute (AtLabel "y"))+ , ("B3", MvBindings [BiVoid (AtLabel "z")])+ ]+ ,+ [ ("B1", MvBindings [BiVoid (AtLabel "a")])+ , ("a1", MvAttribute (AtLabel "b"))+ , ("B2", MvBindings [BiVoid (AtLabel "x"), BiVoid (AtLabel "y")])+ , ("a2", MvAttribute (AtLabel "z"))+ , ("B3", MvBindings [])+ ]+ ,+ [ ("B1", MvBindings [BiVoid (AtLabel "a"), BiVoid (AtLabel "b")])+ , ("a1", MvAttribute (AtLabel "x"))+ , ("B2", MvBindings [])+ , ("a2", MvAttribute (AtLabel "y"))+ , ("B3", MvBindings [BiVoid (AtLabel "z")])+ ]+ ,+ [ ("B1", MvBindings [BiVoid (AtLabel "a"), BiVoid (AtLabel "b")])+ , ("a1", MvAttribute (AtLabel "x"))+ , ("B2", MvBindings [BiVoid (AtLabel "y")])+ , ("a2", MvAttribute (AtLabel "z"))+ , ("B3", MvBindings [])+ ]+ ,+ [ ("B1", MvBindings [BiVoid (AtLabel "a"), BiVoid (AtLabel "b"), BiVoid (AtLabel "x")])+ , ("a1", MvAttribute (AtLabel "y"))+ , ("B2", MvBindings [])+ , ("a2", MvAttribute (AtLabel "z"))+ , ("B3", MvBindings [])+ ] ]- ] ) ] describe "matchExpression: expression => pattern => substitution" $ test matchExpression'- [ ("$ => $ => [()]", ExThis, ExThis, defaultScope, [[]])- , ("Q => Q => [()]", ExGlobal, ExGlobal, defaultScope, [[]])+ [ ("$ => $ => [()]", ExThis, ExThis, defaultScope, substs [[]])+ , ("Q => Q => [()]", ExGlobal, ExGlobal, defaultScope, substs [[]]) , ( "!e => Q => [(!e >> Q)]" , ExMeta "e" , ExGlobal , defaultScope- , [[("e", MvExpression ExGlobal defaultScope)]]+ , substs [[("e", MvExpression ExGlobal defaultScope)]] ) , ( "!e => Q.org(x -> $) => [(!e >> Q.org(x -> $))]" , ExMeta "e" , ExApplication (ExDispatch ExGlobal (AtLabel "org")) (BiTau (AtLabel "x") ExThis) , defaultScope- , [[("e", MvExpression (ExApplication (ExDispatch ExGlobal (AtLabel "org")) (BiTau (AtLabel "x") ExThis)) defaultScope)]]+ , substs [[("e", MvExpression (ExApplication (ExDispatch ExGlobal (AtLabel "org")) (BiTau (AtLabel "x") ExThis)) defaultScope)]] ) , ( "!e1.x => Q.org.x => [(!e1 >> Q.org)]" , ExDispatch (ExMeta "e1") (AtLabel "x") , ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "x") , defaultScope- , [[("e1", MvExpression (ExDispatch ExGlobal (AtLabel "org")) defaultScope)]]+ , substs [[("e1", MvExpression (ExDispatch ExGlobal (AtLabel "org")) defaultScope)]] ) , ( "!e.org.!a => $.org.x => [(!e >> $, !a >> x)]" , ExDispatch (ExDispatch (ExMeta "e") (AtLabel "org")) (AtMeta "a") , ExDispatch (ExDispatch ExThis (AtLabel "org")) (AtLabel "x") , defaultScope- , [[("e", MvExpression ExThis defaultScope), ("a", MvAttribute (AtLabel "x"))]]+ , substs [[("e", MvExpression ExThis defaultScope), ("a", MvAttribute (AtLabel "x"))]] ) , ( "[[!a -> !e, !B]].!a => [[x -> Q, y -> $]].x => [(!a >> x, !e >> Q, !B >> [y -> $])]"@@ -449,50 +442,50 @@ ) (AtLabel "x") , defaultScope- ,- [- [ ("a", MvAttribute (AtLabel "x"))- ,- ( "e"- , MvExpression- ExGlobal- ( ExFormation- [ BiTau (AtLabel "x") ExGlobal- , BiTau (AtLabel "y") ExThis- ]- )- )- , ("B", MvBindings [BiTau (AtLabel "y") ExThis])+ , substs+ [+ [ ("a", MvAttribute (AtLabel "x"))+ ,+ ( "e"+ , MvExpression+ ExGlobal+ ( ExFormation+ [ BiTau (AtLabel "x") ExGlobal+ , BiTau (AtLabel "y") ExThis+ ]+ )+ )+ , ("B", MvBindings [BiTau (AtLabel "y") ExThis])+ ] ]- ] ) , ( "Q * !t => Q.org => [(!t >> [.org])]" , ExMetaTail ExGlobal "t" , ExDispatch ExGlobal (AtLabel "x") , defaultScope- , [[("t", MvTail [TaDispatch (AtLabel "x")])]]+ , substs [[("t", MvTail [TaDispatch (AtLabel "x")])]] ) , ( "Q * !t => Q.org(x -> [[]]) => [(!t >> [.org, (x -> [[]])])]" , ExMetaTail ExGlobal "t" , ExApplication (ExDispatch ExGlobal (AtLabel "org")) (BiTau (AtLabel "x") defaultScope) , defaultScope- , [[("t", MvTail [TaDispatch (AtLabel "org"), TaApplication (BiTau (AtLabel "x") defaultScope)])]]+ , substs [[("t", MvTail [TaDispatch (AtLabel "org"), TaApplication (BiTau (AtLabel "x") defaultScope)])]] ) , ( "Q.!a * !t => Q.org.eolang(x -> [[]]) => [(!a >> org, !t >> [ .eolang, ( x -> [[ ]] ) ])]" , ExMetaTail (ExDispatch ExGlobal (AtMeta "a")) "t" , ExApplication (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang")) (BiTau (AtLabel "x") defaultScope) , defaultScope- , [[("a", MvAttribute (AtLabel "org")), ("t", MvTail [TaDispatch (AtLabel "eolang"), TaApplication (BiTau (AtLabel "x") defaultScope)])]]+ , substs [[("a", MvAttribute (AtLabel "org")), ("t", MvTail [TaDispatch (AtLabel "eolang"), TaApplication (BiTau (AtLabel "x") defaultScope)])]] ) , ( "Q.x(y -> $ * !t1) * !t2 => Q.x(y -> $.q).p => [(!t1 >> [.q], !t2 >> [.p])]" , ExMetaTail (ExApplication (ExDispatch ExGlobal (AtLabel "x")) (BiTau (AtLabel "y") (ExMetaTail ExThis "t1"))) "t2" , ExDispatch (ExApplication (ExDispatch ExGlobal (AtLabel "x")) (BiTau (AtLabel "y") (ExDispatch ExThis (AtLabel "q")))) (AtLabel "p") , defaultScope- , [[("t1", MvTail [TaDispatch (AtLabel "q")]), ("t2", MvTail [TaDispatch (AtLabel "p")])]]+ , substs [[("t1", MvTail [TaDispatch (AtLabel "q")]), ("t2", MvTail [TaDispatch (AtLabel "p")])]] ) , ( "[[!B1, !a ↦ !e1, !B2]](!a ↦ !e2) => ⟦ t ↦ ξ.k, x ↦ ξ.t, k ↦ ∅ ⟧(x ↦ ξ) => [(!B1 >> [[ t -> $.k ]], !a >> x, !B2 >> [[ k -> ? ]], !e1 >> $.t, !e2 >> $)]"@@ -506,25 +499,25 @@ ) (BiTau (AtLabel "x") ExThis) , defaultScope- ,- [- [ ("B1", MvBindings [BiTau (AtLabel "t") (ExDispatch ExThis (AtLabel "k"))])- , ("a", MvAttribute (AtLabel "x"))- , ("B2", MvBindings [BiVoid (AtLabel "k")])- ,- ( "e1"- , MvExpression- (ExDispatch ExThis (AtLabel "t"))- ( ExFormation- [ BiTau (AtLabel "t") (ExDispatch ExThis (AtLabel "k"))- , BiTau (AtLabel "x") (ExDispatch ExThis (AtLabel "t"))- , BiVoid (AtLabel "k")- ]- )- )- , ("e2", MvExpression ExThis defaultScope)+ , substs+ [+ [ ("B1", MvBindings [BiTau (AtLabel "t") (ExDispatch ExThis (AtLabel "k"))])+ , ("a", MvAttribute (AtLabel "x"))+ , ("B2", MvBindings [BiVoid (AtLabel "k")])+ ,+ ( "e1"+ , MvExpression+ (ExDispatch ExThis (AtLabel "t"))+ ( ExFormation+ [ BiTau (AtLabel "t") (ExDispatch ExThis (AtLabel "k"))+ , BiTau (AtLabel "x") (ExDispatch ExThis (AtLabel "t"))+ , BiVoid (AtLabel "k")+ ]+ )+ )+ , ("e2", MvExpression ExThis defaultScope)+ ] ]- ] ) ]
test/MiscSpec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT
test/ParserSpec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
test/PrinterSpec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT
test/ReplacerSpec.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT
test/RuleSpec.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-} -- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com -- SPDX-License-Identifier: MIT