packages feed

phino 0.0.120 → 0.0.121

raw patch · 6 files changed

+56/−5 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Bytes: btsIsUtf8 :: Bytes -> Bool
+ CST: sweetString :: Bytes -> Bool

Files

phino.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: phino-version: 0.0.120+version: 0.0.121 license: MIT synopsis: Command-Line Manipulator of 𝜑-Calculus Expressions description: Please see the README on GitHub at <https://github.com/objectionary/phino#readme>
src/Bytes.hs view
@@ -15,6 +15,7 @@   , unescapeStr   , btsToNum   , btsToUnescapedStr+  , btsIsUtf8   , btsAnd   , btsOr   , btsNot@@ -328,6 +329,22 @@ -- "5" btsToUnescapedStr :: Bytes -> String btsToUnescapedStr bytes = T.unpack (T.decodeUtf8 (B.pack (btsToWord8 bytes)))++-- Whether the byte array is valid UTF-8. The string-side counterpart of the+-- eight-byte check on numbers: a short or malformed datum is legal, and the+-- printer keeps it in its byte form instead of aborting with an uncaught+-- 'decodeUtf8' exception (see #1138).+-- >>> btsIsUtf8 (BtMany ["77", "6F", "72", "6C", "64"])+-- True+-- >>> btsIsUtf8 (BtMany ["F0", "90", "80", "41"])+-- False+-- >>> btsIsUtf8 (BtOne "FE")+-- False+btsIsUtf8 :: Bytes -> Bool+btsIsUtf8 bytes =+  case T.decodeUtf8' (B.pack (btsToWord8 bytes)) of+    Left _ -> False+    Right _ -> True  -- Bitwise conjunction of two byte arrays, byte by byte. EO's 'BytesRaw.and' -- refuses operands of different lengths, so there is nothing to yield for them
src/CST.hs view
@@ -11,7 +11,7 @@ module CST where  import AST-import Bytes (NonFinite, btsSize, btsToNonFinite, btsToNum, btsToStr)+import Bytes (NonFinite, btsIsUtf8, btsSize, btsToNonFinite, btsToNum, btsToStr) import Data.Maybe (isJust) import qualified Data.Text as T import qualified Yaml as Y@@ -276,9 +276,17 @@   Right dbl | isNaN dbl || isInfinite dbl -> isJust (btsToNonFinite bts)   _ -> True +-- A string can be rendered as a literal only when its bytes decode as UTF-8.+-- An arbitrary byte array is a legal datum and nothing promises it decodes, so+-- a malformed one is kept in its byte form, exactly as a payload NaN is kept+-- today (see #1138).+sweetString :: Bytes -> Bool+sweetString = btsIsUtf8+ -- Whether a data object may be collapsed into its sweet literal form. sweetCollapsible :: Expression -> Bool sweetCollapsible (DataNumber bts) = sweetNumber bts+sweetCollapsible (DataString bts) = sweetString bts sweetCollapsible _ = True  attributeToCST :: Attribute -> ATTRIBUTE@@ -353,7 +361,7 @@       withoutLastVoidRho [] = []       withoutLastVoidRho [BiVoid AtRho] = []       withoutLastVoidRho (bd : bds') = bd : withoutLastVoidRho bds'-  toCST (DataString bts) (tabs, _) = EX_STRING (btsToStr bts) (TAB tabs) []+  toCST (DataString bts) (tabs, _) | sweetString bts = EX_STRING (btsToStr bts) (TAB tabs) []   -- The three canonical non-finite doubles have no sweet numeric literal, so   -- they become the root dispatches `Φ.nan`, `Φ.pinf` and `Φ.ninf`. Any other   -- non-finite pattern is left in its byte form `Φ.number(Φ.bytes(⟦ Δ ⤍ … ⟧))`
src/XMIR.hs view
@@ -22,7 +22,7 @@ where  import AST-import Bytes (btsSize, btsToNum, btsToStr, bytesToBts)+import Bytes (btsIsUtf8, btsSize, btsToNum, btsToStr, bytesToBts) import Control.Exception (Exception (displayException), throwIO) import Data.Bifunctor (bimap) import Data.Foldable (foldlM)@@ -131,7 +131,7 @@           [object [("as", "data")] [NodeContent (T.pack (printBytes bytes))]]    in pure         ( "Φ.string"-        , if _omitComments+        , if _omitComments || not (btsIsUtf8 bytes)             then [bts]             else               [ NodeComment (T.pack ('"' : btsToStr bytes ++ "\""))
test/CSTSpec.hs view
@@ -155,6 +155,17 @@       ]       (\(desc, bts, expected) -> it desc (sweetNumber bts `shouldBe` expected)) +  describe "sweetString" $+    forM_+      [ ("is true for a valid ASCII datum", BtMany ["77", "6F", "72", "6C", "64"], True)+      , ("is true for a valid multi-byte datum", BtMany ["D0", "B0"], True)+      , ("is true for empty bytes", BtEmpty, True)+      , ("is false for a lone continuation byte", BtOne "A0", False)+      , ("is false for a truncated surrogate sequence", BtMany ["F0", "90", "80", "41"], False)+      , ("is false for a lone 0xFE byte", BtOne "FE", False)+      ]+      (\(desc, bts, expected) -> it desc (sweetString bts `shouldBe` expected))+   describe "sweetCollapsible" $     forM_       [
test/PrinterSpec.hs view
@@ -116,6 +116,21 @@             parseExpression printed `shouldBe` Right expr       ) +  describe "printExpression keeps a string with a non-UTF-8 datum in byte form" $+    forM_+      [ ("a lone 0xFE", BtOne "FE")+      , ("a truncated surrogate sequence", BtMany ["F0", "90", "80", "41"])+      , ("a bare continuation byte", BtOne "A0")+      ]+      ( \(desc, bts) ->+          it desc $ do+            let expr = DataString bts+                printed = printExpression' expr (SWEET, ASCII, SINGLELINE, defaultMargin)+            printed `shouldContain` "string"+            printed `shouldContain` "bytes"+            parseExpression printed `shouldBe` Right expr+      )+   describe "printExpression keeps a compressed meet atomic under a narrow margin" $     -- A \phinoMeet is a single \overbracket visual unit, so its body must stay     -- on one line even when the surrounding margin forces the outer formation to