{-
-- EPITECH PROJECT, 2023
-- GLaDOS
-- File description:
-- AstEval
-}

module AstEval
  ( evalAst,
    evalBiValOp,
    evalBiBoolOp,
    evalBiCompValOp,
  )
where

import AST
import Data.Bifunctor
import Scope

noEvaluationError :: String -> String
noEvaluationError :: String -> String
noEvaluationError String
s = String
"No evaluation in one or more parameters of " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s

invalidParamsBiOp :: String -> String
invalidParamsBiOp :: String -> String
invalidParamsBiOp String
op =
  String
"One or more parameters of binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is invalid"

tooMuchParams :: String -> String
tooMuchParams :: String -> String
tooMuchParams String
s = String
"Too much parameters for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s

notEnoughParams :: String -> String
notEnoughParams :: String -> String
notEnoughParams String
s = String
"Not enough parameters for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s

recursionLimit :: Int
recursionLimit :: Int
recursionLimit = Int
2000

-- | Evaluate a 'Ast'.
-- Takes a stack representing variables and the Ast to evaluate.
-- Returns a tuple containing either the resulting Ast
-- (can be 'Nothing' for no evaluation is possible)
-- or a 'String' containing the error message in case of error
-- and the stack after evaluation.
evalAst :: [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst :: [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst (ScopeBegin Int
depth : [ScopeMb]
xs) Ast
_
  | Int
depth Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
recursionLimit =
      (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Recursion limit reached", Int -> ScopeMb
ScopeBegin Int
depth ScopeMb -> [ScopeMb] -> [ScopeMb]
forall a. a -> [a] -> [a]
: [ScopeMb]
xs)
evalAst (Variable String
s Ast
ast Int
depth : [ScopeMb]
xs) Ast
_
  | Int
depth Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
recursionLimit =
      (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Recursion limit reached", String -> Ast -> Int -> ScopeMb
Variable String
s Ast
ast Int
depth ScopeMb -> [ScopeMb] -> [ScopeMb]
forall a. a -> [a] -> [a]
: [ScopeMb]
xs)
evalAst [ScopeMb]
stack (Define String
s Ast
v) = case ([ScopeMb] -> String -> Ast -> [ScopeMb])
-> [ScopeMb] -> String -> Ast -> Either String [ScopeMb]
defineVar [ScopeMb] -> String -> Ast -> [ScopeMb]
defineFunc [ScopeMb]
stack String
s Ast
v of
  Left String
err -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
  Right [ScopeMb]
stack' -> (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right Maybe Ast
forall a. Maybe a
Nothing, [ScopeMb]
stack')
  where
    defineFunc :: [ScopeMb] -> String -> Ast -> [ScopeMb]
defineFunc = case [ScopeMb] -> String -> Maybe Ast
getVarInScope [ScopeMb]
stack String
s of
      Maybe Ast
Nothing -> [ScopeMb] -> String -> Ast -> [ScopeMb]
addVarToScope
      Just Ast
_ -> [ScopeMb] -> String -> Ast -> [ScopeMb]
updateVar
evalAst [ScopeMb]
stack (AST.Value Int
i) = (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just (Int -> Ast
AST.Value Int
i)), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (AST.Symbol String
s Maybe [Ast]
asts) = case [ScopeMb] -> String -> Maybe Ast
getVarInScope [ScopeMb]
stack String
s of
  Maybe Ast
Nothing -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"Symbol '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++
      String
"' doesn't exist in the current or global scope"), [ScopeMb]
stack)
  Just (FunctionValue [String]
params Ast
ast Maybe [Ast]
Nothing) ->
    [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack ([String] -> Ast -> Maybe [Ast] -> Ast
FunctionValue [String]
params Ast
ast Maybe [Ast]
asts)
  Just Ast
value -> case Maybe [Ast]
asts of
    Maybe [Ast]
Nothing -> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack Ast
value
    Maybe [Ast]
_ -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"Symbol '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' isn't a function"), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (AST.List [Ast]
l) = case [ScopeMb] -> [Ast] -> Either String (Maybe [Ast])
evalSubParams [ScopeMb]
stack [Ast]
l of
  (Left String
err) -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
  (Right (Just [Ast]
l')) -> (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just ([Ast] -> Ast
AST.List [Ast]
l')), [ScopeMb]
stack)
  (Right Maybe [Ast]
Nothing) -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Cannot have Nothing in a list", [ScopeMb]
stack)
evalAst [ScopeMb]
stack (AST.String String
str) = (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just (String -> Ast
AST.String String
str)), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Boolean Bool
b) = (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just (Bool -> Ast
Boolean Bool
b)), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"+" [AST.String String
s1, AST.String String
s2]) =
  (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just (String -> Ast
AST.String (String
s1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s2))), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"+" [Ast]
astList) = (Int -> Int -> Int)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiValOp Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"+" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"-" [Ast]
astList) = (Int -> Int -> Int)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiValOp (-) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"-" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"*" [Ast]
astList) = (Int -> Int -> Int)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiValOp Int -> Int -> Int
forall a. Num a => a -> a -> a
(*) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"*" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"/" [Ast
_, AST.Value Int
0]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Cannot divide by zero", [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"/" [Ast]
astList) = (Int -> Int -> Int)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiValOp Int -> Int -> Int
forall a. Integral a => a -> a -> a
div [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"/" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"%" [Ast
_, AST.Value Int
0]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Cannot divide by zero", [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"%" [Ast]
astList) = (Int -> Int -> Int)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiValOp Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"%" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"==" [Ast]
astList) =
  (Int -> Int -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiCompValOp Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
(==) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"==" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"!=" [Ast]
astList) =
  (Int -> Int -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiCompValOp Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
(/=) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"!=" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"<" [Ast]
astList) =
  (Int -> Int -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiCompValOp Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
(<) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"<" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"<=" [Ast]
astList) =
  (Int -> Int -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiCompValOp Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
(<=) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"<=" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
">" [Ast]
astList) =
  (Int -> Int -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiCompValOp Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
(>) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
">" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
">=" [Ast]
astList) =
  (Int -> Int -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiCompValOp Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
(>=) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
">=" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"&&" [Ast]
astList) =
  (Bool -> Bool -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiBoolOp Bool -> Bool -> Bool
(&&) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"&&" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"||" [Ast]
astList) =
  (Bool -> Bool -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiBoolOp Bool -> Bool -> Bool
(||) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"||" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"^^" [Ast]
astList) =
  (Bool -> Bool -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiBoolOp (\Bool
a Bool
b -> (Bool
a Bool -> Bool -> Bool
|| Bool
b) Bool -> Bool -> Bool
&& Bool -> Bool
not (Bool
a Bool -> Bool -> Bool
&& Bool
b)) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"||" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"!" [AST.Boolean Bool
b]) =
  (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just (Bool -> Ast
AST.Boolean (Bool -> Bool
not Bool
b))), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"!" [Ast
ast]) = case [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack Ast
ast of
  (Left String
err, [ScopeMb]
_) -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
  (Right (Just (Boolean Bool
b)), [ScopeMb]
_) -> (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just (Bool -> Ast
AST.Boolean (Bool -> Bool
not Bool
b))), [ScopeMb]
stack)
  (Right Maybe Ast
Nothing, [ScopeMb]
_) ->
    (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"No evaluation in parameter of unary operator '!'", [ScopeMb]
stack)
  (Right Maybe Ast
_, [ScopeMb]
_) ->
    (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Parameter of unary operator '!' isn't a boolean", [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"!" [Ast]
_) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Invalid number of parameter for unary operator '!'", [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"@" [Ast
ast]) = case [ScopeMb] -> Ast -> Either String Ast
astToString [ScopeMb]
stack Ast
ast of
  Left String
