REPL import warning; version info in CLI
Adds the ability to toggle result decoding in REPL. Adds several more useful functions to the base library.
This commit is contained in:
		
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							@ -2,7 +2,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Introduction
 | 
					## Introduction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tricu (pronounced "tree-shoe") is a purely functional interpreted language implemented in Haskell. It is fundamentally based on the application of [Tree Calculus](https://github.com/barry-jay-personal/typed_tree_calculus/blob/main/typed_program_analysis.pdf) terms, but minimal syntax sugar is included to provide a useful programming tool. tricu is under active development and you can expect breaking changes with nearly every commit.
 | 
					tricu (pronounced "tree-shoe") is a purely functional interpreted language implemented in Haskell. It is fundamentally based on the application of [Tree Calculus](https://github.com/barry-jay-personal/typed_tree_calculus/blob/main/typed_program_analysis.pdf) terms, but minimal syntax sugar is included to provide a useful programming tool. 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*tricu is under active development and you should expect breaking changes with every commit.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tricu is the word for "tree" in Lojban: `(x1) is a tree of species/cultivar (x2)`.
 | 
					tricu is the word for "tree" in Lojban: `(x1) is a tree of species/cultivar (x2)`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -14,7 +16,7 @@ tricu is the word for "tree" in Lojban: `(x1) is a tree of species/cultivar (x2)
 | 
				
			|||||||
- Lambda abstraction syntax: `id = (\a : a)`
 | 
					- Lambda abstraction syntax: `id = (\a : a)`
 | 
				
			||||||
- List, Number, and String literals: `[(2) ("Hello")]` 
 | 
					- List, Number, and String literals: `[(2) ("Hello")]` 
 | 
				
			||||||
- Function application: `not (not false)`
 | 
					- Function application: `not (not false)`
 | 
				
			||||||
- Higher order/first-class functions: `map (\a : lconcat a "!") [("Hello")]`
 | 
					- Higher order/first-class functions: `map (\a : append a "!") [("Hello")]`
 | 
				
			||||||
- Intensionality blurs the distinction between functions and data (see REPL examples)
 | 
					- Intensionality blurs the distinction between functions and data (see REPL examples)
 | 
				
			||||||
- Simple module system for code organization
 | 
					- Simple module system for code organization
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -23,9 +25,9 @@ tricu is the word for "tree" in Lojban: `(x1) is a tree of species/cultivar (x2)
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
tricu < -- Anything after `--` on a single line is a comment
 | 
					tricu < -- Anything after `--` on a single line is a comment
 | 
				
			||||||
tricu < id = (\a : a) -- Lambda abstraction is eliminated to tree calculus terms
 | 
					tricu < id = (\a : a) -- Lambda abstraction is eliminated to tree calculus terms
 | 
				
			||||||
tricu < head (map (\i : lconcat i " world!") [("Hello, ")])
 | 
					tricu < head (map (\i : append i " world!") [("Hello, ")])
 | 
				
			||||||
tricu > "Hello,  world!"
 | 
					tricu > "Hello,  world!"
 | 
				
			||||||
tricu < id (head (map (\i : lconcat i " world!") [("Hello, ")]))
 | 
					tricu < id (head (map (\i : append i " world!") [("Hello, ")]))
 | 
				
			||||||
tricu > "Hello,  world!"
 | 
					tricu > "Hello,  world!"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tricu < -- Intensionality! We can inspect the structure of a function or data.
 | 
					tricu < -- Intensionality! We can inspect the structure of a function or data.
 | 
				
			||||||
 | 
				
			|||||||
@ -37,21 +37,21 @@ processLevel = y (\self queue : if (emptyList? queue)
 | 
				
			|||||||
  [] 
 | 
					  [] 
 | 
				
			||||||
  (pair (map label queue) (self (filter 
 | 
					  (pair (map label queue) (self (filter 
 | 
				
			||||||
    (\node : not? (emptyList? node)) 
 | 
					    (\node : not? (emptyList? node)) 
 | 
				
			||||||
      (lconcat (map left queue) (map right queue))))))
 | 
					      (append (map left queue) (map right queue))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
levelOrderTraversal_ = \a : processLevel (t a t)
 | 
					levelOrderTraversal_ = \a : processLevel (t a t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
toLineString = y (\self levels : if (emptyList? levels) 
 | 
					toLineString = y (\self levels : if (emptyList? levels) 
 | 
				
			||||||
  "" 
 | 
					  "" 
 | 
				
			||||||
  (lconcat 
 | 
					  (append 
 | 
				
			||||||
    (lconcat (map (\x : lconcat x " ") (head levels)) "") 
 | 
					    (append (map (\x : append x " ") (head levels)) "") 
 | 
				
			||||||
    (if (emptyList? (tail levels)) "" (lconcat (t (t 10 t) t) (self (tail levels))))))
 | 
					    (if (emptyList? (tail levels)) "" (append (t (t 10 t) t) (self (tail levels))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
levelOrderToString = \s : toLineString (levelOrderTraversal_ s)
 | 
					levelOrderToString = \s : toLineString (levelOrderTraversal_ s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
flatten = foldl (\acc x : lconcat acc x) ""
 | 
					flatten = foldl (\acc x : append acc x) ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
levelOrderTraversal = \s : lconcat (t 10 t) (flatten (levelOrderToString s))
 | 
					levelOrderTraversal = \s : append (t 10 t) (flatten (levelOrderToString s))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exampleOne = levelOrderTraversal [("1") 
 | 
					exampleOne = levelOrderTraversal [("1") 
 | 
				
			||||||
                                 [("2") [("4") t t] t] 
 | 
					                                 [("2") [("4") t t] t] 
 | 
				
			||||||
 | 
				
			|||||||
@ -2,17 +2,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
main = size size
 | 
					main = size size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
compose = \f g x : f (g x)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
succ = y (\self :
 | 
					 | 
				
			||||||
  triage
 | 
					 | 
				
			||||||
    1
 | 
					 | 
				
			||||||
    t
 | 
					 | 
				
			||||||
    (triage
 | 
					 | 
				
			||||||
      (t (t t))
 | 
					 | 
				
			||||||
      (\_ tail : t t (self tail))
 | 
					 | 
				
			||||||
      t))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
size = (\x :
 | 
					size = (\x :
 | 
				
			||||||
  (y (\self x :
 | 
					  (y (\self x :
 | 
				
			||||||
    compose succ
 | 
					    compose succ
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										69
									
								
								lib/base.tri
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								lib/base.tri
									
									
									
									
									
								
							@ -15,6 +15,8 @@ y = ((\mut wait fun : wait mut (\x : fun (wait mut x)))
 | 
				
			|||||||
     (\x : x x)
 | 
					     (\x : x x)
 | 
				
			||||||
     (\a0 a1 a2 : t (t a0) (t t a2) a1))
 | 
					     (\a0 a1 a2 : t (t a0) (t t a2) a1))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					compose = \f g x : f (g x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
triage = \leaf stem fork : t (t leaf stem) fork
 | 
					triage = \leaf stem fork : t (t leaf stem) fork
 | 
				
			||||||
test   = triage "Leaf" (\_ : "Stem") (\_ _ : "Fork")
 | 
					test   = triage "Leaf" (\_ : "Stem") (\_ _ : "Fork")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -35,7 +37,14 @@ emptyList? = matchList true (\_ _ : false)
 | 
				
			|||||||
head = matchList t (\head _ : head)
 | 
					head = matchList t (\head _ : head)
 | 
				
			||||||
tail = matchList t (\_ tail : tail)
 | 
					tail = matchList t (\_ tail : tail)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lconcat = y (\self : matchList
 | 
					or? = (\x y : 
 | 
				
			||||||
 | 
						matchBool 
 | 
				
			||||||
 | 
					  	(matchBool (t t) (t t) y)
 | 
				
			||||||
 | 
					  	(matchBool (t t) 0 y)
 | 
				
			||||||
 | 
					  	x)
 | 
				
			||||||
 | 
					xor? = matchBool id not?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					append = y (\self : matchList
 | 
				
			||||||
  (\k : k)
 | 
					  (\k : k)
 | 
				
			||||||
  (\h r k : pair h (self r k)))
 | 
					  (\h r k : pair h (self r k)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -71,6 +80,10 @@ equal? = y (\self : triage
 | 
				
			|||||||
      (\_ : false)
 | 
					      (\_ : false)
 | 
				
			||||||
      (\bx by : lAnd (self ax bx) (self ay by))))
 | 
					      (\bx by : lAnd (self ax bx) (self ay by))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lExist? = y (\self x : matchList
 | 
				
			||||||
 | 
					  false
 | 
				
			||||||
 | 
					  (\h z : or? (equal? x h) (self x z)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
filter_ = y (\self : matchList
 | 
					filter_ = y (\self : matchList
 | 
				
			||||||
  (\_ : t)
 | 
					  (\_ : t)
 | 
				
			||||||
  (\head tail f : matchBool (t head) i (f head) (self tail f)))
 | 
					  (\head tail f : matchBool (t head) i (f head) (self tail f)))
 | 
				
			||||||
@ -81,3 +94,57 @@ foldl  = \f x l : foldl_ f l x
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
foldr_ = y (\self x f l : matchList x (\head tail : f (self x f tail) head) l)
 | 
					foldr_ = y (\self x f l : matchList x (\head tail : f (self x f tail) head) l)
 | 
				
			||||||
foldr  = \f x l : foldr_ x f l
 | 
					foldr  = \f x l : foldr_ x f l
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					succ = y (\self :
 | 
				
			||||||
 | 
					  triage
 | 
				
			||||||
 | 
					    1
 | 
				
			||||||
 | 
					    t
 | 
				
			||||||
 | 
					    (triage
 | 
				
			||||||
 | 
					      (t (t t))
 | 
				
			||||||
 | 
					      (\_ tail : t t (self tail))
 | 
				
			||||||
 | 
					      t))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					length = y (\self : matchList
 | 
				
			||||||
 | 
					  0
 | 
				
			||||||
 | 
					  (\_ tail : succ (self tail)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					reverse = y (\self : matchList
 | 
				
			||||||
 | 
					  t
 | 
				
			||||||
 | 
					  (\head tail : append (self tail) (pair head t)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					snoc = y (\self x : matchList
 | 
				
			||||||
 | 
					  (pair x t)
 | 
				
			||||||
 | 
					  (\h z : pair h (self x z)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					count = y (\self x : matchList
 | 
				
			||||||
 | 
					  0
 | 
				
			||||||
 | 
					  (\h z : matchBool 
 | 
				
			||||||
 | 
					    (succ (self x z))
 | 
				
			||||||
 | 
					    (self x z)
 | 
				
			||||||
 | 
					    (equal? x h)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					last = y (\self : matchList
 | 
				
			||||||
 | 
					  t
 | 
				
			||||||
 | 
					  (\hd tl : matchBool
 | 
				
			||||||
 | 
					    hd
 | 
				
			||||||
 | 
					    (self tl)
 | 
				
			||||||
 | 
					    (emptyList? tl)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					all? = y (\self pred : matchList
 | 
				
			||||||
 | 
					  true
 | 
				
			||||||
 | 
					  (\h z : and? (pred h) (self pred z)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					any? = y (\self pred : matchList
 | 
				
			||||||
 | 
					  false
 | 
				
			||||||
 | 
					  (\h z : or? (pred h) (self pred z)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unique_ = y (\self seen : matchList
 | 
				
			||||||
 | 
					  t
 | 
				
			||||||
 | 
					  (\head rest : matchBool
 | 
				
			||||||
 | 
					    (self seen rest)
 | 
				
			||||||
 | 
					    (pair head (self (pair head seen) rest))
 | 
				
			||||||
 | 
					    (lExist? head seen)))
 | 
				
			||||||
 | 
					unique = \xs : unique_ t xs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					intersect = \xs ys : filter (\x : lExist? x ys) xs
 | 
				
			||||||
 | 
					union     = \xs ys : unique (append xs ys)
 | 
				
			||||||
 | 
				
			|||||||
@ -74,8 +74,6 @@ elimLambda = go
 | 
				
			|||||||
    -- Composition optimization
 | 
					    -- Composition optimization
 | 
				
			||||||
    go (SLambda [f] (SLambda [g] (SLambda [x] body)))
 | 
					    go (SLambda [f] (SLambda [g] (SLambda [x] body)))
 | 
				
			||||||
      | body == SApp (SVar f) (SApp (SVar g) (SVar x)) = _B
 | 
					      | body == SApp (SVar f) (SApp (SVar g) (SVar x)) = _B
 | 
				
			||||||
    go (SLambda [f] (SLambda [x] (SLambda [y] body)))
 | 
					 | 
				
			||||||
      | body == SApp (SApp (SVar f) (SVar y)) (SVar x) = _C
 | 
					 | 
				
			||||||
    -- General elimination
 | 
					    -- General elimination
 | 
				
			||||||
    go (SLambda (v:vs) body)
 | 
					    go (SLambda (v:vs) body)
 | 
				
			||||||
      | null vs                    = toSKI v (elimLambda body)
 | 
					      | null vs                    = toSKI v (elimLambda body)
 | 
				
			||||||
@ -97,7 +95,6 @@ elimLambda = go
 | 
				
			|||||||
    _K       = parseSingle "t t"
 | 
					    _K       = parseSingle "t t"
 | 
				
			||||||
    _I       = parseSingle "t (t (t t)) t"
 | 
					    _I       = parseSingle "t (t (t t)) t"
 | 
				
			||||||
    _B       = parseSingle "t (t (t t (t (t (t t t)) t))) (t t)"
 | 
					    _B       = parseSingle "t (t (t t (t (t (t t t)) t))) (t t)"
 | 
				
			||||||
    _C       = parseSingle "t (t (t (t (t t (t (t (t t t)) t))) (t (t (t t (t t))) (t (t (t t t)) t)))) (t t (t t))"
 | 
					 | 
				
			||||||
    _TRIAGE  = parseSingle "t (t (t t (t (t (t t t))))) t"
 | 
					    _TRIAGE  = parseSingle "t (t (t t (t (t (t t t))))) t"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
isFree :: String -> TricuAST -> Bool
 | 
					isFree :: String -> TricuAST -> Bool
 | 
				
			||||||
 | 
				
			|||||||
@ -60,7 +60,8 @@ preprocessFile' inProgress filePath
 | 
				
			|||||||
        Right asts -> do
 | 
					        Right asts -> do
 | 
				
			||||||
          let (imports, nonImports) = partition isImport asts
 | 
					          let (imports, nonImports) = partition isImport asts
 | 
				
			||||||
          let newInProgress = Set.insert filePath inProgress
 | 
					          let newInProgress = Set.insert filePath inProgress
 | 
				
			||||||
          importedASTs <- concat <$> mapM (processImport newInProgress "") imports
 | 
					          importedASTs <- concat <$> 
 | 
				
			||||||
 | 
					            mapM (processImport newInProgress "") imports
 | 
				
			||||||
          pure $ importedASTs ++ nonImports
 | 
					          pure $ importedASTs ++ nonImports
 | 
				
			||||||
  where
 | 
					  where
 | 
				
			||||||
    isImport :: TricuAST -> Bool
 | 
					    isImport :: TricuAST -> Bool
 | 
				
			||||||
@ -116,13 +117,20 @@ nsBodyScoped moduleName args body = case body of
 | 
				
			|||||||
    if name `elem` args
 | 
					    if name `elem` args
 | 
				
			||||||
      then SVar name
 | 
					      then SVar name
 | 
				
			||||||
      else nsBody moduleName (SVar name)
 | 
					      else nsBody moduleName (SVar name)
 | 
				
			||||||
  SApp func arg -> SApp (nsBodyScoped moduleName args func) (nsBodyScoped moduleName args arg)
 | 
					  SApp func arg -> 
 | 
				
			||||||
  SLambda innerArgs innerBody -> SLambda innerArgs (nsBodyScoped moduleName (args ++ innerArgs) innerBody)
 | 
					    SApp (nsBodyScoped moduleName args func) (nsBodyScoped moduleName args arg)
 | 
				
			||||||
  SList items -> SList (map (nsBodyScoped moduleName args) items)
 | 
					  SLambda innerArgs innerBody -> 
 | 
				
			||||||
  TFork left right -> TFork (nsBodyScoped moduleName args left) (nsBodyScoped moduleName args right)
 | 
					    SLambda innerArgs (nsBodyScoped moduleName (args ++ innerArgs) innerBody)
 | 
				
			||||||
  TStem subtree -> TStem (nsBodyScoped moduleName args subtree)
 | 
					  SList items -> 
 | 
				
			||||||
 | 
					    SList (map (nsBodyScoped moduleName args) items)
 | 
				
			||||||
 | 
					  TFork left right -> 
 | 
				
			||||||
 | 
					    TFork (nsBodyScoped moduleName args left) 
 | 
				
			||||||
 | 
					          (nsBodyScoped moduleName args right)
 | 
				
			||||||
 | 
					  TStem subtree -> 
 | 
				
			||||||
 | 
					    TStem (nsBodyScoped moduleName args subtree)
 | 
				
			||||||
  SDef name innerArgs innerBody ->
 | 
					  SDef name innerArgs innerBody ->
 | 
				
			||||||
    SDef (nsVariable moduleName name) innerArgs (nsBodyScoped moduleName (args ++ innerArgs) innerBody)
 | 
					    SDef (nsVariable moduleName name) innerArgs 
 | 
				
			||||||
 | 
					         (nsBodyScoped moduleName (args ++ innerArgs) innerBody)
 | 
				
			||||||
  other -> other
 | 
					  other -> other
 | 
				
			||||||
 | 
					
 | 
				
			||||||
isPrefixed :: String -> Bool
 | 
					isPrefixed :: String -> Bool
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,9 @@ import Research
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import Control.Monad          (foldM)
 | 
					import Control.Monad          (foldM)
 | 
				
			||||||
import Control.Monad.IO.Class (liftIO)
 | 
					import Control.Monad.IO.Class (liftIO)
 | 
				
			||||||
 | 
					import Data.Version           (showVersion)
 | 
				
			||||||
import Text.Megaparsec        (runParser)
 | 
					import Text.Megaparsec        (runParser)
 | 
				
			||||||
 | 
					import Paths_tricu            (version)
 | 
				
			||||||
import System.Console.CmdArgs
 | 
					import System.Console.CmdArgs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import qualified Data.Map as Map
 | 
					import qualified Data.Map as Map
 | 
				
			||||||
@ -52,10 +54,12 @@ decodeMode = TDecode
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
main :: IO ()
 | 
					main :: IO ()
 | 
				
			||||||
main = do
 | 
					main = do
 | 
				
			||||||
 | 
					  let versionStr = "tricu Evaluator and REPL " ++ showVersion version
 | 
				
			||||||
  args <- cmdArgs $ modes [replMode, evaluateMode, decodeMode]
 | 
					  args <- cmdArgs $ modes [replMode, evaluateMode, decodeMode]
 | 
				
			||||||
    &= help "tricu: Exploring Tree Calculus"
 | 
					    &= help "tricu: Exploring Tree Calculus"
 | 
				
			||||||
    &= program "tricu"
 | 
					    &= program "tricu"
 | 
				
			||||||
    &= summary "tricu Evaluator and REPL"
 | 
					    &= summary versionStr
 | 
				
			||||||
 | 
					    &= versionArg [explicit, name "version", summary versionStr]
 | 
				
			||||||
  case args of
 | 
					  case args of
 | 
				
			||||||
    Repl -> do
 | 
					    Repl -> do
 | 
				
			||||||
      putStrLn "Welcome to the tricu REPL"
 | 
					      putStrLn "Welcome to the tricu REPL"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										64
									
								
								src/REPL.hs
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								src/REPL.hs
									
									
									
									
									
								
							@ -6,55 +6,69 @@ import Lexer
 | 
				
			|||||||
import Parser
 | 
					import Parser
 | 
				
			||||||
import Research
 | 
					import Research
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Control.Exception         (SomeException, catch)
 | 
					import Control.Exception      (SomeException, catch)
 | 
				
			||||||
import Control.Monad.IO.Class    (liftIO)
 | 
					import Control.Monad.IO.Class (liftIO)
 | 
				
			||||||
import Control.Monad.Catch (handle, MonadCatch)
 | 
					import Control.Monad.Catch    (handle, MonadCatch)
 | 
				
			||||||
import Data.Char                 (isSpace)
 | 
					import Data.Char              (isSpace)
 | 
				
			||||||
import Data.List                 (dropWhile, dropWhileEnd, intercalate)
 | 
					import Data.List              ( dropWhile
 | 
				
			||||||
 | 
					                              , dropWhileEnd
 | 
				
			||||||
 | 
					                              , intercalate
 | 
				
			||||||
 | 
					                              , isPrefixOf)
 | 
				
			||||||
import System.Console.Haskeline
 | 
					import System.Console.Haskeline
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import qualified Data.Map as Map
 | 
					import qualified Data.Map as Map
 | 
				
			||||||
 | 
					
 | 
				
			||||||
repl :: Env -> IO ()
 | 
					repl :: Env -> IO ()
 | 
				
			||||||
repl env = runInputT defaultSettings (withInterrupt (loop env))
 | 
					repl env = runInputT defaultSettings (withInterrupt (loop env True))
 | 
				
			||||||
  where
 | 
					  where
 | 
				
			||||||
    loop :: Env -> InputT IO ()
 | 
					    loop :: Env -> Bool -> InputT IO ()
 | 
				
			||||||
    loop env = handle (interruptHandler env) $ do
 | 
					    loop env decode = handle (interruptHandler env decode) $ do
 | 
				
			||||||
      minput <- getInputLine "tricu < "
 | 
					      minput <- getInputLine "tricu < "
 | 
				
			||||||
      case minput of
 | 
					      case minput of
 | 
				
			||||||
        Nothing -> outputStrLn "Exiting tricu"
 | 
					        Nothing -> outputStrLn "Exiting tricu"
 | 
				
			||||||
        Just s
 | 
					        Just s
 | 
				
			||||||
 | 
					          | strip s == "" -> loop env decode
 | 
				
			||||||
          | strip s == "!exit" -> outputStrLn "Exiting tricu"
 | 
					          | strip s == "!exit" -> outputStrLn "Exiting tricu"
 | 
				
			||||||
          | strip s == "" -> loop env
 | 
					          | strip s == "!decode" -> do
 | 
				
			||||||
          | strip s == "!import" -> do
 | 
					              outputStrLn $ "Decoding " ++ (if decode then "disabled" else "enabled")
 | 
				
			||||||
 | 
					              loop env (not decode)
 | 
				
			||||||
 | 
					          | "!import" `isPrefixOf` strip s -> do
 | 
				
			||||||
 | 
					              let afterImport = dropWhile (== ' ') $ drop (length ("!import" :: String)) (strip s)
 | 
				
			||||||
 | 
					              if not (null afterImport)
 | 
				
			||||||
 | 
					                then outputStrLn "Warning: REPL imports are interactive; \
 | 
				
			||||||
 | 
					                                  \additional arguments are ignored."
 | 
				
			||||||
 | 
					                else pure ()
 | 
				
			||||||
              path <- getInputLine "File path to load < "
 | 
					              path <- getInputLine "File path to load < "
 | 
				
			||||||
              case path of
 | 
					              case path of
 | 
				
			||||||
                Nothing -> do
 | 
					                Nothing -> do
 | 
				
			||||||
                  outputStrLn "No input received; stopping import."
 | 
					                  outputStrLn "No input received; stopping import."
 | 
				
			||||||
                  loop env
 | 
					                  loop env decode
 | 
				
			||||||
                Just p -> do
 | 
					                Just p -> do
 | 
				
			||||||
                  loadedEnv <- liftIO $ evaluateFileWithContext env 
 | 
					                  loadedEnv <- liftIO $ evaluateFileWithContext env
 | 
				
			||||||
                    (strip p) `catch` \e -> errorHandler env e
 | 
					                    (strip p) `catch` \e -> errorHandler env e
 | 
				
			||||||
                  loop $ Map.delete "!result" (Map.union loadedEnv env)
 | 
					                  loop (Map.delete "!result" (Map.union loadedEnv env)) decode
 | 
				
			||||||
          | take 2 s == "--" -> loop env
 | 
					          | take 2 s == "--" -> loop env decode
 | 
				
			||||||
          | otherwise -> do
 | 
					          | otherwise -> do
 | 
				
			||||||
              newEnv <- liftIO $ processInput env s `catch` errorHandler env
 | 
					              newEnv <- liftIO $ processInput env s decode `catch` errorHandler env
 | 
				
			||||||
              loop newEnv
 | 
					              loop newEnv decode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    interruptHandler :: Env -> Interrupt -> InputT IO ()
 | 
					    interruptHandler :: Env -> Bool -> Interrupt -> InputT IO ()
 | 
				
			||||||
    interruptHandler env _ = do
 | 
					    interruptHandler env decode _ = do
 | 
				
			||||||
      outputStrLn "Interrupted with CTRL+C\n\
 | 
					      outputStrLn "Interrupted with CTRL+C\n\
 | 
				
			||||||
                  \You can use the !exit command or CTRL+D to exit"
 | 
					                  \You can use the !exit command or CTRL+D to exit"
 | 
				
			||||||
      loop env
 | 
					      loop env decode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    processInput :: Env -> String -> IO Env
 | 
					    processInput :: Env -> String -> Bool -> IO Env
 | 
				
			||||||
    processInput env input = do
 | 
					    processInput env input decode = do
 | 
				
			||||||
      let asts   = parseTricu input
 | 
					      let asts   = parseTricu input
 | 
				
			||||||
          newEnv = evalTricu env asts
 | 
					          newEnv = evalTricu env asts
 | 
				
			||||||
      if
 | 
					      case Map.lookup "!result" newEnv of
 | 
				
			||||||
        | Just r <- Map.lookup "!result" newEnv -> do
 | 
					        Just r -> do
 | 
				
			||||||
          putStrLn $ "tricu > " ++ decodeResult r
 | 
					          putStrLn $ "tricu > " ++ 
 | 
				
			||||||
        | otherwise -> return ()
 | 
					            if decode 
 | 
				
			||||||
 | 
					              then decodeResult r
 | 
				
			||||||
 | 
					              else show r
 | 
				
			||||||
 | 
					        Nothing -> pure ()
 | 
				
			||||||
      return newEnv
 | 
					      return newEnv
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    errorHandler :: Env -> SomeException -> IO (Env)
 | 
					    errorHandler :: Env -> SomeException -> IO (Env)
 | 
				
			||||||
 | 
				
			|||||||
@ -468,7 +468,7 @@ baseLibrary = testGroup "Library Tests"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  , testCase "Concatenate strings" $ do
 | 
					  , testCase "Concatenate strings" $ do
 | 
				
			||||||
      library <- evaluateFile "./lib/base.tri"
 | 
					      library <- evaluateFile "./lib/base.tri"
 | 
				
			||||||
      let input = "lconcat \"Hello, \" \"world!\""
 | 
					      let input = "append \"Hello, \" \"world!\""
 | 
				
			||||||
          env = decodeResult $ result $ evalTricu library (parseTricu input)
 | 
					          env = decodeResult $ result $ evalTricu library (parseTricu input)
 | 
				
			||||||
      env @?= "\"Hello, world!\""
 | 
					      env @?= "\"Hello, world!\""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,2 +1,2 @@
 | 
				
			|||||||
x = map (\i : lconcat "Successfully concatenated " i) [("two strings!")]
 | 
					x = map (\i : append "Successfully concatenated " i) [("two strings!")]
 | 
				
			||||||
main = equal? x [("Successfully concatenated two strings!")]
 | 
					main = equal? x [("Successfully concatenated two strings!")]
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1 @@
 | 
				
			|||||||
head (map (\i : lconcat "String " i) [("test!")])
 | 
					head (map (\i : append "String " i) [("test!")])
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user