diff --git a/eo-phi-normalizer/eo-phi-normalizer.cabal b/eo-phi-normalizer/eo-phi-normalizer.cabal index 8dad4a0f0..c82e60418 100644 --- a/eo-phi-normalizer/eo-phi-normalizer.cabal +++ b/eo-phi-normalizer/eo-phi-normalizer.cabal @@ -394,6 +394,7 @@ extra-source-files: test/eo/phi/dataization.yaml test/eo/phi/from-eo/as-phi.yaml test/eo/phi/metrics.yaml + test/eo/phi/parser/expressions.yaml test/eo/phi/rewriting.yaml test/eo/phi/rules/new.yaml test/eo/phi/rules/streams.yaml @@ -628,6 +629,7 @@ test-suite spec main-is: Main.hs other-modules: Language.EO.Phi.DataizeSpec + Language.EO.Phi.ParserSpec Language.EO.Phi.RewriteSpec Language.EO.PhiSpec Language.EO.Rules.PhiPaperSpec diff --git a/eo-phi-normalizer/grammar/EO/Phi/Syntax.cf b/eo-phi-normalizer/grammar/EO/Phi/Syntax.cf index 29c847fb3..e89066d2f 100644 --- a/eo-phi-normalizer/grammar/EO/Phi/Syntax.cf +++ b/eo-phi-normalizer/grammar/EO/Phi/Syntax.cf @@ -30,15 +30,15 @@ comment "//" ; comment "/*" "*/" ; token Bytes ({"--"} | ["0123456789ABCDEF"] ["0123456789ABCDEF"] {"-"} | ["0123456789ABCDEF"] ["0123456789ABCDEF"] ({"-"} ["0123456789ABCDEF"] ["0123456789ABCDEF"])+) ; -token Function upper (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦"])* ; -token LabelId lower (char - [" \r\n\t,.|':;!?][}{)(⟧⟦"])* ; +token Function upper (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦↦"])* ; +token LabelId lower (char - [" \r\n\t,.|':;!?][}{)(⟧⟦↦"])* ; token AlphaIndex ({"α0"} | {"α"} (digit - ["0"]) (digit)* ) ; -token LabelMetaId {"!τ"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦"])* ; -token TailMetaId {"!t"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦"])* ; -token BindingsMetaId {"!B"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦"])* ; -token ObjectMetaId {"!b"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦"])* ; -token BytesMetaId {"!y"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦"])* ; -token MetaFunctionName {"@"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦"])* ; +token LabelMetaId {"!τ"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦↦"])* ; +token TailMetaId {"!t"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦↦"])* ; +token BindingsMetaId {"!B"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦↦"])* ; +token ObjectMetaId {"!b"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦↦"])* ; +token BytesMetaId {"!y"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦↦"])* ; +token MetaFunctionName {"@"} (char - [" \r\n\t,.|':;!-?][}{)(⟧⟦↦"])* ; token IntegerSigned ('-'? digit+) ; token DoubleSigned ('-'? digit+ '.' digit+ ('e' '-'? digit+)?) ; token StringRaw '"' ((char - ["\"\\"]) | ('\\' ["\"\\tnrfu"]))* '"'; @@ -71,7 +71,7 @@ internal ConstFloat. Object ::= Double; internal ConstInt. Object ::= Integer; internal ConstString. Object ::= String; -AlphaBinding. Binding ::= Attribute "↦" Object ; +AlphaBinding. Binding ::= AttributeSugar "↦" Object ; AlphaBindingSugar. Binding ::= Object ; EmptyBinding. Binding ::= Attribute "↦" "∅" ; DeltaBinding. Binding ::= "Δ" "⤍" Bytes ; @@ -81,14 +81,15 @@ MetaBindings. Binding ::= BindingsMetaId ; MetaDeltaBinding. Binding ::= "Δ" "⤍" BytesMetaId ; separator Binding "," ; +AttributeNoSugar. AttributeSugar ::= "#" Attribute; +AttributeSugar. AttributeSugar ::= "~" LabelId "(" [Attribute] ")"; +separator Attribute ","; + Phi. Attribute ::= "φ" ; -- decoratee object -PhiSugar. Attribute ::= "~" "φ" "(" [LabelId] ")"; Rho. Attribute ::= "ρ" ; -- parent object Label. Attribute ::= LabelId ; Alpha. Attribute ::= AlphaIndex ; MetaAttr. Attribute ::= LabelMetaId ; -AttrSugar. Attribute ::= "~" LabelId "(" [LabelId] ")"; -separator LabelId ","; -- Additional symbols used as attributes in the rules ObjectAttr. RuleAttribute ::= Attribute ; diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Dataize.hs b/eo-phi-normalizer/src/Language/EO/Phi/Dataize.hs index c7f13c3db..b7f773abf 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Dataize.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Dataize.hs @@ -108,7 +108,7 @@ dataizeStepChain mode obj@(Formation bs) ctx <- getContext return (ctx, AsObject obj') | DataizeAll <- mode - , Just (AlphaBinding Phi decoratee) <- listToMaybe [b | b@(AlphaBinding Phi _) <- bs] + , Just (AlphaBinding' Phi decoratee) <- listToMaybe [b | b@(AlphaBinding' Phi _) <- bs] , not hasEmpty = do let decoratee' = substThis obj decoratee logStep "Dataizing inside phi" (AsObject decoratee') diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Dataize/Atoms.hs b/eo-phi-normalizer/src/Language/EO/Phi/Dataize/Atoms.hs index 5f240fc31..006c526c1 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Dataize/Atoms.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Dataize/Atoms.hs @@ -163,11 +163,11 @@ knownAtomsList = where isPackage (LambdaBinding (Function "Package")) = True isPackage _ = False - dataizeBindingChain (AlphaBinding attr o) = do + dataizeBindingChain (AlphaBinding' attr o) = do ctx <- getContext let extendedContext = (extendContextWith obj ctx){currentAttr = attr} dataizationResult <- incLogLevel $ withContext extendedContext $ dataizeRecursivelyChain False o - return (AlphaBinding attr (either id (Formation . singleton . DeltaBinding) dataizationResult)) + return (AlphaBinding' attr (either id (Formation . singleton . DeltaBinding) dataizationResult)) dataizeBindingChain b = return b f name _otherwise = evaluateBuiltinFunChainUnknown name _otherwise in diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Dependencies.hs b/eo-phi-normalizer/src/Language/EO/Phi/Dependencies.hs index 1b80716c6..5726f909c 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Dependencies.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Dependencies.hs @@ -30,7 +30,8 @@ import Language.EO.Phi import Control.Monad (foldM) bindingAttr :: Binding -> Maybe Attribute -bindingAttr (AlphaBinding a _) = Just a +bindingAttr (AlphaBinding' a _) = Just a +bindingAttr b@(AlphaBinding _ _) = errorExpectedDesugaredBinding b bindingAttr (EmptyBinding a) = Just a bindingAttr (DeltaBinding _) = Just (Alpha (AlphaIndex "Δ")) bindingAttr DeltaEmptyBinding = Just (Alpha (AlphaIndex "Δ")) diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Metrics/Collect.hs b/eo-phi-normalizer/src/Language/EO/Phi/Metrics/Collect.hs index f155fa4e2..ebc3e4b66 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Metrics/Collect.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Metrics/Collect.hs @@ -29,6 +29,7 @@ {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedLabels #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} @@ -43,6 +44,7 @@ import Data.Maybe (catMaybes) import Data.Traversable (forM) import Language.EO.Phi.Metrics.Data (BindingMetrics (..), BindingsByPathMetrics (..), MetricsCount, ObjectMetrics (..), Path, ProgramMetrics (..)) import Language.EO.Phi.Rules.Common () +import Language.EO.Phi.Syntax (pattern AlphaBinding') import Language.EO.Phi.Syntax.Abs -- $setup @@ -180,8 +182,8 @@ getObjectByPath object path = x <- bindings Right obj <- case x of - AlphaBinding (Alpha (AlphaIndex name)) obj | name == p -> [getObjectByPath obj ps] - AlphaBinding (Label (LabelId name)) obj | name == p -> [getObjectByPath obj ps] + AlphaBinding' (Alpha (AlphaIndex name)) obj | name == p -> [getObjectByPath obj ps] + AlphaBinding' (Label (LabelId name)) obj | name == p -> [getObjectByPath obj ps] _ -> [Left path] pure obj _ -> Left path @@ -203,8 +205,8 @@ getBindingsByPathMetrics object path = bindingsMetrics = do x <- zip bindings objectMetrics case x of - (AlphaBinding (Alpha (AlphaIndex name)) _, metrics) -> [BindingMetrics{..}] - (AlphaBinding (Label (LabelId name)) _, metrics) -> [BindingMetrics{..}] + (AlphaBinding' (Alpha (AlphaIndex name)) _, metrics) -> [BindingMetrics{..}] + (AlphaBinding' (Label (LabelId name)) _, metrics) -> [BindingMetrics{..}] _ -> [] in Right $ BindingsByPathMetrics{..} Right _ -> Left path diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Preprocess.hs b/eo-phi-normalizer/src/Language/EO/Phi/Preprocess.hs index 0252b0ad7..6eb072107 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Preprocess.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Preprocess.hs @@ -22,15 +22,17 @@ -- SOFTWARE. {- FOURMOLU_ENABLE -} {-# LANGUAGE BlockArguments #-} +{-# LANGUAGE LambdaCase #-} module Language.EO.Phi.Preprocess where import Control.Monad (void) import Data.Void (Void) +import Language.EO.Phi.Syntax.Abs import Replace.Megaparsec (splitCap) -import Text.Megaparsec (MonadParsec (..), Parsec, Stream (..), between, match, sepBy) +import Text.Megaparsec (MonadParsec (..), Parsec, Stream (..), between, choice, match, oneOf, optional, sepBy) import Text.Megaparsec.Byte.Lexer qualified as L -import Text.Megaparsec.Char (lowerChar, space) +import Text.Megaparsec.Char (space, string) symbol :: String -> Parser String symbol = L.symbol space @@ -40,41 +42,96 @@ lexeme = L.lexeme space type Parser = Parsec Void String -parseLabelId :: Parser () +parseTail :: Parser String +parseTail = takeWhileP (Just "LabelId") (`notElem` " \r\n\t,.|':;!?][}{)(⟧⟦↦") + +parseLabelId :: Parser LabelId parseLabelId = lexeme do - void lowerChar - void $ takeWhileP (Just "LabelId") (`notElem` " \r\n\t,.|':;!?][}{)(⟧⟦") + l <- oneOf ['a' .. 'z'] + ls <- parseTail + pure $ LabelId (l : ls) + +parseToken :: String -> (String -> a) -> Parser a +parseToken prefix cons = lexeme do + void $ string prefix + ls <- parseTail + pure $ cons (prefix <> ls) + +parseObjectMetaId :: Parser ObjectMetaId +parseObjectMetaId = parseToken "!b" ObjectMetaId + +parseBytesMetaId :: Parser BytesMetaId +parseBytesMetaId = parseToken "!y" BytesMetaId + +parseLabelMetaId :: Parser LabelMetaId +parseLabelMetaId = parseToken "!τ" LabelMetaId + +parseMetaId :: Parser MetaId +parseMetaId = + choice + [ MetaIdObject <$> parseObjectMetaId + , MetaIdBytes <$> parseBytesMetaId + , MetaIdLabel <$> parseLabelMetaId + ] + +parseAlphaIndex :: Parser AlphaIndex +parseAlphaIndex = parseToken "α" AlphaIndex + +parseAttribute :: Parser Attribute +parseAttribute = lexeme do + choice + [ Phi <$ symbol "φ" + , Rho <$ symbol "ρ" + , Label <$> parseLabelId + , Alpha <$> parseAlphaIndex + ] parseBindingArrow :: Parser () parseBindingArrow = void $ symbol "↦" -parseAlphaAttr :: Parser () -parseAlphaAttr = do - void parseLabelId - void $ between (symbol "(") (symbol ")") (sepBy parseLabelId (symbol ",")) - -parseAlphaBindingSugar :: Parser () +parseAttributeSugar :: Parser AttributeSugar +parseAttributeSugar = do + choice + [ do + labelId <- parseLabelId + attrs <- optional $ between (symbol "(") (symbol ")") (sepBy parseAttribute (symbol ",")) + case attrs of + Nothing -> pure $ AttributeNoSugar (Label labelId) + Just attrs' -> pure $ AttributeSugar labelId attrs' + , AttributeNoSugar <$> parseAttribute + ] + +type Attr = Either MetaId AttributeSugar + +parseAlphaBindingSugar :: Parser Attr parseAlphaBindingSugar = do - parseAlphaAttr + attr <- + choice + [ Left <$> parseMetaId + , Right <$> parseAttributeSugar + ] parseBindingArrow + notFollowedBy (symbol "∅") + pure attr -splitInput :: Parser a -> String -> [Either String (Tokens [Char])] -splitInput sep = splitCap (fst <$> match sep) +splitInput :: Parser a -> String -> [Either String (Tokens [Char], a)] +splitInput sep = splitCap (match sep) -addPrefix :: Parser a -> String -> [String] -addPrefix sep = map (either id ("~" <>)) . splitInput sep +addPrefix :: Parser Attr -> String -> [String] +addPrefix sep = fmap (either id (\(x, a) -> choosePrefix a <> x)) . splitInput sep + where + choosePrefix = \case + Right AttributeSugar{} -> "~" + _ -> "#" -preprocess' :: Parser a -> String -> String +preprocess' :: Parser Attr -> String -> String preprocess' sep = concat . addPrefix sep preprocess :: String -> String preprocess = preprocess' parseAlphaBindingSugar input1 :: String -input1 = "{⟦ org ↦ ⟦ eolang ↦ ⟦ number( as-bytes, abra ) ↦ ⟦ φ ↦ ξ.as-bytes, neg ↦ ξ.times(-1), ⟧, λ ⤍ Package ⟧, λ ⤍ Package ⟧ ⟧}" - --- >>> addPrefix parseAlphaBindingSugar input1 --- ["{\10214 org \8614 \10214 eolang \8614 \10214 ","~number( as-bytes, abra ) \8614 ","\10214 \966 \8614 \958.as-bytes, neg \8614 \958.times(-1), \10215, \955 \10509 Package \10215, \955 \10509 Package \10215 \10215}"] +input1 = "{⟦ org ↦ ⟦ ⟧(α0 ↦ !b1) ⟧}" -- >>> preprocess input1 --- "{\10214 org \8614 \10214 eolang \8614 \10214 ~number( as-bytes, abra ) \8614 \10214 \966 \8614 \958.as-bytes, neg \8614 \958.times(-1), \10215, \955 \10509 Package \10215, \955 \10509 Package \10215 \10215}" +-- "{\10214 #org \8614 \10214 \10215(#\945\&0 \8614 !b1) \10215}" diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Pretty.hs b/eo-phi-normalizer/src/Language/EO/Phi/Pretty.hs index 1faabd55f..1a3fc179c 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Pretty.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Pretty.hs @@ -126,6 +126,11 @@ instance Pretty Abs.Binding where Abs.MetaBindings bindingsmetaid -> pretty bindingsmetaid Abs.MetaDeltaBinding bytesmetaid -> pretty "Δ ⤍" <+> pretty bytesmetaid +instance Pretty Abs.AttributeSugar where + pretty = \case + Abs.AttributeSugar labelid labelids -> pretty labelid <> lparen <> pretty labelids <> rparen + Abs.AttributeNoSugar attribute -> pretty attribute + instance {-# OVERLAPPING #-} Pretty [Abs.Binding] where pretty = vsep . punctuate comma . fmap pretty @@ -136,8 +141,6 @@ instance Pretty Abs.Attribute where Abs.Label labelid -> pretty labelid Abs.Alpha alphaindex -> pretty alphaindex Abs.MetaAttr labelmetaid -> pretty labelmetaid - Abs.AttrSugar labelid labelids -> pretty labelid <> lparen <> pretty labelids <> rparen - Abs.PhiSugar labelids -> pretty Abs.Phi <> lparen <> pretty labelids <> rparen instance {-# OVERLAPPING #-} Pretty [Abs.LabelId] where pretty = hsep . punctuate comma . fmap pretty diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Rules/Common.hs b/eo-phi-normalizer/src/Language/EO/Phi/Rules/Common.hs index 7c01340b0..5a939c27e 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Rules/Common.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Rules/Common.hs @@ -27,6 +27,7 @@ {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralisedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} @@ -40,7 +41,22 @@ import Data.HashMap.Strict qualified as HashMap import Data.List (minimumBy, nubBy, sortOn) import Data.List.NonEmpty (NonEmpty (..), (<|)) import Data.Ord (comparing) -import Language.EO.Phi.Syntax +import Language.EO.Phi.Syntax ( + Attribute (..), + Binding (..), + BindingsMetaId (BindingsMetaId), + Bytes, + LabelId (LabelId), + LabelMetaId (LabelMetaId), + Object (..), + Program (..), + desugar, + errorExpectedDesugaredBinding, + errorExpectedDesugaredObject, + printTree, + pattern AlphaBinding', + pattern AlphaBinding'', + ) -- $setup -- >>> :set -XOverloadedStrings @@ -145,7 +161,7 @@ propagateName2 f (name, obj) bs = (name, f obj bs) withSubObjectBindings :: (Context -> Object -> [(String, Object)]) -> Context -> [Binding] -> [(String, [Binding])] withSubObjectBindings _ _ [] = [] -withSubObjectBindings f ctx (b@(AlphaBinding Rho _) : bs) = +withSubObjectBindings f ctx (b@(AlphaBinding' Rho _) : bs) = -- do not apply rules inside ρ-bindings [(name, b : bs') | (name, bs') <- withSubObjectBindings f ctx bs] withSubObjectBindings f ctx (b : bs) = @@ -156,7 +172,8 @@ withSubObjectBindings f ctx (b : bs) = withSubObjectBinding :: (Context -> Object -> [(String, Object)]) -> Context -> Binding -> [(String, Binding)] withSubObjectBinding f ctx = \case - AlphaBinding a obj -> propagateName1 (AlphaBinding a) <$> withSubObject f (ctx{currentAttr = a}) obj + AlphaBinding' a obj -> propagateName1 (AlphaBinding' a) <$> withSubObject f (ctx{currentAttr = a}) obj + b@AlphaBinding{} -> errorExpectedDesugaredBinding b b@AlphaBindingSugar{} -> errorExpectedDesugaredBinding b EmptyBinding{} -> [] DeltaBinding{} -> [] @@ -258,7 +275,8 @@ equalObjectNamed x y = snd x `equalObject` snd y equalBindings :: [Binding] -> [Binding] -> Bool equalBindings bindings1 bindings2 = and (zipWith equalBinding (sortOn attr bindings1) (sortOn attr bindings2)) where - attr (AlphaBinding a _) = a + attr (AlphaBinding' a _) = a + attr b@(AlphaBinding''{}) = errorExpectedDesugaredBinding b attr (EmptyBinding a) = a attr (DeltaBinding _) = Label (LabelId "Δ") attr DeltaEmptyBinding = Label (LabelId "Δ") @@ -396,9 +414,10 @@ applyRulesChainWith limits@ApplicationLimits{..} obj -- | Lookup a binding by the attribute name. lookupBinding :: Attribute -> [Binding] -> Maybe Object lookupBinding _ [] = Nothing -lookupBinding a (AlphaBinding a' object : bindings) +lookupBinding a (AlphaBinding' a' object : bindings) | a == a' = Just object | otherwise = lookupBinding a bindings +lookupBinding _ (b@(AlphaBinding''{}) : _) = errorExpectedDesugaredBinding b lookupBinding a (_ : bindings) = lookupBinding a bindings objectBindings :: Object -> [Binding] @@ -408,7 +427,7 @@ objectBindings (ObjectDispatch obj _attr) = objectBindings obj objectBindings _ = [] isRhoBinding :: Binding -> Bool -isRhoBinding (AlphaBinding Rho _) = True +isRhoBinding (AlphaBinding' Rho _) = True isRhoBinding _ = False hideRhoInBinding :: Binding -> Binding diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Rules/Fast.hs b/eo-phi-normalizer/src/Language/EO/Phi/Rules/Fast.hs index 25eeda6ad..63aeae7e4 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Rules/Fast.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Rules/Fast.hs @@ -36,8 +36,9 @@ import Language.EO.Phi.Syntax withBinding :: (Context -> Object -> Object) -> Context -> Binding -> Binding withBinding f ctx = \case - AlphaBinding Rho obj -> AlphaBinding Rho obj -- do not apply f inside ρ-bindings - AlphaBinding a obj -> AlphaBinding a (f ctx{currentAttr = a} obj) + AlphaBinding' Rho obj -> AlphaBinding' Rho obj -- do not apply f inside ρ-bindings + AlphaBinding' a obj -> AlphaBinding' a (f ctx{currentAttr = a} obj) + b@AlphaBinding''{} -> errorExpectedDesugaredBinding b binding -> binding isLambdaBinding :: Binding -> Bool @@ -117,13 +118,13 @@ fastYegorInsideOut ctx = \case obj'@(Formation bindings) -> do let argBindings' = map (fastYegorInsideOutBinding ctx) argBindings case argBindings' of - [AlphaBinding (Alpha "α0") arg0, AlphaBinding (Alpha "α1") arg1, AlphaBinding (Alpha "α2") arg2] -> + [AlphaBinding' (Alpha "α0") arg0, AlphaBinding' (Alpha "α1") arg1, AlphaBinding' (Alpha "α2") arg2] -> case filter isEmptyBinding bindings of EmptyBinding a0 : EmptyBinding a1 : EmptyBinding a2 : _ -> Formation - ( AlphaBinding a0 arg0 - : AlphaBinding a1 arg1 - : AlphaBinding a2 arg2 + ( AlphaBinding' a0 arg0 + : AlphaBinding' a1 arg1 + : AlphaBinding' a2 arg2 : [ binding | binding <- bindings , case binding of @@ -134,12 +135,12 @@ fastYegorInsideOut ctx = \case _ | not (any isLambdaBinding bindings) -> Termination | otherwise -> Application obj' argBindings' - [AlphaBinding (Alpha "α0") arg0, AlphaBinding (Alpha "α1") arg1] -> + [AlphaBinding' (Alpha "α0") arg0, AlphaBinding' (Alpha "α1") arg1] -> case filter isEmptyBinding bindings of EmptyBinding a0 : EmptyBinding a1 : _ -> Formation - ( AlphaBinding a0 arg0 - : AlphaBinding a1 arg1 + ( AlphaBinding' a0 arg0 + : AlphaBinding' a1 arg1 : [ binding | binding <- bindings , case binding of @@ -150,11 +151,11 @@ fastYegorInsideOut ctx = \case _ | not (any isLambdaBinding bindings) -> Termination | otherwise -> Application obj' argBindings' - [AlphaBinding (Alpha "α0") arg0] -> + [AlphaBinding' (Alpha "α0") arg0] -> case filter isEmptyBinding bindings of EmptyBinding a0 : _ -> Formation - ( AlphaBinding a0 arg0 + ( AlphaBinding' a0 arg0 : [ binding | binding <- bindings , case binding of @@ -165,10 +166,10 @@ fastYegorInsideOut ctx = \case _ | not (any isLambdaBinding bindings) -> Termination | otherwise -> Application obj' argBindings' - [AlphaBinding a argA] + [AlphaBinding' a argA] | EmptyBinding a `elem` bindings -> Formation - ( AlphaBinding a argA + ( AlphaBinding' a argA : [ binding | binding <- bindings , case binding of @@ -199,10 +200,11 @@ fastYegorInsideOut ctx = \case | binding <- bindings , let binding' = case binding of - AlphaBinding Rho _ -> binding - AlphaBinding a objA -> do + AlphaBinding' Rho _ -> binding + AlphaBinding' a objA -> do let ctx' = (extendContextWith root ctx){insideFormation = True, currentAttr = a} - AlphaBinding a (fastYegorInsideOut ctx' objA) + AlphaBinding' a (fastYegorInsideOut ctx' objA) + b@AlphaBinding''{} -> errorExpectedDesugaredBinding b _ -> binding ] obj@GlobalObjectPhiOrg -> errorExpectedDesugaredObject obj diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Rules/Yaml.hs b/eo-phi-normalizer/src/Language/EO/Phi/Rules/Yaml.hs index 2e5a376ef..1071f47f5 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Rules/Yaml.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Rules/Yaml.hs @@ -248,7 +248,8 @@ objectLabelIds = \case bindingLabelIds :: Binding -> Set LabelId bindingLabelIds = \case - AlphaBinding a obj -> objectLabelIds obj <> attrLabelIds a + AlphaBinding' a obj -> objectLabelIds obj <> attrLabelIds a + b@AlphaBinding{} -> errorExpectedDesugaredBinding b DeltaBinding _bytes -> mempty EmptyBinding a -> attrLabelIds a DeltaEmptyBinding -> mempty @@ -299,7 +300,8 @@ objectMetaIds obj@ConstFloat{} = objectMetaIds (desugar obj) objectMetaIds obj@ConstFloatRaw{} = errorExpectedDesugaredObject obj bindingMetaIds :: Binding -> Set MetaId -bindingMetaIds (AlphaBinding attr obj) = attrMetaIds attr <> objectMetaIds obj +bindingMetaIds (AlphaBinding' attr obj) = attrMetaIds attr <> objectMetaIds obj +bindingMetaIds b@AlphaBinding{} = errorExpectedDesugaredBinding b bindingMetaIds (EmptyBinding attr) = attrMetaIds attr bindingMetaIds (DeltaBinding _) = mempty bindingMetaIds DeltaEmptyBinding = mempty @@ -314,8 +316,6 @@ attrMetaIds Rho = mempty attrMetaIds (Label _) = mempty attrMetaIds (Alpha _) = mempty attrMetaIds (MetaAttr x) = Set.singleton (MetaIdLabel x) -attrMetaIds a@(AttrSugar{}) = errorExpectedDesugaredAttribute a -attrMetaIds a@(PhiSugar{}) = errorExpectedDesugaredAttribute a objectHasMetavars :: Object -> Bool objectHasMetavars (Formation bindings) = any bindingHasMetavars bindings @@ -338,7 +338,8 @@ objectHasMetavars obj@ConstFloat{} = objectHasMetavars (desugar obj) objectHasMetavars obj@ConstFloatRaw{} = errorExpectedDesugaredObject obj bindingHasMetavars :: Binding -> Bool -bindingHasMetavars (AlphaBinding attr obj) = attrHasMetavars attr || objectHasMetavars obj +bindingHasMetavars (AlphaBinding' attr obj) = attrHasMetavars attr || objectHasMetavars obj +bindingHasMetavars b@(AlphaBinding''{}) = errorExpectedDesugaredBinding b bindingHasMetavars (EmptyBinding attr) = attrHasMetavars attr bindingHasMetavars (DeltaBinding _) = False bindingHasMetavars DeltaEmptyBinding = False @@ -353,8 +354,6 @@ attrHasMetavars Rho = False attrHasMetavars (Label _) = False attrHasMetavars (Alpha _) = False attrHasMetavars (MetaAttr _) = True -attrHasMetavars a@AttrSugar{} = errorExpectedDesugaredAttribute a -attrHasMetavars a@PhiSugar{} = errorExpectedDesugaredAttribute a -- | Given a condition, and a substition from object matching -- tells whether the condition matches the object @@ -387,7 +386,7 @@ checkCond ctx (ApplyInAbstractSubformations shouldApply) _subst hasAttr :: RuleAttribute -> [Binding] -> Bool hasAttr attr = any (isAttr attr) where - isAttr (ObjectAttr a) (AlphaBinding a' _) = a == a' + isAttr (ObjectAttr a) (AlphaBinding' a' _) = a == a' isAttr (ObjectAttr a) (EmptyBinding a') = a == a' isAttr DeltaAttr (DeltaBinding _) = True isAttr DeltaAttr DeltaEmptyBinding = True @@ -485,8 +484,9 @@ applySubstBindings subst = concatMap (applySubstBinding subst) applySubstBinding :: Subst -> Binding -> [Binding] applySubstBinding subst@Subst{..} = \case - AlphaBinding a obj -> - [AlphaBinding (applySubstAttr subst a) (applySubst subst obj)] + AlphaBinding' a obj -> + [AlphaBinding' (applySubstAttr subst a) (applySubst subst obj)] + b@AlphaBinding{} -> errorExpectedDesugaredBinding b EmptyBinding a -> [EmptyBinding (applySubstAttr subst a)] DeltaBinding bytes -> [DeltaBinding (coerce bytes)] @@ -616,7 +616,7 @@ matchFindBinding p bindings = matchBinding :: Binding -> Binding -> [Subst] matchBinding MetaBindings{} _ = [] -matchBinding (AlphaBinding a obj) (AlphaBinding a' obj') = do +matchBinding (AlphaBinding' a obj) (AlphaBinding' a' obj') = do subst1 <- matchAttr a a' subst2 <- matchObject obj obj' pure (subst1 <> subst2) @@ -641,7 +641,7 @@ matchAttr _ _ = [] substThis :: Object -> Object -> Object substThis thisObj = go where - isAttachedRho (AlphaBinding Rho _) = True + isAttachedRho (AlphaBinding' Rho _) = True isAttachedRho _ = False isEmptyRho (EmptyBinding Rho) = True @@ -652,7 +652,7 @@ substThis thisObj = go -- IMPORTANT: we are injecting a ρ-attribute in formations! obj@(Formation bindings) | any isAttachedRho bindings -> obj - | otherwise -> Formation (filter (not . isEmptyRho) bindings ++ [AlphaBinding Rho thisObj]) + | otherwise -> Formation (filter (not . isEmptyRho) bindings ++ [AlphaBinding' Rho thisObj]) -- everywhere else we simply recursively traverse the φ-term Application obj bindings -> Application (go obj) (map (substThisBinding thisObj) bindings) ObjectDispatch obj a -> ObjectDispatch (go obj) a diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Syntax.hs b/eo-phi-normalizer/src/Language/EO/Phi/Syntax.hs index c8ff8840b..73a349fdd 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Syntax.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Syntax.hs @@ -82,6 +82,12 @@ module Language.EO.Phi.Syntax ( errorExpectedDesugaredObject, errorExpectedDesugaredBinding, errorExpectedDesugaredAttribute, + + -- * Pattern synonyms + pattern Label', + pattern MetaAttr', + pattern AlphaBinding', + pattern AlphaBinding'', ) where import Data.ByteString (ByteString) @@ -154,14 +160,11 @@ instance DesugarableInitially [Binding] where where go :: Int -> Binding -> Binding go idx = \case - AlphaBinding (AttrSugar l ls) (Formation bindings) -> - let bindingsDesugared = desugarInitially bindings - in AlphaBinding (Label l) (Formation ((EmptyBinding . Label <$> ls) <> bindingsDesugared)) - AlphaBinding (PhiSugar ls) (Formation bindings) -> + AlphaBinding'' l ls (Formation bindings) -> let bindingsDesugared = desugarInitially bindings - in AlphaBinding Phi (Formation ((EmptyBinding . Label <$> ls) <> bindingsDesugared)) + in AlphaBinding' (Label l) (Formation ((EmptyBinding <$> ls) <> bindingsDesugared)) AlphaBinding a obj -> AlphaBinding a (desugarInitially obj) - AlphaBindingSugar obj -> AlphaBinding (Alpha (AlphaIndex [fmt|α{idx}|])) (desugarInitially obj) + AlphaBindingSugar obj -> AlphaBinding' (Alpha (AlphaIndex [fmt|α{idx}|])) (desugarInitially obj) binding -> binding instance DesugarableInitially Program where @@ -174,6 +177,7 @@ instance DesugarableInitially Binding where AlphaBinding a obj -> AlphaBinding a (desugarInitially obj) obj -> obj +instance DesugarableInitially AttributeSugar instance DesugarableInitially Attribute instance DesugarableInitially RuleAttribute instance DesugarableInitially PeeledObject @@ -231,9 +235,8 @@ instance SugarableFinally [Binding] where go :: Int -> Binding -> Bool go idx = \case obj@AlphaBindingSugar{} -> errorExpectedDesugaredBinding obj - obj@(AlphaBinding (AttrSugar _ _) _) -> errorExpectedDesugaredBinding obj - obj@(AlphaBinding (PhiSugar _) _) -> errorExpectedDesugaredBinding obj - AlphaBinding (Alpha (AlphaIndex ('α' : idx'))) _ -> idx == read idx' + obj@(AlphaBinding''{}) -> errorExpectedDesugaredBinding obj + AlphaBinding' (Alpha (AlphaIndex ('α' : idx'))) _ -> idx == read idx' _ -> False instance SugarableFinally Binding where @@ -275,12 +278,12 @@ desugar = \case desugarBinding :: Binding -> Binding desugarBinding = \case - AlphaBinding (AttrSugar l ls) (Formation bindings) -> + AlphaBinding'' l ls (Formation bindings) -> let bindingsDesugared = desugarBinding <$> bindings - in AlphaBinding (Label l) (Formation ((EmptyBinding . Label <$> ls) <> bindingsDesugared)) - AlphaBinding (PhiSugar ls) (Formation bindings) -> + in AlphaBinding' (Label l) (Formation ((EmptyBinding <$> ls) <> bindingsDesugared)) + AlphaBinding' l (Formation bindings) -> let bindingsDesugared = desugarBinding <$> bindings - in AlphaBinding Phi (Formation ((EmptyBinding . Label <$> ls) <> bindingsDesugared)) + in AlphaBinding' l (Formation bindingsDesugared) AlphaBinding a obj -> AlphaBinding a (desugar obj) obj@(AlphaBindingSugar{}) -> errorExpectedDesugaredBinding obj binding -> binding @@ -663,6 +666,7 @@ instance IsString Program where fromString = unsafeParseWith pProgram instance IsString Object where fromString = unsafeParseWith pObject instance IsString Binding where fromString = unsafeParseWith pBinding instance IsString Attribute where fromString = unsafeParseWith pAttribute +instance IsString AttributeSugar where fromString = unsafeParseWith pAttributeSugar instance IsString RuleAttribute where fromString = unsafeParseWith pRuleAttribute instance IsString PeeledObject where fromString = unsafeParseWith pPeeledObject instance IsString ObjectHead where fromString = unsafeParseWith pObjectHead @@ -698,3 +702,15 @@ printTree = -- >>> bytesToInt "00-00-00-00-00-00-00-00" -- 0 + +pattern Label' :: LabelId -> AttributeSugar +pattern Label' a = AttributeNoSugar (Label a) + +pattern MetaAttr' :: LabelMetaId -> AttributeSugar +pattern MetaAttr' a = AttributeNoSugar (MetaAttr a) + +pattern AlphaBinding' :: Attribute -> Object -> Binding +pattern AlphaBinding' a obj = AlphaBinding (AttributeNoSugar a) obj + +pattern AlphaBinding'' :: LabelId -> [Attribute] -> Object -> Binding +pattern AlphaBinding'' a as obj = AlphaBinding (AttributeSugar a as) obj diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Abs.hs b/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Abs.hs index fb120850e..41353cd9a 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Abs.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Abs.hs @@ -81,7 +81,7 @@ data Object deriving (C.Eq, C.Ord, C.Show, C.Read, C.Data, C.Typeable, C.Generic) data Binding - = AlphaBinding Attribute Object + = AlphaBinding AttributeSugar Object | AlphaBindingSugar Object | EmptyBinding Attribute | DeltaBinding Bytes @@ -91,14 +91,16 @@ data Binding | MetaDeltaBinding BytesMetaId deriving (C.Eq, C.Ord, C.Show, C.Read, C.Data, C.Typeable, C.Generic) +data AttributeSugar + = AttributeNoSugar Attribute | AttributeSugar LabelId [Attribute] + deriving (C.Eq, C.Ord, C.Show, C.Read, C.Data, C.Typeable, C.Generic) + data Attribute = Phi - | PhiSugar [LabelId] | Rho | Label LabelId | Alpha AlphaIndex | MetaAttr LabelMetaId - | AttrSugar LabelId [LabelId] deriving (C.Eq, C.Ord, C.Show, C.Read, C.Data, C.Typeable, C.Generic) data RuleAttribute = ObjectAttr Attribute | DeltaAttr | LambdaAttr diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Doc.txt b/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Doc.txt index 321b1d3ee..1ada8b0fc 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Doc.txt +++ b/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Doc.txt @@ -44,38 +44,38 @@ Bytes literals are recognized by the regular expression Function literals are recognized by the regular expression `````upper (char - [" - !'(),-.:;?[]{|}⟦⟧"])*````` + !'(),-.:;?[]{|}↦⟦⟧"])*````` LabelId literals are recognized by the regular expression `````lower (char - [" - !'(),.:;?[]{|}⟦⟧"])*````` + !'(),.:;?[]{|}↦⟦⟧"])*````` AlphaIndex literals are recognized by the regular expression `````{"α0"} | 'α' (digit - '0') digit*````` LabelMetaId literals are recognized by the regular expression `````{"!τ"} (char - [" - !'(),-.:;?[]{|}⟦⟧"])*````` + !'(),-.:;?[]{|}↦⟦⟧"])*````` TailMetaId literals are recognized by the regular expression `````{"!t"} (char - [" - !'(),-.:;?[]{|}⟦⟧"])*````` + !'(),-.:;?[]{|}↦⟦⟧"])*````` BindingsMetaId literals are recognized by the regular expression `````{"!B"} (char - [" - !'(),-.:;?[]{|}⟦⟧"])*````` + !'(),-.:;?[]{|}↦⟦⟧"])*````` ObjectMetaId literals are recognized by the regular expression `````{"!b"} (char - [" - !'(),-.:;?[]{|}⟦⟧"])*````` + !'(),-.:;?[]{|}↦⟦⟧"])*````` BytesMetaId literals are recognized by the regular expression `````{"!y"} (char - [" - !'(),-.:;?[]{|}⟦⟧"])*````` + !'(),-.:;?[]{|}↦⟦⟧"])*````` MetaFunctionName literals are recognized by the regular expression `````'@' (char - [" - !'(),-.:;?[]{|}⟦⟧"])*````` + !'(),-.:;?[]{|}↦⟦⟧"])*````` IntegerSigned literals are recognized by the regular expression `````'-'? digit+````` @@ -99,7 +99,7 @@ The symbols used in Syntax are the following: | ( | ) | . | Φ̇ | ⊥ | [ | ↦ | ] | ⌈ | , | ⌉ | * - | ∅ | ⤍ | ~ | + | ∅ | ⤍ | # | ~ ===Comments=== Single-line comments begin with //.Multiple-line comments are enclosed with /* and */. @@ -131,7 +131,7 @@ All other symbols are terminals. | | **|** | //ObjectMetaId// | | **|** | //Object// ``*`` //TailMetaId// | | **|** | //MetaFunctionName// ``(`` //Object// ``)`` - | //Binding// | -> | //Attribute// ``↦`` //Object// + | //Binding// | -> | //AttributeSugar// ``↦`` //Object// | | **|** | //Object// | | **|** | //Attribute// ``↦`` ``∅`` | | **|** | ``Δ`` ``⤍`` //Bytes// @@ -142,16 +142,16 @@ All other symbols are terminals. | //[Binding]// | -> | **eps** | | **|** | //Binding// | | **|** | //Binding// ``,`` //[Binding]// + | //AttributeSugar// | -> | ``#`` //Attribute// + | | **|** | ``~`` //LabelId// ``(`` //[Attribute]// ``)`` + | //[Attribute]// | -> | **eps** + | | **|** | //Attribute// + | | **|** | //Attribute// ``,`` //[Attribute]// | //Attribute// | -> | ``φ`` - | | **|** | ``~`` ``φ`` ``(`` //[LabelId]// ``)`` | | **|** | ``ρ`` | | **|** | //LabelId// | | **|** | //AlphaIndex// | | **|** | //LabelMetaId// - | | **|** | ``~`` //LabelId// ``(`` //[LabelId]// ``)`` - | //[LabelId]// | -> | **eps** - | | **|** | //LabelId// - | | **|** | //LabelId// ``,`` //[LabelId]// | //RuleAttribute// | -> | //Attribute// | | **|** | ``Δ`` | | **|** | ``λ`` diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Lex.x b/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Lex.x index 945d1192c..368574891 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Lex.x +++ b/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Lex.x @@ -28,7 +28,7 @@ $u = [. \n] -- universal: any character -- Symbols and non-identifier-like reserved words -@rsyms = \Φ | \ξ | \Δ | \λ | \φ | \ρ | \{ | \⟦ | \⟧ | \} | \( | \) | \. | \Φ \̇ | \⊥ | \[ | \↦ | \] | \⌈ | \, | \⌉ | \* | \∅ | \⤍ | \~ +@rsyms = \Φ | \ξ | \Δ | \λ | \φ | \ρ | \{ | \⟦ | \⟧ | \} | \( | \) | \. | \Φ \̇ | \⊥ | \[ | \↦ | \] | \⌈ | \, | \⌉ | \* | \∅ | \⤍ | \# | \~ :- @@ -50,11 +50,11 @@ $white+ ; { tok (eitherResIdent T_Bytes) } -- token Function -$c [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] * +$c [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \↦ \⟦ \⟧]] * { tok (eitherResIdent T_Function) } -- token LabelId -$s [$u # [\t \n \r \ \! \' \( \) \, \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] * +$s [$u # [\t \n \r \ \! \' \( \) \, \. \: \; \? \[ \] \{ \| \} \↦ \⟦ \⟧]] * { tok (eitherResIdent T_LabelId) } -- token AlphaIndex @@ -62,27 +62,27 @@ $s [$u # [\t \n \r \ \! \' \( \) \, \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] * { tok (eitherResIdent T_AlphaIndex) } -- token LabelMetaId -\! τ [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] * +\! τ [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \↦ \⟦ \⟧]] * { tok (eitherResIdent T_LabelMetaId) } -- token TailMetaId -\! t [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] * +\! t [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \↦ \⟦ \⟧]] * { tok (eitherResIdent T_TailMetaId) } -- token BindingsMetaId -\! B [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] * +\! B [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \↦ \⟦ \⟧]] * { tok (eitherResIdent T_BindingsMetaId) } -- token ObjectMetaId -\! b [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] * +\! b [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \↦ \⟦ \⟧]] * { tok (eitherResIdent T_ObjectMetaId) } -- token BytesMetaId -\! y [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] * +\! y [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \↦ \⟦ \⟧]] * { tok (eitherResIdent T_BytesMetaId) } -- token MetaFunctionName -\@ [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] * +\@ [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \↦ \⟦ \⟧]] * { tok (eitherResIdent T_MetaFunctionName) } -- token IntegerSigned @@ -240,19 +240,20 @@ eitherResIdent tv s = treeFind resWords -- | The keywords and symbols of the language organized as binary search tree. resWords :: BTree resWords = - b "\934\775" 13 - (b "]" 7 - (b "," 4 - (b ")" 2 (b "(" 1 N N) (b "*" 3 N N)) (b "[" 6 (b "." 5 N N) N)) - (b "~" 10 - (b "}" 9 (b "{" 8 N N) N) (b "\934" 12 (b "\916" 11 N N) N))) - (b "\8869" 20 - (b "\966" 17 - (b "\958" 15 (b "\955" 14 N N) (b "\961" 16 N N)) - (b "\8709" 19 (b "\8614" 18 N N) N)) - (b "\10214" 23 - (b "\8969" 22 (b "\8968" 21 N N) N) - (b "\10509" 25 (b "\10215" 24 N N) N))) + b "\934\775" 14 + (b "[" 7 + (b "*" 4 + (b "(" 2 (b "#" 1 N N) (b ")" 3 N N)) (b "." 6 (b "," 5 N N) N)) + (b "~" 11 + (b "{" 9 (b "]" 8 N N) (b "}" 10 N N)) + (b "\934" 13 (b "\916" 12 N N) N))) + (b "\8869" 21 + (b "\966" 18 + (b "\958" 16 (b "\955" 15 N N) (b "\961" 17 N N)) + (b "\8709" 20 (b "\8614" 19 N N) N)) + (b "\10214" 24 + (b "\8969" 23 (b "\8968" 22 N N) N) + (b "\10509" 26 (b "\10215" 25 N N) N))) where b s n = B bs (TS bs n) where diff --git a/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Par.y b/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Par.y index 349549b5f..b535cc9d4 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Par.y +++ b/eo-phi-normalizer/src/Language/EO/Phi/Syntax/Par.y @@ -13,8 +13,9 @@ module Language.EO.Phi.Syntax.Par , pObject , pBinding , pListBinding + , pAttributeSugar + , pListAttribute , pAttribute - , pListLabelId , pRuleAttribute , pPeeledObject , pObjectHead @@ -34,8 +35,9 @@ import Language.EO.Phi.Syntax.Lex %name pObject Object %name pBinding Binding %name pListBinding ListBinding +%name pAttributeSugar AttributeSugar +%name pListAttribute ListAttribute %name pAttribute Attribute -%name pListLabelId ListLabelId %name pRuleAttribute RuleAttribute %name pPeeledObject PeeledObject %name pObjectHead ObjectHead @@ -45,31 +47,32 @@ import Language.EO.Phi.Syntax.Lex %monad { Err } { (>>=) } { return } %tokentype {Token} %token - '(' { PT _ (TS _ 1) } - ')' { PT _ (TS _ 2) } - '*' { PT _ (TS _ 3) } - ',' { PT _ (TS _ 4) } - '.' { PT _ (TS _ 5) } - '[' { PT _ (TS _ 6) } - ']' { PT _ (TS _ 7) } - '{' { PT _ (TS _ 8) } - '}' { PT _ (TS _ 9) } - '~' { PT _ (TS _ 10) } - 'Δ' { PT _ (TS _ 11) } - 'Φ' { PT _ (TS _ 12) } - 'Φ̇' { PT _ (TS _ 13) } - 'λ' { PT _ (TS _ 14) } - 'ξ' { PT _ (TS _ 15) } - 'ρ' { PT _ (TS _ 16) } - 'φ' { PT _ (TS _ 17) } - '↦' { PT _ (TS _ 18) } - '∅' { PT _ (TS _ 19) } - '⊥' { PT _ (TS _ 20) } - '⌈' { PT _ (TS _ 21) } - '⌉' { PT _ (TS _ 22) } - '⟦' { PT _ (TS _ 23) } - '⟧' { PT _ (TS _ 24) } - '⤍' { PT _ (TS _ 25) } + '#' { PT _ (TS _ 1) } + '(' { PT _ (TS _ 2) } + ')' { PT _ (TS _ 3) } + '*' { PT _ (TS _ 4) } + ',' { PT _ (TS _ 5) } + '.' { PT _ (TS _ 6) } + '[' { PT _ (TS _ 7) } + ']' { PT _ (TS _ 8) } + '{' { PT _ (TS _ 9) } + '}' { PT _ (TS _ 10) } + '~' { PT _ (TS _ 11) } + 'Δ' { PT _ (TS _ 12) } + 'Φ' { PT _ (TS _ 13) } + 'Φ̇' { PT _ (TS _ 14) } + 'λ' { PT _ (TS _ 15) } + 'ξ' { PT _ (TS _ 16) } + 'ρ' { PT _ (TS _ 17) } + 'φ' { PT _ (TS _ 18) } + '↦' { PT _ (TS _ 19) } + '∅' { PT _ (TS _ 20) } + '⊥' { PT _ (TS _ 21) } + '⌈' { PT _ (TS _ 22) } + '⌉' { PT _ (TS _ 23) } + '⟦' { PT _ (TS _ 24) } + '⟧' { PT _ (TS _ 25) } + '⤍' { PT _ (TS _ 26) } L_doubl { PT _ (TD $$) } L_integ { PT _ (TI $$) } L_quoted { PT _ (TL $$) } @@ -169,7 +172,7 @@ Object Binding :: { Language.EO.Phi.Syntax.Abs.Binding } Binding - : Attribute '↦' Object { Language.EO.Phi.Syntax.Abs.AlphaBinding $1 $3 } + : AttributeSugar '↦' Object { Language.EO.Phi.Syntax.Abs.AlphaBinding $1 $3 } | Object { Language.EO.Phi.Syntax.Abs.AlphaBindingSugar $1 } | Attribute '↦' '∅' { Language.EO.Phi.Syntax.Abs.EmptyBinding $1 } | 'Δ' '⤍' Bytes { Language.EO.Phi.Syntax.Abs.DeltaBinding $3 } @@ -184,21 +187,24 @@ ListBinding | Binding { (:[]) $1 } | Binding ',' ListBinding { (:) $1 $3 } +AttributeSugar :: { Language.EO.Phi.Syntax.Abs.AttributeSugar } +AttributeSugar + : '#' Attribute { Language.EO.Phi.Syntax.Abs.AttributeNoSugar $2 } + | '~' LabelId '(' ListAttribute ')' { Language.EO.Phi.Syntax.Abs.AttributeSugar $2 $4 } + +ListAttribute :: { [Language.EO.Phi.Syntax.Abs.Attribute] } +ListAttribute + : {- empty -} { [] } + | Attribute { (:[]) $1 } + | Attribute ',' ListAttribute { (:) $1 $3 } + Attribute :: { Language.EO.Phi.Syntax.Abs.Attribute } Attribute : 'φ' { Language.EO.Phi.Syntax.Abs.Phi } - | '~' 'φ' '(' ListLabelId ')' { Language.EO.Phi.Syntax.Abs.PhiSugar $4 } | 'ρ' { Language.EO.Phi.Syntax.Abs.Rho } | LabelId { Language.EO.Phi.Syntax.Abs.Label $1 } | AlphaIndex { Language.EO.Phi.Syntax.Abs.Alpha $1 } | LabelMetaId { Language.EO.Phi.Syntax.Abs.MetaAttr $1 } - | '~' LabelId '(' ListLabelId ')' { Language.EO.Phi.Syntax.Abs.AttrSugar $2 $4 } - -ListLabelId :: { [Language.EO.Phi.Syntax.Abs.LabelId] } -ListLabelId - : {- empty -} { [] } - | LabelId { (:[]) $1 } - | LabelId ',' ListLabelId { (:) $1 $3 } RuleAttribute :: { Language.EO.Phi.Syntax.Abs.RuleAttribute } RuleAttribute diff --git a/eo-phi-normalizer/src/Language/EO/Phi/ToLaTeX.hs b/eo-phi-normalizer/src/Language/EO/Phi/ToLaTeX.hs index e614db4cc..234dea6bf 100644 --- a/eo-phi-normalizer/src/Language/EO/Phi/ToLaTeX.hs +++ b/eo-phi-normalizer/src/Language/EO/Phi/ToLaTeX.hs @@ -62,13 +62,12 @@ instance ToLatex Attribute where (Alpha (AlphaIndex a)) -> LaTeX ("\\alpha_" ++ tail a) (Label (LabelId l)) -> LaTeX l (MetaAttr (LabelMetaId l)) -> LaTeX l - (AttrSugar (LabelId l) ls) -> LaTeX [fmt|{l}({mkLabels ls})|] - (PhiSugar ls) -> LaTeX [fmt|@({mkLabels ls})|] - where - mkLabels ls = intercalate ", " ((\(LabelId l') -> l') <$> ls) instance ToLatex Binding where - toLatex (AlphaBinding attr obj) = toLatex attr <> " -> " <> toLatex obj + toLatex (AlphaBinding' attr obj) = toLatex attr <> " -> " <> toLatex obj + toLatex (AlphaBinding'' (LabelId l) ls obj) = LaTeX [fmt|{l}({mkLabels})|] <> " -> " <> toLatex obj + where + mkLabels = intercalate ", " (unLaTeX . toLatex <$> ls) toLatex (EmptyBinding attr) = toLatex attr <> " -> ?" toLatex (DeltaBinding (Bytes bytes)) = "D> " <> LaTeX bytes toLatex DeltaEmptyBinding = "D> ?" diff --git a/eo-phi-normalizer/test/Language/EO/Phi/ParserSpec.hs b/eo-phi-normalizer/test/Language/EO/Phi/ParserSpec.hs new file mode 100644 index 000000000..81723ec4d --- /dev/null +++ b/eo-phi-normalizer/test/Language/EO/Phi/ParserSpec.hs @@ -0,0 +1,75 @@ +{- FOURMOLU_DISABLE -} +-- The MIT License (MIT) + +-- Copyright (c) 2016-2024 Objectionary.com + +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: + +-- The above copyright notice and this permission notice shall be included +-- in all copies or substantial portions of the Software. + +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +{- FOURMOLU_ENABLE -} +{-# LANGUAGE BlockArguments #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DuplicateRecordFields #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE OverloadedRecordDot #-} +{-# LANGUAGE RecordWildCards #-} + +module Language.EO.Phi.ParserSpec where + +import Control.Monad (forM_) +import Test.Hspec + +import Data.Aeson (FromJSON) +import Data.Either (isLeft, isRight) +import Data.Yaml (decodeFileThrow) +import GHC.Generics (Generic) +import Language.EO.Phi (parseProgram) + +data ParserTests = ParserTests + { title :: String + , tests :: TestTypes + } + deriving (Generic, FromJSON) + +data TestTypes = TestTypes + { positive :: [ParserTest] + , negative :: [ParserTest] + } + deriving (Generic, FromJSON) + +data ParserTest = ParserTest + { title :: String + , source :: String + , input :: String + } + deriving (Generic, FromJSON) + +spec :: Spec +spec = do + ParserTests{..} <- runIO (decodeFileThrow "test/eo/phi/parser/expressions.yaml") + describe title do + forM_ + [ ("Positive", tests.positive, isRight) + , ("Negative", tests.negative, isLeft) + ] + $ \(title', set, check) -> + describe title' do + forM_ set $ \test -> do + let p = parseProgram test.input + it test.title do + shouldSatisfy p check diff --git a/eo-phi-normalizer/test/Language/EO/Rules/PhiPaperSpec.hs b/eo-phi-normalizer/test/Language/EO/Rules/PhiPaperSpec.hs index 2dc84c754..21d6b2346 100644 --- a/eo-phi-normalizer/test/Language/EO/Rules/PhiPaperSpec.hs +++ b/eo-phi-normalizer/test/Language/EO/Rules/PhiPaperSpec.hs @@ -28,6 +28,7 @@ {-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE TupleSections #-} {-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-} @@ -48,7 +49,7 @@ import GHC.Generics (Generic) import Language.EO.Phi.Dataize.Context (defaultContext) import Language.EO.Phi.Rules.Common (ApplicationLimits (..), NamedRule, applyOneRule, defaultApplicationLimits, equalObject, objectSize) import Language.EO.Phi.Rules.Yaml (convertRuleNamed, parseRuleSetFromFile, rules) -import Language.EO.Phi.Syntax (errorExpectedDesugaredBinding, intToBytes, printTree) +import Language.EO.Phi.Syntax (errorExpectedDesugaredBinding, intToBytes, printTree, pattern AlphaBinding', pattern AlphaBinding'') import Language.EO.Phi.Syntax.Abs as Phi import Test.Hspec import Test.QuickCheck @@ -103,13 +104,13 @@ instance Arbitrary Binding where ( n , do attr <- arbitrary - AlphaBinding attr <$> arbitrary + AlphaBinding' attr <$> arbitrary ) , (1, DeltaBinding <$> arbitrary) , (1, LambdaBinding <$> arbitrary) , (1, pure DeltaEmptyBinding) ] - shrink (AlphaBinding attr obj) = AlphaBinding attr <$> shrink obj + shrink (AlphaBinding' attr obj) = AlphaBinding' attr <$> shrink obj shrink _ = [] -- do not shrink deltas and lambdas instance Arbitrary Phi.StringRaw where @@ -143,7 +144,8 @@ listOf' x = sized $ \n -> do bindingAttr :: Binding -> Attribute bindingAttr = \case - AlphaBinding a _ -> a + AlphaBinding' a _ -> a + b@AlphaBinding''{} -> errorExpectedDesugaredBinding b EmptyBinding a -> a DeltaBinding{} -> Label "Δ" DeltaEmptyBinding{} -> Label "Δ" @@ -160,7 +162,7 @@ arbitraryBindings = arbitraryAlphaLabelBindings :: Gen [Binding] arbitraryAlphaLabelBindings = List.nubBy ((==) `on` bindingAttr) - <$> listOf' (AlphaBinding <$> (Label <$> arbitrary) <*> arbitrary) + <$> listOf' (AlphaBinding' <$> arbitrary <*> arbitrary) sizedLiftA2 :: (a -> b -> c) -> Gen a -> Gen b -> Gen c sizedLiftA2 f x y = sized $ \n -> do @@ -210,7 +212,7 @@ genCriticalPair rules = do obj <- Formation . List.nubBy sameAttr <$> listOf' arbitrary return (obj, applyOneRule (defaultContext rules obj) obj) - sameAttr (AlphaBinding attr1 _) (AlphaBinding attr2 _) = attr1 == attr2 + sameAttr (AlphaBinding' attr1 _) (AlphaBinding' attr2 _) = attr1 == attr2 sameAttr (EmptyBinding attr1) (EmptyBinding attr2) = attr1 == attr2 sameAttr b1 b2 = toConstr b1 == toConstr b2