err -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
  Right Ast
ast' -> (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just Ast
ast'), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"@" (Ast
_ : [Ast]
_)) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
tooMuchParams String
"string conversion"), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"@" []) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
notEnoughParams String
"string conversion"), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"++" [Ast]
astList) =
  ([Ast] -> Ast -> [Ast])
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiListOp (\[Ast]
l Ast
el -> [Ast]
l [Ast] -> [Ast] -> [Ast]
forall a. [a] -> [a] -> [a]
++ [Ast
el]) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"++" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"--" [Ast]
astList) =
  ([Ast] -> Ast -> [Ast])
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiListOp (\[Ast]
l Ast
el -> (Ast -> Bool) -> [Ast] -> [Ast]
forall a. (a -> Bool) -> [a] -> [a]
filter (Ast -> Ast -> Bool
forall a. Eq a => a -> a -> Bool
/= Ast
el) [Ast]
l) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"++" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"!!" [Ast]
astList) =
  case [ScopeMb] -> Ast -> Either String Ast
getElemInAstList [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"!!" [Ast]
astList) of
    Left String
err -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
    Right Ast
ast' -> (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just Ast
ast'), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"~" [Ast]
astList) =
  ([Ast] -> Ast)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalUnListOp (Int -> Ast
AST.Value (Int -> Ast) -> ([Ast] -> Int) -> [Ast] -> Ast
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Ast] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length) [ScopeMb]
stack (String -> [Ast] -> Ast
Call String
"~" [Ast]
astList)
evalAst [ScopeMb]
stack (Call String
"$" [Ast
ast1, Ast
ast2]) = case [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack Ast
ast1 of
  (Left String
err, [ScopeMb]
_) -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
  (Right Maybe Ast
_, [ScopeMb]
stack') -> case [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack' Ast
ast2 of
    (Left String
err', [ScopeMb]
_) -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err', [ScopeMb]
stack)
    (Right Maybe Ast
ast, [ScopeMb]
stack'') -> (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right Maybe Ast
ast, [ScopeMb]
stack'')
evalAst [ScopeMb]
stack (Call String
"$" (Ast
_ : [Ast]
_)) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
tooMuchParams String
"operator $ (needs 2)"), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
"$" []) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
notEnoughParams String
"operator $ (needs 2)"), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Call String
unknown [Ast]
_) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"Unknown operator: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
unknown), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (FunctionValue [String]
params Ast
ast Maybe [Ast]
Nothing) =
  (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just ([String] -> Ast -> Maybe [Ast] -> Ast
FunctionValue [String]
params Ast
ast Maybe [Ast]
forall a. Maybe a
Nothing)), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (FunctionValue [] Ast
ast (Just [])) =
  ([ScopeMb] -> [ScopeMb])
