Expansion of testing suite to cover incl. library
Expands the testing suite to verify behavior of provided library functions. Updates the README further for clarification on important concepts.
This commit is contained in:
parent
c30f17367f
commit
60a9e3c1ee
23
README.md
23
README.md
@ -2,27 +2,30 @@
|
|||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
tricu (pronounced like "tree-shoe") is a "micro-language" that [I'm](https://eversole.co) working on to investigate [Tree Calculus](https://github.com/barry-jay-personal/typed_tree_calculus/blob/main/typed_program_analysis.pdf).
|
tricu (pronounced like the words "tree-shoe" in English) is a language that [I'm](https://eversole.co) working on to investigate [Tree Calculus](https://github.com/barry-jay-personal/typed_tree_calculus/blob/main/typed_program_analysis.pdf).
|
||||||
|
|
||||||
tricu [means tree in Lojban](https://en.wiktionary.org/wiki/Appendix:Lojban/tricu). This project was named "sapling" until I discovered the name was already being used for other projects in programming language development.
|
tricu is the word for "tree" in Lojban (`(x1) is a tree of species/cultivar (x2)`). This project was named "sapling" until I discovered the name is already being used for other (completely unrelated) programming language development projects.
|
||||||
|
|
||||||
tricu offers a minimal amount of syntax sugar yet provides a complete and intuitive programming environment. tricu offers:
|
tricu offers minimal syntax sugar yet manages to provide a complete, intuitive, and familiar programming environment. There is great power in simplicity. tricu offers:
|
||||||
|
|
||||||
- `t` operator behaving by the rules of Tree Calculus
|
1. `t` operator behaving by the rules of Tree Calculus
|
||||||
- Function ("variable") definitions
|
1. Function definitions/assignments
|
||||||
- Lambda abstractions
|
1. Lambda abstractions eliminated to Tree Calculus forms
|
||||||
- List, Number, and String literals
|
1. List, Number, and String literals
|
||||||
|
1. Parentheses intuitively grouping function application
|
||||||
|
|
||||||
|
These basic features move us cleanly out of the [turing tarpit](https://en.wikipedia.org/wiki/Turing_tarpit) territory that you may find yourself in if you try working only with the `t` operator.
|
||||||
|
|
||||||
## What does it look like?
|
## What does it look like?
|
||||||
|
|
||||||
```
|
```
|
||||||
-- Anything after `--` on a line is a comment
|
-- Anything after `--` on a line is a comment
|
||||||
-- We can define functions or "variables" as tree calculus values
|
-- We can define functions or "variables" as Tree Calculus values
|
||||||
false = t
|
false = t
|
||||||
_ = t
|
_ = t
|
||||||
true = t t
|
true = t t
|
||||||
-- We can define functions as lambda expressions that are eliminated to tree
|
-- We can define functions as lambda expressions that are eliminated to Tree
|
||||||
-- calculus terms.
|
-- Calculus terms.
|
||||||
id = (\a : a) -- `id` evaluates to the TC form of: t (t (t t)) t
|
id = (\a : a) -- `id` evaluates to the TC form of: t (t (t t)) t
|
||||||
triage = (\a b c : t (t a b) c)
|
triage = (\a b c : t (t a b) c)
|
||||||
-- Intensionality! We can inspect program structure, not just inputs/outputs:
|
-- Intensionality! We can inspect program structure, not just inputs/outputs:
|
||||||
|
@ -30,14 +30,13 @@ library = evalTricu Map.empty $ parseTricu $ unlines
|
|||||||
, "matchBool = (\\ot of : triage of (\\_ : ot) (\\_ _ : ot))"
|
, "matchBool = (\\ot of : triage of (\\_ : ot) (\\_ _ : ot))"
|
||||||
, "matchList = (\\oe oc : triage oe _ oc)"
|
, "matchList = (\\oe oc : triage oe _ oc)"
|
||||||
, "matchPair = (\\op : triage _ _ op)"
|
, "matchPair = (\\op : triage _ _ op)"
|
||||||
|
, "not = matchBool false true"
|
||||||
, "and = matchBool id (\\z : false)"
|
, "and = matchBool id (\\z : false)"
|
||||||
, "if = (\\cond then else : t (t else (t t then)) t cond)"
|
, "if = (\\cond then else : t (t else (t t then)) t cond)"
|
||||||
, "test = triage \"leaf\" (\\z : \"stem\") (\\a b : \"fork\")"
|
, "test = triage \"Leaf\" (\\z : \"Stem\") (\\a b : \"Fork\")"
|
||||||
, "emptyList = matchList true (\\y z : false)"
|
, "emptyList = matchList true (\\y z : false)"
|
||||||
, "nonEmptyList = matchList false (\\y z : true)"
|
|
||||||
, "head = matchList t (\\hd tl : hd)"
|
, "head = matchList t (\\hd tl : hd)"
|
||||||
, "tail = matchList t (\\hd tl : tl)"
|
, "tail = matchList t (\\hd tl : tl)"
|
||||||
, "isLeaf = (\\_ : triage true false false)"
|
|
||||||
, "listConcat = y (\\self : matchList (\\k : k) (\\h r k : pair h (self r k)))"
|
, "listConcat = y (\\self : matchList (\\k : k) (\\h r k : pair h (self r k)))"
|
||||||
, "lAnd = triage (\\x : false) (\\_ x : x) (\\_ _ x : x)"
|
, "lAnd = triage (\\x : false) (\\_ x : x) (\\_ _ x : x)"
|
||||||
, "lOr = triage (\\x : x) (\\_ _ : true) (\\_ _ x : true)"
|
, "lOr = triage (\\x : x) (\\_ _ : true) (\\_ _ x : true)"
|
||||||
|
@ -12,7 +12,7 @@ import Text.Megaparsec (runParser)
|
|||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
putStrLn "Welcome to the Tricu Interpreter"
|
putStrLn "Welcome to the tricu Interpreter"
|
||||||
putStrLn "You can exit at any time by typing and entering: "
|
putStrLn "You can exit at any time by typing and entering: "
|
||||||
putStrLn ":_exit"
|
putStrLn ":_exit"
|
||||||
repl library
|
repl library
|
||||||
|
@ -28,7 +28,7 @@ repl env = runInputT defaultSettings (loop env)
|
|||||||
case Map.lookup "__result" newEnv of
|
case Map.lookup "__result" newEnv of
|
||||||
Just r -> do
|
Just r -> do
|
||||||
outputStrLn $ "tricu > " ++ show r
|
outputStrLn $ "tricu > " ++ show r
|
||||||
outputStrLn $ "DECODE -: " ++ decodeResult r
|
outputStrLn $ "DECODE -: \"" ++ decodeResult r ++ "\""
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
loop newEnv
|
loop newEnv
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ decodeResult :: T -> String
|
|||||||
decodeResult tc = case toNumber tc of
|
decodeResult tc = case toNumber tc of
|
||||||
Right num -> show num
|
Right num -> show num
|
||||||
Left _ -> case toString tc of
|
Left _ -> case toString tc of
|
||||||
Right str -> "\"" ++ str ++ "\""
|
Right str -> str
|
||||||
Left _ -> case toList tc of
|
Left _ -> case toList tc of
|
||||||
Right list -> "[" ++ intercalate ", " (map decodeResult list) ++ "]"
|
Right list -> "[" ++ intercalate ", " (map decodeResult list) ++ "]"
|
||||||
Left _ -> ""
|
Left _ -> ""
|
||||||
|
120
test/Spec.hs
120
test/Spec.hs
@ -4,6 +4,7 @@ import Eval
|
|||||||
import Lexer
|
import Lexer
|
||||||
import Library
|
import Library
|
||||||
import Parser
|
import Parser
|
||||||
|
import REPL
|
||||||
import Research
|
import Research
|
||||||
import Control.Exception (evaluate, try, SomeException)
|
import Control.Exception (evaluate, try, SomeException)
|
||||||
import Test.Tasty
|
import Test.Tasty
|
||||||
@ -27,6 +28,7 @@ tests = testGroup "Tricu Tests"
|
|||||||
, integrationTests
|
, integrationTests
|
||||||
, evaluationTests
|
, evaluationTests
|
||||||
, lambdaEvalTests
|
, lambdaEvalTests
|
||||||
|
, libraryTests
|
||||||
, propertyTests
|
, propertyTests
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ lexerTests = testGroup "Lexer Tests"
|
|||||||
|
|
||||||
parserTests :: TestTree
|
parserTests :: TestTree
|
||||||
parserTests = testGroup "Parser Tests"
|
parserTests = testGroup "Parser Tests"
|
||||||
[ --testCase "Error when parsing incomplete definitions" $ do
|
[-- testCase "Error when parsing incomplete definitions" $ do
|
||||||
-- let input = lexTricu "x = "
|
-- let input = lexTricu "x = "
|
||||||
-- case (runParser parseExpression "" input) of
|
-- case (runParser parseExpression "" input) of
|
||||||
-- Left _ -> return ()
|
-- Left _ -> return ()
|
||||||
@ -222,30 +224,6 @@ evaluationTests = testGroup "Evaluation Tests"
|
|||||||
let input = "x = (\\a : a)\nx " ++ not
|
let input = "x = (\\a : a)\nx " ++ not
|
||||||
env = evalTricu Map.empty (parseTricu input)
|
env = evalTricu Map.empty (parseTricu input)
|
||||||
result env @?= Fork (Fork (Stem Leaf) (Fork Leaf Leaf)) Leaf
|
result env @?= Fork (Fork (Stem Leaf) (Fork Leaf Leaf)) Leaf
|
||||||
, testCase "Constant function matches" $ do
|
|
||||||
let input = "k = (\\a b : a)\nk (t t) t"
|
|
||||||
env = evalTricu Map.empty (parseTricu input)
|
|
||||||
result env @?= Stem Leaf
|
|
||||||
, testCase "Boolean AND_ TF" $ do
|
|
||||||
let input = "and (t t) (t)"
|
|
||||||
env = evalTricu library (parseTricu input)
|
|
||||||
result env @?= Leaf
|
|
||||||
, testCase "Boolean AND_ FT" $ do
|
|
||||||
let input = "and (t) (t t)"
|
|
||||||
env = evalTricu library (parseTricu input)
|
|
||||||
result env @?= Leaf
|
|
||||||
, testCase "Boolean AND_ FF" $ do
|
|
||||||
let input = "and (t) (t)"
|
|
||||||
env = evalTricu library (parseTricu input)
|
|
||||||
result env @?= Leaf
|
|
||||||
, testCase "Boolean AND_ TT" $ do
|
|
||||||
let input = "and (t t) (t t)"
|
|
||||||
env = evalTricu library (parseTricu input)
|
|
||||||
result env @?= Stem Leaf
|
|
||||||
, testCase "Verifying Equality" $ do
|
|
||||||
let input = "equal (t t t) (t t t)"
|
|
||||||
env = evalTricu library (parseTricu input)
|
|
||||||
result env @?= Stem Leaf
|
|
||||||
]
|
]
|
||||||
|
|
||||||
lambdaEvalTests :: TestTree
|
lambdaEvalTests :: TestTree
|
||||||
@ -309,6 +287,98 @@ lambdaEvalTests = testGroup "Lambda Evaluation Tests"
|
|||||||
runTricu input @?= "Fork Leaf (Fork (Stem Leaf) Leaf)"
|
runTricu input @?= "Fork Leaf (Fork (Stem Leaf) Leaf)"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
libraryTests :: TestTree
|
||||||
|
libraryTests = testGroup "Library Tests"
|
||||||
|
[ testCase "K combinator 1" $ do
|
||||||
|
let input = "k (t) (t t)"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Leaf
|
||||||
|
, testCase "K combinator 2" $ do
|
||||||
|
let input = "k (t t) (t)"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Stem Leaf
|
||||||
|
, testCase "K combinator 3" $ do
|
||||||
|
let input = "k (t t t) (t)"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Fork Leaf Leaf
|
||||||
|
, testCase "S combinator" $ do
|
||||||
|
let input = "s (t) (t) (t)"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Fork Leaf (Stem Leaf)
|
||||||
|
, testCase "SKK == I" $ do -- Tests for fully expanded I form
|
||||||
|
let input = "s k k"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Fork (Stem (Stem Leaf)) (Stem Leaf)
|
||||||
|
, testCase "I combinator" $ do
|
||||||
|
let input = "i not"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Fork (Fork (Stem Leaf) (Fork Leaf Leaf)) (Fork Leaf (Fork Leaf Leaf))
|
||||||
|
, testCase "Triage test Leaf" $ do
|
||||||
|
let input = "test t"
|
||||||
|
env = decodeResult $ result $ evalTricu library (parseTricu input)
|
||||||
|
env @?= "Leaf"
|
||||||
|
, testCase "Triage test (Stem Leaf)" $ do
|
||||||
|
let input = "test (t t)"
|
||||||
|
env = decodeResult $ result $ evalTricu library (parseTricu input)
|
||||||
|
env @?= "Stem"
|
||||||
|
, testCase "Triage test (Fork Leaf Leaf)" $ do
|
||||||
|
let input = "test (t t t)"
|
||||||
|
env = decodeResult $ result $ evalTricu library (parseTricu input)
|
||||||
|
env @?= "Fork"
|
||||||
|
, testCase "Boolean NOT: true" $ do
|
||||||
|
let input = "not true"
|
||||||
|
env = result $ evalTricu library (parseTricu input)
|
||||||
|
env @?= Leaf
|
||||||
|
, testCase "Boolean NOT: false" $ do
|
||||||
|
let input = "not false"
|
||||||
|
env = result $ evalTricu library (parseTricu input)
|
||||||
|
env @?= Stem Leaf
|
||||||
|
, testCase "Boolean AND TF" $ do
|
||||||
|
let input = "and (t t) (t)"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Leaf
|
||||||
|
, testCase "Boolean AND FT" $ do
|
||||||
|
let input = "and (t) (t t)"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Leaf
|
||||||
|
, testCase "Boolean AND FF" $ do
|
||||||
|
let input = "and (t) (t)"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Leaf
|
||||||
|
, testCase "Boolean AND TT" $ do
|
||||||
|
let input = "and (t t) (t t)"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Stem Leaf
|
||||||
|
, testCase "List head" $ do
|
||||||
|
let input = "head [(t) (t t) (t t t)]"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Leaf
|
||||||
|
, testCase "List tail" $ do
|
||||||
|
let input = "head (tail (tail [(t) (t t) (t t t)]))"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Fork Leaf Leaf
|
||||||
|
, testCase "List map" $ do
|
||||||
|
let input = "head (tail (map (\\a : (t t t)) [(t) (t) (t)]))"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Fork Leaf Leaf
|
||||||
|
, testCase "Empty list check" $ do
|
||||||
|
let input = "emptyList []"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Stem Leaf
|
||||||
|
, testCase "Non-empty list check" $ do
|
||||||
|
let input = "not (emptyList [(1) (2) (3)])"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Stem Leaf
|
||||||
|
, testCase "Concatenate strings" $ do
|
||||||
|
let input = "listConcat \"Hello, \" \"world!\""
|
||||||
|
env = decodeResult $ result $ evalTricu library (parseTricu input)
|
||||||
|
env @?= "Hello, world!"
|
||||||
|
, testCase "Verifying Equality" $ do
|
||||||
|
let input = "equal (t t t) (t t t)"
|
||||||
|
env = evalTricu library (parseTricu input)
|
||||||
|
result env @?= Stem Leaf
|
||||||
|
]
|
||||||
|
|
||||||
propertyTests :: TestTree
|
propertyTests :: TestTree
|
||||||
propertyTests = testGroup "Property Tests"
|
propertyTests = testGroup "Property Tests"
|
||||||
[ testProperty "Lexing and parsing round-trip" $ \input ->
|
[ testProperty "Lexing and parsing round-trip" $ \input ->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user