module LanguageOne where import qualified PythonAst as Py import qualified CommonParsing as P import Data.Bifunctor import Data.Char import Data.Functor import qualified Data.Map as Map import Data.Maybe import qualified Data.Set as Set import Text.Parsec import Text.Parsec.Char import Text.Parsec.Combinator import Control.Monad.State {- Data Types -} data PossibleType = List | Any deriving Eq data SelectorMarker = None | Remove data Op = Add | Subtract | Multiply | Divide | Insert | Concat | LessThan | LessThanEq | GreaterThan | GreaterThanEq | Equal | NotEqual | And | Or data Selector = Selector String Expr data Expr = Var String | IntLiteral Int | ListLiteral [Expr] | Split Expr [Selector] Expr | IfElse Expr Expr Expr | BinOp Op Expr Expr | FunctionCall Expr [Expr] | LengthOf Expr | Random | Access Expr Expr SelectorMarker | Parameter Int data Function = Function String [String] Expr data Prog = Prog [Function] {- Parser -} type Parser = Parsec String (Maybe Int) parseVar :: Parser String parseVar = P.var ["if", "then", "else", "var"] parseThis :: Parser Expr parseThis = do char '&' contextNum <- getState spaces return (Var $ "context_" ++ show contextNum) parseList :: Parser Expr parseList = ListLiteral <$> do char '[' >> spaces es <- sepBy parseExpr (char ',' >> spaces) spaces >> char ']' >> spaces return es parseSplit :: Parser Expr parseSplit = do char '~' >> spaces e <- parseExpr spaces >> string "->" spaces >> char '{' contextNum <- getState putState $ return $ 1 + fromMaybe (-1) contextNum es <- many1 (spaces >> parseSelector) putState contextNum spaces >> char '}' >> spaces >> string "->" >> spaces e' <- parseExpr spaces return $ Split e es e' parseSelectorMarker :: Parser SelectorMarker parseSelectorMarker = (char '!' >> return Remove) <|> return None parseSelector :: Parser Selector parseSelector = do name <- parseVar spaces >> string "<-" >> spaces expr <- parseExpr spaces return $ Selector name expr parseIfElse :: Parser Expr parseIfElse = do P.kwIf >> spaces ec <- parseExpr spaces >> P.kwThen >> spaces et <- parseExpr spaces >> P.kwElse >> spaces ee <- parseExpr spaces return $ IfElse ec et ee parseLength :: Parser Expr parseLength = do char '|' >> spaces e <- parseExpr spaces >> char '|' >> spaces return $ LengthOf e parseParameter :: Parser Expr parseParameter = do char '#' d <- digit spaces return $ Parameter $ read [d] parseParenthesized :: Parser Expr parseParenthesized = do char '(' >> spaces e <- parseExpr spaces >> char ')' >> spaces return e parseBasicExpr :: Parser Expr parseBasicExpr = choice [ IntLiteral <$> P.int , parseThis , parseList , parseSplit , parseLength , parseParameter , parseParenthesized , Var <$> try parseVar , P.kwRand $> Random , parseIfElse ] parsePostfix :: Parser (Expr -> Expr) parsePostfix = parsePostfixAccess <|> parsePostfixCall parsePostfixAccess :: Parser (Expr -> Expr) parsePostfixAccess = do char '[' >> spaces e <- parseExpr spaces >> char ']' >> spaces marker <- parseSelectorMarker spaces return $ \e' -> Access e' e marker parsePostfixCall :: Parser (Expr -> Expr) parsePostfixCall = do char '(' >> spaces es <- sepBy parseExpr (char ',' >> spaces) char ')' >> spaces return $ flip FunctionCall es parsePostfixedExpr :: Parser Expr parsePostfixedExpr = do eb <- parseBasicExpr spaces ps <- many parsePostfix return $ foldl (flip ($)) eb ps parseExpr :: Parser Expr parseExpr = P.precedence BinOp parsePostfixedExpr [ P.op "*" Multiply, P.op "/" Divide , P.op "+" Add, P.op "-" Subtract , P.op "<<" Insert , P.op "++" Concat , try (P.op "<=" LessThanEq) <|> try (P.op ">=" GreaterThanEq) <|> P.op "<" LessThan <|> P.op ">" GreaterThan <|> P.op "==" Equal <|> P.op "!=" NotEqual , P.op "&&" And <|> P.op "||" Or ] parseFunction :: Parser Function parseFunction = do name <- parseVar spaces >> char '(' >> spaces vs <- sepBy parseVar (char ',' >> spaces) spaces >> char ')' >> spaces >> char '=' >> spaces body <- parseExpr spaces return $ Function name vs body parseProg :: Parser Prog parseProg = Prog <$> sepBy1 parseFunction (char ';' >> spaces) parse :: SourceName -> String -> Either ParseError Prog parse = runParser parseProg Nothing {- "Type" checker -} mergePossibleType :: PossibleType -> PossibleType -> PossibleType mergePossibleType List _ = List mergePossibleType _ List = List mergePossibleType _ _ = Any getPossibleType :: String -> Expr -> PossibleType getPossibleType s (Var s') = if s == s' then List else Any getPossibleType _ (ListLiteral _) = List getPossibleType s (Split _ _ e) = getPossibleType s e getPossibleType s (IfElse i t e) = foldl1 mergePossibleType $ map (getPossibleType s) [i, t, e] getPossibleType _ (BinOp Insert _ _) = List getPossibleType _ (BinOp Concat _ _) = List getPossibleType _ _ = Any {- Translator -} type Translator = Control.Monad.State.State (Map.Map String [String], Int) currentTemp :: Translator String currentTemp = do t <- gets snd return $ "temp" ++ show t incrementTemp :: Translator String incrementTemp = do modify (second (+1)) currentTemp hasLambda :: Expr -> Bool hasLambda (ListLiteral es) = any hasLambda es hasLambda (Split e ss r) = hasLambda e || any (\(Selector _ e') -> hasLambda e') ss || hasLambda r hasLambda (IfElse i t e) = hasLambda i || hasLambda t || hasLambda e hasLambda (BinOp o l r) = hasLambda l || hasLambda r hasLambda (FunctionCall e es) = any hasLambda $ e : es hasLambda (LengthOf e) = hasLambda e hasLambda (Access e _ _) = hasLambda e hasLambda Parameter{} = True hasLambda _ = False translate :: Prog -> [Py.PyStmt] translate p = fst $ runState (translateProg p) (Map.empty, 0) translateProg :: Prog -> Translator [Py.PyStmt] translateProg (Prog fs) = concat <$> traverse translateFunction fs translateFunction :: Function -> Translator [Py.PyStmt] translateFunction (Function n ps ex) = do let createIf p = Py.BinOp Py.Equal (Py.Var p) (Py.ListLiteral []) let createReturn p = Py.IfElse (createIf p) [Py.Return (Py.Var p)] [] Nothing let fastReturn = [createReturn p | p <- take 1 ps, getPossibleType p ex == List] (ss, e) <- translateExpr ex return $ return $ Py.FunctionDef n ps $ fastReturn ++ ss ++ [Py.Return e] translateSelector :: Selector -> Translator Py.PyStmt translateSelector (Selector n e) = let cacheCheck = Py.NotIn (Py.StrLiteral n) (Py.Var "cache") cacheAccess = Py.Access (Py.Var "cache") [Py.StrLiteral n] cacheSet = Py.Assign (Py.AccessPat (Py.Var "cache") [Py.StrLiteral n]) body e' = [ Py.IfElse cacheCheck [cacheSet e'] [] Nothing, Py.Return cacheAccess] in do (ss, e') <- translateExpr e vs <- gets fst let callPrereq p = Py.Standalone $ Py.FunctionCall (Py.Var p) [] let prereqs = maybe [] (map callPrereq) $ Map.lookup n vs return $ Py.FunctionDef n [] $ ss ++ prereqs ++ body e' translateExpr :: Expr -> Translator ([Py.PyStmt], Py.PyExpr) translateExpr (Var s) = do vs <- gets fst let sVar = Py.Var s let expr = if Map.member s vs then Py.FunctionCall sVar [] else sVar return ([], expr) translateExpr (IntLiteral i) = return ([], Py.IntLiteral i) translateExpr (ListLiteral l) = do tl <- mapM translateExpr l return (concatMap fst tl, Py.ListLiteral $ map snd tl) translateExpr (Split e ss e') = do vs <- gets fst let cacheAssign = Py.Assign (Py.VarPat "cache") (Py.DictLiteral []) let cacheStmt = [ cacheAssign | Map.size vs == 0 ] let vnames = map (\(Selector n es) -> n) ss let prereqs = snd $ foldl (\(ds, m) (Selector n es) -> (n:ds, Map.insert n ds m)) ([], Map.empty) ss modify $ first $ Map.union prereqs fs <- mapM translateSelector ss (sts, te) <- translateExpr e' modify $ first $ const vs return (cacheStmt ++ fs ++ sts, te) translateExpr (IfElse i t e) = do temp <- incrementTemp let tempPat = Py.VarPat temp (ists, ie) <- translateExpr i (tsts, te) <- translateExpr t (ests, ee) <- translateExpr e let thenSts = tsts ++ [Py.Assign tempPat te] let elseSts = ests ++ [Py.Assign tempPat ee] let newIf = Py.IfElse ie thenSts [] $ Just elseSts return (ists ++ [newIf], Py.Var temp) translateExpr (BinOp o l r) = do (lsts, le) <- translateExpr l (rsts, re) <- translateExpr r (opsts, oe) <- translateOp o le re return (lsts ++ rsts ++ opsts, oe) translateExpr (FunctionCall f ps) = do (fsts, fe) <- translateExpr f tps <- mapM translateExpr ps return (fsts ++ concatMap fst tps, Py.FunctionCall fe $ map snd tps) translateExpr (LengthOf e) = second (Py.FunctionCall (Py.Var "len") . return) <$> translateExpr e translateExpr (Access e Random m) = do temp <- incrementTemp (sts, ce) <- translateExpr e let lenExpr = Py.FunctionCall (Py.Var "len") [Py.Var temp] let randExpr = Py.FunctionCall (Py.Var "randint") [ Py.IntLiteral 0, lenExpr ] return (sts, singleAccess ce randExpr m) translateExpr (Access c i m) = do (csts, ce) <- translateExpr c (ists, ie) <- translateExpr i temp <- incrementTemp if hasLambda i then return (csts ++ ists ++ [createFilterLambda temp ie m], Py.FunctionCall (Py.Var temp) [ce]) else return (csts ++ ists, singleAccess ce ie m) translateExpr (Parameter i) = return $ ([], Py.Var $ "arg" ++ show i) translateExpr _ = fail "Invalid expression" singleAccess :: Py.PyExpr -> Py.PyExpr -> SelectorMarker -> Py.PyExpr singleAccess c i None = Py.Access c [i] singleAccess c i Remove = Py.FunctionCall (Py.Member c "pop") [i] createFilterLambda :: String -> Py.PyExpr -> SelectorMarker -> Py.PyStmt createFilterLambda s e None = Py.FunctionDef s ["arg"] [ Py.Assign (Py.VarPat "out") (Py.ListLiteral []) , Py.For (Py.VarPat "arg0") (Py.Var "arg") [ Py.IfElse e [ Py.Standalone $ Py.FunctionCall (Py.Member (Py.Var "out") "append") [ Py.Var "arg0" ] ] [] Nothing ] , Py.Return $ Py.Var "out" ] createFilterLambda s e Remove = Py.FunctionDef s ["arg"] [ Py.Assign (Py.VarPat "i") $ Py.IntLiteral 0 , Py.Assign (Py.VarPat "out") (Py.ListLiteral []) , Py.While (Py.BinOp Py.LessThan (Py.Var "i") $ Py.FunctionCall (Py.Var "len") [Py.Var "arg"]) [ Py.IfElse e [ Py.Standalone $ Py.FunctionCall (Py.Member (Py.Var "out") "append") [ singleAccess (Py.Var "arg") (Py.Var "i") Remove ] ] [] Nothing , Py.Assign (Py.VarPat "i") (Py.BinOp Py.Add (Py.Var "i") (Py.IntLiteral 1)) ] , Py.Return $ Py.Var "out" ] translateOp :: Op -> Py.PyExpr -> Py.PyExpr -> Translator ([Py.PyStmt], Py.PyExpr) translateOp Add l r = return ([], Py.BinOp Py.Add l r) translateOp Subtract l r = return ([], Py.BinOp Py.Subtract l r) translateOp Multiply l r = return ([], Py.BinOp Py.Multiply l r) translateOp Divide l r = return ([], Py.BinOp Py.Divide l r) translateOp LessThan l r = return ([], Py.BinOp Py.LessThan l r) translateOp LessThanEq l r = return ([], Py.BinOp Py.LessThanEq l r) translateOp GreaterThan l r = return ([], Py.BinOp Py.GreaterThan l r) translateOp GreaterThanEq l r = return ([], Py.BinOp Py.GreaterThanEq l r) translateOp Equal l r = return ([], Py.BinOp Py.Equal l r) translateOp NotEqual l r = return ([], Py.BinOp Py.NotEqual l r) translateOp And l r = return ([], Py.BinOp Py.And l r) translateOp Or l r = return ([], Py.BinOp Py.Or l r) translateOp Concat l r = return ([], Py.BinOp Py.Add l r) translateOp Insert l r = do temp <- incrementTemp let assignStmt = Py.Assign (Py.VarPat temp) l let appendFunc = Py.Member (Py.Var temp) "append" let insertStmt = Py.Standalone $ Py.FunctionCall appendFunc [r] return ([assignStmt, insertStmt], Py.Var temp)