module Graphics.Implicit.ExtOpenScad.Eval.Statement where
import Graphics.Implicit.Definitions
import Graphics.Implicit.ExtOpenScad.Definitions
import Graphics.Implicit.ExtOpenScad.Util.OVal
import Graphics.Implicit.ExtOpenScad.Util.ArgParser
import Graphics.Implicit.ExtOpenScad.Util.StateC
import Graphics.Implicit.ExtOpenScad.Eval.Expr
import Graphics.Implicit.ExtOpenScad.Parser.Statement (parseProgram)
import qualified Data.Maybe as Maybe
import qualified Data.List as List
import qualified Data.Map as Map
import Data.Map (Map)
import qualified Control.Monad as Monad
import qualified Control.Monad.State as State
import Control.Monad.State (State,StateT, get, put, modify, liftIO)
import qualified System.FilePath as FilePath
runStatementI :: StatementI -> StateC ()
runStatementI (StatementI lineN (pat := expr)) = do
val <- evalExpr expr
let posMatch = matchPat pat val
case (getErrors val, posMatch) of
(Just err, _ ) -> errorC lineN err
(_, Just match) -> modifyVarLookup $ Map.union match
(_, Nothing ) -> errorC lineN "pattern match failed in assignment"
runStatementI (StatementI lineN (Echo exprs)) = do
let
show2 (OString s) = s
show2 x = show x
vals <- mapM evalExpr exprs
case getErrors (OList vals) of
Nothing -> liftIO $ putStrLn $ concat $ map show2 vals
Just err -> errorC lineN err
runStatementI (StatementI lineN (For pat expr loopContent)) = do
val <- evalExpr expr
case (getErrors val, val) of
(Just err, _) -> errorC lineN err
(_, OList vals) -> Monad.forM_ vals $ \v ->
case matchPat pat v of
Just match -> do
modifyVarLookup $ Map.union match
runSuite loopContent
Nothing -> return ()
_ -> return ()
runStatementI (StatementI lineN (If expr a b)) = do
val <- evalExpr expr
case (getErrors val, val) of
(Just err, _ ) -> errorC lineN ("In conditional expression of if statement: " ++ err)
(_, OBool True ) -> runSuite a
(_, OBool False) -> runSuite b
_ -> return ()
runStatementI (StatementI lineN (NewModule name argTemplate suite)) = do
argTemplate' <- Monad.forM argTemplate $ \(name, defexpr) -> do
defval <- mapMaybeM evalExpr defexpr
return (name, defval)
(varlookup, _, path, _, _) <- get
runStatementI $ StatementI lineN $ (Name name :=) $ LitE $ OModule $ \vals -> do
newNameVals <- Monad.forM argTemplate' $ \(name, maybeDef) -> do
val <- case maybeDef of
Just def -> argument name `defaultTo` def
Nothing -> argument name
return (name, val)
let
children = ONum $ fromIntegral $ length vals
child = OModule $ \vals -> do
n :: ℕ <- argument "n";
return $ return $ return $
if n <= length vals
then vals !! n
else OUndefined
childBox = OFunc $ \n -> case fromOObj n :: Maybe ℕ of
Just n | n < length vals -> case vals !! n of
_ -> OUndefined
_ -> OUndefined
newNameVals' = newNameVals ++ [("children", children),("child", child), ("childBox", childBox)]
varlookup' = Map.union (Map.fromList newNameVals) varlookup
suiteVals = runSuiteCapture varlookup' path suite
return suiteVals
runStatementI (StatementI lineN (ModuleCall name argsExpr suite)) = do
maybeMod <- lookupVar name
(varlookup, _, path, _, _) <- get
childVals <- fmap reverse $ liftIO $ runSuiteCapture varlookup path suite
argsVal <- Monad.forM argsExpr $ \(posName, expr) -> do
val <- evalExpr expr
return (posName, val)
newVals <- case maybeMod of
Just (OModule mod) -> liftIO ioNewVals where
argparser = mod childVals
ioNewVals = case fst $ argMap argsVal argparser of
Just iovals -> iovals
Nothing -> return []
Just foo -> do
case getErrors foo of
Just err -> errorC lineN err
Nothing -> errorC lineN $ "Object called not module!"
return []
Nothing -> do
errorC lineN $ "Module " ++ name ++ " not in scope."
return []
pushVals newVals
runStatementI (StatementI lineN (Include name injectVals)) = do
name' <- getRelPath name
content <- liftIO $ readFile name'
case parseProgram name content of
Left e -> liftIO $ putStrLn $ "Error parsing " ++ name ++ ":" ++ show e
Right sts -> withPathShiftedBy (FilePath.takeDirectory name) $ do
vals <- getVals
putVals []
runSuite sts
vals' <- getVals
if injectVals then putVals (vals' ++ vals) else putVals vals
runSuite :: [StatementI] -> StateC ()
runSuite stmts = Monad.mapM_ runStatementI stmts
runSuiteCapture :: VarLookup -> FilePath -> [StatementI] -> IO [OVal]
runSuiteCapture varlookup path suite = do
(res, state) <- State.runStateT
(runSuite suite >> getVals)
(varlookup, [], path, (), () )
return res