aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Builtins.hs3
-rw-r--r--src/Interpreter.hs60
-rw-r--r--src/Utils.hs15
3 files changed, 68 insertions, 10 deletions
diff --git a/src/Builtins.hs b/src/Builtins.hs
index e56d00d..dc80db4 100644
--- a/src/Builtins.hs
+++ b/src/Builtins.hs
@@ -38,7 +38,8 @@ builtinEnv = M.fromList [
reservedKeyword "\\",
reservedKeyword "let!",
reservedKeyword "match",
- reservedKeyword "env!"
+ reservedKeyword "env!",
+ reservedKeyword "record!"
]
argError1 :: String -> AST -> String
diff --git a/src/Interpreter.hs b/src/Interpreter.hs
index aefd816..9f56220 100644
--- a/src/Interpreter.hs
+++ b/src/Interpreter.hs
@@ -18,15 +18,6 @@ import Builtins
import Tokenizer ( tokenize' )
import Parser ( parse )
--- _curryCall :: [AST] -> ASTNode -> LContext AST
--- _curryCall (arg:[]) f = f arg
--- _curryCall (arg:rest) f = do
--- g <- _curryCall rest f
--- case astNode g of
--- ASTFunction fIsPure f' -> f' arg
--- other -> throwL (astPos g) $ "cannot call value " ++ show other ++ " as a function"
--- _curryCall _ astFn = throwL "" $ "unreachable: _curryCall, astFn: " ++ show astFn
-
curryCall :: [AST] -> ASTNode -> LContext AST
curryCall [] (ASTFunction fIsPure f) = do
checkPurity fIsPure
@@ -239,6 +230,55 @@ evaluateImport asts = do
_ -> throwL (astPos importAst) $ "invalid arguments passed to import!: " ++ show args
+evaluateRecord :: [AST] -> LContext AST
+evaluateRecord asts = do
+ let recordAst = head asts
+ args = tail asts
+
+ d <- getDepth
+ when (d > 1) $ throwL (astPos recordAst) $ "record! can only be called on the top level, current depth: " ++ show d
+
+ case args of
+ (AST { astNode = ASTSymbol ns }:rest) -> do
+ let nonSymFields = L.find (not . isSymbolAST) rest
+ case nonSymFields of
+ Just invalid -> throwL (astPos invalid)
+ $ "non-symbol field in record definition: " ++ show invalid
+ Nothing -> return ()
+
+ let fields = extractRows rest
+
+ let fnCreateName = ns ++ "/create"
+ let makeFnCreate :: [String] -> [(String, AST)] -> LFunction
+ makeFnCreate (param:[]) argsAcc = fn where
+ fn arg = do
+ let record = M.fromList $ (param, arg) : argsAcc
+ return $ makeNonsenseAST $ ASTRecord ns record
+ makeFnCreate (param:restParams) argsAcc = fn where
+ fn :: LFunction
+ fn arg = return $ makeNonsenseAST $ ASTFunction True $
+ makeFnCreate restParams ((param, arg):argsAcc)
+
+ makeFnCreate _ _ = error $ "unreachable: makeFnCreate " ++ fnCreateName
+
+ let namespacedFields = map (\name -> ns ++ "/" ++ name) fields
+ let createFn = makeFnCreate fields []
+
+ insertThisEnv fnCreateName $ recordAst { astNode = ASTFunction True createFn }
+ return $ recordAst { astNode = ASTUnit }
+
+ _ -> throwL (astPos recordAst) $ "invalid arguments passed to import!: " ++ show args
+
+ where
+ isSymbolAST AST { astNode = ASTSymbol _ } = True
+ isSymbolAST _ = False
+ extractRows (AST { astNode = ASTSymbol sym }:rest) = sym : extractRows rest
+ extractRows _ = []
+ processField ns field =
+ let fnGetName = ns ++ "/" ++ "get-" ++ field
+ fnSetName = ns ++ "/" ++ "set-" ++ field
+ in () -- todo
+
evaluateUserFunction :: [AST] -> LContext AST
evaluateUserFunction children = do
let fnAst = head children
@@ -297,6 +337,8 @@ evaluate ast@AST { astNode = fnc@(ASTFunctionCall args@(x:_)) } =
evaluateEnv args
ASTSymbol "import!" ->
evaluateImport args
+ ASTSymbol "record!" ->
+ evaluateRecord args
_ ->
evaluateUserFunction args
diff --git a/src/Utils.hs b/src/Utils.hs
index b68de18..bcac58e 100644
--- a/src/Utils.hs
+++ b/src/Utils.hs
@@ -6,6 +6,7 @@ import Control.Monad.State
import qualified Data.Map as M
import qualified Data.List as L
import qualified Data.Char as C
+import qualified Data.Text as T
-- TYPES
@@ -130,6 +131,8 @@ instance (Show Token) where
type Purity = Bool
type LFunction = AST -> LContext AST
+type LRecord = M.Map String AST
+
data ASTNode
= ASTInteger Int
| ASTDouble Double
@@ -140,6 +143,7 @@ data ASTNode
| ASTFunctionCall [AST]
| ASTHashMap (M.Map AST AST)
| ASTFunction Purity LFunction
+ | ASTRecord String LRecord
| ASTUnit
| ASTHole
@@ -167,6 +171,9 @@ instance (Show ASTNode) where
show (ASTFunction isPure _) = case isPure of
True -> "<pure fn>"
False -> "<impure fn>"
+ show (ASTRecord identifier record) =
+ let assocsStrList = map (\(k, v) -> k ++ ":" ++ show v) (M.assocs record)
+ in "(" ++ identifier ++ " " ++ L.intercalate " " assocsStrList ++ ")"
show ASTUnit = "<unit>"
show ASTHole = "<hole>"
@@ -286,3 +293,11 @@ astPos AST { astRow = r, astColumn = c, astFileName = f } = f ++ ":" ++ show r +
tokenPos :: Token -> String
tokenPos Token { tokenRow = r, tokenColumn = c, tokenFileName = f } = f ++ ":" ++ show r ++ ":" ++ show c
+
+separateNsIdPart :: String -> (String, String)
+separateNsIdPart identifier =
+ let t = T.pack identifier
+ parts = T.splitOn (T.pack "/") t
+ nsPartText = T.concat $ L.init parts
+ idPartText = L.last parts
+ in (T.unpack nsPartText, T.unpack idPartText)