Rough draft of modules
This includes a naive implementation of a module system where imported files have their imports recursively handled, strips the module/import AST nodes, and then evals everything into a flat environment using namespace prefixes like "Module.function".
This commit is contained in:
parent
79317bf4e3
commit
63504ba939
@ -1,3 +1,7 @@
|
|||||||
|
!module Equality
|
||||||
|
|
||||||
|
!import "lib/base.tri" Lib
|
||||||
|
|
||||||
main = lambdaEqualsTC
|
main = lambdaEqualsTC
|
||||||
|
|
||||||
-- We represent `false` with a Leaf and `true` with a Stem Leaf
|
-- We represent `false` with a Leaf and `true` with a Stem Leaf
|
||||||
@ -24,7 +28,7 @@ not_Lambda? = demo_matchBool demo_false demo_true
|
|||||||
-- to different tree representations even if they share extensional behavior.
|
-- to different tree representations even if they share extensional behavior.
|
||||||
|
|
||||||
-- Let's see if these are the same:
|
-- Let's see if these are the same:
|
||||||
lambdaEqualsTC = equal? not_TC? not_Lambda?
|
lambdaEqualsTC = Lib.equal? not_TC? not_Lambda?
|
||||||
|
|
||||||
-- Here are some checks to verify their extensional behavior is the same:
|
-- Here are some checks to verify their extensional behavior is the same:
|
||||||
true_TC? = not_TC? demo_false
|
true_TC? = not_TC? demo_false
|
||||||
@ -33,5 +37,5 @@ false_TC? = not_TC? demo_true
|
|||||||
true_Lambda? = not_Lambda? demo_false
|
true_Lambda? = not_Lambda? demo_false
|
||||||
false_Lambda? = not_Lambda? demo_true
|
false_Lambda? = not_Lambda? demo_true
|
||||||
|
|
||||||
bothTrueEqual? = equal? true_TC? true_Lambda?
|
bothTrueEqual? = Lib.equal? true_TC? true_Lambda?
|
||||||
bothFalseEqual? = equal? false_TC? false_Lambda?
|
bothFalseEqual? = Lib.equal? false_TC? false_Lambda?
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
!module LOT
|
||||||
|
|
||||||
|
!import "lib/base.tri" Lib
|
||||||
|
|
||||||
main = exampleTwo
|
main = exampleTwo
|
||||||
-- Level Order Traversal of a labelled binary tree
|
-- Level Order Traversal of a labelled binary tree
|
||||||
-- Objective: Print each "level" of the tree on a separate line
|
-- Objective: Print each "level" of the tree on a separate line
|
||||||
@ -15,41 +19,41 @@ main = exampleTwo
|
|||||||
-- / / \
|
-- / / \
|
||||||
-- 4 5 6
|
-- 4 5 6
|
||||||
|
|
||||||
label = \node : head node
|
label = \node : Lib.head node
|
||||||
|
|
||||||
left = (\node : if (emptyList? node)
|
left = (\node : Lib.if (Lib.emptyList? node)
|
||||||
[]
|
[]
|
||||||
(if (emptyList? (tail node))
|
(Lib.if (Lib.emptyList? (Lib.tail node))
|
||||||
[]
|
[]
|
||||||
(head (tail node))))
|
(Lib.head (Lib.tail node))))
|
||||||
|
|
||||||
right = (\node : if (emptyList? node)
|
right = (\node : Lib.if (Lib.emptyList? node)
|
||||||
[]
|
[]
|
||||||
(if (emptyList? (tail node))
|
(Lib.if (Lib.emptyList? (Lib.tail node))
|
||||||
[]
|
[]
|
||||||
(if (emptyList? (tail (tail node)))
|
(Lib.if (Lib.emptyList? (Lib.tail (Lib.tail node)))
|
||||||
[]
|
[]
|
||||||
(head (tail (tail node))))))
|
(Lib.head (Lib.tail (Lib.tail node))))))
|
||||||
|
|
||||||
processLevel = y (\self queue : if (emptyList? queue)
|
processLevel = Lib.y (\self queue : Lib.if (Lib.emptyList? queue)
|
||||||
[]
|
[]
|
||||||
(pair (map label queue) (self (filter
|
(Lib.pair (Lib.map label queue) (self (Lib.filter
|
||||||
(\node : not? (emptyList? node))
|
(\node : Lib.not? (Lib.emptyList? node))
|
||||||
(lconcat (map left queue) (map right queue))))))
|
(Lib.lconcat (Lib.map left queue) (Lib.map right queue))))))
|
||||||
|
|
||||||
levelOrderTraversal_ = \a : processLevel (t a t)
|
levelOrderTraversal_ = \a : processLevel (t a t)
|
||||||
|
|
||||||
toLineString = y (\self levels : if (emptyList? levels)
|
toLineString = Lib.y (\self levels : Lib.if (Lib.emptyList? levels)
|
||||||
""
|
""
|
||||||
(lconcat
|
(Lib.lconcat
|
||||||
(lconcat (map (\x : lconcat x " ") (head levels)) "")
|
(Lib.lconcat (Lib.map (\x : Lib.lconcat x " ") (Lib.head levels)) "")
|
||||||
(if (emptyList? (tail levels)) "" (lconcat (t (t 10 t) t) (self (tail levels))))))
|
(Lib.if (Lib.emptyList? (Lib.tail levels)) "" (Lib.lconcat (t (t 10 t) t) (self (Lib.tail levels))))))
|
||||||
|
|
||||||
levelOrderToString = \s : toLineString (levelOrderTraversal_ s)
|
levelOrderToString = \s : toLineString (levelOrderTraversal_ s)
|
||||||
|
|
||||||
flatten = foldl (\acc x : lconcat acc x) ""
|
flatten = Lib.foldl (\acc x : Lib.lconcat acc x) ""
|
||||||
|
|
||||||
levelOrderTraversal = \s : lconcat (t 10 t) (flatten (levelOrderToString s))
|
levelOrderTraversal = \s : Lib.lconcat (t 10 t) (flatten (levelOrderToString s))
|
||||||
|
|
||||||
exampleOne = levelOrderTraversal [("1")
|
exampleOne = levelOrderTraversal [("1")
|
||||||
[("2") [("4") t t] t]
|
[("2") [("4") t t] t]
|
||||||
|
@ -1,20 +1,24 @@
|
|||||||
|
!module Size
|
||||||
|
|
||||||
|
!import "lib/base.tri" Lib
|
||||||
|
|
||||||
main = size size
|
main = size size
|
||||||
|
|
||||||
compose = \f g x : f (g x)
|
compose = \f g x : f (g x)
|
||||||
|
|
||||||
succ = y (\self :
|
succ = Lib.y (\self :
|
||||||
triage
|
Lib.triage
|
||||||
1
|
1
|
||||||
t
|
t
|
||||||
(triage
|
(Lib.triage
|
||||||
(t (t t))
|
(t (t t))
|
||||||
(\_ tail : t t (self tail))
|
(\_ Lib.tail : t t (self Lib.tail))
|
||||||
t))
|
t))
|
||||||
|
|
||||||
size = (\x :
|
size = (\x :
|
||||||
(y (\self x :
|
(Lib.y (\self x :
|
||||||
compose succ
|
compose succ
|
||||||
(triage
|
(Lib.triage
|
||||||
(\x : x)
|
(\x : x)
|
||||||
self
|
self
|
||||||
(\x y : compose (self x) (self y))
|
(\x y : compose (self x) (self y))
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
main = toSource not?
|
!module ToSource
|
||||||
|
|
||||||
|
!import "lib/base.tri" Lib
|
||||||
|
|
||||||
|
main = toSource Lib.not?
|
||||||
-- Thanks to intensionality, we can inspect the structure of a given value
|
-- Thanks to intensionality, we can inspect the structure of a given value
|
||||||
-- even if it's a function. This includes lambdas which are eliminated to
|
-- even if it's a function. This includes lambdas which are eliminated to
|
||||||
-- Tree Calculus (TC) terms during evaluation.
|
-- Tree Calculus (TC) terms during evaluation.
|
||||||
@ -12,29 +16,29 @@ main = toSource not?
|
|||||||
-- triage = (\leaf stem fork : t (t leaf stem) fork)
|
-- triage = (\leaf stem fork : t (t leaf stem) fork)
|
||||||
|
|
||||||
-- Base case of a single Leaf
|
-- Base case of a single Leaf
|
||||||
sourceLeaf = t (head "t")
|
sourceLeaf = t (Lib.head "t")
|
||||||
|
|
||||||
-- Stem case
|
-- Stem case
|
||||||
sourceStem = (\convert : (\a rest :
|
sourceStem = (\convert : (\a rest :
|
||||||
t (head "(") -- Start with a left parenthesis "(".
|
t (Lib.head "(") -- Start with a left parenthesis "(".
|
||||||
(t (head "t") -- Add a "t"
|
(t (Lib.head "t") -- Add a "t"
|
||||||
(t (head " ") -- Add a space.
|
(t (Lib.head " ") -- Add a space.
|
||||||
(convert a -- Recursively convert the argument.
|
(convert a -- Recursively convert the argument.
|
||||||
(t (head ")") rest)))))) -- Close with ")" and append the rest.
|
(t (Lib.head ")") rest)))))) -- Close with ")" and append the rest.
|
||||||
|
|
||||||
-- Fork case
|
-- Fork case
|
||||||
sourceFork = (\convert : (\a b rest :
|
sourceFork = (\convert : (\a b rest :
|
||||||
t (head "(") -- Start with a left parenthesis "(".
|
t (Lib.head "(") -- Start with a left parenthesis "(".
|
||||||
(t (head "t") -- Add a "t"
|
(t (Lib.head "t") -- Add a "t"
|
||||||
(t (head " ") -- Add a space.
|
(t (Lib.head " ") -- Add a space.
|
||||||
(convert a -- Recursively convert the first arg.
|
(convert a -- Recursively convert the first arg.
|
||||||
(t (head " ") -- Add another space.
|
(t (Lib.head " ") -- Add another space.
|
||||||
(convert b -- Recursively convert the second arg.
|
(convert b -- Recursively convert the second arg.
|
||||||
(t (head ")") rest)))))))) -- Close with ")" and append the rest.
|
(t (Lib.head ")") rest)))))))) -- Close with ")" and append the rest.
|
||||||
|
|
||||||
-- Wrapper around triage
|
-- Wrapper around triage
|
||||||
toSource_ = y (\self arg :
|
toSource_ = Lib.y (\self arg :
|
||||||
triage
|
Lib.triage
|
||||||
sourceLeaf -- `triage` "a" case, Leaf
|
sourceLeaf -- `triage` "a" case, Leaf
|
||||||
(sourceStem self) -- `triage` "b" case, Stem
|
(sourceStem self) -- `triage` "b" case, Stem
|
||||||
(sourceFork self) -- `triage` "c" case, Fork
|
(sourceFork self) -- `triage` "c" case, Fork
|
||||||
@ -43,5 +47,5 @@ toSource_ = y (\self arg :
|
|||||||
-- toSource takes a single TC term and returns a String
|
-- toSource takes a single TC term and returns a String
|
||||||
toSource = \v : toSource_ v ""
|
toSource = \v : toSource_ v ""
|
||||||
|
|
||||||
exampleOne = toSource true -- OUT: "(t t)"
|
exampleOne = toSource Lib.true -- OUT: "(t t)"
|
||||||
exampleTwo = toSource not? -- OUT: "(t (t (t t) (t t t)) (t t (t t t)))"
|
exampleTwo = toSource Lib.not? -- OUT: "(t (t (t t) (t t t)) (t t (t t t)))"
|
||||||
|
@ -113,6 +113,7 @@ freeVars (SDef _ _ b) = freeVars b
|
|||||||
freeVars (TStem t ) = freeVars t
|
freeVars (TStem t ) = freeVars t
|
||||||
freeVars (TFork l r ) = freeVars l <> freeVars r
|
freeVars (TFork l r ) = freeVars l <> freeVars r
|
||||||
freeVars (SLambda v b ) = foldr Set.delete (freeVars b) v
|
freeVars (SLambda v b ) = foldr Set.delete (freeVars b) v
|
||||||
|
freeVars _ = Set.empty
|
||||||
|
|
||||||
reorderDefs :: Env -> [TricuAST] -> [TricuAST]
|
reorderDefs :: Env -> [TricuAST] -> [TricuAST]
|
||||||
reorderDefs env defs
|
reorderDefs env defs
|
||||||
|
125
src/FileEval.hs
125
src/FileEval.hs
@ -1,9 +1,12 @@
|
|||||||
module FileEval where
|
module FileEval where
|
||||||
|
|
||||||
import Eval
|
import Eval
|
||||||
|
import Lexer
|
||||||
import Parser
|
import Parser
|
||||||
import Research
|
import Research
|
||||||
|
|
||||||
|
import Data.List (partition)
|
||||||
|
import Control.Monad (foldM)
|
||||||
import System.IO
|
import System.IO
|
||||||
|
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
@ -11,8 +14,15 @@ import qualified Data.Map as Map
|
|||||||
evaluateFileResult :: FilePath -> IO T
|
evaluateFileResult :: FilePath -> IO T
|
||||||
evaluateFileResult filePath = do
|
evaluateFileResult filePath = do
|
||||||
contents <- readFile filePath
|
contents <- readFile filePath
|
||||||
let asts = parseTricu contents
|
let tokens = lexTricu contents
|
||||||
let finalEnv = evalTricu Map.empty asts
|
let moduleName = case parseProgram tokens of
|
||||||
|
Right ((SModule name) : _) -> name
|
||||||
|
_ -> ""
|
||||||
|
case parseProgram tokens of
|
||||||
|
Left err -> errorWithoutStackTrace (handleParseError err)
|
||||||
|
Right _ -> do
|
||||||
|
ast <- preprocessFile filePath
|
||||||
|
let finalEnv = mainAlias moduleName $ evalTricu Map.empty ast
|
||||||
case Map.lookup "main" finalEnv of
|
case Map.lookup "main" finalEnv of
|
||||||
Just finalResult -> return finalResult
|
Just finalResult -> return finalResult
|
||||||
Nothing -> errorWithoutStackTrace "No `main` function detected"
|
Nothing -> errorWithoutStackTrace "No `main` function detected"
|
||||||
@ -20,11 +30,114 @@ evaluateFileResult filePath = do
|
|||||||
evaluateFile :: FilePath -> IO Env
|
evaluateFile :: FilePath -> IO Env
|
||||||
evaluateFile filePath = do
|
evaluateFile filePath = do
|
||||||
contents <- readFile filePath
|
contents <- readFile filePath
|
||||||
let asts = parseTricu contents
|
let tokens = lexTricu contents
|
||||||
pure $ evalTricu Map.empty asts
|
let moduleName = case parseProgram tokens of
|
||||||
|
Right ((SModule name) : _) -> name
|
||||||
|
_ -> ""
|
||||||
|
case parseProgram tokens of
|
||||||
|
Left err -> errorWithoutStackTrace (handleParseError err)
|
||||||
|
Right _ -> do
|
||||||
|
ast <- preprocessFile filePath
|
||||||
|
pure $ mainAlias moduleName $ evalTricu Map.empty ast
|
||||||
|
|
||||||
evaluateFileWithContext :: Env -> FilePath -> IO Env
|
evaluateFileWithContext :: Env -> FilePath -> IO Env
|
||||||
evaluateFileWithContext env filePath = do
|
evaluateFileWithContext env filePath = do
|
||||||
contents <- readFile filePath
|
contents <- readFile filePath
|
||||||
let asts = parseTricu contents
|
let tokens = lexTricu contents
|
||||||
pure $ evalTricu env asts
|
let moduleName = case parseProgram tokens of
|
||||||
|
Right ((SModule name) : _) -> name
|
||||||
|
_ -> ""
|
||||||
|
case parseProgram tokens of
|
||||||
|
Left err -> errorWithoutStackTrace (handleParseError err)
|
||||||
|
Right _ -> do
|
||||||
|
ast <- preprocessFile filePath
|
||||||
|
pure $ mainAlias moduleName $ evalTricu env ast
|
||||||
|
|
||||||
|
mainAlias :: String -> Env -> Env
|
||||||
|
mainAlias "" env = env
|
||||||
|
mainAlias moduleName env =
|
||||||
|
case Map.lookup (moduleName ++ ".main") env of
|
||||||
|
Just value -> Map.insert "main" value env
|
||||||
|
Nothing -> env
|
||||||
|
|
||||||
|
preprocessFile :: FilePath -> IO [TricuAST]
|
||||||
|
preprocessFile filePath = do
|
||||||
|
contents <- readFile filePath
|
||||||
|
let tokens = lexTricu contents
|
||||||
|
case parseProgram tokens of
|
||||||
|
Left err -> errorWithoutStackTrace (handleParseError err)
|
||||||
|
Right asts -> do
|
||||||
|
let (moduleName, restAST) = extractModule asts
|
||||||
|
let (imports, nonImports) = partition isImport restAST
|
||||||
|
importedASTs <- concat <$> mapM (processImport moduleName) imports
|
||||||
|
let namespacedAST = namespaceDefinitions moduleName nonImports
|
||||||
|
let fullyNamespacedImports = map (namespaceBody moduleName) importedASTs
|
||||||
|
pure $ fullyNamespacedImports ++ namespacedAST
|
||||||
|
where
|
||||||
|
extractModule :: [TricuAST] -> (String, [TricuAST])
|
||||||
|
extractModule ((SModule name) : xs) = (name, xs)
|
||||||
|
extractModule xs = ("", xs)
|
||||||
|
|
||||||
|
isImport :: TricuAST -> Bool
|
||||||
|
isImport (SImport _ _) = True
|
||||||
|
isImport _ = False
|
||||||
|
|
||||||
|
processImport :: String -> TricuAST -> IO [TricuAST]
|
||||||
|
processImport _ (SImport filePath moduleName) = do
|
||||||
|
importedAST <- preprocessFile filePath
|
||||||
|
pure $ namespaceDefinitions moduleName importedAST
|
||||||
|
processImport _ _ = error "Unexpected non-import AST node in processImport"
|
||||||
|
|
||||||
|
namespaceDefinitions :: String -> [TricuAST] -> [TricuAST]
|
||||||
|
namespaceDefinitions moduleName = map (namespaceDefinition moduleName)
|
||||||
|
|
||||||
|
namespaceDefinition :: String -> TricuAST -> TricuAST
|
||||||
|
namespaceDefinition "" def = def
|
||||||
|
namespaceDefinition moduleName (SDef name args body)
|
||||||
|
| isPrefixed name = SDef name args (namespaceBody moduleName body)
|
||||||
|
| otherwise = SDef (namespaceVariable moduleName name)
|
||||||
|
args (namespaceBody moduleName body)
|
||||||
|
namespaceDefinition moduleName other =
|
||||||
|
namespaceBody moduleName other
|
||||||
|
|
||||||
|
namespaceBody :: String -> TricuAST -> TricuAST
|
||||||
|
namespaceBody moduleName (SVar name)
|
||||||
|
| isPrefixed name = SVar name
|
||||||
|
| otherwise = SVar (namespaceVariable moduleName name)
|
||||||
|
namespaceBody moduleName (SApp func arg) =
|
||||||
|
SApp (namespaceBody moduleName func) (namespaceBody moduleName arg)
|
||||||
|
namespaceBody moduleName (SLambda args body) =
|
||||||
|
SLambda args (namespaceBodyScoped moduleName args body)
|
||||||
|
namespaceBody moduleName (SList items) =
|
||||||
|
SList (map (namespaceBody moduleName) items)
|
||||||
|
namespaceBody moduleName (TFork left right) =
|
||||||
|
TFork (namespaceBody moduleName left) (namespaceBody moduleName right)
|
||||||
|
namespaceBody moduleName (TStem subtree) =
|
||||||
|
TStem (namespaceBody moduleName subtree)
|
||||||
|
namespaceBody moduleName (SDef name args body)
|
||||||
|
| isPrefixed name = SDef name args (namespaceBody moduleName body)
|
||||||
|
| otherwise = SDef (namespaceVariable moduleName name)
|
||||||
|
args (namespaceBody moduleName body)
|
||||||
|
namespaceBody _ other = other
|
||||||
|
|
||||||
|
namespaceBodyScoped :: String -> [String] -> TricuAST -> TricuAST
|
||||||
|
namespaceBodyScoped moduleName args body = case body of
|
||||||
|
SVar name ->
|
||||||
|
if name `elem` args
|
||||||
|
then SVar name
|
||||||
|
else namespaceBody moduleName (SVar name)
|
||||||
|
SApp func arg -> SApp (namespaceBodyScoped moduleName args func) (namespaceBodyScoped moduleName args arg)
|
||||||
|
SLambda innerArgs innerBody -> SLambda innerArgs (namespaceBodyScoped moduleName (args ++ innerArgs) innerBody)
|
||||||
|
SList items -> SList (map (namespaceBodyScoped moduleName args) items)
|
||||||
|
TFork left right -> TFork (namespaceBodyScoped moduleName args left) (namespaceBodyScoped moduleName args right)
|
||||||
|
TStem subtree -> TStem (namespaceBodyScoped moduleName args subtree)
|
||||||
|
SDef name innerArgs innerBody ->
|
||||||
|
SDef (namespaceVariable moduleName name) innerArgs (namespaceBodyScoped moduleName (args ++ innerArgs) innerBody)
|
||||||
|
other -> other
|
||||||
|
|
||||||
|
isPrefixed :: String -> Bool
|
||||||
|
isPrefixed name = '.' `elem` name
|
||||||
|
|
||||||
|
namespaceVariable :: String -> String -> String
|
||||||
|
namespaceVariable "" name = name
|
||||||
|
namespaceVariable moduleName name = moduleName ++ "." ++ name
|
||||||
|
28
src/Lexer.hs
28
src/Lexer.hs
@ -20,7 +20,7 @@ identifier = do
|
|||||||
first <- letterChar <|> char '_'
|
first <- letterChar <|> char '_'
|
||||||
rest <- many $ letterChar
|
rest <- many $ letterChar
|
||||||
<|> digitChar
|
<|> digitChar
|
||||||
<|> char '_' <|> char '-' <|> char '?' <|> char '!'
|
<|> char '_' <|> char '-' <|> char '?' <|> char '.'
|
||||||
<|> char '$' <|> char '#' <|> char '@' <|> char '%'
|
<|> char '$' <|> char '#' <|> char '@' <|> char '%'
|
||||||
let name = first : rest
|
let name = first : rest
|
||||||
if (name == "t" || name == "!result")
|
if (name == "t" || name == "!result")
|
||||||
@ -39,6 +39,22 @@ stringLiteral = do
|
|||||||
char '"' --"
|
char '"' --"
|
||||||
return (LStringLiteral content)
|
return (LStringLiteral content)
|
||||||
|
|
||||||
|
lModule :: Lexer LToken
|
||||||
|
lModule = do
|
||||||
|
_ <- string "!module"
|
||||||
|
space1
|
||||||
|
LIdentifier moduleName <- identifier
|
||||||
|
return (LModule moduleName)
|
||||||
|
|
||||||
|
lImport :: Lexer LToken
|
||||||
|
lImport = do
|
||||||
|
_ <- string "!import"
|
||||||
|
space1
|
||||||
|
LStringLiteral path <- stringLiteral
|
||||||
|
space1
|
||||||
|
LIdentifier name <- identifier
|
||||||
|
return (LImport path name)
|
||||||
|
|
||||||
assign :: Lexer LToken
|
assign :: Lexer LToken
|
||||||
assign = char '=' *> pure LAssign
|
assign = char '=' *> pure LAssign
|
||||||
|
|
||||||
@ -72,13 +88,21 @@ sc = space
|
|||||||
tricuLexer :: Lexer [LToken]
|
tricuLexer :: Lexer [LToken]
|
||||||
tricuLexer = do
|
tricuLexer = do
|
||||||
sc
|
sc
|
||||||
|
header <- many $ do
|
||||||
|
tok <- choice
|
||||||
|
[ try lModule
|
||||||
|
, try lImport
|
||||||
|
, lnewline
|
||||||
|
]
|
||||||
|
sc
|
||||||
|
pure tok
|
||||||
tokens <- many $ do
|
tokens <- many $ do
|
||||||
tok <- choice tricuLexer'
|
tok <- choice tricuLexer'
|
||||||
sc
|
sc
|
||||||
pure tok
|
pure tok
|
||||||
sc
|
sc
|
||||||
eof
|
eof
|
||||||
pure tokens
|
pure (header ++ tokens)
|
||||||
where
|
where
|
||||||
tricuLexer' =
|
tricuLexer' =
|
||||||
[ try lnewline
|
[ try lnewline
|
||||||
|
@ -73,10 +73,30 @@ parseSingle input =
|
|||||||
|
|
||||||
parseProgramM :: ParserM [TricuAST]
|
parseProgramM :: ParserM [TricuAST]
|
||||||
parseProgramM = do
|
parseProgramM = do
|
||||||
|
skipMany topLevelNewline
|
||||||
|
moduleNode <- optional parseModuleM
|
||||||
|
skipMany topLevelNewline
|
||||||
|
importNodes <- many parseImportM
|
||||||
skipMany topLevelNewline
|
skipMany topLevelNewline
|
||||||
exprs <- sepEndBy parseOneExpression (some topLevelNewline)
|
exprs <- sepEndBy parseOneExpression (some topLevelNewline)
|
||||||
skipMany topLevelNewline
|
skipMany topLevelNewline
|
||||||
return exprs
|
return (maybe [] (: []) moduleNode ++ importNodes ++ exprs)
|
||||||
|
|
||||||
|
parseModuleM :: ParserM TricuAST
|
||||||
|
parseModuleM = do
|
||||||
|
LModule moduleName <- satisfyM isModule
|
||||||
|
pure (SModule moduleName)
|
||||||
|
where
|
||||||
|
isModule (LModule _) = True
|
||||||
|
isModule _ = False
|
||||||
|
|
||||||
|
parseImportM :: ParserM TricuAST
|
||||||
|
parseImportM = do
|
||||||
|
LImport filePath moduleName <- satisfyM isImport
|
||||||
|
pure (SImport filePath moduleName)
|
||||||
|
where
|
||||||
|
isImport (LImport _ _) = True
|
||||||
|
isImport _ = False
|
||||||
|
|
||||||
parseOneExpression :: ParserM TricuAST
|
parseOneExpression :: ParserM TricuAST
|
||||||
parseOneExpression = scnParserM *> parseExpressionM
|
parseOneExpression = scnParserM *> parseExpressionM
|
||||||
|
@ -26,7 +26,7 @@ repl env = runInputT defaultSettings (loop env)
|
|||||||
| Just s <- minput, strip s == "" -> do
|
| Just s <- minput, strip s == "" -> do
|
||||||
outputStrLn ""
|
outputStrLn ""
|
||||||
loop env
|
loop env
|
||||||
| Just s <- minput, strip s == "!load" -> do
|
| Just s <- minput, strip s == "!import" -> do
|
||||||
path <- getInputLine "File path to load < "
|
path <- getInputLine "File path to load < "
|
||||||
if
|
if
|
||||||
| Nothing <- path -> do
|
| Nothing <- path -> do
|
||||||
|
@ -26,6 +26,8 @@ data TricuAST
|
|||||||
| TFork TricuAST TricuAST
|
| TFork TricuAST TricuAST
|
||||||
| SLambda [String] TricuAST
|
| SLambda [String] TricuAST
|
||||||
| SEmpty
|
| SEmpty
|
||||||
|
| SModule String
|
||||||
|
| SImport String String
|
||||||
deriving (Show, Eq, Ord)
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
-- Lexer Tokens
|
-- Lexer Tokens
|
||||||
@ -42,6 +44,8 @@ data LToken
|
|||||||
| LOpenBracket
|
| LOpenBracket
|
||||||
| LCloseBracket
|
| LCloseBracket
|
||||||
| LNewline
|
| LNewline
|
||||||
|
| LModule String
|
||||||
|
| LImport String String
|
||||||
deriving (Show, Eq, Ord)
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
-- Output formats
|
-- Output formats
|
||||||
|
20
test/Spec.hs
20
test/Spec.hs
@ -501,19 +501,15 @@ fileEval = testGroup "File evaluation tests"
|
|||||||
demos :: TestTree
|
demos :: TestTree
|
||||||
demos = testGroup "Test provided demo functionality"
|
demos = testGroup "Test provided demo functionality"
|
||||||
[ testCase "Structural equality demo" $ do
|
[ testCase "Structural equality demo" $ do
|
||||||
library <- liftIO $ evaluateFile "./lib/base.tri"
|
res <- liftIO $ evaluateFileResult "./demos/equality.tri"
|
||||||
res <- liftIO $ evaluateFileWithContext library "./demos/equality.tri"
|
decodeResult res @?= "t t"
|
||||||
decodeResult (result res) @?= "t t"
|
|
||||||
, testCase "Convert values back to source code demo" $ do
|
, testCase "Convert values back to source code demo" $ do
|
||||||
library <- liftIO $ evaluateFile "./lib/base.tri"
|
res <- liftIO $ evaluateFileResult "./demos/toSource.tri"
|
||||||
res <- liftIO $ evaluateFileWithContext library "./demos/toSource.tri"
|
decodeResult res @?= "\"(t (t (t t) (t t t)) (t t (t t t)))\""
|
||||||
decodeResult (result res) @?= "\"(t (t (t t) (t t t)) (t t (t t t)))\""
|
|
||||||
, testCase "Determining the size of functions" $ do
|
, testCase "Determining the size of functions" $ do
|
||||||
library <- liftIO $ evaluateFile "./lib/base.tri"
|
res <- liftIO $ evaluateFileResult "./demos/size.tri"
|
||||||
res <- liftIO $ evaluateFileWithContext library "./demos/size.tri"
|
decodeResult res @?= "454"
|
||||||
decodeResult (result res) @?= "454"
|
|
||||||
, testCase "Level Order Traversal demo" $ do
|
, testCase "Level Order Traversal demo" $ do
|
||||||
library <- liftIO $ evaluateFile "./lib/base.tri"
|
res <- liftIO $ evaluateFileResult "./demos/levelOrderTraversal.tri"
|
||||||
res <- liftIO $ evaluateFileWithContext library "./demos/levelOrderTraversal.tri"
|
decodeResult res @?= "\"\n1 \n2 3 \n4 5 6 7 \n8 11 10 9 12 \""
|
||||||
decodeResult (result res) @?= "\"\n1 \n2 3 \n4 5 6 7 \n8 11 10 9 12 \""
|
|
||||||
]
|
]
|
||||||
|
5
test/modules-1.tri
Normal file
5
test/modules-1.tri
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
!module Test
|
||||||
|
|
||||||
|
!import "lib/base.tri" Lib
|
||||||
|
|
||||||
|
main = Lib.not? t
|
1
test/modules-2.tri
Normal file
1
test/modules-2.tri
Normal file
@ -0,0 +1 @@
|
|||||||
|
n = t t t
|
@ -1,7 +1,7 @@
|
|||||||
cabal-version: 1.12
|
cabal-version: 1.12
|
||||||
|
|
||||||
name: tricu
|
name: tricu
|
||||||
version: 0.11.0
|
version: 0.12.0
|
||||||
description: A micro-language for exploring Tree Calculus
|
description: A micro-language for exploring Tree Calculus
|
||||||
author: James Eversole
|
author: James Eversole
|
||||||
maintainer: james@eversole.co
|
maintainer: james@eversole.co
|
||||||
|
Loading…
x
Reference in New Issue
Block a user