phino-0.0.157: test/LambdasSpec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
-- SPDX-License-Identifier: MIT
module LambdasSpec (spec) where
import AST
import Control.Exception (SomeException)
import Control.Monad (forM_)
import Data.List (isInfixOf)
import Data.Text qualified as T
import Fixtures (withLambdasOf)
import Functions (buildTerm)
import Lambdas (Ending (..), Lambda (..), Lambdas, Line (..), Meta (..), emptyLambdas, matched, minted, readLambdas, rewritten, stayed, symbolized, taken)
import Parser (parseExpressionThrows)
import Rule (RuleContext (..), normal)
import Test.Hspec
import Yaml qualified as Y
lambdasOf :: T.Text -> IO Lambdas
lambdasOf text = withLambdasOf text readLambdas
entry :: T.Text -> T.Text
entry key = "- Ξ»: " <> key <> "\n dataize:\n πΏ1: $.Ο\n π: β¦ Ξ» β€ π β§\n"
joint :: T.Text
joint = "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n join:\n on: πΏ1\n left: $.a\n right: $.b\n"
answering :: Lambdas -> T.Text -> Maybe T.Text
answering known func = _key <$> matched known func
lined :: Lambdas -> T.Text -> [Line]
lined known func = maybe [] _lines (matched known func)
order :: Lambdas -> T.Text -> [T.Text]
order known func = map bound (lined known func)
where
bound :: Line -> T.Text
bound (Morphed meta _) = _spelling meta
bound (Evaluated meta _) = _spelling meta
bound (Deferred meta _) = _spelling meta
bound (Stayed meta _) = _spelling meta
bound (Symbolized meta _) = _spelling meta
bound (Rewritten meta _ _) = _spelling meta
morphs :: Lambdas -> T.Text -> [(T.Text, T.Text)]
morphs known func = [(_spelling meta, _spelling source) | Morphed meta source <- lined known func]
fired :: Lambdas -> T.Text -> [(T.Text, T.Text)]
fired known func = [(_spelling meta, _spelling source) | Evaluated meta source <- lined known func]
defers :: Lambdas -> T.Text -> [(T.Text, T.Text)]
defers known func = [(_spelling meta, _spelling source) | Deferred meta source <- lined known func]
stays :: Lambdas -> T.Text -> [(T.Text, T.Text)]
stays known func = [(_spelling meta, _spelling source) | Stayed meta source <- lined known func]
symbolizes :: Lambdas -> T.Text -> [(T.Text, T.Text)]
symbolizes known func = [(_spelling meta, _spelling source) | Symbolized meta source <- lined known func]
rewrites :: Lambdas -> T.Text -> [(T.Text, T.Text, Int)]
rewrites known func = [(_spelling meta, _spelling source, length rules) | Rewritten meta source rules <- lined known func]
truth :: T.Text
truth = " rules:\n - name: true-literal\n pattern: Ξ¦.true\n result: Ξ¦.bool( if β¦ β¦ Ξ β€ 01- β§ )\n"
rewrote :: [(String, String)] -> String -> IO Expression
rewrote rules term = do
parsed <- mapM (\(source, target) -> (\from to -> Y.Rule "kq" Nothing Nothing from to Nothing Nothing Nothing) <$> parseExpressionThrows source <*> parseExpressionThrows target) rules
parseExpressionThrows term >>= rewritten (RuleContext buildTerm Nothing normal) parsed
answers :: Lambdas -> T.Text -> Maybe Expression
answers known func = case _ending <$> matched known func of
Just (Answering term) -> Just term
_ -> Nothing
joining :: Lambdas -> T.Text -> Maybe (Either T.Text Expression)
joining known func = case _ending <$> matched known func of
Just (Joining on _ _ _) -> Just (either (Left . _spelling) Right on)
_ -> Nothing
sides :: Lambdas -> T.Text -> Maybe (Expression, Expression)
sides known func = case _ending <$> matched known func of
Just (Joining _ left right _) -> Just (left, right)
_ -> Nothing
fallback :: Lambdas -> T.Text -> Maybe Function
fallback known func = case _ending <$> matched known func of
Just (Joining _ _ _ name) -> name
_ -> Nothing
spec :: Spec
spec = do
describe "readLambdas" $ do
it "reads the Ξ» function its key names" $ do
known <- lambdasOf (entry "L_number_plus")
answering known "L_number_plus" `shouldBe` Just "L_number_plus"
it "reads one Ξ» function for the whole family its key spells" $ do
known <- lambdasOf (entry "L_box_[0-9]+_number")
answering known "L_box_42_number" `shouldBe` Just "L_box_[0-9]+_number"
it "reads two keys whose families share no Ξ» name" $ do
known <- lambdasOf (entry "L_[a-z]+_plus" <> entry "L_number_[0-9]+")
answering known "L_number_42" `shouldBe` Just "L_number_[0-9]+"
it "cannot read a Ξ» function whose name merely starts with a key" $ do
known <- lambdasOf (entry "L_number_plus")
answering known "L_number_plus_twice" `shouldBe` Nothing
it "reads a single key that no other key is compared with, even an anchored one" $ do
known <- lambdasOf (entry "^L_a$")
answering known "L_a" `shouldBe` Just "^L_a$"
it "cannot read a Ξ» function no entry answers" $ do
known <- lambdasOf (entry "L_number_plus")
answering known "L_bytes_not" `shouldBe` Nothing
it "reads the operands of 'dataize' in the order their metas number them" $ do
known <- lambdasOf "- Ξ»: L_pair\n dataize:\n πΏ2: $.x\n πΏ1: $.Ο\n π: β¦ Ξ» β€ π β§\n"
map (_spelling . fst) (maybe [] _dataized (matched known "L_pair")) `shouldBe` ["πΏ1", "πΏ2"]
it "reads the operands of 'dataize' in numeric order past nine" $ do
known <- lambdasOf "- Ξ»: L_pair\n dataize:\n πΏ10: $.b\n πΏ9: $.a\n πΏ1: $.Ο\n π: β¦ Ξ» β€ π β§\n"
map (_spelling . fst) (maybe [] _dataized (matched known "L_pair")) `shouldBe` ["πΏ1", "πΏ9", "πΏ10"]
it "reads a meta under both the name it is spelled with and the name it binds" $ do
known <- lambdasOf "- Ξ»: L_pair\n dataize:\n πΏ1: $.Ο\n π: β¦ Ξ» β€ π β§\n"
map (_name . fst) (maybe [] _dataized (matched known "L_pair")) `shouldBe` ["d1"]
it "reads the operands of 'morph' under expression metas" $ do
known <- lambdasOf "- Ξ»: L_pick\n morph:\n π1: $.then\n π2: $.else\n π: π1\n"
map (_spelling . fst) (maybe [] _morphed (matched known "L_pick")) `shouldBe` ["π1", "π2"]
it "keeps under 'morph' only the operands reading '$'" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π3: π2\n stay:\n π2: π1\n π: π3\n"
map (_spelling . fst) (maybe [] _morphed (matched known "L_hold")) `shouldBe` ["π1"]
it "reads an operand of 'morph' naming a meta as a line reading that meta" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π3: π2\n stay:\n π2: π1\n π: π3\n"
morphs known "L_hold" `shouldBe` [("π3", "π2")]
it "runs a 'morph' line after the 'rewrite' line binding the meta it reads" $ do
known <- lambdasOf ("- Ξ»: L_hold\n morph:\n π1: $.a\n π3: π2\n rewrite:\n π2:\n of: π1\n" <> truth <> " π: π3\n")
order known "L_hold" `shouldBe` ["π2", "π3"]
it "runs a 'morph' line before an 'evaluate' line no meta orders" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π4: π2\n stay:\n π2: π1\n evaluate:\n π3: π2\n π: π3\n"
order known "L_hold" `shouldBe` ["π2", "π4", "π3"]
it "reads the term an operand is reduced from" $ do
known <- lambdasOf "- Ξ»: L_pair\n dataize:\n πΏ1: $.x\n π: β¦ Ξ» β€ π β§\n"
operand <- parseExpressionThrows "$.x"
map snd (maybe [] _dataized (matched known "L_pair")) `shouldBe` [operand]
it "reads the term the firing answers with" $ do
known <- lambdasOf "- Ξ»: L_pair\n π: Ξ¦.number( Ο β¦ β¦ Ξ» β€ π β§ )\n"
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π β§ )"
answers known "L_pair" `shouldBe` Just term
it "reads a 'join' block joining on a meta 'dataize' bound" $ do
known <- lambdasOf joint
joining known "L_fork" `shouldBe` Just (Left "πΏ1")
it "reads a 'join' block joining on a path from '$' as one that dataizes nothing" $ do
known <- lambdasOf "- Ξ»: L_join\n join:\n on: $.on\n left: $.left\n right: $.right\n"
path <- parseExpressionThrows "$.on"
joining known "L_join" `shouldBe` Just (Right path)
it "reads the two sides of a 'join' block as terms" $ do
known <- lambdasOf joint
left <- parseExpressionThrows "$.a"
right <- parseExpressionThrows "$.b"
sides known "L_fork" `shouldBe` Just (left, right)
it "reads a 'join' block whose sides are metas 'morph' and 'stay' bound" $ do
known <- lambdasOf "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n morph:\n π1: $.a\n π2: $.b\n stay:\n π3: π1\n join:\n on: πΏ1\n left: π3\n right: π2\n"
left <- parseExpressionThrows "π3"
right <- parseExpressionThrows "π2"
sides known "L_fork" `shouldBe` Just (left, right)
it "reads a 'join' block whose sides are metas 'symbolize' bound" $ do
known <- lambdasOf "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n morph:\n π1: $.a\n π2: $.b\n symbolize:\n π3: π1\n π4: π2\n join:\n on: πΏ1\n left: π3\n right: π4\n"
left <- parseExpressionThrows "π3"
right <- parseExpressionThrows "π4"
sides known "L_fork" `shouldBe` Just (left, right)
it "reads a 'join' block whose sides are metas 'defer' bound" $ do
known <- lambdasOf "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n morph:\n π1: $.a\n π2: $.b\n defer:\n π3: π1\n π4: π2\n join:\n on: πΏ1\n left: π3\n right: π4\n"
left <- parseExpressionThrows "π3"
right <- parseExpressionThrows "π4"
sides known "L_fork" `shouldBe` Just (left, right)
it "reads a 'join' block whose sides are metas 'evaluate' bound" $ do
known <- lambdasOf "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n morph:\n π1: $.a\n π2: $.b\n evaluate:\n π3: π1\n π4: π2\n join:\n on: πΏ1\n left: π3\n right: π4\n"
left <- parseExpressionThrows "π3"
right <- parseExpressionThrows "π4"
sides known "L_fork" `shouldBe` Just (left, right)
it "runs each 'evaluate' line of a join right after the 'stay' line it reads" $ do
known <- lambdasOf "- Ξ»: L_fork\n dataize:\n πΏ1: $.Ο\n morph:\n π1: $.left\n π2: $.right\n stay:\n π3: π1\n π4: π2\n evaluate:\n π5: π3\n π6: π4\n symbolize:\n π7: π5\n π8: π6\n defer:\n π9: π7\n π10: π8\n join:\n on: πΏ1\n left: π9\n right: π10\n"
order known "L_fork" `shouldBe` ["π3", "π5", "π4", "π6", "π7", "π9", "π8", "π10"]
it "runs each 'defer' line of a join right after the 'symbolize' line it reads" $ do
known <- lambdasOf "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n morph:\n π1: $.a\n π2: $.b\n defer:\n π7: π5\n π8: π6\n symbolize:\n π5: π3\n π6: π4\n stay:\n π3: π1\n π4: π2\n join:\n on: πΏ1\n left: π7\n right: π8\n"
order known "L_fork" `shouldBe` ["π3", "π4", "π5", "π7", "π6", "π8"]
it "reads a 'join' block with one side a path and the other a meta" $ do
known <- lambdasOf "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n morph:\n π1: $.b\n join:\n on: πΏ1\n left: $.a\n right: π1\n"
left <- parseExpressionThrows "$.a"
right <- parseExpressionThrows "π1"
sides known "L_fork" `shouldBe` Just (left, right)
it "reads the Ξ» function the 'otherwise' of a 'join' block names" $ do
known <- lambdasOf (joint <> " otherwise: L_join\n")
fallback known "L_fork" `shouldBe` Just (Function "L_join")
it "reads a 'join' block with no 'otherwise' as one fabricating nothing" $ do
known <- lambdasOf joint
fallback known "L_fork" `shouldBe` Nothing
it "reads an entry with a 'join' block as one answering no term of its own" $ do
known <- lambdasOf joint
answers known "L_fork" `shouldBe` Nothing
it "reads an entry with an 'π' key as one joining nowhere" $ do
known <- lambdasOf (entry "L_pair")
joining known "L_pair" `shouldBe` Nothing
it "reads the lines of 'defer' with the metas they read" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n defer:\n π4: π2\n π3: π1\n π: π3\n"
defers known "L_hold" `shouldBe` [("π3", "π1"), ("π4", "π2")]
it "reads the metas the lines of 'evaluate' fire" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n evaluate:\n π3: π1\n π4: π2\n π: π3\n"
fired known "L_hold" `shouldBe` [("π3", "π1"), ("π4", "π2")]
it "reads an 'evaluate' line firing what the line above it fired" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π2: π1\n π3: π2\n π: π3\n"
fired known "L_hold" `shouldBe` [("π2", "π1"), ("π3", "π2")]
it "runs an 'evaluate' line before a 'defer' line no meta orders" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n defer:\n π4: π2\n evaluate:\n π3: π1\n π: π3\n"
order known "L_hold" `shouldBe` ["π3", "π4"]
it "runs a line before the line of its own block reading what it made" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π2: π3\n π3: π1\n π: π2\n"
order known "L_hold" `shouldBe` ["π3", "π2"]
it "runs the lines in the order of the metas they read, whatever the order of their blocks" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π3: π2\n defer:\n π2: π1\n π: π3\n"
order known "L_hold" `shouldBe` ["π2", "π3"]
it "reads an entry naming no 'evaluate' block at all" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π: π1\n"
fired known "L_hold" `shouldBe` []
it "reads the lines of 'stay' with the metas they read" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n stay:\n π4: π2\n π3: π1\n π: π3\n"
stays known "L_hold" `shouldBe` [("π3", "π1"), ("π4", "π2")]
it "runs a 'stay' line after the line binding the meta it reads" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n stay:\n π3: π2\n evaluate:\n π2: π1\n π: π3\n"
order known "L_hold" `shouldBe` ["π2", "π3"]
it "runs a 'defer' line before a 'stay' line no meta orders" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n stay:\n π3: π1\n defer:\n π4: π2\n π: π3\n"
order known "L_hold" `shouldBe` ["π4", "π3"]
it "reads an entry naming no 'stay' block at all" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π: π1\n"
stays known "L_hold" `shouldBe` []
it "reads the lines of 'symbolize' with the metas they read" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n symbolize:\n π4: π2\n π3: π1\n π: π3\n"
symbolizes known "L_hold" `shouldBe` [("π3", "π1"), ("π4", "π2")]
it "runs a 'symbolize' line after the 'stay' line binding the meta it reads" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n symbolize:\n π3: π2\n stay:\n π2: π1\n π: π3\n"
order known "L_hold" `shouldBe` ["π2", "π3"]
it "runs a 'stay' line before a 'symbolize' line no meta orders" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n symbolize:\n π3: π1\n stay:\n π4: π2\n π: π3\n"
order known "L_hold" `shouldBe` ["π4", "π3"]
it "reads an entry naming no 'symbolize' block at all" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π: π1\n"
symbolizes known "L_hold" `shouldBe` []
it "reads the lines of 'rewrite' with the metas they read and the count of their rules" $ do
known <- lambdasOf ("- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n rewrite:\n π4:\n of: π2\n" <> truth <> " - name: false-literal\n pattern: Ξ¦.false\n result: Ξ¦.bool( if β¦ β¦ Ξ β€ 00- β§ )\n π3:\n of: π1\n" <> truth <> " π: π3\n")
rewrites known "L_hold" `shouldBe` [("π3", "π1", 1), ("π4", "π2", 2)]
it "reads a line of 'rewrite' sharing its rules with another one through a YAML anchor" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n rewrite:\n π3:\n of: π1\n rules: &bool\n - name: true-literal\n pattern: Ξ¦.true\n result: Ξ¦.bool( if β¦ β¦ Ξ β€ 01- β§ )\n π4:\n of: π2\n rules: *bool\n π: π3\n"
rewrites known "L_hold" `shouldBe` [("π3", "π1", 1), ("π4", "π2", 1)]
it "runs a 'rewrite' line after the 'evaluate' line binding the meta it reads" $ do
known <- lambdasOf ("- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π3:\n of: π2\n" <> truth <> " evaluate:\n π2: π1\n π: π3\n")
order known "L_hold" `shouldBe` ["π2", "π3"]
it "runs a 'rewrite' line before a 'symbolize' line no meta orders" $ do
known <- lambdasOf ("- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n symbolize:\n π3: π1\n rewrite:\n π4:\n of: π2\n" <> truth <> " π: π3\n")
order known "L_hold" `shouldBe` ["π4", "π3"]
it "reads a 'join' block whose sides are metas 'rewrite' bound" $ do
known <- lambdasOf ("- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n morph:\n π1: $.a\n π2: $.b\n rewrite:\n π3:\n of: π1\n" <> truth <> " π4:\n of: π2\n" <> truth <> " join:\n on: πΏ1\n left: π3\n right: π4\n")
left <- parseExpressionThrows "π3"
right <- parseExpressionThrows "π4"
sides known "L_fork" `shouldBe` Just (left, right)
it "reads an entry naming no 'rewrite' block at all" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π: π1\n"
rewrites known "L_hold" `shouldBe` []
it "reads an entry naming no 'defer' block at all" $ do
known <- lambdasOf "- Ξ»: L_hold\n morph:\n π1: $.a\n π: π1\n"
defers known "L_hold" `shouldBe` []
it "reads an entry naming neither operand block" $ do
known <- lambdasOf "- Ξ»: L_pair\n π: β¦ Ξ» β€ π β§\n"
map (_spelling . fst) (maybe [] _dataized (matched known "L_pair")) `shouldBe` []
forM_
[ ("a file which is no list of entries" :: String, "Ξ»: L_pair\n" :: T.Text, "cannot be read" :: String)
, ("an entry with no Ξ» key", "- π: β¦ Ξ» β€ π β§\n", "no 'Ξ»' key")
, ("an entry with no answer at all", "- Ξ»: L_pair\n", "The entry of Ξ» function 'L_pair' has neither an 'π' key nor a 'join' block")
, ("an entry whose answer is no term of the calculus", "- Ξ»: L_pair\n π: β¦ Ξ» β€\n", "cannot be read")
, ("two entries under one key", entry "L_pair" <> entry "L_pair", "is used by more than one entry")
,
( "two entries with overlapping regular expressions"
, entry "L_(foo|bar)" <> entry "L_foo"
, "match some of the same lambda names"
)
,
( "two keys overlapping on a name neither of them spells"
, entry "L_[a-z]+_plus" <> entry "L_number_[a-z]+"
, "such as 'L_number_plus'"
)
, ("a key with a back reference phino cannot compare", entry "L_(a)\\1" <> entry "L_b", "cannot be compared")
, ("a key which is no regular expression", entry "L_[pair", "is not a regular expression")
, ("an operand of 'dataize' which is no bytes meta", "- Ξ»: L_pair\n dataize:\n π1: $.x\n π: β¦ Ξ» β€ π β§\n", "is not a bytes meta")
, ("an operand of 'morph' which is no expression meta", "- Ξ»: L_pair\n morph:\n πΏ1: $.x\n π: β¦ Ξ» β€ π β§\n", "is not an expression meta")
, ("an operand referencing a meta the entry never matched", "- Ξ»: L_pair\n dataize:\n πΏ1: '!n'\n π: β¦ Ξ» β€ π β§\n", "cannot be referenced")
, ("an answer reading the data its operands came down to", "- Ξ»: L_pair\n dataize:\n πΏ1: $.Ο\n π: β¦ Ξ β€ πΏ1 β§\n", "reads data")
, ("an answer writing a numbered symbol", "- Ξ»: L_pair\n π: 'β¦ a β¦ β¦ Ξ» β€ π1 β§, b β¦ β¦ Ξ» β€ π β§ β§'\n", "writes the numbered symbol 'π1'")
, ("an answer carrying an anonymous meta of another kind", "- Ξ»: L_pair\n π: 'β¦ Ο β¦ !n β§'\n", "cannot be referenced")
, ("an 'evaluate' line firing a meta the entry never bound", "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π3: π2\n π: π3\n", "names no meta bound by 'morph' or by any line")
, ("an 'evaluate' line bound to what is no expression meta", "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n πΏ1: π1\n π: π1\n", "is not an expression meta")
, ("an 'evaluate' line firing a meta that came down to data", "- Ξ»: L_hold\n dataize:\n πΏ1: $.Ο\n evaluate:\n π1: πΏ1\n π: π1\n", "is not an expression meta")
, ("an 'evaluate' line firing a term instead of a meta", "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π2: $.a\n π: π2\n", "is not an expression meta")
, ("a meta bound by 'morph' and again by 'evaluate'", "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π1: π1\n π: π1\n", "The meta 'π1' of Ξ» function 'L_hold' is bound by more than one line")
, ("a line reading the meta it binds", "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π2: π2\n π: π2\n", "The line binding 'π2' of Ξ» function 'L_hold' reads the meta it binds")
, ("two lines reading what each other made", "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π2: π3\n defer:\n π3: π2\n π: π2\n", "The line binding 'π2' of Ξ» function 'L_hold' reads the meta it binds")
, ("a line reading what two lines reading each other made, blaming one of the two", "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π5: π3\n defer:\n π3: π4\n π4: π3\n π: π5\n", "The line binding 'π3' of Ξ» function 'L_hold' reads the meta it binds")
, ("an answer naming a meta no block binds", "- Ξ»: L_pair\n dataize:\n πΏ1: $.Ο\n π: π7\n", "reads the meta 'n7' that no block binds")
, ("an operand of 'dataize' reading a meta", "- Ξ»: L_pair\n dataize:\n πΏ1: π5\n π: β¦ Ξ» β€ π β§\n", "of 'dataize' of Ξ» function 'L_pair' reads the meta 'n5'")
, ("an operand of 'morph' reading a meta", "- Ξ»: L_pair\n morph:\n π1: $.x.π1\n π: π1\n", "of 'morph' of Ξ» function 'L_pair' reads the meta 't1'")
, ("an operand of 'morph' reading a meta inside a term", "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: π1.x\n π: π2\n", "The operand 'π2' of 'morph' of Ξ» function 'L_hold' reads the meta 'n1', while only a path from '$' or a meta alone can be reduced there")
, ("an operand of 'morph' naming a meta nothing binds", "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: π5\n π: π2\n", "The operand 'π5' of Ξ» function 'L_hold' names no meta bound by 'morph' or by any line")
, ("an operand of 'morph' which is no term of the calculus", "- Ξ»: L_hold\n morph:\n π1: β¦ Ξ» β€\n π: π1\n", "Error in $[0].morph.π1: expression:1:6")
, ("an operand of 'morph' naming the meta it binds", "- Ξ»: L_hold\n morph:\n π1: π1\n π: π1\n", "The line binding 'π1' of Ξ» function 'L_hold' reads the meta it binds")
, ("a 'defer' line deferring a meta the entry never bound", "- Ξ»: L_hold\n morph:\n π1: $.a\n defer:\n π3: π2\n π: π3\n", "names no meta bound by 'morph' or by any line")
, ("a 'defer' line bound to what is no expression meta", "- Ξ»: L_hold\n morph:\n π1: $.a\n defer:\n πΏ1: π1\n π: π1\n", "is not an expression meta")
, ("a meta bound by 'defer' and again by 'evaluate'", "- Ξ»: L_hold\n morph:\n π1: $.a\n defer:\n π2: π1\n evaluate:\n π2: π1\n π: π2\n", "The meta 'π2' of Ξ» function 'L_hold' is bound by more than one line")
, ("a meta bound by 'evaluate' and again by 'defer' in its other spelling", "- Ξ»: L_hold\n morph:\n π1: $.a\n evaluate:\n π3: π1\n defer:\n \"!n3\": π1\n π: π3\n", "The meta '!n3' of Ξ» function 'L_hold' is bound by more than one line")
, ("a meta bound twice by 'defer' in its two spellings", "- Ξ»: L_hold\n morph:\n π1: $.a\n π2: $.b\n defer:\n π3: π1\n \"!n3\": π2\n π: π3\n", "is bound by more than one line")
, ("a 'stay' line keeping a meta the entry never bound", "- Ξ»: L_hold\n morph:\n π1: $.a\n stay:\n π3: π2\n π: π3\n", "names no meta bound by 'morph' or by any line")
, ("a 'stay' line bound to what is no expression meta", "- Ξ»: L_hold\n morph:\n π1: $.a\n stay:\n πΏ1: π1\n π: π1\n", "is not an expression meta")
, ("a 'stay' line keeping a term instead of a meta", "- Ξ»: L_hold\n morph:\n π1: $.a\n stay:\n π2: $.a\n π: π2\n", "is not an expression meta")
, ("a 'symbolize' line reading a meta the entry never bound", "- Ξ»: L_hold\n morph:\n π1: $.a\n symbolize:\n π3: π2\n π: π3\n", "names no meta bound by 'morph' or by any line")
, ("a 'symbolize' line reading a term instead of a meta", "- Ξ»: L_hold\n morph:\n π1: $.a\n symbolize:\n π2: $.a\n π: π2\n", "is not an expression meta")
, ("a meta bound by 'stay' and again by 'symbolize'", "- Ξ»: L_hold\n morph:\n π1: $.a\n stay:\n π2: π1\n symbolize:\n π2: π1\n π: π2\n", "The meta 'π2' of Ξ» function 'L_hold' is bound by more than one line")
, ("a 'rewrite' line reading a meta the entry never bound", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π3:\n of: π2\n" <> truth <> " π: π3\n", "names no meta bound by 'morph' or by any line")
, ("a 'rewrite' line bound to what is no expression meta", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n πΏ1:\n of: π1\n" <> truth <> " π: π1\n", "is not an expression meta")
, ("a 'rewrite' line reading a term instead of a meta", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π2:\n of: $.a\n" <> truth <> " π: π2\n", "is not an expression meta")
, ("a 'rewrite' line naming no meta it reads", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π2:\n" <> truth <> " π: π2\n", "The line 'π2' of the 'rewrite' block of Ξ» function 'L_hold' has no 'of' key")
, ("a 'rewrite' line holding no rules", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π2:\n of: π1\n π: π2\n", "The line 'π2' of the 'rewrite' block of Ξ» function 'L_hold' has no 'rules' key")
, ("a 'rewrite' line with a key it does not read", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π2:\n of: π1\n once: true\n" <> truth <> " π: π2\n", "The key 'once' of the line 'π2' of the 'rewrite' block of Ξ» function 'L_hold' is none of its keys: of, rules")
, ("a 'rewrite' line naming its meta alone, as a 'stay' line does", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π2: π1\n π: π2\n", "rewrite.π2: parsing KeyMap failed, expected Object, but encountered String")
, ("a rule of 'rewrite' minting a fresh symbol", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π2:\n of: π1\n rules:\n - name: minting\n pattern: Ξ¦.true\n result: β¦ Ξ» β€ π β§\n π: π2\n", "anonymous meta '!S' cannot be referenced in 'result' of rule 'minting'")
, ("a rule of 'rewrite' writing a symbol nobody minted", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π2:\n of: π1\n rules:\n - name: naming\n pattern: Ξ¦.true\n result: β¦ Ξ» β€ π4 β§\n π: π2\n", "The rule 'naming' of the 'rewrite' block of Ξ» function 'L_hold' writes the symbol 'π4' into its result, while only a firing mints a symbol")
, ("a rule of 'rewrite' reading a meta it never binds", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π2:\n of: π1\n rules:\n - name: unbound\n pattern: β¦ Ο β¦ π1 β§\n result: β¦ Ο β¦ π2 β§\n π: π2\n", "The rule 'unbound' reads the meta 'e2' it never binds")
, ("a rule of 'rewrite' with no result", "- Ξ»: L_hold\n morph:\n π1: $.a\n rewrite:\n π2:\n of: π1\n rules:\n - name: empty\n pattern: Ξ¦.true\n π: π2\n", "key \"result\" not found")
, ("a meta bound by 'morph' and again by 'stay'", "- Ξ»: L_hold\n morph:\n π1: $.a\n stay:\n π1: π1\n π: π1\n", "The meta 'π1' of Ξ» function 'L_hold' is bound by more than one line")
, ("a meta bound by 'morph' and again by 'defer'", "- Ξ»: L_hold\n morph:\n π1: $.a\n defer:\n π1: π1\n π: π1\n", "The meta 'π1' of Ξ» function 'L_hold' is bound by more than one line")
, ("an entry with both an 'π' key and a 'join' block", joint <> " π: β¦ Ξ» β€ π β§\n", "The entry of Ξ» function 'L_fork' has both an 'π' key and a 'join' block, while a join answers the term it joins")
, ("a 'join' block joining on an expression meta", "- Ξ»: L_fork\n join:\n on: π1\n left: $.a\n right: $.b\n", "The 'on' of the 'join' block of Ξ» function 'L_fork' is 'π1', while it must name a bytes meta of 'dataize', such as 'πΏ1', or be a path from '$', such as '$.on'")
, ("a 'join' block joining on a bytes meta 'dataize' never bound", "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n join:\n on: πΏ2\n left: $.a\n right: $.b\n", "The 'on' of the 'join' block of Ξ» function 'L_fork' is 'πΏ2', while it must name a bytes meta of 'dataize'")
, ("a 'join' block joining on a path off 'Ξ¦'", "- Ξ»: L_fork\n join:\n on: Ξ¦.c\n left: $.a\n right: $.b\n", "The 'on' of the 'join' block of Ξ» function 'L_fork' is 'Ξ¦.c'")
, ("a 'join' block joining on an application", "- Ξ»: L_fork\n join:\n on: $.c(x β¦ $.d)\n left: $.a\n right: $.b\n", "The 'on' of the 'join' block of Ξ» function 'L_fork' is '$.c(x β¦ $.d)'")
, ("a 'join' block with no 'on' key", "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n join:\n left: $.a\n right: $.b\n", "The 'join' block of Ξ» function 'L_fork' has no 'on' key")
, ("a 'join' block with no 'left' key", "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n join:\n on: πΏ1\n right: $.b\n", "The 'join' block of Ξ» function 'L_fork' has no 'left' key")
, ("a 'join' block with no 'right' key", "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n join:\n on: πΏ1\n left: $.a\n", "The 'join' block of Ξ» function 'L_fork' has no 'right' key")
, ("a 'join' block with a key it does not read", joint <> " middle: $.m\n", "The key 'middle' of the 'join' block of Ξ» function 'L_fork' is none of its keys: on, left, right, otherwise")
, ("a 'join' block whose 'otherwise' is no Ξ» name", joint <> " otherwise: l_join\n", "The 'otherwise' of the 'join' block of Ξ» function 'L_fork' is 'l_join', while it must name a Ξ» function, such as 'L_join'")
, ("a 'join' block whose 'otherwise' names a symbol", joint <> " otherwise: π3\n", "The 'otherwise' of the 'join' block of Ξ» function 'L_fork' is 'π3', while it must name a Ξ» function, such as 'L_join'")
, ("a 'join' block which is no mapping", "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n join: [πΏ1, $.a, $.b]\n", "join: parsing")
, ("a side of a 'join' block naming a meta nothing binds", "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n join:\n on: πΏ1\n left: π1\n right: $.b\n", "The side 'left' of the 'join' block of Ξ» function 'L_fork' reads the meta 'n1' that none of 'morph', 'evaluate', 'stay', 'rewrite', 'symbolize' and 'defer' binds")
, ("a side of a 'join' block reading a meta inside a term", "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n morph:\n π1: $.a\n join:\n on: πΏ1\n left: π1.x\n right: $.b\n", "The side 'left' of the 'join' block of Ξ» function 'L_fork' reads the meta 'n1' inside a term, while a side is a path from '$' or a meta alone")
, ("a side of a 'join' block which is no term of the calculus", "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n join:\n on: πΏ1\n left: β¦ Ξ» β€\n right: $.b\n", "cannot be read")
, ("a 'fork' block, which is gone", "- Ξ»: L_fork\n dataize:\n πΏ1: $.c\n fork:\n on: πΏ1\n left: $.a\n right: $.b\n", "The key 'fork' of Ξ» function 'L_fork' is none of the keys an entry reads")
, ("an 'unfold' block, which is gone", "- Ξ»: L_fork\n morph:\n π1: $.a\n unfold:\n π2: π1\n π: π2\n", "The key 'unfold' of Ξ» function 'L_fork' is none of the keys an entry reads")
, ("an 'unbox' block, which is gone", "- Ξ»: L_fork\n morph:\n π1: $.a\n unbox:\n π2: π1\n π: π2\n", "The key 'unbox' of Ξ» function 'L_fork' is none of the keys an entry reads")
, ("an 'upcast' block, which is gone", "- Ξ»: L_fork\n morph:\n π1: $.a\n π2: $.b\n upcast:\n π3: π1\n π4: π2\n π: π3\n", "The key 'upcast' of Ξ» function 'L_fork' is none of the keys an entry reads")
, ("a 'terminators' key, which is gone", "- Ξ»: L_fork\n morph:\n π1: $.a\n terminators: [L_throw]\n π: π1\n", "The key 'terminators' of Ξ» function 'L_fork' is none of the keys an entry reads")
, ("a 'lenient' key, which is gone", "- Ξ»: L_fork\n morph:\n π1: $.a\n lenient: []\n π: π1\n", "The key 'lenient' of Ξ» function 'L_fork' is none of the keys an entry reads")
, ("a misspelled 'dataize' block", "- Ξ»: L_pair\n datize:\n πΏ1: $.Ο\n π: β¦ Ξ» β€ π β§\n", "The key 'datize' of Ξ» function 'L_pair' is none of the keys an entry reads")
, ("a 'defer' key saying a flag instead of holding lines", "- Ξ»: L_hold\n morph:\n π1: $.a\n defer: true\n π: π1\n", "defer: parsing")
]
( \(desc, text, reason) ->
it ("cannot read " ++ desc) $
lambdasOf text `shouldThrow` (\err -> reason `isInfixOf` show (err :: SomeException))
)
describe "stayed" $ do
it "drops the Ο a dispatch is applied to" $ do
term <- parseExpressionThrows "Ξ¦.bytes( Ο β¦ β¦ x β¦ β
β§ )"
kept <- parseExpressionThrows "Ξ¦.bytes"
stayed term `shouldBe` kept
it "drops the Ο a dispatch is applied to after an argument binding no Ο" $ do
term <- parseExpressionThrows "Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π1 β§ )( Ο β¦ β¦ x β¦ β
β§ )"
kept <- parseExpressionThrows "Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π1 β§ )"
stayed term `shouldBe` kept
it "drops every Ο a chain of applications gives a dispatch" $ do
term <- parseExpressionThrows "ΞΎ.f( Ο β¦ β¦ a β¦ β
β§ )( Ξ±0 β¦ β¦β§ )( Ο β¦ β¦ b β¦ β
β§ )"
kept <- parseExpressionThrows "ΞΎ.f( Ξ±0 β¦ β¦β§ )"
stayed term `shouldBe` kept
it "keeps the Ο a formation is applied to" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β
, t β¦ β
β§( t β¦ β¦β§ )( Ο β¦ β¦ x β¦ β
β§ )"
kept <- parseExpressionThrows "β¦ Ο β¦ β
, t β¦ β
β§( t β¦ β¦β§ )( Ο β¦ β¦ x β¦ β
β§ )"
stayed term `shouldBe` kept
it "drops a Ο standing deep inside the argument of an application" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π1 β§ )( Ο β¦ β¦ x β¦ β
β§ ) )"
kept <- parseExpressionThrows "Ξ¦.number( Ο β¦ Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π1 β§ ) )"
stayed term `shouldBe` kept
it "drops a Ο standing in a method of a formation and not only in its Ο" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦β§, m β¦ β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ x β¦ β
β§ ) β§ β§"
kept <- parseExpressionThrows "β¦ Ο β¦ β¦β§, m β¦ β¦ Ο β¦ Ξ¦.f β§ β§"
stayed term `shouldBe` kept
it "drops a Ο standing inside a Ο the term keeps" $ do
term <- parseExpressionThrows "β¦ x β¦ β
β§( Ο β¦ Ξ¦.f( Ο β¦ β¦ y β¦ β
β§ ) )"
kept <- parseExpressionThrows "β¦ x β¦ β
β§( Ο β¦ Ξ¦.f )"
stayed term `shouldBe` kept
it "keeps a term carrying no Ο at all" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π2 β§ ) )"
kept <- parseExpressionThrows "Ξ¦.number( Ο β¦ Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π2 β§ ) )"
stayed term `shouldBe` kept
describe "rewritten" $ do
it "rewrites the term a rule matches as a whole" $ do
made <- rewrote [("Ξ¦.true", "Ξ¦.bool( if β¦ β¦ Ξ β€ 01- β§ )")] "Ξ¦.true"
expected <- parseExpressionThrows "Ξ¦.bool( if β¦ β¦ Ξ β€ 01- β§ )"
made `shouldBe` expected
it "rewrites a term a rule matches inside the argument of an application" $ do
made <- rewrote [("Ξ¦.true", "Ξ¦.bool( if β¦ β¦ Ξ β€ 01- β§ )")] "Ξ¦.jq( Ξ±0 β¦ Ξ¦.true )"
expected <- parseExpressionThrows "Ξ¦.jq( Ξ±0 β¦ Ξ¦.bool( if β¦ β¦ Ξ β€ 01- β§ ) )"
made `shouldBe` expected
it "rewrites every place a rule matches inside a formation" $ do
made <- rewrote [("Ξ¦.true", "Ξ¦.vw")] "β¦ kq β¦ Ξ¦.true, Ο β¦ β¦ zt β¦ Ξ¦.true β§ β§"
expected <- parseExpressionThrows "β¦ kq β¦ Ξ¦.vw, Ο β¦ β¦ zt β¦ Ξ¦.vw β§ β§"
made `shouldBe` expected
it "binds the metas of the pattern in the result" $ do
made <- rewrote [("Ξ¦.flag( Ξ±0 β¦ π1 )", "Ξ¦.bool( if β¦ π1 )")] "Ξ¦.flag( Ξ±0 β¦ β¦ Ξ» β€ π6 β§ )"
expected <- parseExpressionThrows "Ξ¦.bool( if β¦ β¦ Ξ» β€ π6 β§ )"
made `shouldBe` expected
it "takes the first rule matching a term" $ do
made <- rewrote [("Ξ¦.true", "Ξ¦.yq"), ("Ξ¦.π1", "Ξ¦.nx")] "Ξ¦.true"
expected <- parseExpressionThrows "Ξ¦.yq"
made `shouldBe` expected
it "tries a later rule where an earlier one does not match" $ do
made <- rewrote [("Ξ¦.false", "Ξ¦.yq"), ("Ξ¦.true", "Ξ¦.nx")] "Ξ¦.true"
expected <- parseExpressionThrows "Ξ¦.nx"
made `shouldBe` expected
it "rewrites the outermost term a rule matches and nothing inside what it made" $ do
made <- rewrote [("β¦ Ο β¦ π1 β§", "π1")] "β¦ Ο β¦ β¦ Ο β¦ ΞΎ.Ο.kq β§ β§"
expected <- parseExpressionThrows "β¦ Ο β¦ ΞΎ.Ο.kq β§"
made `shouldBe` expected
it "leaves what a rule made as it is, not normalized" $ do
made <- rewrote [("Ξ¦.true", "β¦ hv β¦ β¦β§ β§.hv")] "Ξ¦.true"
expected <- parseExpressionThrows "β¦ hv β¦ β¦β§ β§.hv"
made `shouldBe` expected
it "keeps a term no rule matches" $ do
term <- parseExpressionThrows "Ξ¦.false( Ξ±0 β¦ β¦ Ξ β€ 2E- β§ )"
made <- rewrote [("Ξ¦.true", "Ξ¦.vw")] "Ξ¦.false( Ξ±0 β¦ β¦ Ξ β€ 2E- β§ )"
made `shouldBe` term
describe "symbolized" $ do
it "turns the datum of a formation into a fresh symbol" $ do
term <- parseExpressionThrows "β¦ Ξ β€ 4A-2C β§"
masked <- parseExpressionThrows "β¦ Ξ» β€ π8 β§"
(\(made, _, _) -> made) (symbolized term 7) `shouldBe` masked
it "tells the datum every fresh symbol stands for" $ do
term <- parseExpressionThrows "β¦ Ξ β€ 4A-2C β§"
(\(_, known, _) -> known) (symbolized term 7) `shouldBe` [(8, BtMany ["4A", "2C"])]
it "counts every symbol it minted" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ β¦ Ξ β€ 0E- β§ )"
(\(_, _, spent) -> spent) (symbolized term 11) `shouldBe` 12
it "walks the Ο an application binds down to the datum" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ Ξ¦.bytes( Ο β¦ β¦ Ξ β€ 3F-F0-00-00-00-00-00-00 β§ ) )"
masked <- parseExpressionThrows "Ξ¦.number( Ο β¦ Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π3 β§ ) )"
(\(made, _, _) -> made) (symbolized term 2) `shouldBe` masked
it "walks the head of an application binding no Ο" $ do
term <- parseExpressionThrows "Ξ¦.bytes( Ο β¦ β¦ Ξ β€ 61- β§ )( Ο β¦ β¦ w β¦ β
β§ )"
masked <- parseExpressionThrows "Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π20 β§ )( Ο β¦ β¦ w β¦ β
β§ )"
(\(made, _, _) -> made) (symbolized term 19) `shouldBe` masked
it "walks the Ο of a formation down to the datum" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦ Ο β¦ β¦ Ξ β€ 07- β§ β§ β§"
masked <- parseExpressionThrows "β¦ Ο β¦ β¦ Ο β¦ β¦ Ξ» β€ π5 β§ β§ β§"
(\(made, _, _) -> made) (symbolized term 4) `shouldBe` masked
it "turns the datum a Ο of a formation holds into a fresh symbol" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ β€ 02- β§, q β¦ β
β§"
masked <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ» β€ π10 β§, q β¦ β
β§"
(\(made, _, _) -> made) (symbolized term 9) `shouldBe` masked
it "turns the datum a method of a formation holds into a fresh symbol" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦β§, neg β¦ β¦ Ξ β€ BF-F0-00-00-00-00-00-00 β§ β§"
masked <- parseExpressionThrows "β¦ Ο β¦ β¦β§, neg β¦ β¦ Ξ» β€ π10 β§ β§"
(\(made, _, _) -> made) (symbolized term 9) `shouldBe` masked
it "turns the datum a named argument other than Ο holds into a fresh symbol" $ do
term <- parseExpressionThrows "Ξ¦.f( q β¦ β¦ Ξ β€ 1D- β§ )"
masked <- parseExpressionThrows "Ξ¦.f( q β¦ β¦ Ξ» β€ π4 β§ )"
(\(made, _, _) -> made) (symbolized term 3) `shouldBe` masked
it "turns the datum a positional argument holds into a fresh symbol" $ do
term <- parseExpressionThrows "Ξ¦.vk( Ξ±0 β¦ β¦ Ξ β€ 5B- β§ )"
masked <- parseExpressionThrows "Ξ¦.vk( Ξ±0 β¦ β¦ Ξ» β€ π14 β§ )"
(\(made, _, _) -> made) (symbolized term 13) `shouldBe` masked
it "walks the target of a dispatch down to the datum" $ do
term <- parseExpressionThrows "β¦ Ξ β€ 6E- β§.kx"
masked <- parseExpressionThrows "β¦ Ξ» β€ π8 β§.kx"
(\(made, _, _) -> made) (symbolized term 7) `shouldBe` masked
it "walks a formation bound to an argument down to the datum it holds in Ο" $ do
term <- parseExpressionThrows "Ξ¦.bool( if β¦ β¦ Ξ» β€ L_fork, Ο β¦ β¦ Ξ β€ FF- β§ β§ )"
masked <- parseExpressionThrows "Ξ¦.bool( if β¦ β¦ Ξ» β€ L_fork, Ο β¦ β¦ Ξ» β€ π147 β§ β§ )"
(\(made, _, _) -> made) (symbolized term 146) `shouldBe` masked
it "mints the symbols in the order the term spells its data" $ do
term <- parseExpressionThrows "Ξ¦.ws( Ο β¦ β¦ Ξ β€ 3C- β§ )( tz β¦ β¦ Ξ β€ 9D- β§ )"
(\(_, known, _) -> known) (symbolized term 5) `shouldBe` [(6, BtOne "3C"), (7, BtOne "9D")]
it "mints nothing for a term holding no datum" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π2 β§ ) )"
(\(_, _, spent) -> spent) (symbolized term 6) `shouldBe` 6
describe "emptyLambdas" $
it "cannot read a Ξ» function without the file naming one" $
answering emptyLambdas "L_number_plus" `shouldBe` Nothing
describe "minted" $ do
it "mints one fresh symbol per bare π the answer carries" $ do
answer <- parseExpressionThrows "β¦ a β¦ β¦ Ξ» β€ π β§, b β¦ β¦ Ξ» β€ π β§ β§"
map snd (fst (minted answer 4)) `shouldBe` [FnSymbol 5, FnSymbol 6]
it "counts every symbol it minted into the state" $ do
answer <- parseExpressionThrows "β¦ a β¦ β¦ Ξ» β€ π β§, b β¦ β¦ Ξ» β€ π β§ β§"
snd (minted answer 4) `shouldBe` 6
it "mints nothing for a symbol the answer already numbers" $ do
answer <- parseExpressionThrows "β¦ Ξ» β€ π1 β§"
fst (minted answer 4) `shouldBe` []
it "mints nothing for an answer carrying no symbol at all" $ do
answer <- parseExpressionThrows "β¦ Ξ β€ 00- β§"
snd (minted answer 4) `shouldBe` 4
describe "taken" $ do
it "takes the last symbol the program already carries" $ do
program <- parseExpressionThrows "β¦ a β¦ β¦ Ξ» β€ π3 β§, b β¦ β¦ Ξ» β€ π7 β§ β§"
taken program `shouldBe` 7
it "takes nothing from a program carrying no symbol" $ do
program <- parseExpressionThrows "β¦ Ξ β€ 00- β§"
taken program `shouldBe` 0