module IRTS.CodegenJava (codegenJava) where import Core.TT import IRTS.BCImp import IRTS.CodegenCommon import IRTS.Lang import IRTS.Simplified import Paths_idris import Util.System import Control.Applicative import Control.Arrow import Control.Monad import qualified Control.Monad.Trans as T import Control.Monad.Trans.State import Data.Char import Data.Maybe (fromJust) import Data.List (isPrefixOf, isSuffixOf, intercalate, foldl') import Data.Int import qualified Data.Text as T import qualified Data.Text.IO as TIO import Language.Java.Parser import Language.Java.Pretty import Language.Java.Syntax hiding (Name) import qualified Language.Java.Syntax as J import System.Directory import System.Exit import System.FilePath import System.IO import System.Process data CodeGenerationEnv = CodeGenerationEnv { globalVariablePositions :: [(Name, Integer)] } type CodeGeneration = StateT (CodeGenerationEnv) (Either String) codegenJava :: [(Name, SExp)] -> -- initialization of globals [(Name, SDecl)] -> FilePath -> -- output file name [String] -> -- headers [String] -> -- libs OutputType -> IO () codegenJava globalInit defs out hdrs libs exec = do withTempdir (takeBaseName out) $ \ tmpDir -> do let srcdir = tmpDir "src" "main" "java" createDirectoryIfMissing True srcdir let (Ident clsName) = either error id (evalStateT (mkClassName out) (mkCodeGenEnv globalInit)) let outjava = srcdir clsName <.> "java" let jout = either error (flatIndent . prettyPrint) (evalStateT (mkCompilationUnit globalInit defs hdrs out) (mkCodeGenEnv globalInit)) writeFile outjava jout if (exec == Raw) then copyFile outjava (takeDirectory out clsName <.> "java") else do execPom <- getExecutablePom execPomTemplate <- TIO.readFile execPom let execPom = T.replace (T.pack "$MAIN-CLASS$") (T.pack clsName) (T.replace (T.pack "$ARTIFACT-NAME$") (T.pack $ takeBaseName out) (T.replace (T.pack "$DEPENDENCIES$") (mkPomDependencies libs) execPomTemplate ) ) TIO.writeFile (tmpDir "pom.xml") execPom mvnCmd <- getMvn let args = ["-f", (tmpDir "pom.xml")] (exit, mvout, err) <- readProcessWithExitCode mvnCmd (args ++ ["compile"]) "" when (exit /= ExitSuccess) $ error ("FAILURE: " ++ mvnCmd ++ " compile\n" ++ err ++ mvout) if (exec == Object) then do classFiles <- map (\ clsFile -> tmpDir "target" "classes" clsFile) . filter ((".class" ==) . takeExtension) <$> getDirectoryContents (tmpDir "target" "classes") mapM_ (\ clsFile -> copyFile clsFile (takeDirectory out takeFileName clsFile)) classFiles else do (exit, mvout, err) <- readProcessWithExitCode mvnCmd (args ++ ["package"]) "" when (exit /= ExitSuccess) (error ("FAILURE: " ++ mvnCmd ++ " package\n" ++ err ++ mvout)) copyFile (tmpDir "target" (takeBaseName out) <.> "jar") out handle <- openBinaryFile out ReadMode contents <- TIO.hGetContents handle hClose handle handle <- openBinaryFile out WriteMode TIO.hPutStr handle (T.append (T.pack jarHeader) contents) hFlush handle hClose handle perms <- getPermissions out setPermissions out (setOwnerExecutable True perms) readProcess mvnCmd (args ++ ["clean"]) "" removeFile (tmpDir "pom.xml") jarHeader :: String jarHeader = "#!/bin/sh\n" ++ "MYSELF=`which \"$0\" 2>/dev/null`\n" ++ "[ $? -gt 0 -a -f \"$0\" ] && MYSELF=\"./$0\"\n" ++ "java=java\n" ++ "if test -n \"$JAVA_HOME\"; then\n" ++ " java=\"$JAVA_HOME/bin/java\"\n" ++ "fi\n" ++ "exec \"$java\" $java_args -jar $MYSELF \"$@\"" ++ "exit 1\n" mkPomDependencies :: [String] -> T.Text mkPomDependencies deps = T.concat $ map (T.concat . map (T.append (T.pack " ")) . mkDependency . T.pack) deps where mkDependency s = case T.splitOn (T.pack ":") s of [g, a, v] -> [ T.pack $ "\n" , T.append (T.pack " ") $ mkGroupId g , T.append (T.pack " ") $ mkArtifactId a , T.append (T.pack " ") $ mkVersion v , T.pack $ "\n" ] _ -> [] mkGroupId g = T.append (T.pack $ "") (T.append g $ T.pack "\n") mkArtifactId a = T.append (T.pack $ "") (T.append a $ T.pack "\n") mkVersion v = T.append (T.pack $ "") (T.append v $ T.pack "\n") mkCodeGenEnv :: [(Name, SExp)] -> CodeGenerationEnv mkCodeGenEnv globalInit = CodeGenerationEnv $ zipWith (\ (name, _) pos -> (name, pos)) globalInit [0..] mkCompilationUnit :: [(Name, SExp)] -> [(Name, SDecl)] -> [String] -> FilePath -> CodeGeneration CompilationUnit mkCompilationUnit globalInit defs hdrs out = CompilationUnit Nothing ( [ ImportDecl False idrisRts True , ImportDecl True idrisForeign True , ImportDecl False bigInteger False , ImportDecl False stringBuffer False , ImportDecl False runtimeException False , ImportDecl False scanner False , ImportDecl False arrays False ] ++ otherHdrs ) <$> mkTypeDecl globalInit defs out where idrisRts = J.Name $ map Ident ["org", "idris", "rts"] idrisForeign = J.Name $ map Ident ["org", "idris", "rts", "ForeignPrimitives"] bigInteger = J.Name $ map Ident ["java", "math", "BigInteger"] stringBuffer = J.Name $ map Ident ["java", "lang", "StringBuffer"] runtimeException = J.Name $ map Ident ["java", "lang", "RuntimeException"] scanner = J.Name $ map Ident ["java", "util", "Scanner"] arrays = J.Name $ map Ident ["java", "util", "Arrays"] otherHdrs = map ( (\ name -> ImportDecl False name False) . J.Name . map (Ident . T.unpack) . T.splitOn (T.pack ".") . T.pack) $ filter (not . isSuffixOf ".h") hdrs flatIndent :: String -> String flatIndent (' ' : ' ' : xs) = flatIndent xs flatIndent (x:xs) = x:flatIndent xs flatIndent [] = [] prefixCallNamespaces :: Ident -> SExp -> SExp prefixCallNamespaces (Ident name) (SApp tail (NS n ns) args) = SApp tail (NS n (name:ns)) args prefixCallNamespaces name (SLet var e1 e2) = SLet var (prefixCallNamespaces name e1) (prefixCallNamespaces name e2) prefixCallNamespaces name (SUpdate var e) = SUpdate var (prefixCallNamespaces name e) prefixCallNamespaces name (SCase var alts) = SCase var (map (prefixCallNamespacesCase name) alts) prefixCallNamespaces name (SChkCase var alts) = SChkCase var (map (prefixCallNamespacesCase name) alts) prefixCallNamespaces _ exp = exp prefixCallNamespacesCase :: Ident -> SAlt -> SAlt prefixCallNamespacesCase name (SConCase x y n ns e) = SConCase x y n ns (prefixCallNamespaces name e) prefixCallNamespacesCase name (SConstCase c e) = SConstCase c (prefixCallNamespaces name e) prefixCallNamespacesCase name (SDefaultCase e) = SDefaultCase (prefixCallNamespaces name e) prefixCallNamespacesDecl :: Ident -> SDecl -> SDecl prefixCallNamespacesDecl name (SFun fname args i e) = SFun fname args i (prefixCallNamespaces name e) mkTypeDecl :: [(Name, SExp)] -> [(Name, SDecl)] -> FilePath -> CodeGeneration [TypeDecl] mkTypeDecl globalInit defs out = (\ name body -> [ClassTypeDecl $ ClassDecl [ Public , Annotation $ SingleElementAnnotation (J.Name [Ident "SuppressWarnings"]) (EVVal . InitExp . Lit $ String "unchecked") ] name [] Nothing [] body]) <$> mkClassName out <*> ( mkClassName out >>= (\ ident -> mkClassBody globalInit (map (second (prefixCallNamespacesDecl ident)) defs)) ) mkClassName :: FilePath -> CodeGeneration Ident mkClassName path = T.lift $ left (\ err -> "Parser error in \"" ++ path ++ "\": " ++ (show err)) (parser ident . takeBaseName $ takeFileName path) mkClassBody :: [(Name, SExp)] -> [(Name, SDecl)] -> CodeGeneration ClassBody mkClassBody globalInit defs = (\ globals defs -> ClassBody . (globals++) . addMainMethod . mergeInnerClasses $ defs) <$> mkGlobalContext globalInit <*> mapM mkDecl defs mkGlobalContext :: [(Name, SExp)] -> CodeGeneration [Decl] mkGlobalContext [] = return [] mkGlobalContext initExps = (\ exps -> [ MemberDecl $ FieldDecl [Private, Static, Final] objectArrayType [VarDecl (VarId $ Ident "globalContext") (Just . InitArray $ ArrayInit exps) ] ] ) <$> mapM (\ (_, exp) -> InitExp <$> mkExp exp) initExps addMainMethod :: [Decl] -> [Decl] addMainMethod decls | findMain decls = mkMainMethod : decls | otherwise = decls where findMain ((MemberDecl (MemberClassDecl (ClassDecl _ (Ident "Main") _ _ _ (ClassBody body)))):_) = findMainMethod body findMain (_:decls) = findMain decls findMain [] = False findMainMethod ((MemberDecl (MethodDecl _ _ _ (Ident "main") [] _ _)):_) = True findMainMethod (_:decls) = findMainMethod decls findMainMethod [] = False mkMainMethod :: Decl mkMainMethod = MemberDecl $ MethodDecl [Public, Static] [] Nothing (Ident "main") [FormalParam [] stringArrayType False (VarId $ Ident "args")] [] (MethodBody . Just $ Block [ BlockStmt . ExpStmt . MethodInv $ MethodCall (J.Name [Ident "idris_initArgs"]) [ MethodInv $ TypeMethodCall (J.Name [Ident "Thread"]) [] (Ident "currentThread") [] , ExpName $ J.Name [Ident "args"] ] , BlockStmt . ExpStmt . MethodInv $ MethodCall (J.Name [Ident "runMain_0"]) [] ] ) mergeInnerClasses :: [Decl] -> [Decl] mergeInnerClasses = foldl' mergeInner [] where mergeInner ((decl@(MemberDecl (MemberClassDecl (ClassDecl priv name targs ext imp (ClassBody body))))):decls) decl'@(MemberDecl (MemberClassDecl (ClassDecl _ name' _ ext' imp' (ClassBody body')))) | name == name' = (MemberDecl $ MemberClassDecl $ ClassDecl priv name targs (mplus ext ext') (imp ++ imp') (ClassBody $ mergeInnerClasses (body ++ body'))) : decls | otherwise = decl:(mergeInner decls decl') mergeInner (decl:decls) decl' = decl:(mergeInner decls decl') mergeInner [] decl' = [decl'] mkIdentifier :: Name -> CodeGeneration Ident mkIdentifier (NS name _) = mkIdentifier name mkIdentifier (MN i name) = (\ (Ident x) -> Ident $ x ++ ('_' : show i)) <$> mkIdentifier (UN name) mkIdentifier (UN name) = T.lift $ left (\ err -> "Parser error in \"" ++ name ++ "\": " ++ (show err)) ( parser ident . cleanReserved . cleanNonLetter . cleanStart $ cleanWs False name) where cleanStart (x:xs) | isNumber x = '_' : (x:xs) | otherwise = (x:xs) cleanStart [] = [] cleanNonLetter (x:xs) | x == '#' = "_Hash" ++ cleanNonLetter xs | x == '@' = "_At" ++ cleanNonLetter xs | x == '$' = "_Dollar" ++ cleanNonLetter xs | x == '!' = "_Bang" ++ cleanNonLetter xs | x == '.' = "_Dot" ++ cleanNonLetter xs | x == '\'' = "_Prime" ++ cleanNonLetter xs | x == '*' = "_Times" ++ cleanNonLetter xs | x == '+' = "_Plus" ++ cleanNonLetter xs | x == '/' = "_Divide" ++ cleanNonLetter xs | x == '-' = "_Minus" ++ cleanNonLetter xs | x == '%' = "_Mod" ++ cleanNonLetter xs | x == '<' = "_LessThan" ++ cleanNonLetter xs | x == '=' = "_Equals" ++ cleanNonLetter xs | x == '>' = "_MoreThan" ++ cleanNonLetter xs | x == '[' = "_LSBrace" ++ cleanNonLetter xs | x == ']' = "_RSBrace" ++ cleanNonLetter xs | x == '(' = "_LBrace" ++ cleanNonLetter xs | x == ')' = "_RBrace" ++ cleanNonLetter xs | x == '_' = "__" ++ cleanNonLetter xs | not (isAlphaNum x) = "_" ++ (show $ ord x) ++ xs | otherwise = x:cleanNonLetter xs cleanNonLetter [] = [] cleanWs capitalize (x:xs) | isSpace x = cleanWs True xs | capitalize = (toUpper x) : (cleanWs False xs) | otherwise = x : (cleanWs False xs) cleanWs _ [] = [] cleanReserved "param" = "_param" cleanReserved "globalContext" = "_globalContext" cleanReserved "context" = "_context" cleanReserved "newcontext" = "_newcontext" cleanReserved "void" = "_void" cleanReserved "null" = "_null" cleanReserved "int" = "_int" cleanReserved "long" = "_long" cleanReserved "char" = "_char" cleanReserved "byte" = "_byte" cleanReserved "double" = "_double" cleanReserved "float" = "_float" cleanReserved "boolean" = "_boolean" cleanReserved "Object" = "_Object" cleanReserved "String" = "_String" cleanReserved "StringBuilder" = "_StringBuilder" cleanReserved "StringBuffer" = "_StringBuffer" cleanReserved "Scanner" = "_Scanner" cleanReserved "Integer" = "_Integer" cleanReserved "Double" = "_Double" cleanReserved "Byte" = "_Byte" cleanReserved "Character" = "_Character" cleanReserved "BigInteger" = "_BigInteger" cleanReserved "Boolean" = "_Boolean" cleanReserved "Closure" = "_Closure" cleanReserved "IdrisObject" = "_IdrisObject" cleanReserved "TailCallClosure" = "_TailCallClosure" cleanReserved "System" = "_System" cleanReserved "Math" = "_Math" cleanReserved "Arrays" = "_Arrays" cleanReserved "RuntimeException" = "_RuntimeException" cleanReserved "Comparable" = "_Comparable" cleanReserved "class" = "_class" cleanReserved "enum" = "_enum" cleanReserved "interface" = "_interface" cleanReserved "extends" = "_extends" cleanReserved "implements" = "_implements" cleanReserved "public" = "_public" cleanReserved "private" = "_private" cleanReserved "protected" = "_protected" cleanReserved "static" = "_static" cleanReserved "final" = "_final" cleanReserved "abstract" = "_abstract" cleanReserved "strict" = "_strict" cleanReserved "volatile" = "_volatile" cleanReserved "transient" = "_transient" cleanReserved "native" = "_native" cleanReserved "const" = "_const" cleanReserved "import" = "_import" cleanReserved "package" = "_package" cleanReserved "throw" = "_throw" cleanReserved "throws" = "_throws" cleanReserved "try" = "_try" cleanReserved "catch" = "_catch" cleanReserved "synchronized" = "_synchronized" cleanReserved "if" = "_if" cleanReserved "else" = "_else" cleanReserved "switch" = "_switch" cleanReserved "case" = "_case" cleanReserved "default" = "_default" cleanReserved "while" = "_while" cleanReserved "for" = "_for" cleanReserved "do" = "_do" cleanReserved "break" = "_break" cleanReserved "continue" = "_continue" cleanReserved "goto" = "_goto" cleanReserved "this" = "_this" cleanReserved "super" = "_super" cleanReserved "new" = "_new" cleanReserved "return" = "_return" cleanReserved "idris_initArgs" = "_idris_initArgs" cleanReserved "idris_numArgs" = "_idris_numArgs" cleanReserved "idris_getArg" = "_idris_getArg" cleanReserved "getenv" = "_getenv" cleanReserved "exit" = "_exit" cleanReserved "usleep" = "_usleep" cleanReserved "idris_sendMessage" = "_idris_sendMessage" cleanReserved "idris_checkMessage" = "_idris_checkMessage" cleanReserved "idris_recvMessage" = "_idris_recvMessage" cleanReserved "putStr" = "_putStr" cleanReserved "putchar" = "_putchar" cleanReserved "getchar" = "_getchar" cleanReserved "fileOpen" = "_fileOpen" cleanReserved "fileClose" = "_fileClose" cleanReserved "fputStr" = "_fputStr" cleanReserved "fileEOF" = "_fileEOF" cleanReserved "isNull" = "_isNull" cleanReserved "idris_K" = "_idris_K" cleanReserved "idris_flipK" = "_idris_flipK" cleanReserved "idris_assignStack" = "_idris_assignStack" cleanReserved "free" = "_free" cleanReserved "malloc" = "_malloc" cleanReserved "idris_memset" = "_idris_memset" cleanReserved "idris_peek" = "_idris_peek" cleanReserved "idris_poke" = "_idris_poke" cleanReserved "idris_memmove" = "_idris_memmove" cleanReserved x = x mkName :: Name -> CodeGeneration J.Name mkName (NS name nss) = (\ n ns -> J.Name (n:ns)) <$> mkIdentifier name <*> mapM (mkIdentifier . UN) nss mkName n = J.Name . (:[]) <$> mkIdentifier n voidType :: ClassType voidType = ClassType [(Ident "Void", [])] objectType :: ClassType objectType = ClassType [(Ident "Object", [])] objectArrayType :: Language.Java.Syntax.Type objectArrayType = RefType . ArrayType . RefType . ClassRefType $ objectType idrisClosureType :: ClassType idrisClosureType = ClassType [(Ident "Closure", [])] idrisTailCallClosureType :: ClassType idrisTailCallClosureType = ClassType [(Ident "TailCallClosure", [])] idrisObjectType :: ClassType idrisObjectType = ClassType [(Ident "IdrisObject", [])] contextArray :: LVar -> Exp contextArray (Loc _) = ExpName $ J.Name [Ident "context"] contextArray (Glob _) = ExpName $ J.Name [Ident "globalContext"] charType :: ClassType charType = ClassType [(Ident "Character", [])] byteType :: ClassType byteType = ClassType [(Ident "Byte", [])] shortType :: ClassType shortType = ClassType [(Ident "Short", [])] integerType :: ClassType integerType = ClassType [(Ident "Integer", [])] longType :: ClassType longType = ClassType [(Ident "Long", [])] nextIntTy :: IntTy -> IntTy nextIntTy IT8 = IT16 nextIntTy IT16 = IT32 nextIntTy IT32 = IT64 nextIntTy IT64 = IT64 nextIntTy ITNative = IT64 intTyToIdent :: IntTy -> Ident intTyToIdent IT8 = Ident "Byte" intTyToIdent IT16 = Ident "Short" intTyToIdent IT32 = Ident "Integer" intTyToIdent IT64 = Ident "Long" intTyToIdent ITNative = Ident "Integer" intTyToIdent ITBig = Ident "BigInteger" intTyToClass :: IntTy -> ClassType intTyToClass ty = ClassType [(intTyToIdent ty, [])] intTyToMethod :: IntTy -> String intTyToMethod IT8 = "byteValue" intTyToMethod IT16 = "shortValue" intTyToMethod IT32 = "intValue" intTyToMethod IT64 = "longValue" intTyToMethod ITNative = "intValue" intTyToPrimTy :: IntTy -> PrimType intTyToPrimTy IT8 = ByteT intTyToPrimTy IT16 = ShortT intTyToPrimTy IT32 = IntT intTyToPrimTy IT64 = LongT intTyToPrimTy ITNative = IntT bigIntegerType :: ClassType bigIntegerType = ClassType [(Ident "BigInteger", [])] doubleType :: ClassType doubleType = ClassType [(Ident "Double", [])] stringType :: ClassType stringType = ClassType [(Ident "String", [])] stringArrayType :: Language.Java.Syntax.Type stringArrayType = RefType . ArrayType . RefType . ClassRefType $ stringType exceptionType :: ClassType exceptionType = ClassType [(Ident "Throwable", [])] runtimeExceptionType :: ClassType runtimeExceptionType = ClassType [(Ident "RuntimeException", [])] comparableType :: ClassType comparableType = ClassType [(Ident "Comparable", [])] mkDecl :: (Name, SDecl) -> CodeGeneration Decl mkDecl ((NS n (ns:nss)), decl) = (\ name body -> MemberDecl $ MemberClassDecl $ ClassDecl [Public, Static] name [] Nothing [] body) <$> mkIdentifier (UN ns) <*> mkClassBody [] [(NS n nss, decl)] mkDecl (_, SFun name params stackSize body) = (\ name params paramNames methodBody -> MemberDecl $ MethodDecl [Public, Static] [] (Just . RefType $ ClassRefType objectType) name params [] (MethodBody . Just $ Block [ LocalVars [Final] objectArrayType [ VarDecl (VarDeclArray . VarId $ Ident "context") (Just . InitArray . ArrayInit $ paramNames ++ replicate stackSize (InitExp . Lit $ Null)) ] , BlockStmt . Return $ Just methodBody ] ) ) <$> mkIdentifier name <*> mapM mkFormalParam params <*> mapM (\ p -> (InitExp . ExpName) <$> mkName p) params <*> mkExp body mkClosure :: [Name] -> Int -> SExp -> CodeGeneration Exp mkClosure params stackSize body = (\ paramArray body -> InstanceCreation [] idrisClosureType [paramArray] (Just $ ClassBody [body]) ) <$> mkStackInit params stackSize <*> mkClosureCall body mkFormalParam :: Name -> CodeGeneration FormalParam mkFormalParam name = (\ name -> FormalParam [Final] (RefType . ClassRefType $ objectType) False (VarId name)) <$> mkIdentifier name mkClosureCall :: SExp -> CodeGeneration Decl mkClosureCall body = (\ body -> MemberDecl $ MethodDecl [Public] [] (Just . RefType $ ClassRefType objectType) (Ident "call") [] [] body) <$> mkMethodBody body mkMethodBody :: SExp -> CodeGeneration MethodBody mkMethodBody exp = (\ exp -> MethodBody . Just . Block $ [BlockStmt . Return . Just $ exp]) <$> mkExp exp mkStackInit :: [Name] -> Int -> CodeGeneration Exp mkStackInit params stackSize = (\ localVars -> ArrayCreateInit objectArrayType 0 . ArrayInit $ (map (InitExp . ExpName) localVars) ++ (replicate (stackSize) (InitExp $ Lit Null))) <$> mapM mkName params mkK :: Exp -> Exp -> Exp mkK result drop = MethodInv $ MethodCall (J.Name [Ident "idris_K"]) [ result, drop ] mkFlipK :: Exp -> Exp -> Exp mkFlipK drop result = MethodInv $ MethodCall (J.Name [Ident "idris_flipK"]) [ drop, result ] mkLet :: LVar -> SExp -> SExp -> CodeGeneration Exp mkLet (Loc pos) oldExp newExp = (\ oldExp newExp -> mkFlipK ( Assign ( ArrayLhs $ ArrayIndex (ExpName $ J.Name [Ident "context"]) (Lit $ Int (toInteger pos))) EqualA newExp ) oldExp ) <$> mkExp oldExp <*> mkExp newExp mkLet (Glob _) _ _ = T.lift $ Left "Cannot let bind to global variable" reverseNameSpace :: J.Name -> J.Name reverseNameSpace (J.Name ids) = J.Name ((tail ids) ++ [head ids]) mkCase :: Bool -> LVar -> [SAlt] -> CodeGeneration Exp mkCase checked var ((SConCase parentStackPos consIndex _ params branchExpression):cases) = mkConsCase checked var parentStackPos consIndex params branchExpression (SCase var cases) mkCase checked var (c@(SConstCase constant branchExpression):cases) = (\ constant branchExpression alternative var-> Cond ( MethodInv $ PrimaryMethodCall (constant) [] (Ident "equals") [var] ) branchExpression alternative ) <$> mkExp (SConst constant) <*> mkExp branchExpression <*> mkCase checked var cases <*> mkVarAccess Nothing var mkCase checked var (SDefaultCase exp:cases) = mkExp exp mkCase checked _ [] = mkExp (SError "Non-exhaustive pattern") mkConsCase :: Bool -> LVar -> Int -> Int -> [Name] -> SExp -> SExp -> CodeGeneration Exp mkConsCase checked toDeconstruct parentStackStart consIndex params branchExpression alternative = (\ caseBinding alternative var varCasted-> Cond (BinOp (InstanceOf (var) (ClassRefType idrisObjectType) ) CAnd ( BinOp ( MethodInv $ PrimaryMethodCall (varCasted) [] (Ident "getConstructorId") [] ) Equal (Lit $ Int (toInteger consIndex)) ) ) (caseBinding) alternative ) <$> mkCaseBinding checked toDeconstruct parentStackStart params branchExpression <*> mkExp alternative <*> mkVarAccess (Nothing) toDeconstruct <*> mkVarAccess (Just idrisObjectType) toDeconstruct mkCaseBinding :: Bool -> LVar -> Int -> [Name] -> SExp -> CodeGeneration Exp mkCaseBinding True var parentStackStart params branchExpression = (\ branchExpression deconstruction -> mkFlipK (MethodInv $ MethodCall (J.Name [Ident "idris_assignStack"]) ( (ExpName $ J.Name [Ident "context"]) : (Lit $ Int (toInteger parentStackStart)) : deconstruction )) (branchExpression) ) <$> mkExp branchExpression <*> mkCaseBindingDeconstruction var params mkCaseBinding False var parentStackStart params branchExpression = (\ bindingMethod deconstruction -> MethodInv $ PrimaryMethodCall ( MethodInv $ PrimaryMethodCall (InstanceCreation [] (ClassType [(Ident "Object", [])]) [] (Just $ ClassBody [MemberDecl $ bindingMethod]) ) [] (Ident "apply") ( contextArray (Loc undefined) : deconstruction ) ) [] (Ident "call") [] ) <$> mkCaseBindingMethod parentStackStart params branchExpression <*> mkCaseBindingDeconstruction var params mkCaseBindingDeconstruction :: LVar -> [Name] -> CodeGeneration [Exp] mkCaseBindingDeconstruction var members = mapM (mkProjection var) ([0..(length members - 1)]) mkCaseBindingMethod :: Int -> [Name] -> SExp -> CodeGeneration MemberDecl mkCaseBindingMethod parentStackStart params branchExpression = (\ formalParams caseBindingStack branchExpression -> MethodDecl [Final, Public] [] (Just . RefType $ ClassRefType idrisClosureType) (Ident "apply") (mkContextParam:formalParams) [] (MethodBody . Just . Block $ caseBindingStack ++ [BlockStmt . Return $ Just branchExpression])) <$> mapM mkFormalParam params <*> mkBindingStack False parentStackStart params <*> mkBindingClosure branchExpression mkContextParam :: FormalParam mkContextParam = FormalParam [Final] (objectArrayType) False (VarId (Ident "context")) mkBindingClosure :: SExp -> CodeGeneration Exp mkBindingClosure oldExp = (\ oldCall -> InstanceCreation [] idrisClosureType [ ExpName $ J.Name [Ident "new_context"] ] (Just $ ClassBody [oldCall]) ) <$> mkClosureCall oldExp mkBindingStack :: Bool -> Int -> [Name] -> CodeGeneration [BlockStmt] mkBindingStack checked parentStackStart params = (\ paramNames -> ( LocalVars [Final] objectArrayType [ VarDecl (VarDeclArray . VarId $ Ident "new_context") (Just . InitExp $ mkContextCopy checked parentStackStart params) ]) : ( map (\ (param, pos) -> BlockStmt . ExpStmt $ Assign (ArrayLhs $ ArrayIndex (ExpName $ J.Name [Ident "new_context"]) (Lit $ Int (toInteger pos))) EqualA (ExpName param)) $ zip paramNames [parentStackStart..] ) ) <$> mapM mkName params mkContextCopy :: Bool -> Int -> [Name] -> Exp mkContextCopy True parentStackStart params = MethodInv $ PrimaryMethodCall (ExpName $ J.Name [Ident "context"]) [] (Ident "clone") [] mkContextCopy False parentStackStart params = MethodInv $ TypeMethodCall (J.Name [Ident "Arrays"]) [] (Ident "copyOf") [ ExpName $ J.Name [Ident "context"] , MethodInv $ TypeMethodCall (J.Name [Ident "Math"]) [] (Ident "max") [ FieldAccess $ PrimaryFieldAccess (ExpName $ J.Name [Ident "context"]) (Ident "length") , Lit . Int $ toInteger (parentStackStart + length params) ] ] mkProjection :: LVar -> Int -> CodeGeneration Exp mkProjection var memberNr = (\ var -> ArrayAccess $ ArrayIndex ( MethodInv $ PrimaryMethodCall (var) [] (Ident "getData") [] ) (Lit $ Int (toInteger memberNr)) ) <$> mkVarAccess (Just idrisObjectType) var type ClassName = String mkPrimitive :: ClassName -> Literal -> Exp mkPrimitive className value = MethodInv $ TypeMethodCall (J.Name [Ident className]) [] (Ident "valueOf") [Lit $ value] mkClass :: ClassType -> Exp mkClass classType = ClassLit . Just . RefType .ClassRefType $ classType mkBinOpExp :: ClassType -> Op -> [LVar] -> CodeGeneration Exp mkBinOpExp castTo op (var:vars) = do start <- mkVarAccess (Just castTo) var foldM (\ exp var -> BinOp exp op <$> mkVarAccess (Just castTo) var) start vars mkBinOpExpTrans :: (Exp -> Exp) -> (Exp -> Exp) -> ClassType -> Op -> [LVar] -> CodeGeneration Exp mkBinOpExpTrans opTransformation resultTransformation castTo op (var:vars) = do start <- (mkVarAccess (Just castTo) var) foldM (\ exp var -> resultTransformation . BinOp (opTransformation exp) op . opTransformation <$> mkVarAccess (Just castTo) var) start vars mkBinOpExpConv :: String -> PrimType -> ClassType -> Op -> [LVar] -> CodeGeneration Exp mkBinOpExpConv fromMethodName toType fromType@(ClassType [(cls@(Ident _), [])]) op args = mkBinOpExpTrans (\ exp -> MethodInv $ TypeMethodCall (J.Name [cls]) [] (Ident fromMethodName) [exp] ) (\ exp -> MethodInv $ TypeMethodCall (J.Name [cls]) [] (Ident "valueOf") [Cast (PrimType $ toType) exp] ) fromType op args mkLogicalBinOpExp :: ClassType -> Op -> [LVar] -> CodeGeneration Exp mkLogicalBinOpExp castTo op (var:vars) = do start <- mkVarAccess (Just castTo) var foldM (\ exp var -> mkBoolToNumber castTo . BinOp exp op <$> mkVarAccess (Just castTo) var) start vars mkMethodOpChain1 :: (Exp -> Exp) -> ClassType -> String -> [LVar] -> CodeGeneration Exp mkMethodOpChain1 = mkMethodOpChain id mkMethodOpChain :: (Exp -> Exp) -> (Exp -> Exp) -> ClassType -> String -> [LVar] -> CodeGeneration Exp mkMethodOpChain initialTransformation resultTransformation castTo method (arg:args) = do start <- initialTransformation <$> mkVarAccess (Just $ castTo) arg foldM (\ exp arg' -> resultTransformation . MethodInv . PrimaryMethodCall exp [] (Ident method) . (:[]) <$> mkVarAccess (Just $ castTo) arg' ) start args mkBoolToNumber :: ClassType -> Exp -> Exp mkBoolToNumber (ClassType [(Ident name, [])]) boolExp = Cond boolExp (mkPrimitive name (Int 1)) (mkPrimitive name (Int 0)) mkZeroExt :: String -> Int -> ClassType -> ClassType -> LVar -> CodeGeneration Exp mkZeroExt toMethod bits fromType toType@(ClassType [(toTypeName, [])]) var = do (\ var sext -> MethodInv $ TypeMethodCall (J.Name [toTypeName]) [] (Ident "valueOf") [ Cond ( BinOp (var) LThan (Lit $ Int 0) ) ( BinOp (Lit $ Int (2^bits)) Add (sext) ) sext ] ) <$> mkVarAccess (Just $ fromType) var <*> mkSignedExt' toMethod fromType var mkSignedExt :: String -> ClassType -> ClassType -> LVar -> CodeGeneration Exp mkSignedExt toMethod fromType (ClassType [(toTypeName, [])]) var = (\ sext -> MethodInv $ TypeMethodCall (J.Name [toTypeName]) [] (Ident "valueOf") [ sext ] ) <$> mkSignedExt' toMethod fromType var mkSignedExt' :: String -> ClassType -> LVar -> CodeGeneration Exp mkSignedExt' toMethod fromType var = (\ var -> MethodInv $ PrimaryMethodCall (var) [] (Ident toMethod) [] ) <$> mkVarAccess (Just $ fromType) var data SPartialOrder = SLt | SLe | SEq | SGe | SGt mkPartialOrder :: SPartialOrder -> Exp -> Exp mkPartialOrder SLt x = (BinOp (Lit $ Int (-1)) Equal x) mkPartialOrder SLe x = BinOp (BinOp (Lit $ Int (-1)) Equal x) COr (BinOp (Lit $ Int 0) Equal x) mkPartialOrder SEq x = BinOp (Lit $ Int 0) Equal x mkPartialOrder SGe x = BinOp (BinOp (Lit $ Int 1) Equal x) COr (BinOp (Lit $ Int 0) Equal x) mkPartialOrder SGt x = (BinOp (Lit $ Int 1) Equal x) varPos :: LVar -> CodeGeneration Integer varPos (Loc i) = return (toInteger i) varPos (Glob name) = do positions <- globalVariablePositions <$> get case lookup name positions of (Just pos) -> return pos Nothing -> T.lift . Left $ "Invalid global variable id: " ++ show name mkVarAccess :: Maybe ClassType -> LVar -> CodeGeneration Exp mkVarAccess Nothing var = (\ pos -> ArrayAccess $ ArrayIndex (contextArray var) (Lit $ Int pos)) <$> varPos var mkVarAccess (Just castTo) var = Cast (RefType . ClassRefType $ castTo) <$> (mkVarAccess Nothing var) mkPrimitiveCast :: ClassType -> ClassType -> LVar -> CodeGeneration Exp mkPrimitiveCast fromType (ClassType [(toType, [])]) var = (\ var -> MethodInv $ TypeMethodCall (J.Name [toType]) [] (Ident "valueOf") [var] ) <$> mkVarAccess (Just fromType) var mkToString :: ClassType -> LVar -> CodeGeneration Exp mkToString castTo var = (\ var -> MethodInv $ PrimaryMethodCall (var) [] (Ident "toString") [] ) <$> mkVarAccess (Just castTo) var data Std = In | Out | Err instance Show Std where show In = "in" show Out = "out" show Err = "err" mkSystemStd :: Std -> Exp mkSystemStd std = FieldAccess $ PrimaryFieldAccess (ExpName $ J.Name [Ident "System"]) (Ident $ show std) mkSystemOutPrint :: Exp -> Exp mkSystemOutPrint value = MethodInv $ PrimaryMethodCall (mkSystemStd Out) [] (Ident "print") [value] mkMathFun :: String -> LVar -> CodeGeneration Exp mkMathFun funName var = (\ var -> MethodInv $ TypeMethodCall (J.Name [Ident "Double"]) [] (Ident "valueOf") [ MethodInv $ TypeMethodCall (J.Name [Ident "Math"]) [] (Ident funName) [var] ] ) <$> mkVarAccess (Just doubleType) var mkStringAtIndex :: LVar -> Exp -> CodeGeneration Exp mkStringAtIndex var indexExp = (\ var -> MethodInv $ TypeMethodCall (J.Name [Ident "Integer"]) [] (Ident "valueOf") [ MethodInv $ PrimaryMethodCall (var) [] (Ident "charAt") [indexExp] ] ) <$> mkVarAccess (Just stringType) var mkForeignType :: FType -> Maybe ClassType mkForeignType (FInt ty) = return (intTyToClass ty) mkForeignType FChar = return integerType mkForeignType FString = return stringType mkForeignType FPtr = return objectType mkForeignType FDouble = return doubleType mkForeignType FAny = return objectType mkForeignType FUnit = Nothing mkForeignVarAccess :: FType -> LVar -> CodeGeneration Exp mkForeignVarAccess (FInt ty) var = (\ var -> MethodInv $ PrimaryMethodCall var [] (Ident (intTyToMethod ty)) [] ) <$> mkVarAccess (Just $ intTyToClass ty) var mkForeignVarAccess FChar var = Cast (PrimType CharT) <$> mkForeignVarAccess (FInt IT32) var mkForeignVarAccess FDouble var = (\ var -> MethodInv $ PrimaryMethodCall (var) [] (Ident "doubleValue") [] ) <$> mkVarAccess (Just doubleType) var mkForeignVarAccess otherType var = mkVarAccess (mkForeignType otherType) var mkFromForeignType :: FType -> Exp -> Exp mkFromForeignType (FInt ty) from = MethodInv $ TypeMethodCall (J.Name [intTyToIdent ty]) [] (Ident "valueOf") [from] mkFromForeignType FChar from = mkFromForeignType (FInt IT32) from mkFromForeignType FDouble from = MethodInv $ TypeMethodCall (J.Name [Ident "Double"]) [] (Ident "valueOf") [from] mkFromForeignType _ from = from mkForeignInvoke :: FType -> String -> [(FType, LVar)] -> CodeGeneration Exp mkForeignInvoke fType method args = (\ foreignInvokeMeth -> MethodInv $ PrimaryMethodCall (InstanceCreation [] objectType [] (Just $ ClassBody [ MemberDecl $ foreignInvokeMeth ]) ) [] (Ident "foreignInvoke") [] ) <$> mkForeignInvokeMethod fType method args mkForeignInvokeMethod :: FType -> String -> [(FType, LVar)] -> CodeGeneration MemberDecl mkForeignInvokeMethod fType method args = (\ tryBlock -> MethodDecl [Public, Final] [] (Just . RefType $ ClassRefType objectType) (Ident "foreignInvoke") [] [] (MethodBody . Just $ Block [ BlockStmt $ Try tryBlock [ Catch (FormalParam [] (RefType $ ClassRefType exceptionType) False (VarId $ Ident "ex") ) (Block [ BlockStmt . Throw $ InstanceCreation [] runtimeExceptionType [ExpName $ J.Name [Ident "ex"]] Nothing ] ) ] Nothing ] ) ) <$> mkForeignInvokeTryBlock fType method args mkForeignInvokeTryBlock :: FType -> String -> [(FType, LVar)] -> CodeGeneration Block mkForeignInvokeTryBlock FUnit method args = (\ method args -> Block [ BlockStmt . ExpStmt . MethodInv $ MethodCall method args , BlockStmt $ Return (Just $ Lit Null) ] ) <$> ( T.lift $ left (\ err -> "Error parsing name \"" ++ method ++ "\" :" ++ (show err)) (parser name method) ) <*> mapM (uncurry mkForeignVarAccess) args mkForeignInvokeTryBlock fType method args = (\ method args -> Block [ BlockStmt . Return . Just . mkFromForeignType fType . MethodInv $ MethodCall method args ] ) <$> ( T.lift $ left (\ err -> "Error parsing name \"" ++ method ++ "\" :" ++ (show err)) (parser name method) ) <*> mapM (uncurry mkForeignVarAccess) args mkMethodClosure :: Name -> [LVar] -> CodeGeneration Exp mkMethodClosure name args = (\ name args -> InstanceCreation [] idrisClosureType [ (ExpName $ J.Name [Ident "context"]) ] ( Just $ ClassBody [ MemberDecl $ MethodDecl [Public, Final] [] (Just . RefType $ ClassRefType objectType) (Ident "call") [] [] ( MethodBody . Just $ Block [ BlockStmt . Return . Just . MethodInv $ MethodCall (reverseNameSpace name) args ] ) ] ) ) <$> mkName name <*> mapM (mkExp . SV) args mkThread :: LVar -> CodeGeneration Exp mkThread arg = (\ eval -> MethodInv $ PrimaryMethodCall (InstanceCreation [] (ClassType [(Ident "Thread", [])]) [ eval ] ( Just $ ClassBody [ MemberDecl $ MethodDecl [Public, Final] [] (Just . RefType $ ClassRefType objectType) (Ident "_start") [] [] ( MethodBody . Just $ Block [ BlockStmt . ExpStmt . MethodInv $ MethodCall (J.Name [Ident "start"]) [] , BlockStmt . Return . Just $ This ] ) ] ) ) [] (Ident "_start") [] ) <$> mkThreadBinding arg mkThreadBinding :: LVar -> CodeGeneration Exp mkThreadBinding var = (\ bindingMethod var -> MethodInv $ PrimaryMethodCall ( InstanceCreation [] objectType [] (Just $ ClassBody [MemberDecl $ bindingMethod]) ) [] (Ident "apply") [ var ] ) <$> mkThreadBindingMethod <*> mkVarAccess Nothing var mkThreadBindingMethod :: CodeGeneration MemberDecl mkThreadBindingMethod = (\ compute -> MethodDecl [Final, Public] [] (Just . RefType $ ClassRefType idrisClosureType) (Ident "apply") [ FormalParam [Final] (RefType . ClassRefType $ objectType) False (VarId $ Ident "param") ] [] (MethodBody . Just $ Block [ mkThreadBindingStack , BlockStmt . Return $ Just compute ] ) ) <$> mkBindingClosure (SUpdate (Loc 0) (SApp False (MN 0 "EVAL") [Loc 0])) mkThreadBindingStack :: BlockStmt mkThreadBindingStack = LocalVars [Final] objectArrayType [ VarDecl (VarDeclArray . VarId $ Ident "new_context") (Just . InitArray $ ArrayInit [InitExp . ExpName $ J.Name [Ident "param"]]) ] mkExp :: SExp -> CodeGeneration Exp mkExp (SV var) = mkVarAccess Nothing var mkExp (SApp False name args) = (\ methClosure -> MethodInv $ PrimaryMethodCall ( InstanceCreation [] idrisTailCallClosureType [ methClosure ] Nothing ) [] (Ident "call") [] ) <$> mkMethodClosure name args mkExp (SApp True name args) = (\ methClosure -> ( InstanceCreation [] idrisTailCallClosureType [ methClosure ] Nothing ) ) <$> mkMethodClosure name args mkExp (SLet var new old) = mkLet var old new mkExp (SUpdate var exp) = (\ rhs varPos -> Assign (ArrayLhs $ ArrayIndex (contextArray var) (Lit $ Int varPos)) EqualA rhs ) <$> mkExp exp <*> varPos var mkExp (SCon conId name args) = (\ args -> InstanceCreation [] idrisObjectType ((Lit $ Int (toInteger conId)):args) Nothing) <$> mapM (mkExp .SV) args mkExp (SCase var alts) = mkCase False var alts mkExp (SChkCase var alts) = mkCase True var alts mkExp (SProj var i) = mkProjection var i mkExp (SConst (I x)) = let x' :: Int32; x' = fromInteger (toInteger x) in return $ mkPrimitive "Integer" (Int (fromInteger (toInteger x'))) mkExp (SConst (BI x)) = return $ InstanceCreation [] (ClassType [(Ident "BigInteger", [])]) [Lit $ String (show x)] Nothing mkExp (SConst (Fl x)) = return $ mkPrimitive "Double" (Double x) mkExp (SConst (Ch x)) = return $ mkPrimitive "Integer" (Char x) mkExp (SConst (Str x)) = return $ Lit $ String x mkExp (SConst IType) = return $ mkClass integerType mkExp (SConst BIType) = return $ mkClass bigIntegerType mkExp (SConst FlType) = return $ mkClass doubleType mkExp (SConst ChType) = return $ mkClass charType mkExp (SConst StrType) = return $ mkClass stringType mkExp (SConst (B8 x)) = return $ mkPrimitive "Byte" (String (show x)) mkExp (SConst (B16 x)) = return $ mkPrimitive "Short" (String (show x)) mkExp (SConst (B32 x)) = return $ mkPrimitive "Integer" (Int (toInteger x)) mkExp (SConst (B64 x)) = return $ mkPrimitive "Long" (String (show x)) mkExp (SConst (B8Type))= return $ mkClass byteType mkExp (SConst (B16Type)) = return $ mkClass shortType mkExp (SConst (B32Type)) = return $ mkClass integerType mkExp (SConst (B64Type)) = return $ mkClass longType mkExp (SConst (PtrType)) = return $ mkClass objectType mkExp (SConst (VoidType)) = return $ mkClass voidType mkExp (SConst (Forgot)) = return $ mkClass objectType mkExp (SForeign _ fType meth args) = mkForeignInvoke fType meth args mkExp (SOp (LPlus ITNative) args) = mkExp (SOp (LPlus IT32) args) mkExp (SOp (LMinus ITNative) args) = mkExp (SOp (LMinus IT32) args) mkExp (SOp (LTimes ITNative) args) = mkExp (SOp (LTimes IT32) args) mkExp (SOp (LSDiv ITNative) args) = mkExp (SOp (LSDiv IT32) args) mkExp (SOp (LSRem ITNative) args) = mkExp (SOp (LSRem IT32) args) mkExp (SOp (LAnd ITNative) args) = mkExp (SOp (LAnd IT32) args) mkExp (SOp (LOr ITNative) args) = mkExp (SOp (LOr IT32) args) mkExp (SOp (LXOr ITNative) args) = mkExp (SOp (LXOr IT32) args) mkExp (SOp (LCompl ITNative) args) = mkExp (SOp (LCompl IT32) args) mkExp (SOp (LSHL ITNative) args) = mkExp (SOp (LSHL IT32) args) mkExp (SOp (LASHR ITNative) args) = mkExp (SOp (LASHR IT32) args) mkExp (SOp (LEq ITNative) args) = mkExp (SOp (LEq IT32) args) mkExp (SOp (LLt ITNative) args) = mkExp (SOp (LLt IT32) args) mkExp (SOp (LLe ITNative) args) = mkExp (SOp (LLe IT32) args) mkExp (SOp (LGt ITNative) args) = mkExp (SOp (LGt IT32) args) mkExp (SOp (LGe ITNative) args) = mkExp (SOp (LGe IT32) args) mkExp (SOp LFPlus args) = mkBinOpExp doubleType Add args mkExp (SOp LFMinus args) = mkBinOpExp doubleType Sub args mkExp (SOp LFTimes args) = mkBinOpExp doubleType Mult args mkExp (SOp LFDiv args) = mkBinOpExp doubleType Div args mkExp (SOp LFEq args) = mkMethodOpChain1 (mkBoolToNumber doubleType) doubleType "equals" args mkExp (SOp LFLt args) = mkLogicalBinOpExp integerType LThan args mkExp (SOp LFLe args) = mkLogicalBinOpExp integerType LThanE args mkExp (SOp LFGt args) = mkLogicalBinOpExp integerType GThan args mkExp (SOp LFGe args) = mkLogicalBinOpExp integerType GThanE args mkExp (SOp (LPlus ITBig) args) = mkMethodOpChain1 id bigIntegerType "add" args mkExp (SOp (LMinus ITBig) args) = mkMethodOpChain1 id bigIntegerType "subtract" args mkExp (SOp (LTimes ITBig) args) = mkMethodOpChain1 id bigIntegerType "multiply" args mkExp (SOp (LSDiv ITBig) args) = mkMethodOpChain1 id bigIntegerType "divide" args mkExp (SOp (LSRem ITBig) args) = mkMethodOpChain1 id bigIntegerType "mod" args mkExp (SOp (LEq ITBig) args) = mkMethodOpChain1 (mkBoolToNumber bigIntegerType) bigIntegerType "equals" args mkExp (SOp (LLt ITBig) args) = mkMethodOpChain1 ( mkBoolToNumber bigIntegerType . mkPartialOrder SLt ) bigIntegerType "compareTo" args mkExp (SOp (LLe ITBig) args) = mkMethodOpChain1 ( mkBoolToNumber bigIntegerType . mkPartialOrder SLe ) bigIntegerType "compareTo" args mkExp (SOp (LGt ITBig) args) = mkMethodOpChain1 ( mkBoolToNumber bigIntegerType . mkPartialOrder SGt ) bigIntegerType "compareTo" args mkExp (SOp (LGe ITBig) args) = mkMethodOpChain1 ( mkBoolToNumber bigIntegerType . mkPartialOrder SGe ) bigIntegerType "compareTo" args mkExp (SOp LStrConcat args) = mkMethodOpChain (\ exp -> InstanceCreation [] (ClassType [(Ident "StringBuilder", [])]) [exp] Nothing ) (\ exp -> MethodInv $ PrimaryMethodCall exp [] (Ident "toString") []) stringType "append" args mkExp (SOp LStrLt args@[_, _]) = mkMethodOpChain1 ( mkBoolToNumber integerType . mkPartialOrder SLt ) stringType "compareTo" args mkExp (SOp LStrEq args@[_, _]) = mkMethodOpChain1 ( mkBoolToNumber integerType) stringType "equals" args mkExp (SOp LStrLen [arg]) = (\ var -> MethodInv $ PrimaryMethodCall var [] (Ident "length") []) <$> mkVarAccess (Just stringType) arg mkExp (SOp (LIntFloat ity) [arg]) = mkPrimitiveCast (intTyToClass ity) doubleType arg mkExp (SOp (LFloatInt ity) [arg]) = mkPrimitiveCast doubleType (intTyToClass ity) arg mkExp (SOp (LIntStr ITBig) [arg]) = (\ var -> InstanceCreation [] bigIntegerType [var] Nothing) <$> mkVarAccess (Just stringType) arg mkExp (SOp (LIntStr ity) [arg]) = mkToString (intTyToClass ity) arg mkExp (SOp (LStrInt ity) [arg]) = mkPrimitiveCast stringType (intTyToClass ity) arg mkExp (SOp LFloatStr [arg]) = mkToString doubleType arg mkExp (SOp LStrFloat [arg]) = mkPrimitiveCast doubleType stringType arg mkExp (SOp (LSExt ITNative ITBig) [arg]) = mkPrimitiveCast integerType bigIntegerType arg mkExp (SOp (LTrunc ITBig ITNative) [arg]) = mkPrimitiveCast bigIntegerType integerType arg mkExp (SOp (LChInt ITNative) [arg]) = mkVarAccess (Just integerType) arg mkExp (SOp (LIntCh ITNative) [arg]) = mkVarAccess (Just integerType) arg mkExp (SOp LPrintNum [arg]) = mkSystemOutPrint <$> (mkVarAccess Nothing arg) mkExp (SOp LPrintStr [arg]) = mkSystemOutPrint <$> (mkVarAccess (Just stringType) arg) mkExp (SOp LReadStr [arg]) = mkExp (SForeign LANG_C FString "idris_readStr" [(FPtr, arg)]) mkExp (SOp (LLt ty) args) = mkLogicalBinOpExp (intTyToClass ty) LThan args mkExp (SOp (LLe ty) args) = mkLogicalBinOpExp (intTyToClass ty) LThanE args mkExp (SOp (LEq ty) args) = mkMethodOpChain1 (mkBoolToNumber (intTyToClass ty)) (intTyToClass ty) "equals" args mkExp (SOp (LGt ty) args) = mkLogicalBinOpExp (intTyToClass ty) GThan args mkExp (SOp (LGe ty) args) = mkLogicalBinOpExp (intTyToClass ty) GThanE args mkExp (SOp (LPlus ty) args) = mkBinOpExp (intTyToClass ty) Add args mkExp (SOp (LMinus ty) args) = mkBinOpExp (intTyToClass ty) Sub args mkExp (SOp (LTimes ty) args) = mkBinOpExp (intTyToClass ty) Mult args mkExp (SOp (LUDiv IT64) (arg:args)) = do (arg:args) <- mapM (mkVarAccess (Just longType)) (arg:args) return $ foldl (\ exp arg -> MethodInv $ PrimaryMethodCall ( MethodInv $ PrimaryMethodCall ( MethodInv $ TypeMethodCall (J.Name [Ident "BigInteger"]) [] (Ident "valueOf") [ exp ] ) [] (Ident "divide") [ MethodInv $ TypeMethodCall (J.Name [Ident "BigInteger"]) [] (Ident "valueOf") [ arg ] ] ) [] (Ident "longValue") [] ) arg args mkExp (SOp (LUDiv ty) args) = mkBinOpExpConv (intTyToMethod $ nextIntTy ty) (intTyToPrimTy $ nextIntTy ty) (intTyToClass ty) Div args mkExp (SOp (LSDiv ty) args) = mkBinOpExp (intTyToClass ty) Div args mkExp (SOp (LURem IT64) (arg:args)) = do (arg:args) <- mapM (mkVarAccess (Just longType)) (arg:args) return $ foldl (\ exp arg -> MethodInv $ PrimaryMethodCall ( MethodInv $ PrimaryMethodCall ( MethodInv $ TypeMethodCall (J.Name [Ident "BigInteger"]) [] (Ident "valueOf") [ exp ] ) [] (Ident "remainder") [ MethodInv $ TypeMethodCall (J.Name [Ident "BigInteger"]) [] (Ident "valueOf") [ arg ] ] ) [] (Ident "longValue") [] ) arg args mkExp (SOp (LURem ty) args) = mkBinOpExpConv (intTyToMethod $ nextIntTy ty) (intTyToPrimTy $ nextIntTy ty) (intTyToClass ty) Rem args mkExp (SOp (LSRem ty) args) = mkBinOpExp (intTyToClass ty) Rem args mkExp (SOp (LSHL ty) args) = mkBinOpExp (intTyToClass ty) LShift args mkExp (SOp (LLSHR ty) args) = mkBinOpExp (intTyToClass ty) RRShift args mkExp (SOp (LASHR ty) args) = mkBinOpExp (intTyToClass ty) RShift args mkExp (SOp (LAnd ty) args) = mkBinOpExp (intTyToClass ty) And args mkExp (SOp (LOr ty) args) = mkBinOpExp (intTyToClass ty) Or args mkExp (SOp (LXOr ty) args) = mkBinOpExp (intTyToClass ty) Xor args mkExp (SOp (LCompl ty) [var]) = PreBitCompl <$> mkVarAccess (Just $ intTyToClass ty) var mkExp (SOp (LZExt from to) [var]) | intTyWidth from < intTyWidth to = mkZeroExt (intTyToMethod to) (intTyWidth from) (intTyToClass from) (intTyToClass to) var mkExp (SOp (LSExt from to) [var]) | intTyWidth from < intTyWidth to = mkSignedExt (intTyToMethod to) (intTyToClass from) (intTyToClass to) var mkExp (SOp (LTrunc from to) [var]) | intTyWidth from > intTyWidth to = (\ var -> MethodInv $ TypeMethodCall (J.Name [intTyToIdent to]) [] (Ident "valueOf") [ MethodInv $ PrimaryMethodCall var [] (Ident (intTyToMethod to)) [] ] ) <$> mkVarAccess (Just $ intTyToClass from) var mkExp (SOp LFExp [arg]) = mkMathFun "exp" arg mkExp (SOp LFLog [arg]) = mkMathFun "log" arg mkExp (SOp LFSin [arg]) = mkMathFun "sin" arg mkExp (SOp LFCos [arg]) = mkMathFun "cos" arg mkExp (SOp LFTan [arg]) = mkMathFun "tan" arg mkExp (SOp LFASin [arg]) = mkMathFun "asin" arg mkExp (SOp LFACos [arg]) = mkMathFun "acos" arg mkExp (SOp LFATan [arg]) = mkMathFun "atan" arg mkExp (SOp LFSqrt [arg]) = mkMathFun "sqrt" arg mkExp (SOp LFFloor [arg]) = mkMathFun "floor" arg mkExp (SOp LFCeil [arg]) = mkMathFun "ceil" arg mkExp (SOp LStrHead [arg]) = mkStringAtIndex arg (Lit $ Int 0) mkExp (SOp LStrTail [arg]) = (\ var -> MethodInv $ PrimaryMethodCall (var) [] (Ident "substring") [Lit $ Int 1] ) <$> mkVarAccess (Just stringType) arg mkExp (SOp LStrCons [c, cs]) = (\ cVar csVar -> MethodInv $ PrimaryMethodCall ( MethodInv $ PrimaryMethodCall (InstanceCreation [] (ClassType [(Ident "StringBuilder", [])]) [csVar] Nothing ) [] (Ident "insert") [ Lit $ Int 0, Cast (PrimType CharT) (MethodInv $ PrimaryMethodCall (cVar) [] (Ident "intValue") [] ) ] ) [] (Ident "toString") [] ) <$> mkVarAccess (Just integerType) c <*> mkVarAccess (Just stringType) cs mkExp (SOp LStrIndex [str, i]) = mkVarAccess (Just integerType) i >>= mkStringAtIndex str mkExp (SOp LStrRev [str]) = (\ var -> MethodInv $ PrimaryMethodCall ( MethodInv $ PrimaryMethodCall (InstanceCreation [] (ClassType [(Ident "StringBuffer", [])]) [var] Nothing ) [] (Ident "reverse") [] ) [] (Ident "toString") [] ) <$> mkVarAccess (Just stringType) str mkExp (SOp LStdIn []) = return $ mkSystemStd In mkExp (SOp LStdOut []) = return $ mkSystemStd Out mkExp (SOp LStdErr []) = return $ mkSystemStd Err mkExp (SOp LFork [arg]) = mkThread arg mkExp (SOp LPar [arg]) = mkExp (SV arg) mkExp (SOp LVMPtr []) = return $ MethodInv $ TypeMethodCall (J.Name [Ident "Thread"]) [] (Ident "currentThread") [] mkExp (SOp LNoOp args) = mkExp . SV $ last args mkExp (SNothing) = return $ Lit Null mkExp (SError err) = return . MethodInv $ PrimaryMethodCall (InstanceCreation [] runtimeExceptionType [Lit $ String err] ( Just $ ClassBody [ MemberDecl $ MethodDecl [Public, Final] [] (Just . RefType $ ClassRefType objectType) (Ident "throwSelf") [] [] ( MethodBody . Just $ Block [ BlockStmt (Throw This) ] ) ] ) ) [] (Ident "throwSelf") [] mkExp other = error (show other)