phino-0.0.145: 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 Lambdas (Lambda (..), Lambdas, Meta (..), emptyLambdas, joined, matched, minted, readLambdas, symbolized, taken)
import Parser (parseExpressionThrows)
import Test.Hspec
lambdasOf :: T.Text -> IO Lambdas
lambdasOf text = withLambdasOf text readLambdas
entry :: T.Text -> T.Text
entry key = "- Ξ»: " <> key <> "\n dataize:\n πΏ1: $.Ο\n π: β¦ Ξ» β€ π β§\n"
answering :: Lambdas -> T.Text -> Maybe T.Text
answering known func = _key <$> matched known func
joins :: Lambdas -> T.Text -> [(T.Text, (T.Text, T.Text))]
joins known func = map spelled (maybe [] _paired (matched known func))
where
spelled :: (Meta, (Meta, Meta)) -> (T.Text, (T.Text, T.Text))
spelled (meta, (left, right)) = (_spelling meta, (_spelling left, _spelling right))
rewriting :: T.Text -> T.Text
rewriting lines' = "- Ξ»: L_fork\n morph:\n π1: $.a\n rewrite:\n" <> lines'
rules :: T.Text
rules = " rules:\n - name: no-x\n pattern: β¦ !B1, x β¦ β¦β§, !B2 β§\n result: β¦ !B1, !B2 β§\n"
rewrote :: (Meta, (Meta, [a])) -> (T.Text, T.Text, Int)
rewrote (meta, (source, written)) = (_spelling meta, _spelling source, length written)
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 "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 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_fork\n morph:\n π1: $.then\n π2: $.else\n π: π1\n"
map (_spelling . fst) (maybe [] _morphed (matched known "L_fork")) `shouldBe` ["π1", "π2"]
it "reads the operands of 'symbolize' under expression metas" $ do
known <- lambdasOf "- Ξ»: L_fork\n morph:\n π1: $.then\n symbolize:\n π2: π1\n π: π2\n"
map (_spelling . fst) (maybe [] _symbolized (matched known "L_fork")) `shouldBe` ["π2"]
it "reads a 'symbolize' line standing the term the line above it made" $ do
known <- lambdasOf "- Ξ»: L_fork\n morph:\n π1: $.then\n symbolize:\n π2: π1\n π3: π2\n π: π3\n"
map (_spelling . fst) (maybe [] _symbolized (matched known "L_fork")) `shouldBe` ["π2", "π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( Ο β¦ β¦ Ξ» β€ π β§ )"
fmap _answer (matched known "L_pair") `shouldBe` Just term
it "reads the two metas a 'join' line joins" $ do
known <- lambdasOf "- Ξ»: L_fork\n morph:\n π1: $.then\n π2: $.else\n join:\n π3: [π1, π2]\n π: π3\n"
joins known "L_fork" `shouldBe` [("π3", ("π1", "π2"))]
it "reads the two metas of a 'join' line in the order it lists them" $ do
known <- lambdasOf "- Ξ»: L_fork\n morph:\n π1: $.then\n π2: $.else\n join:\n π3: [π2, π1]\n π: π3\n"
joins known "L_fork" `shouldBe` [("π3", ("π2", "π1"))]
it "reads a 'join' line joining the terms a 'symbolize' line stood" $ do
known <- lambdasOf "- Ξ»: L_fork\n morph:\n π1: $.then\n π2: $.else\n symbolize:\n π3: π1\n π4: π2\n join:\n π5: [π3, π4]\n π: π5\n"
joins known "L_fork" `shouldBe` [("π5", ("π3", "π4"))]
it "reads a 'join' line joining what a line above it joined" $ do
known <- lambdasOf "- Ξ»: L_fork\n morph:\n π1: $.a\n π2: $.b\n π3: $.c\n join:\n π4: [π1, π2]\n π5: [π4, π3]\n π: π5\n"
joins known "L_fork" `shouldBe` [("π4", ("π1", "π2")), ("π5", ("π4", "π3"))]
it "reads the lines of 'rewrite' with the metas they read and their rules" $ do
known <- lambdasOf (rewriting " π2:\n of: π1\n" <> rules <> " π3:\n of: π2\n" <> rules <> " π: π3\n")
map rewrote (maybe [] _rewritten (matched known "L_fork")) `shouldBe` [("π2", "π1", 1), ("π3", "π2", 1)]
it "reads a 'symbolize' line standing the term a 'rewrite' line made" $ do
known <- lambdasOf (rewriting " π2:\n of: π1\n" <> rules <> " symbolize:\n π3: π2\n π: π3\n")
map (_spelling . fst) (maybe [] _symbolized (matched known "L_fork")) `shouldBe` ["π3"]
it "reads an entry naming no 'join' block at all" $ do
known <- lambdasOf "- Ξ»: L_pair\n π: β¦ Ξ» β€ π β§\n"
joins known "L_pair" `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", "no 'π' key")
, ("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", "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 of 'symbolize' which is no expression meta", "- Ξ»: L_pair\n morph:\n π1: $.x\n symbolize:\n πΏ1: π1\n π: π1\n", "is not an expression meta")
, ("an operand of 'symbolize' the entry never bound", "- Ξ»: L_pair\n symbolize:\n π2: π1\n π: π2\n", "names no meta")
, ("an operand of 'symbolize' which is no meta at all", "- Ξ»: L_pair\n morph:\n π1: $.x\n symbolize:\n π2: $.x\n π: π2\n", "names no meta")
, ("an operand of 'symbolize' standing the term of a line below it", "- Ξ»: L_pair\n morph:\n π1: $.x\n symbolize:\n π2: π3\n π3: π1\n π: π2\n", "names no 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 carrying an anonymous meta of another kind", "- Ξ»: L_pair\n π: 'β¦ Ο β¦ !n β§'\n", "cannot be referenced")
, ("a 'join' line joining one meta alone", "- Ξ»: L_fork\n morph:\n π1: $.then\n join:\n π2: [π1]\n π: π2\n", "must join exactly two metas")
, ("a 'join' line joining three metas", "- Ξ»: L_fork\n morph:\n π1: $.a\n π2: $.b\n π3: $.c\n join:\n π4: [π1, π2, π3]\n π: π4\n", "must join exactly two metas")
, ("a 'join' line joining what is no expression meta", "- Ξ»: L_fork\n morph:\n π1: $.then\n join:\n π2: [π1, $.else]\n π: π2\n", "is not an expression meta")
, ("a 'join' line bound to what is no expression meta", "- Ξ»: L_fork\n morph:\n π1: $.a\n π2: $.b\n join:\n πΏ1: [π1, π2]\n π: π1\n", "is not an expression meta")
, ("a 'join' line joining a meta the entry never bound", "- Ξ»: L_fork\n morph:\n π1: $.then\n join:\n π3: [π1, π2]\n π: π3\n", "names no meta bound by 'morph' or by a line above it")
, ("a 'join' line joining a meta that came down to data", "- Ξ»: L_fork\n dataize:\n πΏ1: $.Ο\n morph:\n π1: $.then\n join:\n π2: [π1, πΏ1]\n π: π2\n", "is not an expression meta")
, ("a 'join' line joining what a line below it made", "- Ξ»: L_fork\n morph:\n π1: $.a\n π2: $.b\n join:\n π3: [π1, π4]\n π4: [π1, π2]\n π: π3\n", "names no meta bound by 'morph' or by a line above it")
, ("a 'rewrite' line rewriting a meta the entry never bound", rewriting " π2:\n of: π5\n" <> rules <> " π: π2\n", "names no meta bound by 'morph' or by a line above it")
, ("a 'rewrite' line rewriting what a line below it made", rewriting " π2:\n of: π3\n" <> rules <> " π3:\n of: π1\n" <> rules <> " π: π2\n", "names no meta bound by 'morph' or by a line above it")
, ("a 'rewrite' line rewriting what a 'symbolize' line made", rewriting " π3:\n of: π2\n" <> rules <> " symbolize:\n π2: π1\n π: π3\n", "names no meta bound by 'morph' or by a line above it")
, ("a 'rewrite' line bound to what is no expression meta", rewriting " πΏ1:\n of: π1\n" <> rules <> " π: π1\n", "is not an expression meta")
, ("a 'rewrite' line with no rules at all", rewriting " π2:\n of: π1\n π: π2\n", "cannot be read")
, ("a rule of 'rewrite' minting a fresh symbol", rewriting " π2:\n of: π1\n rules:\n - name: minting\n pattern: β¦ Ο β¦ π1 β§\n result: β¦ Ξ» β€ π β§\n π: π2\n", "writes a symbol π into its result")
, ("a rule of 'rewrite' writing a symbol nobody minted", rewriting " π2:\n of: π1\n rules:\n - name: naming\n pattern: β¦ Ο β¦ π1 β§\n result: β¦ Ξ» β€ π1 β§\n π: π2\n", "writes a symbol π into its result")
, ("a rule of 'rewrite' reading a meta it never binds", rewriting " π2:\n of: π1\n rules:\n - name: unbound\n pattern: β¦ Ο β¦ π1 β§\n result: β¦ Ο β¦ π2 β§\n π: π2\n", "reads the meta 'e2' it never binds")
, ("a rule of 'rewrite' with no result", rewriting " π2:\n of: π1\n rules:\n - name: empty\n pattern: β¦ Ο β¦ π1 β§\n π: π2\n", "cannot be read")
, ("a 'symbolize' line standing what a 'join' line made", "- Ξ»: L_fork\n morph:\n π1: $.a\n π2: $.b\n symbolize:\n π5: π3\n join:\n π3: [π1, π2]\n π: π5\n", "names no meta bound by 'morph' or by a line above it")
]
( \(desc, text, message) ->
it ("cannot read " ++ desc) $
lambdasOf text `shouldThrow` (\err -> message `isInfixOf` show (err :: SomeException))
)
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 "symbolized" $ do
it "stands every datum of a term into an unknown" $ do
term <- parseExpressionThrows "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ β€ 00- β§ )( t β¦ β¦ Ξ β€ FF- β§ ) β§"
unknown <- parseExpressionThrows "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ» β€ π5 β§ )( t β¦ β¦ Ξ» β€ π6 β§ ) β§"
let (masked, _, _) = symbolized term 4
masked `shouldBe` unknown
it "tells the data every symbol it minted stands for" $ do
term <- parseExpressionThrows "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ β€ 00- β§ )( t β¦ β¦ Ξ β€ FF- β§ ) β§"
let (_, known, _) = symbolized term 4
known `shouldBe` [(5, BtOne "00"), (6, BtOne "FF")]
it "counts every symbol it minted into the state" $ do
term <- parseExpressionThrows "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ β€ 00- β§ )( t β¦ β¦ Ξ β€ FF- β§ ) β§"
let (_, _, spent) = symbolized term 4
spent `shouldBe` 6
it "leaves a datum standing outside the Ο chain alone" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ β€ 00- β§, neg β¦ β¦ Ο β¦ β¦ Ξ β€ FF- β§ β§ β§"
unknown <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ» β€ π5 β§, neg β¦ β¦ Ο β¦ β¦ Ξ β€ FF- β§ β§ β§"
let (masked, known, spent) = symbolized term 4
masked `shouldBe` unknown
known `shouldBe` [(5, BtOne "00")]
spent `shouldBe` 5
it "leaves a term carrying no datum as it was written" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π1 β§ )"
let (masked, _, _) = symbolized term 4
masked `shouldBe` term
it "stands a datum standing as the argument of an application" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ Ξ¦.bytes( Ο β¦ β¦ Ξ β€ 00- β§ ) )"
unknown <- parseExpressionThrows "Ξ¦.number( Ο β¦ Ξ¦.bytes( Ο β¦ β¦ Ξ» β€ π5 β§ ) )"
let (masked, _, _) = symbolized term 4
masked `shouldBe` unknown
it "keeps what the formation of a datum carries besides the datum" $ do
term <- parseExpressionThrows "β¦ Ξ β€ 00-, Ο β¦ β¦β§ β§"
unknown <- parseExpressionThrows "β¦ Ξ» β€ π5, Ο β¦ β¦β§ β§"
let (masked, _, _) = symbolized term 4
masked `shouldBe` unknown
it "leaves the data a Ο carries alone" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ β€ 00- β§, Ο β¦ β¦ x β¦ β¦ Ξ β€ FF- β§ β§ β§"
unknown <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ» β€ π5 β§, Ο β¦ β¦ x β¦ β¦ Ξ β€ FF- β§ β§ β§"
let (masked, _, _) = symbolized term 4
masked `shouldBe` unknown
it "mints nothing for a term carrying no datum at all" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π1 β§ )"
let (_, _, spent) = symbolized term 4
spent `shouldBe` 4
describe "joined" $ do
let joining :: String -> String -> Int -> IO (Maybe (Expression, [(Int, (Int, Int))], Int))
joining left right spent = do
one <- parseExpressionThrows left
two <- parseExpressionThrows right
pure (joined one two spent)
it "joins two branches differing in one symbol into a fresh one" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ» β€ π5 β§ β§"
made <- joining "β¦ Ο β¦ β¦ Ξ» β€ π1 β§ β§" "β¦ Ο β¦ β¦ Ξ» β€ π2 β§ β§" 4
fmap (\(joint, _, _) -> joint) made `shouldBe` Just term
it "tells the two symbols every fresh one stands for" $ do
made <- joining "β¦ Ο β¦ β¦ Ξ» β€ π1 β§ β§" "β¦ Ο β¦ β¦ Ξ» β€ π2 β§ β§" 4
fmap (\(_, facts, _) -> facts) made `shouldBe` Just [(5, (1, 2))]
it "counts every symbol it minted into the state" $ do
made <- joining "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ» β€ π1 β§ )( t β¦ β¦ Ξ» β€ π2 β§ ) β§" "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ» β€ π3 β§ )( t β¦ β¦ Ξ» β€ π4 β§ ) β§" 4
fmap (\(_, _, spent) -> spent) made `shouldBe` Just 6
it "mints one symbol per pair of differing symbols" $ do
made <- joining "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ» β€ π1 β§ )( t β¦ β¦ Ξ» β€ π2 β§ ) β§" "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ» β€ π3 β§ )( t β¦ β¦ Ξ» β€ π4 β§ ) β§" 4
fmap (\(_, facts, _) -> facts) made `shouldBe` Just [(5, (1, 3)), (6, (2, 4))]
it "mints one symbol for the pair it meets twice" $ do
term <- parseExpressionThrows "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ» β€ π5 β§ )( t β¦ β¦ Ξ» β€ π5 β§ ) β§"
made <- joining "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ» β€ π1 β§ )( t β¦ β¦ Ξ» β€ π1 β§ ) β§" "β¦ Ο β¦ Ξ¦.f( Ο β¦ β¦ Ξ» β€ π2 β§ )( t β¦ β¦ Ξ» β€ π2 β§ ) β§" 4
made `shouldBe` Just (term, [(5, (1, 2))], 5)
it "carries a method from the first branch and mints nothing for it" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ» β€ π5 β§, neg β¦ β¦ Ο β¦ β¦ Ξ» β€ π7 β§ β§ β§"
made <- joining "β¦ Ο β¦ β¦ Ξ» β€ π1 β§, neg β¦ β¦ Ο β¦ β¦ Ξ» β€ π7 β§ β§ β§" "β¦ Ο β¦ β¦ Ξ» β€ π2 β§, neg β¦ β¦ Ο β¦ β¦ Ξ» β€ π8 β§ β§ β§" 4
made `shouldBe` Just (term, [(5, (1, 2))], 5)
it "refuses two branches whose bindings are named differently" $ do
made <- joining "β¦ Ο β¦ β¦ Ξ» β€ π1 β§, m β¦ β¦ x β¦ β
β§ β§" "β¦ Ο β¦ β¦ Ξ» β€ π2 β§, other β¦ β¦ x β¦ β
β§ β§" 4
made `shouldBe` Nothing
it "joins two branches that are one term into that very term" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π1 β§ )"
made <- joining "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π1 β§ )" "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π1 β§ )" 4
made `shouldBe` Just (term, [], 4)
it "joins two branches through the argument of an application" $ do
term <- parseExpressionThrows "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π5 β§ )"
made <- joining "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π1 β§ )" "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π2 β§ )" 4
fmap (\(joint, _, _) -> joint) made `shouldBe` Just term
it "leaves what a Ο carries alone" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ» β€ π5 β§, Ο β¦ β¦ x β¦ β¦ Ξ β€ 00- β§ β§ β§"
made <- joining "β¦ Ο β¦ β¦ Ξ» β€ π1 β§, Ο β¦ β¦ x β¦ β¦ Ξ β€ 00- β§ β§ β§" "β¦ Ο β¦ β¦ Ξ» β€ π2 β§, Ο β¦ β¦ y β¦ β¦ Ξ β€ FF- β§ β§ β§" 4
made `shouldBe` Just (term, [(5, (1, 2))], 5)
it "joins two branches differing in their Ο alone" $ do
term <- parseExpressionThrows "β¦ Ο β¦ β¦ Ξ» β€ π1 β§, Ο β¦ β¦ x β¦ β¦ Ξ β€ 00- β§ β§ β§"
made <- joining "β¦ Ο β¦ β¦ Ξ» β€ π1 β§, Ο β¦ β¦ x β¦ β¦ Ξ β€ 00- β§ β§ β§" "β¦ Ο β¦ β¦ Ξ» β€ π1 β§, Ο β¦ β¦ y β¦ β¦ Ξ β€ FF- β§ β§ β§" 4
made `shouldBe` Just (term, [], 4)
forM_
[ ("a datum with a symbol" :: String, "β¦ Ο β¦ β¦ Ξ β€ 00- β§ β§" :: String, "β¦ Ο β¦ β¦ Ξ» β€ π1 β§ β§" :: String)
, ("two different data", "β¦ Ο β¦ β¦ Ξ β€ 00- β§ β§", "β¦ Ο β¦ β¦ Ξ β€ FF- β§ β§")
, ("a symbol with a Ξ» function nothing else names", "β¦ Ο β¦ β¦ Ξ» β€ π1 β§ β§", "β¦ Ο β¦ β¦ Ξ» β€ L_number_plus β§ β§")
, ("two branches one of which carries a binding more", "β¦ Ο β¦ β¦ Ξ» β€ π1 β§ β§", "β¦ Ο β¦ β¦ Ξ» β€ π2 β§, x β¦ β¦β§ β§")
, ("two branches binding their symbols under different attributes", "β¦ a β¦ β¦ Ξ» β€ π1 β§ β§", "β¦ b β¦ β¦ Ξ» β€ π2 β§ β§")
, ("two branches of different forma", "Ξ¦.number( Ο β¦ β¦ Ξ» β€ π1 β§ )", "Ξ¦.bool( Ο β¦ β¦ Ξ» β€ π2 β§ )")
]
( \(desc, left, right) ->
it ("cannot join " ++ desc) $ do
made <- joining left right 4
fmap (\(joint, _, _) -> joint) made `shouldBe` Nothing
)
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