-> (Either String (Maybe Ast), [ScopeMb])
-> (Either String (Maybe Ast), [ScopeMb])
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
Data.Bifunctor.second [ScopeMb] -> [ScopeMb]
clearScope ([ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst ([ScopeMb] -> [ScopeMb]
beginScope [ScopeMb]
stack) Ast
ast)
evalAst [ScopeMb]
stack (FunctionValue [String]
params Ast
ast (Just [])) =
  (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just ([String] -> Ast -> Maybe [Ast] -> Ast
FunctionValue [String]
params Ast
ast Maybe [Ast]
forall a. Maybe a
Nothing)), [ScopeMb]
stack)
evalAst [ScopeMb]
stack (FunctionValue [String]
params Ast
ast (Just [Ast]
asts))
  | [String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
params Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< [Ast] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Ast]
asts =
      (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"Expression takes " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ([String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
params) String -> String -> String
forall a. [a] -> [a] -> [a]
++
        String
" parameters, got " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ([Ast] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Ast]
asts)), [ScopeMb]
stack)
  | Bool
otherwise = case [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack ([Ast] -> Ast
forall a. HasCallStack => [a] -> a
head [Ast]
asts) of
      (Left String
err, [ScopeMb]
_) -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
      (Right Maybe Ast
Nothing, [ScopeMb]
_) -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
noEvaluationError String
"expression"), [ScopeMb]
stack)
      (Right (Just Ast
ast'), [ScopeMb]
_) -> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack
        ([String] -> Ast -> Maybe [Ast] -> Ast
FunctionValue ([String] -> [String]
forall a. HasCallStack => [a] -> [a]
tail [String]
params)
        (String -> [Ast] -> Ast
Call String
"$" [String -> Ast -> Ast
Define ([String] -> String
forall a. HasCallStack => [a] -> a
head [String]
params) Ast
ast', Ast
ast]) ([Ast] -> Maybe [Ast]
forall a. a -> Maybe a
Just ([Ast] -> [Ast]
forall a. HasCallStack => [a] -> [a]
tail [Ast]
asts)))
evalAst [ScopeMb]
stack (Cond (AST.Boolean Bool
b) Ast
a1 (Just Ast
a2))
  | Bool
b = [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack Ast
a1
  | Bool
otherwise = [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack Ast
a2
evalAst [ScopeMb]
stack (Cond (AST.Boolean Bool
b) Ast
a1 Maybe Ast
Nothing)
  | Bool
b = [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack Ast
a1
  | Bool
otherwise = (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right Maybe Ast
forall a. Maybe a
Nothing, [ScopeMb]
stack)
evalAst [ScopeMb]
stack (Cond Ast
ast Ast
a1 Maybe Ast
a2) = case (Either String (Maybe Ast), [ScopeMb]) -> Either String (Maybe Ast)
forall a b. (a, b) -> a
fst ([ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack Ast
ast) of
  Left String
err -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
  Right Maybe Ast
mEAst -> case Maybe Ast
mEAst of
    Maybe Ast
Nothing -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"No evaluation in condition", [ScopeMb]
stack)
    Just Ast
eAst
      | Ast
eAst Ast -> Ast -> Bool
forall a. Eq a => a -> a -> Bool
== Ast
ast -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Condition isn't a boolean", [ScopeMb]
stack)
      | Bool
otherwise -> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack (Ast -> Ast -> Maybe Ast -> Ast
Cond Ast
eAst Ast
a1 Maybe Ast
a2)

-- | Evaluate the 'Ast' for a given binary value operator
-- such as '+', '-', or '*'.
-- Takes a function that takes two 'Int' and return one 'Int',
-- the stack as a '[ScopeMb]', and the 'Ast' to evaluate.
-- Return a tuple containing the new stack post evaluation, and the
-- application of the function onto the values inside the given 'Ast'
-- or a 'String' containing the error message in case of error
evalBiValOp ::
  (Int -> Int -> Int) ->
  [ScopeMb] ->
  Ast ->
  (Either String (Maybe Ast), [ScopeMb])
evalBiValOp :: (Int -> Int -> Int)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [AST.Boolean Bool
_, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.Boolean Bool
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [AST.String String
_, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.String String
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [AST.List [Ast]
_, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.List [Ast]
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
f [ScopeMb]
stack (Call String
_ [AST.Value Int
a, AST.Value Int
b]) =
  (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just (Int -> Ast
AST.Value (Int -> Int -> Int
f Int
a Int
b))), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [Ast
ast1, Ast
ast2]) =
  case [ScopeMb] -> [Ast] -> Either String (Maybe [Ast])
evalSubParams [ScopeMb]
stack [Ast
ast1, Ast
ast2] of
    Left String
err -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
    Right Maybe [Ast]
asts ->
      (Either String (Maybe Ast), [ScopeMb])
-> ([Ast] -> (Either String (Maybe Ast), [ScopeMb]))
-> Maybe [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
        (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
noEvaluationError String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
        ([ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack (Ast -> (Either String (Maybe Ast), [ScopeMb]))
-> ([Ast] -> Ast)
-> [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [Ast] -> Ast
Call String
op)
        Maybe [Ast]
asts
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op (Ast
_ : Ast
_ : [Ast]
_)) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
tooMuchParams String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack (Call String
op [Ast]
_) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
notEnoughParams String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalBiValOp Int -> Int -> Int
_ [ScopeMb]
stack Ast
_ = (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Ast isn't a Call", [ScopeMb]
stack)

-- | Evaluate the 'Ast' for a given binary boolean operator
-- such as '&&' or '||'.
-- Takes a function that takes two 'Bool' and return one 'Bool',
-- the stack as a '[ScopeMb]', and the 'Ast' to evaluate.
-- Return a tuple containing the new stack post evaluation, and the
-- application of the function onto the booleans inside the given 'Ast'
-- or a 'String' containing the error message in case of error
evalBiBoolOp ::
  (Bool -> Bool -> Bool) ->
  [ScopeMb] ->
  Ast ->
  (Either String (Maybe Ast), [ScopeMb])
evalBiBoolOp :: (Bool -> Bool -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [AST.Value Int
_, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.Value Int
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [AST.String String
_, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.String String
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [AST.List [Ast]
_, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.List [Ast]
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
f [ScopeMb]
stack (Call String
_ [AST.Boolean Bool
a, AST.Boolean Bool
b]) =
  (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just (Bool -> Ast
AST.Boolean (Bool -> Bool -> Bool
f Bool
a Bool
b))), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
ast1, Ast
ast2]) =
  case [ScopeMb] -> [Ast] -> Either String (Maybe [Ast])
evalSubParams [ScopeMb]
stack [Ast
ast1, Ast
ast2] of
    Left String
err -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
    Right Maybe [Ast]
asts ->
      (Either String (Maybe Ast), [ScopeMb])
-> ([Ast] -> (Either String (Maybe Ast), [ScopeMb]))
-> Maybe [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
        (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
noEvaluationError String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
        ([ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack (Ast -> (Either String (Maybe Ast), [ScopeMb]))
-> ([Ast] -> Ast)
-> [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [Ast] -> Ast
Call String
op)
        Maybe [Ast]
asts
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op (Ast
_ : Ast
_ : [Ast]
_)) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
tooMuchParams String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack (Call String
op [Ast]
_) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
notEnoughParams String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalBiBoolOp Bool -> Bool -> Bool
_ [ScopeMb]
stack Ast
_ = (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Ast isn't a Call", [ScopeMb]
stack)

-- | Evaluate the 'Ast' for a given binary comparison operator
-- such as '==', '>', or '<='.
-- Takes a function that takes two 'Int' and return one 'Bool',
-- the stack as a '[ScopeMb]', and the 'Ast' to evaluate.
-- Return a tuple containing the new stack post evaluation, and the
-- application of the function onto the values inside the given 'Ast'
-- or a 'String' containing the error message in case of error
evalBiCompValOp ::
  (Int -> Int -> Bool) ->
  [ScopeMb] ->
  Ast ->
  (Either String (Maybe Ast), [ScopeMb])
evalBiCompValOp :: (Int -> Int -> Bool)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [AST.Boolean Bool
_, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.Boolean Bool
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [AST.String String
_, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.String String
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [AST.List [Ast]
_, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.List [Ast]
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing, Ast
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
_, AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
op), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
f [ScopeMb]
stack (Call String
_ [AST.Value Int
a, AST.Value Int
b]) =
  (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just (Bool -> Ast
AST.Boolean (Int -> Int -> Bool
f Int
a Int
b))), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [Ast
ast1, Ast
ast2]) =
  case [ScopeMb] -> [Ast] -> Either String (Maybe [Ast])
evalSubParams [ScopeMb]
stack [Ast
ast1, Ast
ast2] of
    Left String
err -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
    Right Maybe [Ast]
asts ->
      (Either String (Maybe Ast), [ScopeMb])
-> ([Ast] -> (Either String (Maybe Ast), [ScopeMb]))
-> Maybe [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
        (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
noEvaluationError String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
        ([ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack (Ast -> (Either String (Maybe Ast), [ScopeMb]))
-> ([Ast] -> Ast)
-> [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [Ast] -> Ast
Call String
op)
        Maybe [Ast]
asts
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op (Ast
_ : Ast
_ : [Ast]
_)) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
tooMuchParams String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack (Call String
op [Ast]
_) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
notEnoughParams String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalBiCompValOp Int -> Int -> Bool
_ [ScopeMb]
stack Ast
_ = (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Ast isn't a Call", [ScopeMb]
stack)

-- | Evaluate the 'Ast' for a given binary list operator
-- such as '++', '--'.
-- Takes a function that takes one '[Ast]' and one 'Ast' and return one '[Ast]',
-- the stack as a '[ScopeMb]', and the 'Ast' to evaluate.
-- Return a tuple containing the new stack post evaluation, and the
-- application of the function onto the values inside the given 'Ast'
-- or a 'String' containing the error message in case of error
evalBiListOp ::
  ([Ast] -> Ast -> [Ast]) ->
  [ScopeMb] ->
  Ast ->
  (Either String (Maybe Ast), [ScopeMb])
evalBiListOp :: ([Ast] -> Ast -> [Ast])
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalBiListOp [Ast] -> Ast -> [Ast]
_ [ScopeMb]
stack (Call String
op [AST.Boolean Bool
_, Ast
_]) =
  ( String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"First parameter of binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is invalid"),
    [ScopeMb]
stack
  )
evalBiListOp [Ast] -> Ast -> [Ast]
_ [ScopeMb]
stack (Call String
op [AST.Value Int
_, Ast
_]) =
  ( String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"First parameter of binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is invalid"),
    [ScopeMb]
stack
  )
evalBiListOp [Ast] -> Ast -> [Ast]
_ [ScopeMb]
stack (Call String
op [AST.String String
_, Ast
_]) =
  ( String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"First parameter of binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is invalid"),
    [ScopeMb]
stack
  )
evalBiListOp [Ast] -> Ast -> [Ast]
_ [ScopeMb]
stack (Call String
op [AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing, Ast
_]) =
  ( String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"First parameter of binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is invalid"),
    [ScopeMb]
stack
  )
evalBiListOp [Ast] -> Ast -> [Ast]
f [ScopeMb]
stack (Call String
_ [AST.List [Ast]
a, Ast
ast]) =
  (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just ([Ast] -> Ast
AST.List ([Ast] -> Ast -> [Ast]
f [Ast]
a Ast
ast))), [ScopeMb]
stack)
evalBiListOp [Ast] -> Ast -> [Ast]
_ [ScopeMb]
stack (Call String
op [Ast
ast1, Ast
ast2]) =
  case [ScopeMb] -> [Ast] -> Either String (Maybe [Ast])
evalSubParams [ScopeMb]
stack [Ast
ast1, Ast
ast2] of
    Left String
err -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
    Right Maybe [Ast]
asts ->
      (Either String (Maybe Ast), [ScopeMb])
-> ([Ast] -> (Either String (Maybe Ast), [ScopeMb]))
-> Maybe [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
        (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
noEvaluationError String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
        ([ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack (Ast -> (Either String (Maybe Ast), [ScopeMb]))
-> ([Ast] -> Ast)
-> [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [Ast] -> Ast
Call String
op)
        Maybe [Ast]
asts
evalBiListOp [Ast] -> Ast -> [Ast]
_ [ScopeMb]
stack (Call String
op (Ast
_ : Ast
_ : [Ast]
_)) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
tooMuchParams String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalBiListOp [Ast] -> Ast -> [Ast]
_ [ScopeMb]
stack (Call String
op [Ast]
_) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
notEnoughParams String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalBiListOp [Ast] -> Ast -> [Ast]
_ [ScopeMb]
stack Ast
_ = (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Ast isn't a Call", [ScopeMb]
stack)

-- | Evaluate the 'Ast' for '!!'.
-- Takes the stack as a '[ScopeMb]', and the 'Ast' to evaluate.
-- Return the 'Ast' contained at the nth index if the 'Ast' is a list
-- or a 'String' containing the error message in case of error
getElemInAstList :: [ScopeMb] -> Ast -> Either String Ast
getElemInAstList :: [ScopeMb] -> Ast -> Either String Ast
getElemInAstList [ScopeMb]
_ (Call String
"!!" [AST.Boolean Bool
_, Ast
_]) =
  String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
"!!")
getElemInAstList [ScopeMb]
_ (Call String
"!!" [Ast
_, AST.Boolean Bool
_]) =
  String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
"!!")
getElemInAstList [ScopeMb]
_ (Call String
"!!" [Ast
_, AST.String String
_]) =
  String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
"!!")
getElemInAstList [ScopeMb]
_ (Call String
"!!" [Ast
_, AST.List [Ast]
_]) =
  String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
"!!")
getElemInAstList [ScopeMb]
_ (Call String
"!!" [AST.Value Int
_, Ast
_]) =
  String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
"!!")
getElemInAstList [ScopeMb]
_ (Call String
"!!" [AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing, Ast
_]) =
  String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
"!!")
getElemInAstList [ScopeMb]
_ (Call String
"!!" [Ast
_, AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing]) =
  String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
invalidParamsBiOp String
"!!")
getElemInAstList [ScopeMb]
_ (Call String
"!!" [AST.List [Ast]
a, AST.Value Int
b])
  | Int
b Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = String -> Either String Ast
forall a b. a -> Either a b
Left String
"Index out of range"
  | [Ast] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Ast]
a Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
b = Ast -> Either String Ast
forall a b. b -> Either a b
Right ([Ast]
a [Ast] -> Int -> Ast
forall a. HasCallStack => [a] -> Int -> a
!! Int
b)
  | Bool
otherwise = String -> Either String Ast
forall a b. a -> Either a b
Left String
"Index out of range"
getElemInAstList [ScopeMb]
_ (Call String
"!!" [AST.String String
a, AST.Value Int
b])
  | Int
b Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = String -> Either String Ast
forall a b. a -> Either a b
Left String
"Index out of range"
  | String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
a Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
b = Ast -> Either String Ast
forall a b. b -> Either a b
Right (String -> Ast
AST.String [String
a String -> Int -> Char
forall a. HasCallStack => [a] -> Int -> a
!! Int
b])
  | Bool
otherwise = String -> Either String Ast
forall a b. a -> Either a b
Left String
"Index out of range"
getElemInAstList [ScopeMb]
stack (Call String
"!!" [Ast
ast1, Ast
ast2]) =
  case [ScopeMb] -> [Ast] -> Either String (Maybe [Ast])
evalSubParams [ScopeMb]
stack [Ast
ast1, Ast
ast2] of
    Left String
err -> String -> Either String Ast
forall a b. a -> Either a b
Left String
err
    Right Maybe [Ast]
asts -> case (Either String (Maybe Ast), [ScopeMb])
-> ([Ast] -> (Either String (Maybe Ast), [ScopeMb]))
-> Maybe [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
      (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
noEvaluationError String
"binary operator '!!'"), [ScopeMb]
stack)
      ([ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack (Ast -> (Either String (Maybe Ast), [ScopeMb]))
-> ([Ast] -> Ast)
-> [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [Ast] -> Ast
Call String
"!!") Maybe [Ast]
asts of
        (Left String
err, [ScopeMb]
_) -> String -> Either String Ast
forall a b. a -> Either a b
Left String
err
        (Right Maybe Ast
ast, [ScopeMb]
_) ->
          Either String Ast
-> (Ast -> Either String Ast) -> Maybe Ast -> Either String Ast
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
noEvaluationError String
"binary operator '!!'"))
            Ast -> Either String Ast
forall a b. b -> Either a b
Right Maybe Ast
ast
getElemInAstList [ScopeMb]
_ (Call String
"!!" (Ast
_ : Ast
_ : [Ast]
_)) =
  String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
tooMuchParams String
"binary operator '!!'")
getElemInAstList [ScopeMb]
_ (Call String
"!!" [Ast]
_) =
  String -> Either String Ast
forall a b. a -> Either a b
Left (String -> String
notEnoughParams String
"binary operator '!!'")
getElemInAstList [ScopeMb]
_ Ast
_ = String -> Either String Ast
forall a b. a -> Either a b
Left String
"Ast isn't a '!!' Call"

-- | Evaluate the 'Ast' for a given unary list operator
-- such as '~'.
-- Takes a function that takes one '[Ast]' and return one 'Ast',
-- the stack as a '[ScopeMb]', and the 'Ast' to evaluate.
-- Return a tuple containing the new stack post evaluation, and the
-- application of the function onto the values inside the given 'Ast'
-- or a 'String' containing the error message in case of error
evalUnListOp ::
  ([Ast] -> Ast) ->
  [ScopeMb] ->
  Ast ->
  (Either String (Maybe Ast), [ScopeMb])
evalUnListOp :: ([Ast] -> Ast)
-> [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalUnListOp [Ast] -> Ast
_ [ScopeMb]
stack (Call String
op [AST.Boolean Bool
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"The parameter of unary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is invalid"), [ScopeMb]
stack)
evalUnListOp [Ast] -> Ast
_ [ScopeMb]
stack (Call String
op [AST.String String
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"The parameter of unary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is invalid"), [ScopeMb]
stack)
evalUnListOp [Ast] -> Ast
_ [ScopeMb]
stack (Call String
op [AST.Value Int
_]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"The parameter of unary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is invalid"), [ScopeMb]
stack)
evalUnListOp [Ast] -> Ast
_ [ScopeMb]
stack (Call String
op [AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing]) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String
"The parameter of unary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is invalid"), [ScopeMb]
stack)
evalUnListOp [Ast] -> Ast
f [ScopeMb]
stack (Call String
_ [AST.List [Ast]
a]) =
  (Maybe Ast -> Either String (Maybe Ast)
forall a b. b -> Either a b
Right (Ast -> Maybe Ast
forall a. a -> Maybe a
Just ([Ast] -> Ast
f [Ast]
a)), [ScopeMb]
stack)
evalUnListOp [Ast] -> Ast
_ [ScopeMb]
stack (Call String
op [Ast
ast]) =
  case [ScopeMb] -> [Ast] -> Either String (Maybe [Ast])
evalSubParams [ScopeMb]
stack [Ast
ast] of
    Left String
err -> (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
err, [ScopeMb]
stack)
    Right Maybe [Ast]
asts ->
      (Either String (Maybe Ast), [ScopeMb])
-> ([Ast] -> (Either String (Maybe Ast), [ScopeMb]))
-> Maybe [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
        (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
noEvaluationError String
"binary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
        ([ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack (Ast -> (Either String (Maybe Ast), [ScopeMb]))
-> ([Ast] -> Ast)
-> [Ast]
-> (Either String (Maybe Ast), [ScopeMb])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [Ast] -> Ast
Call String
op)
        Maybe [Ast]
asts
evalUnListOp [Ast] -> Ast
_ [ScopeMb]
stack (Call String
op (Ast
_ : Ast
_ : [Ast]
_)) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
tooMuchParams String
"unary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalUnListOp [Ast] -> Ast
_ [ScopeMb]
stack (Call String
op [Ast]
_) =
  (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left (String -> String
notEnoughParams String
"unary operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"), [ScopeMb]
stack)
evalUnListOp [Ast] -> Ast
_ [ScopeMb]
stack Ast
_ = (String -> Either String (Maybe Ast)
forall a b. a -> Either a b
Left String
"Ast isn't a Call", [ScopeMb]
stack)

-- | Evaluate the list of 'Ast'
-- Takes the stack as a '[ScopeMb]' and a '[Ast]' to evaluate
-- Returns a list of the results of the evaluation
-- (can be 'Nothing' if one 'Ast' isn't evaluable)
-- or a 'String' containing the error message in case of error.
evalSubParams :: [ScopeMb] -> [Ast] -> Either String (Maybe [Ast])
evalSubParams :: [ScopeMb] -> [Ast] -> Either String (Maybe [Ast])
evalSubParams [ScopeMb]
stack [Ast]
astList = case (Ast -> Either String (Maybe Ast))
-> [Ast] -> Either String [Maybe Ast]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM ((Either String (Maybe Ast), [ScopeMb]) -> Either String (Maybe Ast)
forall a b. (a, b) -> a
fst ((Either String (Maybe Ast), [ScopeMb])
 -> Either String (Maybe Ast))
-> (Ast -> (Either String (Maybe Ast), [ScopeMb]))
-> Ast
-> Either String (Maybe Ast)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack) [Ast]
astList of
  Left String
err -> String -> Either String (Maybe [Ast])
forall a b. a -> Either a b
Left String
err
  Right [Maybe Ast]
asts -> Maybe [Ast] -> Either String (Maybe [Ast])
forall a b. b -> Either a b
Right ([Maybe Ast] -> Maybe [Ast]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence [Maybe Ast]
asts)

-- | Transform the given 'Ast' into a 'String',
-- return an error message when unable to convert
astToString :: [ScopeMb] -> Ast -> Either String Ast
astToString :: [ScopeMb] -> Ast -> Either String Ast
astToString [ScopeMb]
_ (AST.String String
str) = Ast -> Either String Ast
forall a b. b -> Either a b
Right (String -> Ast
AST.String String
str)
astToString [ScopeMb]
_ (AST.Value Int
val) = Ast -> Either String Ast
forall a b. b -> Either a b
Right (String -> Ast
AST.String (Int -> String
forall a. Show a => a -> String
show Int
val))
astToString [ScopeMb]
_ (AST.Boolean Bool
bool) = Ast -> Either String Ast
forall a b. b -> Either a b
Right (String -> Ast
AST.String (Bool -> String
forall a. Show a => a -> String
show Bool
bool))
astToString [ScopeMb]
_ (AST.FunctionValue [String]
_ Ast
_ Maybe [Ast]
Nothing) =
  String -> Either String Ast
forall a b. a -> Either a b
Left String
"Cannot convert lambda to string"
astToString [ScopeMb]
_ (AST.List [Ast]
_) =
  String -> Either String Ast
forall a b. a -> Either a b
Left String
"Cannot convert list to string"
astToString [ScopeMb]
stack Ast
ast = case [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack Ast
ast of
  (Left String
err, [ScopeMb]
_) -> String -> Either String Ast
forall a b. a -> Either a b
Left String
err
  (Right Maybe Ast
ast', [ScopeMb]
_) ->
    Either String Ast
-> (Ast -> Either String Ast) -> Maybe Ast -> Either String Ast
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
      (String -> Either String Ast
forall a b. a -> Either a b
Left String
"Cannot convert no evaluation to string")
      ([ScopeMb] -> Ast -> Either String Ast
astToString [ScopeMb]
stack)
      Maybe Ast
ast'

defineVar ::
  ([ScopeMb] -> String -> Ast -> [ScopeMb]) ->
  [ScopeMb] ->
  String ->
  Ast ->
  Either String [ScopeMb]
defineVar :: ([ScopeMb] -> String -> Ast -> [ScopeMb])
-> [ScopeMb] -> String -> Ast -> Either String [ScopeMb]
defineVar [ScopeMb] -> String -> Ast -> [ScopeMb]
f [ScopeMb]
stack String
name Ast
ast = case [ScopeMb] -> Ast -> (Either String (Maybe Ast), [ScopeMb])
evalAst [ScopeMb]
stack Ast
ast of
  (Left String
err, [ScopeMb]
_) -> String -> Either String [ScopeMb]
forall a b. a -> Either a b
Left String
err
  (Right (Just Ast
ast'), [ScopeMb]
_) -> [ScopeMb] -> Either String [ScopeMb]
forall a b. b -> Either a b
Right ([ScopeMb] -> String -> Ast -> [ScopeMb]
f [ScopeMb]
stack String
name Ast
ast')
  (Right Maybe Ast
Nothing, [ScopeMb]
_) -> String -> Either String [ScopeMb]
forall a b. a -> Either a b
Left String
"Cannot define with no value"