diff --git a/Debug.hs b/Debug.hs new file mode 100644 index 0000000000000000000000000000000000000000..6c66e0c069b2ce8c7fae62ccb78ef2ff8dc1ef94 --- /dev/null +++ b/Debug.hs @@ -0,0 +1,2 @@ +module Debug where +notImplemented = error "Not implemented yet" diff --git a/Eval.hs b/Eval.hs new file mode 100644 index 0000000000000000000000000000000000000000..712aeffed0d73b9972a08678c1be2b06dd4e8293 --- /dev/null +++ b/Eval.hs @@ -0,0 +1,27 @@ +eval :: ResultEnvironment -> Expr -> Expr --only focus on one expression +type Environment = ResultEnvironment +findVar :: Environment -> SymbolName -> Expr +findVar = notImplemented +addVar :: Environment -> SymbolName -> Expr -> Environment + +eval env expr = let eval' = eval env in case expr of -- evaluates expression to weak-head normal form (i.e. top level data structure is not a FuncCall) + FuncCall func inputSets args -> case func of + (PredefFunc f) -> case f of + (Filter) -> let (Set inputRecords,predicate) = (eval' $ head inputSets, eval' $ head args) in + Set $ filter ((==Boolean True).eval')(map (\r -> FuncCall predicate [] [r]) inputRecords) -- result is weak-head normal form + --Set $ map (eval env) (map (\r -> FuncCall predicate [] [r]) inputRecords) # don't evaluate last step + + (IsEqual) -> let (e1:e2:_) = args in + Boolean (eval' e1 == eval' e2) + + (RecordIndex) -> let (Record recordData, Int index) = (eval' $ args !! 0, eval' $ args !! 1) in + recordData !! index + + --implement later + --(Map) -> Set $ (map (\r -> FuncCall predicate [] [r]) inputRecords) + (FuncDef setParams argParams body) -> eval new_env body + where + newEnv = foldl (\env entry@(name, expr) -> addVar env name expr) env --adds entries to environment + -- TODO FIx + (Var name) -> findVar env name + _ -> expr diff --git a/Interpreter.hs b/Interpreter.hs new file mode 100644 index 0000000000000000000000000000000000000000..2fe210e256f73daac1fd68b70bd35e4c8351a44c --- /dev/null +++ b/Interpreter.hs @@ -0,0 +1,31 @@ +import Types +import Debug + +type Control = (ResultEnvironment, [Expr]) +type ResultEnvironment = [(SymbolName, Expr)] -- (result of last calculation, other bindings e.g. let statements) + +prepare :: Program -> IO Control -- takes in the AST for the program, reads the csv files and prepares the environment based on the CSV files +prepare (inputSets,instructions) = zipM (environment, return instructions) + where environment = fmap (zip inputSets) $ loadInputFiles inputSets + +---eval :: Control -> Expr -- fully evaluates the program, returning a set +zipM (a,b) = do + a' <- a + b' <- b + return (a',b') + +--pairmap f s = (s, fs) + +-------------------------------------------- + +programStep :: Control -> Control -- updates environment and list +programStep = notImplemented + + +-------------------------------------------- + +loadInputFiles :: [String] -> IO [[String]] +loadInputFiles = mapM readCSV + +readCSV :: FilePath -> IO [[String]] +readCSV _ = error "" \ No newline at end of file diff --git a/ReadCSV.hs b/ReadCSV.hs new file mode 100644 index 0000000000000000000000000000000000000000..53231accd75e40cdad1b0ad94a0ca3b9b46485c4 --- /dev/null +++ b/ReadCSV.hs @@ -0,0 +1,20 @@ +module ReadCSV where + +import System.IO + +readCSV :: FilePath -> IO [[String]] +readCSV fname = do + str <- readFile fname + return $ readCSVString str + +readCSVString :: String -> [[String]] +readCSVString whole = [splitElem ',' line | line <- splitElem '\n' whole] + +splitElem :: Eq a => a -> [a] -> [[a]] +splitElem elem = split (/=elem) + +split :: (a -> Bool) -> [a] -> [[a]] +split p l = case span p l of + ([], _) -> [] + (match, []) -> [match] + (match, _:rem') -> match:split p rem' \ No newline at end of file diff --git a/Types.hs b/Types.hs index 85b17489ae3e6625ca2001a024c70e464fff58c6..54db017b2fc199284f2878a17a07c3e6d2885930 100644 --- a/Types.hs +++ b/Types.hs @@ -3,22 +3,26 @@ type Program = (InputSymbols,Output) type SymbolName = String type InputSymbols = [String] -- .in section -type Output = [OutputLine] -- .out section - -data OutputLine = Let SymbolName Expr | Expr -- Expr always a function call for a set function, but not enforced by AST. +--type Output = [OutputLine] -- .out section +--data OutputLine = Let SymbolName Expr | Expr -- Expr always a function call for a set function, but not enforced by AST. +type Output = [Expr] data PredefFunc = XProduct | XXProduct | IsEqual | IsNotEqual | Add --operators | Map | Filter | RecordIndex -- [] operator | IsEmpty | NotEmpty -- string functions + deriving (Show, Eq) --n.b. these definitions do not enforce type checking! The use of any function or operator will be associated with a FuncCall. --Therefore, it is possible to have ASTs with ridiculous things where e.g. a XX product is applied to and int and a String, or a function call has an Int as a function! --These issues will be checked via the type checker after the AST has been built. +-- filter [A] (\(r) -> r[1] == "hello") +-- FuncCall (PredefFunc Filter) [Var "A"] [FuncDef [] ["r"] [(FuncCall (PredefFunc IsEqual) [] (r[1]) ("hello"))]] data Expr = FuncCall {func::Expr, inputSets::[Expr], args::[Expr]} -- args: function to call, input sets, extra argument. Applicable for all kinds of functions: the set functions e.g. filter, map or simple functions or even the operators e.g. ==, /= ! We don't define separate expr for each operator - | FuncDef {name::SymbolName, inputSetNames::[SymbolName], argsNames::[SymbolName], body::Expr} -- function definition + -- | FuncDef {name::SymbolName, inputSetNames::[SymbolName], argsNames::[SymbolName], body::Expr} -- function definition + | FuncDef {inputSetNames::[SymbolName], argsNames::[SymbolName], body::Expr} -- function definition | If Expr Expr Expr | Set [Expr] | Tuple [Expr] @@ -28,5 +32,6 @@ data Expr = FuncCall {func::Expr, inputSets::[Expr], args::[Expr]} -- args: func | Int Int | String String | Boolean Bool - + deriving (Show, Eq) + data Parameter = NamedParam SymbolName | TupleMatch [SymbolName] \ No newline at end of file