├── .gitignore ├── .travis.yml ├── README.md ├── build.gradle ├── deploy.sh ├── frege-interpreter-core ├── build.gradle └── src │ ├── main │ ├── frege │ │ └── frege │ │ │ ├── interpreter │ │ │ └── FregeInterpreter.fr │ │ │ └── scriptengine │ │ │ └── FregeScriptEngine.fr │ └── resources │ │ └── META-INF │ │ └── services │ │ └── javax.script.ScriptEngineFactory │ └── test │ └── java │ └── frege │ └── interpreter │ └── scriptengine │ └── FregeScriptEngineTest.java ├── frege-interpreter-java-support ├── build.gradle └── src │ └── main │ └── java │ └── frege │ └── interpreter │ └── javasupport │ ├── CompilationInfo.java │ ├── InterpreterClassLoader.java │ ├── JavaUtils.java │ ├── MemoryJavaCompiler.java │ └── MemoryStoreManager.java ├── gradle.properties ├── gradle ├── sonatype.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | ########################## 2 | # those should be ignored 3 | ########################## 4 | *~ 5 | *.class 6 | #*.jar 7 | target/ 8 | 9 | 10 | ################## 11 | ## Emacs autosave 12 | ################## 13 | \#*# 14 | .\#* 15 | 16 | ################# 17 | ## Eclipse 18 | ################# 19 | .classpath 20 | .project 21 | .metadata 22 | tmp/ 23 | *.tmp 24 | *.bak 25 | *.swp 26 | *~.nib 27 | local.properties 28 | .settings/ 29 | .loadpath 30 | 31 | # External tool builders 32 | .externalToolBuilders/ 33 | 34 | # Locally stored "Eclipse launch configurations" 35 | *.launch 36 | 37 | # CDT-specific 38 | .cproject 39 | 40 | # PDT-specific 41 | .buildpath 42 | 43 | ############ 44 | ## Windows 45 | ############ 46 | 47 | # Windows image file caches 48 | Thumbs.db 49 | 50 | # Folder config file 51 | Desktop.ini 52 | 53 | *.versionsBackup 54 | 55 | #Intellij IDEA 56 | *.iml 57 | 58 | .gradle 59 | .idea 60 | build 61 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | sudo: false 5 | env: 6 | global: 7 | - secure: B6ckh2pJYwvbyjWOoWmMar8X9uwbVORDXjT0XBl5BIUNW1NwARpTyWm6hpjAFqoMu7P/JTOQHBIRl5CNHGC/1W09Viy6RZ9TNT6qyZJWr1ArwqxxXATwLK32QUq48ETVBOA3XLFQcwSN+sRu1obBuXQfIbC0sLrO9ITarpS6QJg= 8 | after_success: 9 | - chmod +x ./deploy.sh; ./deploy.sh 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Frege Interpreter [![Build Status](https://travis-ci.org/Frege/frege-interpreter.svg)](https://travis-ci.org/Frege/frege-interpreter) 2 | 3 | This is an interpreter for Frege. 4 | 5 | Frege REPL and [Online REPL](http://try.frege-lang.org/) make use of this to provide an interactive 6 | environment on terminal as well as on the browser. 7 | 8 | #### JSR 223 Scripting support #### 9 | 10 | This project also implements JSR 223, a scripting engine for Frege. 11 | 12 | ### How to get frege-interpreter? ### 13 | 14 | **Build from sources** 15 | 16 | Checkout this project and then from project root, run ```./gradlew install``` 17 | 18 | **Binary** 19 | 20 | Under releases page [here](https://github.com/Frege/frege-interpreter/releases). 21 | 22 | ## Continuous Integration 23 | 24 | Travis: https://travis-ci.org/Frege/frege-interpreter/ 25 | 26 | Sonatype: https://oss.sonatype.org/content/groups/public/org/frege-lang/ 27 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | 2 | buildscript { 3 | repositories { 4 | mavenLocal() 5 | maven { 6 | url "https://plugins.gradle.org/m2/" 7 | } 8 | maven { 9 | url = "https://oss.sonatype.org/content/groups/public" 10 | } 11 | mavenCentral() 12 | } 13 | dependencies { 14 | classpath "gradle.plugin.org.frege-lang:frege-gradle-plugin:0.5" 15 | classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.5.3" 16 | } 17 | } 18 | 19 | apply plugin: 'io.codearte.nexus-staging' 20 | 21 | allprojects { 22 | defaultTasks "build" 23 | 24 | tasks.withType(JavaCompile) { 25 | options.encoding = 'UTF-8' 26 | } 27 | } 28 | 29 | subprojects { 30 | 31 | def urlFile = { url, name -> 32 | File file = new File("$buildDir/download/${name}.jar") 33 | file.parentFile.mkdirs() 34 | if (!file.exists()) { 35 | new URL(url).withInputStream { downloadStream -> 36 | file.withOutputStream { fileOut -> 37 | fileOut << downloadStream 38 | } 39 | } 40 | } 41 | files(file.absolutePath) 42 | } 43 | 44 | apply plugin: "java" 45 | apply plugin: "groovy" 46 | apply plugin: "maven" 47 | apply plugin: "signing" 48 | 49 | ext { 50 | baseVersion = "1.3" 51 | isSnapshot = true 52 | snapshotAppendix = "-SNAPSHOT" 53 | projectVersion = baseVersion + (isSnapshot ? snapshotAppendix : "") 54 | fregeReleaseName = "3.24public" 55 | fregeVersion = "3.24.405" 56 | } 57 | 58 | apply from: "$rootDir/gradle/sonatype.gradle" 59 | 60 | sourceCompatibility = 1.8 61 | targetCompatibility = 1.8 62 | 63 | version = projectVersion 64 | group = groupName 65 | archivesBaseName = project.name 66 | 67 | repositories { 68 | mavenLocal() 69 | maven { 70 | url = sonatypeRepositoryUrl 71 | } 72 | mavenCentral() 73 | } 74 | 75 | dependencies { 76 | compile urlFile("https://github.com/Frege/frege/releases/download/$fregeReleaseName/frege${fregeVersion}.jar", "frege${fregeVersion}") 77 | } 78 | 79 | nexusStaging { 80 | packageGroup = groupName 81 | stagingProfileId = "a622b6773bea07" 82 | } 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./gradlew uploadArchives -DsonatypeUsername="${SONATYPE_USERNAME}" -DsonatypePassword="${SONATYPE_PASSWORD}" -i -s 4 | RETVAL=$? 5 | 6 | if [ $RETVAL -eq 0 ]; then 7 | echo 'Completed publish!' 8 | else 9 | echo 'Publish failed.' 10 | return 1 11 | fi 12 | -------------------------------------------------------------------------------- /frege-interpreter-core/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: "org.frege-lang" 3 | 4 | dependencies { 5 | compile project(":frege-interpreter-java-support") 6 | testCompile("junit:junit:4.12") 7 | } 8 | 9 | compileFrege { 10 | target = "1.8" 11 | } 12 | 13 | compileTestFrege { 14 | enabled = false 15 | } 16 | -------------------------------------------------------------------------------- /frege-interpreter-core/src/main/frege/frege/interpreter/FregeInterpreter.fr: -------------------------------------------------------------------------------- 1 | {-- 2 | Frege Interpreter 3 | -} 4 | module frege.interpreter.FregeInterpreter where 5 | 6 | import frege.Prelude hiding(<+>, Reader) 7 | import Lib.PP(msgdoc, text, <+>) 8 | import Control.monad.State 9 | import Data.TreeMap (TreeMap Tree, values) 10 | import Data.List (sort, uniq, intersperse, nubBy, groupBy, sortBy, isPrefixOf) 11 | 12 | import Compiler.enums.Flags 13 | import Compiler.types.Global hiding (Message, Severity, liftIO) 14 | import Compiler.types.Global (Message CompilerMessage, Severity(), SubSt, GenSt) 15 | import Compiler.common.Desugar hiding (Program) 16 | import Compiler.common.Desugar (Program (Module ModuleProgram, Expression ExpressionProgram)) 17 | import Compiler.common.JavaName (javaName) 18 | import Compiler.types.SourceDefinitions 19 | import Compiler.common.CompilerOptions (standardGlobal, stdOptions, getOpts, theClassLoader, pathSep, ourPath) 20 | import Compiler.common.Errors as E() 21 | import Compiler.types.ImportDetails 22 | import Compiler.types.Tokens 23 | import Compiler.enums.TokenID 24 | import Compiler.types.Packs 25 | import Compiler.types.Positions 26 | import Compiler.types.Symbols 27 | import Compiler.types.External (defEA) 28 | import Compiler.types.NSNames 29 | import Compiler.types.JNames 30 | import Compiler.types.QNames 31 | import Compiler.types.SNames 32 | import Compiler.types.Types 33 | import Compiler.passes.Imp (importClass) 34 | import Compiler.classes.Nice(Nice, category) 35 | import Compiler.common.Resolve as R 36 | import Compiler.common.Types as CommonTypes(instanceHead) 37 | import Compiler.types.Targets (Target) 38 | 39 | import Compiler.grammar.Lexer as L() 40 | import Compiler.grammar.Frege as F() 41 | import Compiler.passes.Fix() 42 | import Compiler.passes.Imp() 43 | import Compiler.passes.Enter() 44 | import Compiler.passes.Fields() 45 | import Compiler.passes.TypeAlias() 46 | import Compiler.passes.Instances() 47 | import Compiler.passes.Transdef() 48 | import Compiler.Classes() 49 | import Compiler.Typecheck as TC() 50 | import Compiler.passes.GlobalLam as GL() 51 | import Compiler.passes.Easy as EA() 52 | import Compiler.passes.LetUnroll as LU() 53 | import Compiler.passes.Strict as SC() 54 | import Compiler.GenMeta as GM() 55 | import Compiler.passes.GenCode() 56 | 57 | import Control.monad.Reader 58 | import Control.monad.trans.MonadIO 59 | import Control.monad.trans.MonadTrans 60 | import Control.arrow.Kleisli 61 | 62 | import Ide.Utilities as Util (verbose, symbolDocumentation, packDocumentation, symbols) 63 | 64 | import Java.Net (URLClassLoader) 65 | 66 | data InterpreterConfig = InterpreterConfig 67 | { predefs :: String 68 | , compilerFlags :: Flags 69 | , useSandbox :: Bool 70 | } where 71 | 72 | initialState = InterpreterConfig 73 | { predefs = "" 74 | , compilerFlags = Flags.fromList [WARNINGS, HINTS, INLINE] 75 | , useSandbox = false 76 | } 77 | 78 | type InterpreterState = StateT (MutableIO InterpreterClassLoader) StIO 79 | 80 | newtype Interpreter result = Interpreter 81 | { un :: ReaderT InterpreterState InterpreterConfig result } where 82 | 83 | get :: Interpreter (MutableIO InterpreterClassLoader) 84 | get = Interpreter (Kleisli (\_ -> StateT.get)) 85 | 86 | put :: MutableIO InterpreterClassLoader -> Interpreter () 87 | put s = Interpreter (Kleisli (\_ -> StateT.put s)) 88 | 89 | getCompilerState :: Interpreter Global 90 | getCompilerState = Interpreter (Kleisli (\_ -> lift getSTT)) 91 | 92 | putCompilerState :: Global -> Interpreter () 93 | putCompilerState g = Interpreter (Kleisli (\_ -> lift (StateT.put g))) 94 | 95 | ask :: Interpreter InterpreterConfig 96 | ask = Interpreter Reader.ask 97 | 98 | modify f = do 99 | s <- Interpreter.get 100 | Interpreter.put (f s) 101 | 102 | run :: Interpreter result 103 | -> InterpreterConfig 104 | -> MutableIO InterpreterClassLoader 105 | -> IO (result, MutableIO InterpreterClassLoader) 106 | run (Interpreter interpreter) config !state = do 107 | global <- interpreterCompilerEnv state config.compilerFlags 108 | ((result, loader), newGlobal) <- StateT.run (StateT.run (Kleisli.run interpreter config) state) global 109 | return (result, loader) 110 | 111 | instance Monad Interpreter where 112 | pure = Interpreter . pure 113 | (Interpreter r) >>= f = Interpreter $ r >>= g where 114 | g = Interpreter.un . f 115 | 116 | instance MonadIO Interpreter where 117 | liftIO io = Interpreter $ Kleisli (\_ -> lift (liftIO io)) 118 | 119 | 120 | --- utility function to create 'Options' data structure 121 | createopts sp flags dir path prefix source = stdOptions.{ 122 | source = source, 123 | target = Target{major=1, minor=8}, 124 | sourcePath = sp, 125 | flags, 126 | dir, 127 | path = path, 128 | prefix} 129 | 130 | standardOptions :: MutableIO InterpreterClassLoader -> IO Global 131 | standardOptions classLoader = do 132 | err <- StringWriter.new () >>= StringWriter.printer 133 | out <- StringWriter.new () >>= StringWriter.printer 134 | urlClassLoader <- asURLClassLoader classLoader 135 | global <- standardGlobal 136 | return global.{ 137 | sub <- SubSt.{loader=urlClassLoader, stderr=err}, 138 | gen <- GenSt.{printer=out} 139 | } 140 | 141 | data InterpreterResult = Success 142 | { sourceRepr :: SourceInfo, 143 | compilerState :: Global 144 | } 145 | | Failure [Message] 146 | 147 | javaSourceGen :: Global -> Interpreter (Maybe String) 148 | javaSourceGen global = do 149 | let 150 | javagenST :: StIO (Maybe String) 151 | javagenST = do 152 | javaSourceWriter <- liftIO $ StringWriter.new () -- Java source will be written here 153 | let steps = javaSourcePasses javaSourceWriter 154 | forsome steps runpass 155 | global <- getSTT 156 | if global.errors == 0 157 | then do 158 | javaSource <- liftIO $ javaSourceWriter.toString 159 | return (Just javaSource) 160 | else return Nothing 161 | res <- liftIO $ StateT.run javagenST global 162 | return $ fst res 163 | 164 | javagen :: Global -> Interpreter (Maybe String) 165 | javagen global = do 166 | state <- Interpreter.get 167 | let 168 | javagenSTT :: StIO (MutableIO InterpreterClassLoader, Maybe String) 169 | javagenSTT = do 170 | javaSourceWriter <- liftIO $ StringWriter.new () -- Java source will be written here 171 | javac <- liftIO $ MemoryJavaCompiler.new state 172 | let steps = javagenPasses javaSourceWriter javac 173 | forsome steps runpass 174 | global <- getSTT 175 | if global.errors == 0 176 | then do 177 | classLoader <- liftIO javac.classLoader 178 | javaSource <- liftIO $ javaSourceWriter.toString 179 | return (classLoader, Just javaSource) 180 | else return (state, Nothing) 181 | ((loader, jsrc), g) <- liftIO $ StateT.run javagenSTT global 182 | Interpreter.putCompilerState g 183 | Interpreter.put loader 184 | return jsrc 185 | 186 | typecheck :: String -> Interpreter (Global, Maybe SourceInfo) 187 | typecheck src = do 188 | config <- Interpreter.ask 189 | state <- Interpreter.get 190 | env <- liftIO $ interpreterCompilerEnv state config.compilerFlags 191 | (sourceType, global) <- liftIO $ StateT.run (run src config.predefs (typecheckPasses config)) env 192 | return (global, sourceType) 193 | 194 | interpret :: String -> Interpreter InterpreterResult 195 | interpret line = do 196 | (tcGlobal, srcInfo) <- typecheck line 197 | case srcInfo of 198 | Just sourceInfo -> do 199 | jsrc <- javagen tcGlobal 200 | g <- Interpreter.getCompilerState 201 | let fail = InterpreterResult.Failure (Message.fromGlobal g) 202 | success = InterpreterResult.Success sourceInfo g 203 | return $ maybe fail (const success) jsrc 204 | Nothing -> return (InterpreterResult.Failure $ Message.fromGlobal tcGlobal) 205 | 206 | {-- 207 | * 'run' all passes, one after another 208 | * until one of them returns an error 209 | -} 210 | run :: String 211 | -> String 212 | -> (String-> [(StateT Global IO (String,Int), String)]) 213 | -> StateT Global IO (Maybe SourceInfo) 214 | run src predefs steps = do 215 | scriptType <- findSourceType src predefs 216 | let varName = findUnusedVariableName freshVarPrefix (predefs ++ src) 217 | source = buildScript src scriptType predefs "frege.interpreter.Console" varName 218 | changeSTT Global.{gen <- GenSt.{printer = stdout}} -- just to have no undefined value there 219 | forsome (steps source) runpass 220 | g <- getSTT 221 | let generatedSym = fst $ StG.run (resolveSymbol varName) g 222 | if g.errors == 0 223 | then case scriptType of 224 | ModuleSource -> return . Just $ SourceInfo.Module $ className g 225 | DefinitionsSource -> return . Just $ SourceInfo.Definitions (getSymbols g g.thisTab) 226 | ExpressionSource -> return $ SourceInfo.Expression <$> listToMaybe generatedSym 227 | else return Nothing 228 | 229 | browseModule :: String -> Interpreter (Maybe ([Symbol], Global)) 230 | browseModule moduleName = do 231 | (g, srcInfo) <- typecheck "\"\"" 232 | syms <- liftIO $ StateT.run (browseSymbols moduleName) g 233 | return $ fmap (const syms) srcInfo 234 | 235 | browse :: String -> Interpreter (Maybe ([Symbol], Global)) 236 | browse src = do 237 | res <- interpret src 238 | case res of 239 | InterpreterResult.Success {sourceRepr=Definitions syms, compilerState=g} -> 240 | return $ Just (syms, g) 241 | _ -> return Nothing 242 | 243 | typeof :: String -> Interpreter ([Message] | String) 244 | typeof expr = do 245 | res <- typecheck expr 246 | case res of 247 | (g, Just (Expression s)) -> return . Right $ getSymbolType g s 248 | (_, Just _) -> return . Left $ [Message.info "Not an expression!"] 249 | (g, _) -> return . Left $ map (Message.fromCompilerMessage) g.sub.messages 250 | 251 | 252 | javaSource :: String -> Interpreter ([Message] | String) 253 | javaSource line = do 254 | (g, srcInfo) <- typecheck line 255 | let f = do 256 | jsrcMaybe <- javaSourceGen g 257 | javagenGlobal <- Interpreter.getCompilerState 258 | return $ maybe (Left $ Message.fromGlobal javagenGlobal) Right jsrcMaybe 259 | maybe (return . Left $ Message.fromGlobal g) (const f) srcInfo 260 | 261 | docHelp :: String -> Interpreter ([Message] | String) 262 | docHelp source = do 263 | (g, srcInfo) <- typecheck "\"\"" 264 | doc <- liftIO $ fst <$> ((helpDoc source).run g) 265 | let help = Right (unlines doc) 266 | return $ maybe (Left $ Message.fromGlobal g) (const help) srcInfo 267 | 268 | removeDuplicateDefs :: [DefinitionS] -> StG [DefinitionS] 269 | removeDuplicateDefs defs = do 270 | let ds = nubBy matching $ reverse defs 271 | fm (x:xs) (y:ys) = funcMatching x y 272 | fm _ _ = false 273 | uniqds = reverse . concat $ nubBy fm $ groupBy funcMatching ds 274 | return uniqds 275 | 276 | data MessageType = INFO | ERROR | WARNING | HINT where 277 | translateCompilerMsgType Severity.HINT = HINT 278 | translateCompilerMsgType Severity.WARNING = WARNING 279 | translateCompilerMsgType Severity.ERROR = ERROR 280 | derive Show MessageType 281 | 282 | data Message = Message {pos :: Position, msgType :: MessageType, text :: String} where 283 | fromCompilerMessage (CompilerMessage.Msg pos sev text) = 284 | Message pos (MessageType.translateCompilerMsgType sev) text 285 | 286 | info txt = Message Position.null INFO txt 287 | error txt = Message Position.null ERROR txt 288 | hint txt = Message Position.null HINT txt 289 | warning txt = Message Position.null WARNING txt 290 | fromGlobal (g :: Global) = reverse $ map fromCompilerMessage g.sub.messages 291 | 292 | instance Show Message where 293 | show msg = show msg.pos ++ ": " ++ msg.text 294 | 295 | symbolVar :: Symbol -> Global -> String 296 | symbolVar SymV{nativ} g | Just nativSig <- nativ = elemAt (split nativSig "\\.") 1 297 | symbolVar SymL{alias, name} g = maybe (error $ "Not found: " ++ show name) (flip symbolVar g) $ g.find alias 298 | symbolVar symbol g = JName.base $ javaName g symbol.name 299 | 300 | symbolClass :: Symbol -> Global -> String 301 | symbolClass SymV{nativ} g | Just nativSig <- nativ = elemAt (split nativSig "\\.") 0 302 | symbolClass SymL{alias, name} g = maybe (error $ "Not found: " ++ show name) (flip symbolClass g) $ g.find alias 303 | symbolClass symbol g = g.unpack symbol.name.getpack 304 | 305 | findSourceType :: String -> String -> StIO SourceType 306 | findSourceType src predefs = do 307 | initialState ← getSTT 308 | pw <- liftIO $ StringWriter.new () >>= StringWriter.printer 309 | changeSTT Global.{sub <- SubSt.{stderr=pw}} 310 | runpass (lexPass src, "lexical analysis") 311 | g <- getSTT 312 | if g.errors != 0 313 | then return SourceType.DefinitionsSource -- TODO: Should we just throw an error? 314 | else do 315 | StateT.put initialState 316 | let tokens = filter noDocComment g.sub.toks.toList 317 | case tokens of 318 | (firstTok: rest) | firstTok.tokid == PACKAGE → return SourceType.ModuleSource 319 | otherwise → isDefinitionOrExpr src predefs 320 | 321 | isDefinitionOrExpr src predefs = do 322 | let defSrc = buildScript src SourceType.DefinitionsSource predefs "T" "test" 323 | initialState ← getSTT 324 | runpass (lexPass defSrc, "lexical analysis") 325 | g <- getSTT 326 | if g.errors != 0 327 | then return SourceType.ExpressionSource 328 | else do 329 | liftStG $ F.pass (filter Token.noComment g.sub.toks.toList) 330 | g <- getSTT 331 | StateT.put initialState 332 | if g.errors != 0 333 | then return SourceType.ExpressionSource 334 | else return SourceType.DefinitionsSource 335 | 336 | {- 337 | Compiler state with interpreter options 338 | There is no IO; The classes are loaded in memory. 339 | -} 340 | interpreterCompilerEnv :: MutableIO InterpreterClassLoader -> Flags -> IO Global 341 | interpreterCompilerEnv loader compilerFlags = do 342 | g <- standardOptions loader 343 | let opts = createopts ["."] compilerFlags "." [] "" ".fr" 344 | return g.{options = opts} 345 | 346 | runpass :: (StIO (String, Int), String) -> StIO () 347 | runpass (pass,description) = do 348 | state <- getSTT 349 | when (state.errors == 0) (pass >> return ()) 350 | 351 | browseSymbols :: String -> StIO [Symbol] 352 | browseSymbols s = do 353 | let p = Pack.new $ magicPack s 354 | importClass Position.null p.nsName p 355 | g <- getSTT 356 | let resolveSName = do 357 | qNames <- liftStG $ sNameToQName (createSName s) 358 | let qNameSyms q = maybe [] (getSymbols g) $ getEnv g q 359 | return $ qNames >>= qNameSyms 360 | resolvePackage d p = maybe d (return . (getSymbols g)) $ g.packages.lookup p 361 | resolveNSPackage d = maybe d (resolvePackage d) $ g.namespaces.lookup (NSX s) 362 | resolvePackage (resolveNSPackage resolveSName) p 363 | 364 | getEnv :: Global -> QName -> Maybe Symtab 365 | getEnv g q = g.find q >>= symEnv 366 | where 367 | symEnv s 368 | | s.{env?} = Just s.env 369 | | otherwise = Nothing 370 | 371 | outlineSymbols :: Global -> [String] 372 | outlineSymbols g = map (Util.label g) $ Util.symbols g.thisTab 373 | 374 | newLine = maybe "\n" id $ System.getProperty "line.separator" 375 | 376 | className :: Global -> String 377 | className global = global.unpack global.sub.thisPack 378 | 379 | data SourceType = ModuleSource | DefinitionsSource | ExpressionSource 380 | derive Show SourceType 381 | 382 | data SourceInfo = Module String 383 | | Expression Symbol 384 | | Definitions [Symbol] 385 | 386 | instance Show SourceInfo where 387 | show (Module packName) = "Module " ++ packName 388 | show (Expression _) = "Expression" 389 | show (Definitions _) = "Definitions" 390 | 391 | noDocComment Token{tokid} = tokid != COMMENT && tokid != DOCUMENTATION 392 | 393 | moduleDeclScript moduleName = "module " ++ moduleName ++ " where" 394 | variableDeclScript varName script = varName ++ " = \n" ++ (indent 2 script) 395 | 396 | intercalateNewLine :: [String] → String 397 | intercalateNewLine = fold (++) "" . intersperse "\n" 398 | 399 | buildScript script SourceType.DefinitionsSource predefs moduleName _ = 400 | if null predefs 401 | then (moduleDeclScript moduleName) ++ "\n" ++ script 402 | else intercalateNewLine [moduleDeclScript moduleName, predefs, script] 403 | 404 | buildScript script SourceType.ExpressionSource predefs moduleName varName = 405 | if null predefs 406 | then intercalateNewLine [moduleDeclScript moduleName, variableDeclScript varName script] 407 | else intercalateNewLine [moduleDeclScript moduleName, predefs, variableDeclScript varName script] 408 | 409 | buildScript script SourceType.ModuleSource predefs _ _ = script 410 | 411 | freshVarPrefix = "frege_interpreter_var" 412 | 413 | freshVarRegex :: Regex 414 | freshVarRegex = regforce (freshVarPrefix ++ "(\\d+)") 415 | 416 | findUnusedVariableName prefix script = prefix ++ show unusedVarNum where 417 | unusedVarNum = maybe 1 id . listToMaybe $ dropWhile (flip elem used) [1..] 418 | used = reverse $ map (maybe 1 atoi . maybe Nothing (_.group 1) . (=~ freshVarRegex)) (script ~~* freshVarRegex) 419 | 420 | helpDoc :: String -> StIO [String] 421 | helpDoc source = do 422 | global <- getSTT 423 | let qNames = fst $ (sNameToQName (createSName source)).run global 424 | syms = catMaybes $ global.find <$> qNames 425 | symdocs <- sequence $ map Util.symbolDocumentation syms 426 | if (any (not . null) symdocs) 427 | then return symdocs 428 | else (:[]) <$> Util.packDocumentation (magicPack source) 429 | 430 | sNameToQName :: SName -> StG [QName] 431 | sNameToQName sName = do 432 | g <- getST 433 | qNames <- R.resolve (VName g.thisPack) Position.null sName 434 | return qNames 435 | 436 | resolveSymbol :: String -> StG [Symbol] 437 | resolveSymbol source = do 438 | global <- getST 439 | qNames <- sNameToQName (createSName source) 440 | return . catMaybes $ global.find <$> qNames 441 | createSName s 442 | | Just (Just ns : Just ty : Just id : _) <- s `match` '^(.*)\.(.*)\.(\p{Lu}.*)$' = with2con ns ty id 443 | | Just (Just ns : Just ty : Just id : _) <- s `match` '^(.*)\.(.*)\.(.*)$' = with2var ns ty id 444 | | Just (Just ty : Just id : _) <- s `match` '^(.*)\.(\p{Lu}.*)$' = with1con ty id 445 | | Just (Just ty : Just id : _) <- s `match` '^(.*)\.(.*)$' = with1var ty id 446 | | s ~ '^\p{Lu}.*$' = Simple (Token CONID s 1 0 0 []) 447 | | otherwise = Simple (Token VARID s 1 0 0 []) 448 | where with2con ns ty id = With2 (qual ns) (qual ty) (con id) 449 | with2var ns ty id = With2 (qual ns) (qual ty) (var id) 450 | with1con ty id = With1 (qual ty) (con id) 451 | with1var ty id = With1 (qual ty) (var id) 452 | qual name = Token QUALIFIER name 1 0 0 [] 453 | con name = Token CONID name 1 0 0 [] 454 | var name = Token VARID name 1 0 0 [] 455 | 456 | match s regex = groups <$> s =~ regex where groups m = [m.group i | i <- [1..groupCount m]] 457 | 458 | buildShowScript :: String -> Int -> Global -> Symbol -> String 459 | buildShowScript varName showLimit state symbol 460 | | isIO state symbol = limit ++ " . showChars $ IO.performUnsafe " ++ varName 461 | | otherwise = limit ++ " . showChars $ " ++ varName 462 | where 463 | limit = "packed . take " ++ show showLimit 464 | 465 | openPrinter pw = do 466 | g <- getSTT 467 | printer <- liftIO $ StringWriter.printer pw 468 | changeSTT Global.{gen <- GenSt.{printer=printer}} 469 | return ("file", 1) 470 | 471 | javaSourcePasses jw = [ 472 | (liftStG EA.pass, "simplify expressions"), -- TRACE9 473 | (liftStG GL.pass, "globalize anonymous lambdas"), -- TRACE8 474 | (liftStG SC.pass, "strictness analysis"), 475 | (openPrinter jw, "open file"), 476 | (GM.genmeta, "generate meta data"), -- none 477 | (GenCode.pass, "generate java code") -- TRACEG 478 | ] 479 | 480 | javagenPasses jw javac = javaSourcePasses jw ++ [ 481 | (javacPass javac jw, "run java compiler") 482 | ] 483 | 484 | typecheckPasses (config :: InterpreterConfig) src = [ 485 | (lexPass src, "lexer"), 486 | (liftStG (iparsePass (transformDefs config)), "parser"), 487 | (liftStG Fix.pass, "join definitions"), 488 | (Imp.pass, "import packages"), 489 | (liftStG (Classes.passI true), "verify imported instances"), 490 | (liftStG Enter.pass, "enter definitions"), 491 | (liftStG Fields.pass, "field definitions"), 492 | (liftStG TypeAlias.pass, "process type aliases"), 493 | (liftStG derivePass, "derive and enter instances"), 494 | (Transdef.pass, "resolve names"), 495 | (liftStG Classes.passC, "verify class definitions"), -- TRACE6 496 | (liftStG $ Classes.passI false, "verify own instances"), -- TRACE6 497 | (liftStG LU.pass, "simplify lets"), -- TRACE7 498 | (TC.pass, "type check") -- TRACET, TRACEO 499 | ] 500 | 501 | derivePass = Instances.pass () 502 | 503 | javacPass :: MutableIO MemoryJavaCompiler -> StringWriter -> StIO (String, Int) 504 | javacPass compiler src = do 505 | g <- getSTT 506 | let !packName = g.unpack g.sub.thisPack 507 | !jsrc <- liftIO $ src.toString 508 | res <- liftIO $ compiler.compile jsrc packName 509 | isSuccess <- liftIO $ res.isSuccess 510 | if !isSuccess 511 | then do 512 | msg <- liftIO $ res.errorsAsString 513 | liftStG $ E.error Position.null (text msg) 514 | return ("javac", 1) 515 | else 516 | return ("javac", 0) 517 | 518 | matching (_@TypDcl{name=x}) (_@TypDcl{name=y}) = x == y 519 | matching (_@ClaDcl{name=x}) (_@ClaDcl{name=y}) = x == y 520 | matching (_@AnnDcl{name=x}) (_@AnnDcl{name=y}) = x == y 521 | matching (_@NatDcl{name=x}) (_@NatDcl{name=y}) = x == y 522 | matching (_@DatDcl{name=x}) (_@DatDcl{name=y}) = x == y 523 | matching (_@JavDcl{name=x}) (_@JavDcl{name=y}) = x == y 524 | matching _ _ = false 525 | 526 | funcMatching d1 d2 = fromMaybe false $ funcEq <$> funbinding d1 <*> funbinding d2 where 527 | funcEq :: Token -> Token -> Bool 528 | funcEq t1 t2 = t1.tokid == t2.tokid && t1.value == t2.value 529 | 530 | getSymbolType :: Global -> Symbol -> String 531 | getSymbolType g SymI{typ} = Util.verbose g typ 532 | getSymbolType g SymV{typ} = Util.verbose g typ 533 | getSymbolType g SymD{typ} = Util.verbose g typ 534 | getSymbolType g SymL{alias} = maybe "" (getSymbolType g) $ g.find alias 535 | getSymbolType g SymC{name,tau} = show tau.kind 536 | getSymbolType g SymT{name, nativ = Just n, pur} 537 | | pur = "immutable native " ++ n 538 | | otherwise = "mutable native " ++ n 539 | getSymbolType g sym 540 | | sym.{kind?} = show sym.kind 541 | | otherwise = "" 542 | 543 | showSymbol :: Global -> Symbol -> String 544 | showSymbol g sym = category sym g ++ " " ++ Util.label g sym 545 | 546 | getSymbols :: Global → Symtab → [Symbol] 547 | getSymbols g tab = (sortBy positionAndName • filter wanted • values) tab 548 | where 549 | positionAndName a b = case Symbol.pos a <=> Symbol.pos b of 550 | Eq -> comparing (QName.base • Symbol.name) a b 551 | ne -> ne 552 | wanted :: Symbol -> Bool 553 | wanted sym 554 | | sym.{alias?} = false 555 | | Local{} <- sym.name = false 556 | -- sym.vis == Private = false 557 | | sym.name.base ~ ´^(chg|upd|has|let|anon|lc)\$´ = false 558 | | otherwise = true 559 | 560 | 561 | iparsePass f = do 562 | g <- getST 563 | result <- F.pass (filter Token.noComment g.sub.toks.toList) 564 | case result of 565 | Just (ModuleProgram (packname, defs, doc)) -> do 566 | changeST Global.{sub <- SubSt.{thisPack = Pack.new packname}} 567 | newDefs <- f defs 568 | changeST Global.{sub <- (SubSt.{sourcedefs = newDefs } 569 | • SubSt.{packageDoc = Nothing})} 570 | stio ("tokens", g.sub.toks.length) 571 | Just _ -> error "FATAL: Expected module" 572 | Nothing -> stio ("tokens", g.sub.toks.length) 573 | 574 | interpreterPreludeImport = ImpDcl { 575 | pos = Position.null, 576 | pack = "frege.interpreter.PreludeInterpreter", 577 | as = Nothing, 578 | imports = linkAll 579 | } 580 | 581 | preludeHidingImport = ImpDcl { 582 | pos = Position.null, 583 | pack = "frege.Prelude", 584 | as = Nothing, 585 | imports = Imports { 586 | publik = false, 587 | except = true, 588 | items = [ 589 | fnImport "getLine", fnImport "getChar", fnImport "getContents" 590 | ] 591 | } 592 | } where 593 | fnImport name = Item {publik = false, name = fn name, members = Nothing, alias=""} 594 | fn name = Simple {id = Token VARID name 1 0 0 []} 595 | 596 | transformDefs :: InterpreterConfig -> [DefinitionS] -> StG [DefinitionS] 597 | transformDefs config defs | config.useSandbox = do 598 | uniqdefs <- removeDuplicateDefs defs 599 | return (interpreterPreludeImport : preludeHidingImport : uniqdefs) 600 | transformDefs config defs = removeDuplicateDefs defs 601 | 602 | indent n src = (unlines . map (spaces ++) . lines $ src) where 603 | spaces = concat $ replicate n " " 604 | 605 | lexPass src = do 606 | changeSTT Global.{sub <- SubSt.{toks = arrayFromList []} 607 | . SubSt.{sourcedefs = []} 608 | . SubSt.{packageDoc = Nothing} 609 | . SubSt.{thisPack = Pack.new ""}} 610 | changeSTT Global.{locals = Tree.empty, typEnv = []} 611 | tokens <- liftStG $ L.passCS (L.CharSeq.fromString src) 612 | return ("tokens", length tokens) 613 | 614 | isVariable :: Global -> Symbol -> Bool 615 | isVariable g SymV{name,typ} = case typ.rho of 616 | RhoFun _ _ _ = false 617 | RhoTau ctx _ = ctx == [] 618 | isVariable g SymD{} = true 619 | isVariable g SymL{alias} = maybe false (isVariable g) $ g.find alias 620 | isVariable _ _ = false 621 | 622 | isIO :: Global -> Symbol -> Bool 623 | isIO g SymV{typ} = "ST RealWorld" `isPrefix` nice typ g where 624 | isPrefix = isPrefixOf `on` toList 625 | isIO g SymL{alias} = maybe false (isIO g) $ g.find alias 626 | isIO _ _ = false 627 | 628 | isString g SymV{typ} = nice typ g == "StringJ Char" 629 | isString g SymL{alias} = maybe false (isString g) $ g.find alias 630 | isString g _ = false 631 | 632 | -- Find the cause not more than 10 level deep 633 | showThrowableCause t = showThrowableCause' 10 t 634 | 635 | showThrowableCause' depth t | depth <= 0 = showNative t 636 | showThrowableCause' depth t = maybe (showNative t) (showThrowableCause' (pred depth)) $ throwableCause t 637 | 638 | -- Native Definitions 639 | 640 | data MemoryJavaCompiler = native frege.interpreter.javasupport.MemoryJavaCompiler where 641 | native new :: Mutable s InterpreterClassLoader -> STMutable s MemoryJavaCompiler 642 | native compile :: Mutable s MemoryJavaCompiler -> String -> String -> STMutable s JavaCompilationInfo 643 | native classLoader :: Mutable s MemoryJavaCompiler -> STMutable s InterpreterClassLoader 644 | 645 | data InterpreterClassLoader = native frege.interpreter.javasupport.InterpreterClassLoader where 646 | native new :: () -> STMutable s InterpreterClassLoader 647 | | ClassLoader -> IOMutable InterpreterClassLoader 648 | | Mutable s (JMap String ByteArray) -> STMutable s InterpreterClassLoader 649 | | ClassLoader → MutableIO (JMap String ByteArray) -> IOMutable InterpreterClassLoader 650 | native classes :: MutableIO InterpreterClassLoader -> IOMutable (JMap String ByteArray) 651 | 652 | data JavaCompilationInfo = native frege.interpreter.javasupport.CompilationInfo where 653 | native isSuccess :: Mutable s JavaCompilationInfo -> ST s Bool 654 | native errorsAsString :: Mutable s JavaCompilationInfo -> ST s String 655 | --native classLoader :: MutableIO JavaCompilationInfo -> IO ClassLoader 656 | -- native classes :: Mutable s JavaCompilationInfo -> STMutable s (JMap String ByteArray) 657 | 658 | type ByteArray = JArray Byte 659 | 660 | data JMap k v = native java.util.Map where 661 | native put :: Mutable s (JMap k v) -> k -> v -> ST s () 662 | native get :: Mutable s (JMap k v) -> k -> ST s (Maybe v) 663 | native putAll :: Mutable s (JMap k v) -> Mutable s (JMap k v) -> ST s () 664 | native isEmpty :: Mutable s (JMap k v) -> ST s Bool 665 | 666 | data HashMap k v = native java.util.HashMap where 667 | native new :: () -> STMutable s (HashMap k v) 668 | 669 | pure native groupCount :: MatchResult -> Int 670 | 671 | native fieldValue frege.interpreter.javasupport.JavaUtils.fieldValue :: 672 | String -> String -> MutableIO InterpreterClassLoader -> IO (Maybe Object) 673 | 674 | native sandboxFieldValue frege.interpreter.javasupport.JavaUtils.sandboxFieldValue :: 675 | String -> String -> String -> StringWriter -> StringWriter -> MutableIO InterpreterClassLoader -> IO (Maybe Object) 676 | 677 | native fieldValueWithRuntime frege.interpreter.javasupport.JavaUtils.fieldValueWithRuntime :: 678 | String -> String -> String -> StringWriter -> StringWriter -> MutableIO InterpreterClassLoader -> IO (Maybe Object) 679 | 680 | pure native longToString Long.toString :: Long -> Int -> String 681 | 682 | pure native showNative String.valueOf :: a -> String 683 | pure native throwableCause getCause :: Throwable -> Maybe Throwable 684 | 685 | data Method = pure native java.lang.reflect.Method where 686 | pure native getName :: Method -> String 687 | 688 | pure native split :: String -> String -> JArray String 689 | pure native trim :: String -> String 690 | 691 | native asURLClassLoader "(java.net.URLClassLoader)" :: MutableIO InterpreterClassLoader -> IO URLClassLoader 692 | -------------------------------------------------------------------------------- /frege-interpreter-core/src/main/frege/frege/scriptengine/FregeScriptEngine.fr: -------------------------------------------------------------------------------- 1 | module frege.scriptengine.FregeScriptEngine where 2 | 3 | import frege.interpreter.FregeInterpreter 4 | import Data.List (intersperse) 5 | import frege.Prelude hiding (init) 6 | 7 | native module where { 8 | 9 | private static final String FREGE_BINDINGS_KEY = "frege.scriptengine.bindings"; 10 | private static final String PRELUDE_SCRIPT_CLASS_NAME = "frege.scriptengine.PreludeScript"; 11 | private static final String PRELUDE_SCRIPT_KEY = "frege.scriptengine.preludeScript"; 12 | 13 | public static class FregeScriptEngineFactory implements javax.script.ScriptEngineFactory { 14 | 15 | private static final java.util.List NAMES = java.util.Arrays.asList("fr", "frege"); 16 | 17 | 18 | @Override 19 | public String getEngineName() { 20 | return "frege"; 21 | } 22 | 23 | @Override 24 | public String getEngineVersion() { 25 | return "1.0"; 26 | } 27 | 28 | @Override 29 | public java.util.List getExtensions() { 30 | return NAMES; 31 | } 32 | 33 | @Override 34 | public java.util.List getMimeTypes() { 35 | return java.util.Arrays.asList(""); 36 | } 37 | 38 | @Override 39 | public java.util.List getNames() { 40 | return NAMES; 41 | } 42 | 43 | @Override 44 | public String getLanguageName() { 45 | return "frege"; 46 | } 47 | 48 | @Override 49 | public String getLanguageVersion() { 50 | return frege.Version.version; 51 | } 52 | 53 | @Override 54 | public Object getParameter(final String key) { 55 | return null; 56 | } 57 | 58 | @Override 59 | public String getMethodCallSyntax(final String obj, final String m, final String... args) { 60 | return null; 61 | } 62 | 63 | @Override 64 | public String getOutputStatement(final String toDisplay) { 65 | return null; 66 | } 67 | 68 | @Override 69 | public String getProgram(final String... statements) { 70 | return null; 71 | } 72 | 73 | @Override 74 | public javax.script.ScriptEngine getScriptEngine() { 75 | try { 76 | return new JFregeScriptEngine(this); 77 | } catch (final Throwable e) { 78 | e.printStackTrace(); 79 | } 80 | return null; 81 | } 82 | 83 | } 84 | 85 | private static class FregeBindings extends javax.script.SimpleBindings { 86 | 87 | @Override 88 | public Object put(String key, Object value) { 89 | checkKey(key); 90 | String existingKey = findExistingVariable(key); 91 | if (existingKey != null) { 92 | remove(existingKey); 93 | } 94 | return super.put(key, value); 95 | } 96 | 97 | private String findExistingVariable(String key) { 98 | String keyName = getVariableName(key); 99 | for (String thatKeyName: keySet()) { 100 | if (getVariableName(thatKeyName).equals(keyName)) { 101 | return thatKeyName; 102 | } 103 | } 104 | return null; 105 | } 106 | 107 | private String getVariableName(String key) { 108 | return key.split("::")[0].trim(); 109 | } 110 | 111 | private void checkKey(Object key) { 112 | if (key == null) { 113 | throw new NullPointerException("key can not be null"); 114 | } 115 | if (key.equals("")) { 116 | throw new IllegalArgumentException("key can not be empty"); 117 | } 118 | } 119 | } 120 | 121 | public static class JFregeScriptEngine extends javax.script.AbstractScriptEngine implements 122 | javax.script.Compilable { 123 | 124 | private final javax.script.ScriptEngineFactory factory; 125 | 126 | public JFregeScriptEngine(final javax.script.ScriptEngineFactory factory) { 127 | super(new FregeBindings()); 128 | this.factory = factory; 129 | frege.prelude.PreludeBase.TST.run( 130 | frege.scriptengine.FregeScriptEngine.init(this, factory)).call(); 131 | } 132 | 133 | @Override 134 | public Object eval(final String script, final javax.script.ScriptContext context) 135 | throws javax.script.ScriptException { 136 | frege.prelude.PreludeBase.TST.performUnsafe( 137 | frege.scriptengine.FregeScriptEngine.removeBindingVars(this, context)).call(); 138 | 139 | bindVarsAndLoadPrelude(); 140 | 141 | Object res = frege.prelude.PreludeBase.TST.performUnsafe( 142 | frege.scriptengine.FregeScriptEngine.eval(script, context)).call(); 143 | if (res instanceof frege.prelude.PreludeBase.TMaybe) { 144 | frege.prelude.PreludeBase.TMaybe maybe = (frege.prelude.PreludeBase.TMaybe) res; 145 | if (frege.prelude.Maybe.isJust(maybe)) { 146 | return unwrapThunk(frege.prelude.Maybe.unJust(maybe)); 147 | } 148 | } 149 | return null; 150 | } 151 | 152 | @Override 153 | public Object eval(final java.io.Reader reader, final javax.script.ScriptContext context) 154 | throws javax.script.ScriptException { 155 | String script = new java.util.Scanner(reader).useDelimiter("\\A").next(); 156 | return eval(script, context); 157 | } 158 | 159 | @Override 160 | public javax.script.Bindings createBindings() { 161 | return new javax.script.SimpleBindings(); 162 | } 163 | 164 | @Override 165 | public javax.script.ScriptEngineFactory getFactory() { 166 | return this.factory; 167 | } 168 | 169 | @Override 170 | public javax.script.CompiledScript compile(final String script) throws javax.script.ScriptException { 171 | return frege.prelude.PreludeBase.TST.performUnsafe( 172 | frege.scriptengine.FregeScriptEngine.compile(this, script, context)).call(); 173 | } 174 | 175 | @Override 176 | public javax.script.CompiledScript compile(final java.io.Reader reader) throws javax.script.ScriptException { 177 | return frege.prelude.PreludeBase.TST.performUnsafe( 178 | frege.scriptengine.FregeScriptEngine.compileReader(this, reader, context)).call(); 179 | } 180 | 181 | private void bindVariable(String key, Object value) { 182 | final String[] nameAndType = key.split("::"); 183 | final String name = nameAndType[0].trim(); 184 | 185 | if (name.equals("import")) { 186 | frege.prelude.PreludeBase.TST.performUnsafe( 187 | frege.scriptengine.FregeScriptEngine.addImport(this, context, value.toString())).call(); 188 | } else { 189 | final String type = nameAndType.length < 2 ? "a" : nameAndType[1].trim(); 190 | frege.prelude.PreludeBase.TST.performUnsafe( 191 | frege.scriptengine.FregeScriptEngine.put(this, context, key, value)).call(); 192 | } 193 | } 194 | 195 | private void bindVarsAndLoadPrelude() { 196 | java.util.Map bindings = getBindings(javax.script.ScriptContext.ENGINE_SCOPE); 197 | if (hasVars(bindings)) { 198 | for (java.util.Map.Entry entry: new java.util.HashSet<>(bindings.entrySet())) { 199 | if (isUserBindingVar(entry.getKey())) 200 | bindVariable(entry.getKey(), entry.getValue()); 201 | } 202 | frege.prelude.PreludeBase.TST.performUnsafe( 203 | frege.scriptengine.FregeScriptEngine.loadScriptingPrelude(context)).call(); 204 | } 205 | } 206 | 207 | @Override 208 | public void put(final String key, final Object value) { 209 | getBindings(javax.script.ScriptContext.ENGINE_SCOPE).put(key, value); 210 | } 211 | } 212 | 213 | public static Object unwrapThunk(Object thunk) { 214 | if (thunk instanceof frege.run8.Thunk) { 215 | return ((frege.run8.Thunk) thunk).call(); 216 | } else if (thunk instanceof frege.run7.Thunk) { 217 | return ((frege.run7.Thunk) thunk).call(); 218 | } else { 219 | return thunk; 220 | } 221 | } 222 | 223 | public static Object jEvalSym(final javax.script.ScriptContext context, 224 | final frege.interpreter.javasupport.InterpreterClassLoader classLoader, 225 | final String className, 226 | final String varName) throws javax.script.ScriptException { 227 | final Object res; 228 | java.util.Map bindings = context.getBindings(javax.script.ScriptContext.ENGINE_SCOPE); 229 | try { 230 | if (bindings != null && hasVars(bindings)) { 231 | Class preludeClass = classLoader.loadClass(PRELUDE_SCRIPT_CLASS_NAME); 232 | injectValues(bindings, preludeClass); 233 | } 234 | res = frege.interpreter.javasupport.JavaUtils.fieldValue(className, varName, classLoader); 235 | } catch (Exception exception) { 236 | throw new javax.script.ScriptException(exception); 237 | } 238 | 239 | return res; 240 | } 241 | 242 | private static boolean hasVars(java.util.Map bindings) { 243 | if (bindings == null) return false; 244 | for (final java.util.Map.Entry entry: bindings.entrySet()) { 245 | if (isUserBindingVar(entry.getKey())) { 246 | return true; 247 | } 248 | } 249 | return false; 250 | } 251 | 252 | private static boolean isUserBindingVar(String varName) { 253 | return !varName.startsWith("frege.scriptengine.") && !varName.endsWith("fregeScriptEngineVar"); 254 | } 255 | 256 | public static void injectValues(final java.util.Map bindings, 257 | final Class clazz) { 258 | try { 259 | for (final java.util.Map.Entry entry: bindings.entrySet()) { 260 | if (entry.getKey().endsWith("fregeScriptEngineVar")) { 261 | final java.lang.reflect.Field field = clazz.getDeclaredField(entry.getKey()); 262 | final Ref ref = (Ref) field.get(null); 263 | ref.set(entry.getValue()); 264 | } 265 | } 266 | } catch (final Exception e) { 267 | throw new RuntimeException(e); 268 | } 269 | } 270 | 271 | public static javax.script.CompiledScript newFregeCompiledScript( 272 | String script, 273 | javax.script.ScriptEngine scriptEngine, 274 | frege.interpreter.FregeInterpreter.TInterpreterConfig config, 275 | frege.interpreter.FregeInterpreter.TInterpreterResult result, 276 | frege.interpreter.javasupport.InterpreterClassLoader classLoader) { 277 | return new FregeCompiledScript(script, scriptEngine, config, result, classLoader); 278 | 279 | } 280 | 281 | public static class FregeCompiledScript extends javax.script.CompiledScript { 282 | 283 | private String script; 284 | private javax.script.ScriptEngine scriptEngine; 285 | private frege.interpreter.FregeInterpreter.TInterpreterConfig config; 286 | private frege.interpreter.FregeInterpreter.TInterpreterResult result; 287 | private frege.interpreter.javasupport.InterpreterClassLoader classLoader; 288 | 289 | public FregeCompiledScript( 290 | String script, 291 | javax.script.ScriptEngine scriptEngine, 292 | frege.interpreter.FregeInterpreter.TInterpreterConfig config, 293 | frege.interpreter.FregeInterpreter.TInterpreterResult result, 294 | frege.interpreter.javasupport.InterpreterClassLoader classLoader) { 295 | 296 | this.script = script; 297 | this.scriptEngine = scriptEngine; 298 | this.config = config; 299 | this.result = result; 300 | this.classLoader = classLoader; 301 | } 302 | 303 | @Override 304 | public Object eval(final javax.script.ScriptContext context) throws javax.script.ScriptException { 305 | return frege.prelude.PreludeBase.TST.performUnsafe( 306 | FregeScriptEngine.evalResult(script, config, context, result, classLoader)).call(); 307 | } 308 | 309 | @Override 310 | public javax.script.ScriptEngine getEngine() { 311 | return scriptEngine; 312 | } 313 | } 314 | 315 | /** 316 | * Used in Frege Script Engine to pass values from host environment to scripting 317 | * environment 318 | * 319 | * @param 320 | */ 321 | public static class Ref { 322 | 323 | private A value; 324 | 325 | public A get() { 326 | return value; 327 | } 328 | 329 | public void set(final A value) { 330 | this.value = value; 331 | } 332 | 333 | } 334 | 335 | } 336 | 337 | eval :: String -> MutableIO ScriptContext -> IO (Maybe Object) 338 | eval !script !context = do 339 | state <- getInterpreterState context 340 | config <- getInterpreterConfig context 341 | (res, newState) <- Interpreter.run (interpret script) config state 342 | evalResult script config context res newState 343 | 344 | evalResult :: String -> InterpreterConfig -> MutableIO ScriptContext -> InterpreterResult -> MutableIO InterpreterClassLoader -> IO (Maybe Object) 345 | evalResult !script !config !context !res !state = do 346 | case res of 347 | InterpreterResult.Success{sourceRepr=sourceRepr, compilerState=g} -> do 348 | case sourceRepr of 349 | Module moduleName -> do 350 | context.setAttribute classLoaderKey state ScriptContext.engineScope 351 | return Nothing 352 | Definitions syms -> do 353 | let updatePredefs predefs = predefs ++ "\n" ++ script 354 | newConfig = config.{predefs<-updatePredefs} 355 | context.setAttribute configKey newConfig ScriptContext.engineScope 356 | return Nothing 357 | Expression sym | isVariable g sym -> do 358 | let className = symbolClass sym g 359 | varName = symbolVar sym g 360 | Just <$> evalSym context state className varName 361 | Expression sym = return Nothing 362 | InterpreterResult.Failure messages -> error $ show messages 363 | 364 | compile :: MutableIO ScriptEngine -> String -> MutableIO ScriptContext -> IOMutable CompiledScript 365 | compile !engine !script !context = do 366 | state <- getInterpreterState context 367 | config <- getInterpreterConfig context 368 | (res, newState) <- Interpreter.run (interpret script) config state 369 | createFregeCompiledScript script engine config res newState 370 | 371 | compileReader :: MutableIO ScriptEngine -> Reader -> MutableIO ScriptContext -> IOMutable CompiledScript 372 | compileReader !engine !reader !context = do 373 | bufReader <- BufferedReader.new reader 374 | lines <- bufReader.getLines 375 | compile engine (fold (++) "" $ intersperse "\n" lines) context 376 | 377 | put :: MutableIO ScriptEngine -> MutableIO ScriptContext -> String -> Object -> IO () 378 | put !engine !context !key !value = do 379 | let xs = map trim . toList $ split key "::" 380 | f name typ = do 381 | bindVariable engine context name typ 382 | updatePreludeScript engine context name typ 383 | updateBindings engine context value name 384 | case xs of 385 | (name: typ: _) -> f name typ 386 | (name: _) -> f name "a" 387 | _ -> pure () 388 | 389 | removeBindingVars :: MutableIO ScriptEngine -> MutableIO ScriptContext -> IO () 390 | removeBindingVars !engine !context = do 391 | config <- getInterpreterConfig context 392 | preludeScript <- context.getAttribute fregePreludeScriptKey ScriptContext.engineScope 393 | let newPreludeScript = unlines . filter (not . isVarDef) . lines $ fromMaybe "" (asString <$> preludeScript) 394 | newPredefs = unlines $ filter (not . isVarDef) $ lines config.predefs 395 | newConfig = config.{predefs=newPredefs} 396 | isVarDef line = line.contains "fregeScriptEngineVar" 397 | context.setAttribute fregePreludeScriptKey newPreludeScript ScriptContext.engineScope 398 | context.setAttribute configKey newConfig ScriptContext.engineScope 399 | 400 | bindVariable :: MutableIO ScriptEngine -> MutableIO ScriptContext -> String -> String -> IO () 401 | bindVariable engine context name typ = do 402 | config <- getInterpreterConfig context 403 | let newScript = String.format "\n%1$s :: %2$s--fregeScriptEngineVar\n%1$s = FregeScriptEngineRef.get %3$s" name typ 404 | (name ++ "fregeScriptEngineVar") 405 | updateCurrentScript engine context newScript 406 | 407 | updateCurrentScript :: MutableIO ScriptEngine -> MutableIO ScriptContext -> String -> IO () 408 | updateCurrentScript engine context script = do 409 | config <- getInterpreterConfig context 410 | let importIfNecessary = if config.predefs.contains preludeImport then "" else preludeImport ++ "\n" 411 | newPredefs = config.predefs ++ "\n" ++ importIfNecessary ++ script 412 | newConfig = config.{predefs=newPredefs} 413 | context.setAttribute configKey newConfig ScriptContext.engineScope 414 | 415 | addImport :: MutableIO ScriptEngine -> MutableIO ScriptContext -> String -> IO () 416 | addImport !engine !context !imp = do 417 | config <- getInterpreterConfig context 418 | preludeScript <- context.getAttribute fregePreludeScriptKey ScriptContext.engineScope 419 | let importScript = "\nimport " ++ imp ++ "\n" 420 | newPreludeScript = fromMaybe "" (fmap asString preludeScript) ++ importScript 421 | context.setAttribute fregePreludeScriptKey newPreludeScript ScriptContext.engineScope 422 | updateCurrentScript engine context importScript 423 | 424 | updatePreludeScript :: MutableIO ScriptEngine -> MutableIO ScriptContext -> String -> String -> IO () 425 | updatePreludeScript engine context name typName = do 426 | let typ = "FregeScriptEngineRef (" ++ typName ++ ")" 427 | newDef = String.format ("\n%1$s :: %2$s\n" ++ "!%1$s = IO.performUnsafe $ FregeScriptEngineRef.new ()\n") 428 | (name ++ "fregeScriptEngineVar") typ 429 | preludeScript <- context.getAttribute fregePreludeScriptKey ScriptContext.engineScope 430 | let newPreludeScript = fromMaybe "" (fmap asString preludeScript) ++ "\n" ++ newDef 431 | context.setAttribute fregePreludeScriptKey newPreludeScript ScriptContext.engineScope 432 | 433 | updateBindings :: MutableIO ScriptEngine -> MutableIO ScriptContext -> Object -> String -> IO () 434 | updateBindings engine context value name = do 435 | bindings ← context.getBindings ScriptContext.engineScope 436 | bindings.put (name ++ "fregeScriptEngineVar") value 437 | return () 438 | 439 | loadScriptingPrelude :: MutableIO ScriptContext -> IO () 440 | loadScriptingPrelude !context = do 441 | scriptMaybe <- context.getAttribute fregePreludeScriptKey ScriptContext.engineScope 442 | maybe (pure ()) (\script -> eval (asString script) context >> pure ()) scriptMaybe 443 | 444 | getInterpreterState :: Mutable s ScriptContext -> STMutable s InterpreterClassLoader 445 | getInterpreterState context = do 446 | classLoaderMaybe <- context.getAttribute classLoaderKey 447 | maybe (InterpreterClassLoader.new ()) asInterpreterClassLoader classLoaderMaybe 448 | 449 | getInterpreterConfig :: Mutable s ScriptContext -> ST s InterpreterConfig 450 | getInterpreterConfig context = do 451 | configMaybe <- context.getAttribute configKey 452 | return $ maybe InterpreterConfig.initialState asInterpreterConfig configMaybe 453 | 454 | native evalSym frege.scriptengine.FregeScriptEngine.jEvalSym 455 | :: MutableIO ScriptContext -> MutableIO InterpreterClassLoader -> String -> String -> IO Object throws ScriptException 456 | 457 | init :: Mutable s ScriptEngine -> Mutable s ScriptEngineFactory -> ST s () 458 | init !engine !factory = do 459 | context <- getContext engine 460 | context.setAttribute fregePreludeScriptKey preludeDef ScriptContext.engineScope 461 | 462 | native getContext :: Mutable s ScriptEngine -> STMutable s ScriptContext 463 | 464 | data ScriptEngine = native javax.script.ScriptEngine 465 | 466 | data Bindings = native javax.script.Bindings where 467 | native get :: Mutable s Bindings → String → ST s (Maybe Object) 468 | native put :: Mutable s Bindings → String → a → ST s () 469 | 470 | data ScriptEngineFactory = native javax.script.ScriptEngineFactory 471 | data ScriptException = native javax.script.ScriptException 472 | derive Exceptional ScriptException 473 | 474 | data ScriptContext = native javax.script.ScriptContext where 475 | pure native engineScope javax.script.ScriptContext.ENGINE_SCOPE :: Int 476 | native getAttribute :: Mutable s ScriptContext -> String -> ST s (Maybe Object) 477 | | Mutable s ScriptContext -> String -> Int -> ST s (Maybe Object) 478 | 479 | native setAttribute :: Mutable s ScriptContext -> String -> a -> Int -> ST s () 480 | native getBindings :: Mutable s ScriptContext → Int → STMutable s Bindings 481 | 482 | data CompiledScript = native javax.script.CompiledScript 483 | 484 | pure native asString "(String)" :: a → String 485 | 486 | pure native asInterpreterConfig "(frege.interpreter.FregeInterpreter.TInterpreterConfig)" :: a → InterpreterConfig 487 | native asInterpreterClassLoader "(frege.interpreter.javasupport.InterpreterClassLoader)" :: a → STMutable s InterpreterClassLoader 488 | native asMapStringObject "(java.util.Map)" :: a → IOMutable (JMap String Object) 489 | 490 | native createFregeCompiledScript FregeScriptEngine.newFregeCompiledScript 491 | :: String -> Mutable s ScriptEngine -> InterpreterConfig -> InterpreterResult -> Mutable s InterpreterClassLoader -> STMutable s CompiledScript 492 | 493 | fregePreludeScriptKey = "frege.scriptengine.preludeScript" 494 | classLoaderKey = "frege.scriptengine.classloader" 495 | configKey = "frege.scriptengine.currentDefs" 496 | preludeScriptClassName = "frege.scriptengine.PreludeScript" 497 | fregeBindingsKey = "frege.scriptengine.bindings" 498 | preludeImport = "import " ++ preludeScriptClassName 499 | 500 | preludeDef = 501 | "module " ++ preludeScriptClassName ++ " where\n" 502 | ++ "data FregeScriptEngineRef a = pure native " ++ "frege.scriptengine.FregeScriptEngine.Ref" ++ " where\n" 503 | ++ " native new :: () -> ST s (FregeScriptEngineRef a)\n" 504 | ++ " pure native get :: FregeScriptEngineRef a -> a\n" -------------------------------------------------------------------------------- /frege-interpreter-core/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory: -------------------------------------------------------------------------------- 1 | frege.scriptengine.FregeScriptEngine$FregeScriptEngineFactory -------------------------------------------------------------------------------- /frege-interpreter-core/src/test/java/frege/interpreter/scriptengine/FregeScriptEngineTest.java: -------------------------------------------------------------------------------- 1 | package frege.interpreter.scriptengine; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import javax.script.Bindings; 7 | import javax.script.Compilable; 8 | import javax.script.CompiledScript; 9 | import javax.script.ScriptEngine; 10 | import javax.script.ScriptEngineManager; 11 | import javax.script.ScriptException; 12 | import java.math.BigInteger; 13 | 14 | import static javax.script.ScriptContext.ENGINE_SCOPE; 15 | import static org.junit.Assert.assertEquals; 16 | 17 | public class FregeScriptEngineTest { 18 | 19 | private ScriptEngine frege; 20 | 21 | @Before 22 | public void beforeTest() { 23 | final ScriptEngineManager factory = new ScriptEngineManager(); 24 | this.frege = factory.getEngineByName("frege"); 25 | } 26 | 27 | @Test 28 | public void testExpression() throws ScriptException { 29 | final Object actual = frege.eval("show $ take 10 [2,4..]"); 30 | final Object expected = "[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]"; 31 | assertEquals(expected, actual); 32 | } 33 | 34 | @Test 35 | public void testDefinition() throws ScriptException { 36 | frege.eval("f x y = x + y"); 37 | final Object actual = frege.eval("f 3 4"); 38 | final Object expected = 7; 39 | assertEquals(expected, actual); 40 | } 41 | 42 | @Test 43 | public void testDefinitionWithTypeAnn() throws ScriptException { 44 | frege.eval("f :: Int -> Int -> Int\n" + 45 | "f x y = x + y"); 46 | frege.eval("g :: Int -> Int -> Int\n" + 47 | "g x y = x + y"); 48 | final Object actual = frege.eval("f 3 4"); 49 | final Object expected = 7; 50 | assertEquals(expected, actual); 51 | } 52 | 53 | @Test 54 | public void testInlineDefinitionWithTypeAnn() throws ScriptException { 55 | frege.eval("type F = (forall b. [b] -> [b]) -> Int"); 56 | frege.eval("g :: F -> Int; g f = f reverse"); 57 | frege.eval("k2 (f :: [Int] -> [Int]) = 42"); 58 | final Object expected = frege.eval("g k2"); 59 | final Object actual = 42; 60 | assertEquals(expected, actual); 61 | } 62 | 63 | @Test 64 | public void testBinding() throws ScriptException { 65 | frege.put("bar :: Integer", new BigInteger("12312332142343244")); 66 | final Object actual = frege.eval("bar + 3.big"); 67 | final Object expected = new BigInteger("12312332142343247"); 68 | assertEquals(expected, actual); 69 | } 70 | 71 | @Test 72 | public void testBindingWithTypeAnn() throws ScriptException { 73 | frege.put("foo::String", "I am foo"); 74 | final Object actual = frege.eval("\"Hello World, \" ++ foo"); 75 | final Object expected = "Hello World, I am foo"; 76 | assertEquals(expected, actual); 77 | } 78 | 79 | @Test 80 | public void testCompilable() throws ScriptException { 81 | final Compilable compilableFrege = (Compilable) frege; 82 | final CompiledScript compiled = 83 | compilableFrege.compile("fib = 0 : 1 : zipWith (+) fib (tail fib)"); 84 | compiled.eval(); 85 | final Object actual = frege.eval("show $ take 6 fib"); 86 | final Object expected = "[0, 1, 1, 2, 3, 5]"; 87 | assertEquals(expected, actual); 88 | } 89 | 90 | @Test 91 | public void testModule() throws ScriptException { 92 | frege.eval("module foo.Foo where { bar = \"I am bar from foo\"}"); 93 | frege.eval("import foo.Foo"); 94 | frege.eval("baz = bar"); 95 | final Object actual = frege.eval("baz"); 96 | final Object expected = "I am bar from foo"; 97 | assertEquals(expected, actual); 98 | } 99 | 100 | 101 | @Test 102 | public void testModuleWithComment() throws ScriptException { 103 | frege.eval("module foo.Foo where\n" + 104 | "\n" + 105 | "{--asdfasdf\n" + 106 | "sadfasdfsadf-}\n" + 107 | "\n" + 108 | "baz = \"I am foo!\""); 109 | frege.eval("import foo.Foo"); 110 | final Object actual = frege.eval("baz"); 111 | final Object expected = "I am foo!"; 112 | assertEquals(expected, actual); 113 | } 114 | 115 | @Test 116 | public void testUnpackagedModule() throws ScriptException { 117 | frege.eval("module Bar where { bar = \"I am bar\"}"); 118 | frege.eval("pure native bar Bar.bar :: String"); 119 | final Object actual = frege.eval("bar"); 120 | final Object expected = "I am bar"; 121 | assertEquals(expected, actual); 122 | } 123 | 124 | @Test 125 | public void testOperators() throws ScriptException { 126 | frege.eval("infix 1 `³`"); 127 | frege.eval("(x³) = x^3"); 128 | final Object actual = frege.eval("(2³)"); 129 | final Object expected = 8; 130 | assertEquals(expected, actual); 131 | } 132 | 133 | @Test 134 | public void testImportOperators() throws ScriptException { 135 | frege.eval("import Data.Monoid"); 136 | frege.eval("import frege.data.wrapper.Num"); 137 | final Object actual = frege.eval("Sum.unwrap $ Sum 1 <> Sum 0"); 138 | final Object expected = 1; 139 | assertEquals(expected, actual); 140 | } 141 | 142 | @Test 143 | public void testTypeAnnotation() throws ScriptException { 144 | final Object actual = frege.eval("one + one :: Int"); 145 | final Object expected = 2; 146 | assertEquals(expected, actual); 147 | } 148 | 149 | @Test 150 | public void testWhere() throws ScriptException { 151 | final Object actual = frege.eval("x + 3 where x = 5"); 152 | final Object expected = 8; 153 | assertEquals(expected, actual); 154 | } 155 | 156 | @Test 157 | public void testLet() throws ScriptException { 158 | final Object actual = frege.eval("let x = 5 in x + 3"); 159 | final Object expected = 8; 160 | assertEquals(expected, actual); 161 | } 162 | 163 | @Test 164 | public void testTickInName() throws ScriptException { 165 | frege.eval("conanOBrien' = \"It's a-me, Conan O'Brien!\""); 166 | final Object actual = frege.eval("conanOBrien'"); 167 | final Object expected = "It's a-me, Conan O'Brien!"; 168 | assertEquals(expected, actual); 169 | } 170 | 171 | @Test 172 | public void testRebinding() throws ScriptException { 173 | Bindings bindings = frege.getBindings(ENGINE_SCOPE); 174 | bindings.put("bar :: Integer", new BigInteger("12312332142343244")); 175 | final Object actual1 = frege.eval("bar + 3.big"); 176 | final Object expected1 = new BigInteger("12312332142343247"); 177 | bindings.put("bar :: String", "hello "); 178 | final Object actual2 = frege.eval("bar ++ \"world\""); 179 | final Object expected2 = "hello world"; 180 | assertEquals(expected1, actual1); 181 | assertEquals(expected2, actual2); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /frege-interpreter-java-support/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | dependencies { 3 | } 4 | -------------------------------------------------------------------------------- /frege-interpreter-java-support/src/main/java/frege/interpreter/javasupport/CompilationInfo.java: -------------------------------------------------------------------------------- 1 | package frege.interpreter.javasupport; 2 | 3 | import javax.tools.Diagnostic; 4 | import javax.tools.DiagnosticCollector; 5 | import javax.tools.JavaFileObject; 6 | import javax.xml.stream.events.Attribute; 7 | import java.util.Locale; 8 | 9 | public class CompilationInfo { 10 | 11 | private final boolean isSuccess; 12 | private final DiagnosticCollector diagnostics; 13 | 14 | public CompilationInfo(final boolean isSuccess, 15 | final DiagnosticCollector diagnostics) { 16 | this.isSuccess = isSuccess; 17 | this.diagnostics = diagnostics; 18 | } 19 | 20 | public boolean isSuccess() { 21 | return isSuccess; 22 | } 23 | 24 | public String errorsAsString() { 25 | final StringBuilder msgs = new StringBuilder(); 26 | for (final Diagnostic diagnostic : diagnostics 27 | .getDiagnostics()) { 28 | final JavaFileObject source = diagnostic.getSource(); 29 | final String message = String.format("Error:%s[%s:%s]: %s\n", 30 | source != null ? source.getName() : "", 31 | diagnostic.getLineNumber(), diagnostic.getColumnNumber(), 32 | diagnostic.getMessage(Locale.getDefault())); 33 | msgs.append(message); 34 | } 35 | return msgs.toString(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /frege-interpreter-java-support/src/main/java/frege/interpreter/javasupport/InterpreterClassLoader.java: -------------------------------------------------------------------------------- 1 | package frege.interpreter.javasupport; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.InputStream; 5 | import java.net.URL; 6 | import java.net.URLClassLoader; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public class InterpreterClassLoader extends URLClassLoader { 11 | private final Map classes; 12 | 13 | public InterpreterClassLoader() { 14 | this(Thread.currentThread().getContextClassLoader(), new HashMap<>()); 15 | } 16 | 17 | public InterpreterClassLoader(final Map classes) { 18 | this(Thread.currentThread().getContextClassLoader(), classes); 19 | } 20 | 21 | public InterpreterClassLoader(final ClassLoader parent) { 22 | this(parent, new HashMap<>()); 23 | } 24 | 25 | public InterpreterClassLoader(final ClassLoader parent, 26 | final Map classFiles) { 27 | super(new URL[0], parent); 28 | this.classes = new HashMap<>(classFiles); 29 | } 30 | 31 | @Override 32 | protected Class findClass(final String className) 33 | throws ClassNotFoundException { 34 | byte[] bytecode = classes.get(className); 35 | if (bytecode == null) 36 | bytecode = classes.get(className.replace('.', '/')); 37 | 38 | if (bytecode != null) return defineClass(className, bytecode, 0, bytecode.length); 39 | else { 40 | final Class clazz = super.findClass(className); 41 | return clazz; 42 | } 43 | } 44 | 45 | @Override 46 | public InputStream getResourceAsStream(final String name) { 47 | final InputStream contents = super.getResourceAsStream(name); 48 | if (contents != null) { 49 | return contents; 50 | } 51 | if (name.endsWith(".class")) { 52 | final String noSuffix = name.substring(0, name.lastIndexOf('.')); 53 | final String relativeName; 54 | if (name.startsWith("/")) { 55 | relativeName = noSuffix.substring(1); 56 | } else { 57 | relativeName = noSuffix; 58 | } 59 | final String className = relativeName.replace('/', '.'); 60 | final byte[] bytecode = classes.get(className); 61 | if (bytecode != null) { 62 | return new ByteArrayInputStream(bytecode); 63 | } 64 | } 65 | return null; 66 | } 67 | 68 | public Map classes() { 69 | return new HashMap<>(classes); 70 | } 71 | } -------------------------------------------------------------------------------- /frege-interpreter-java-support/src/main/java/frege/interpreter/javasupport/JavaUtils.java: -------------------------------------------------------------------------------- 1 | package frege.interpreter.javasupport; 2 | 3 | import frege.runtime.Runtime; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.FilePermission; 7 | import java.io.PrintWriter; 8 | import java.io.StringReader; 9 | import java.io.StringWriter; 10 | import java.security.Permission; 11 | import java.util.concurrent.Callable; 12 | import java.util.concurrent.FutureTask; 13 | import java.util.concurrent.TimeUnit; 14 | import java.util.concurrent.atomic.AtomicBoolean; 15 | 16 | public class JavaUtils { 17 | 18 | public static Object fieldValue(final String className, 19 | final String variableName, final InterpreterClassLoader loader) { 20 | final Class clazz; 21 | try { 22 | clazz = loader.loadClass(className); 23 | return unwrapThunk(clazz.getDeclaredField(variableName).get(null)); 24 | } catch (Exception e) { 25 | throw new RuntimeException(e); 26 | } 27 | } 28 | 29 | public static Object unwrapThunk(Object possibleThunk) { 30 | if (possibleThunk instanceof frege.run8.Thunk) { 31 | return ((frege.run8.Thunk) possibleThunk).call(); 32 | } else if (possibleThunk instanceof frege.run7.Thunk) { 33 | return ((frege.run7.Thunk) possibleThunk).call(); 34 | } else { 35 | return possibleThunk; 36 | } 37 | } 38 | 39 | public static Object sandboxFieldValue(final String className, 40 | final String variableName, 41 | final String stdinStr, 42 | final StringWriter outWriter, 43 | final StringWriter errWriter, 44 | final InterpreterClassLoader loader) { 45 | return sandbox(new FutureTask<>(new Callable() { 46 | @Override 47 | public Object call() throws Exception { 48 | return fieldValueWithRuntime(className, variableName, stdinStr, outWriter, errWriter, loader); 49 | } 50 | }), 5, TimeUnit.SECONDS); 51 | } 52 | 53 | public static Object fieldValueWithRuntime(final String className, 54 | final String variableName, 55 | final String stdinStr, 56 | final StringWriter outWriter, 57 | final StringWriter errWriter, 58 | final InterpreterClassLoader loader) { 59 | prepareRuntime(stdinStr, outWriter, errWriter); 60 | return fieldValue(className, variableName, loader); 61 | } 62 | 63 | private static void prepareRuntime(final String stdinStr, final StringWriter outWriter, final StringWriter errWriter) { 64 | final BufferedReader stdin = new BufferedReader(new StringReader(stdinStr + "\n")); 65 | final PrintWriter stdout = new PrintWriter(outWriter); 66 | final PrintWriter stderr = new PrintWriter(errWriter); 67 | Runtime.stdin.set(stdin); 68 | Runtime.stdout.set(stdout); 69 | Runtime.stderr.set(stderr); 70 | } 71 | 72 | public static V sandbox(final FutureTask task, 73 | final long timeout, 74 | final TimeUnit unit 75 | ) { 76 | 77 | final Thread thread = new Thread(task); 78 | final SecurityManager oldSecurityManager = System.getSecurityManager(); 79 | final AtomicBoolean isDisabled = new AtomicBoolean(false); 80 | final SecurityManager securityManager = new SecurityManager() { 81 | @Override 82 | public void checkPermission(final Permission perm) { 83 | if (!isDisabled.get()) { 84 | if (perm instanceof RuntimePermission) { 85 | final RuntimePermission runtimePerm = (RuntimePermission) perm; 86 | if (runtimePerm.getName().equals("accessDeclaredMembers")) { 87 | return; 88 | } 89 | } else if (perm instanceof FilePermission) { 90 | final FilePermission filePerm = (FilePermission) perm; 91 | final String fileName = filePerm.getName(); 92 | if (filePerm.getActions().equals("read") && 93 | (fileName.endsWith(".jar") || fileName.endsWith(".class"))) { 94 | return; 95 | } 96 | } 97 | super.checkPermission(perm); 98 | } 99 | } 100 | }; 101 | try { 102 | System.setSecurityManager(securityManager); 103 | thread.start(); 104 | return task.get(timeout, unit); 105 | } catch (Exception e) { 106 | isDisabled.set(true); 107 | task.cancel(true); 108 | thread.stop(); 109 | throw new RuntimeException(e); 110 | } finally { 111 | isDisabled.set(true); 112 | System.setSecurityManager(oldSecurityManager); 113 | } 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /frege-interpreter-java-support/src/main/java/frege/interpreter/javasupport/MemoryJavaCompiler.java: -------------------------------------------------------------------------------- 1 | package frege.interpreter.javasupport; 2 | 3 | import javax.tools.DiagnosticCollector; 4 | import javax.tools.JavaCompiler; 5 | import javax.tools.JavaCompiler.CompilationTask; 6 | import javax.tools.JavaFileObject; 7 | import javax.tools.ToolProvider; 8 | import java.io.File; 9 | import java.net.URL; 10 | import java.net.URLClassLoader; 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | public class MemoryJavaCompiler { 17 | private final JavaCompiler compiler; 18 | private MemoryStoreManager fileManager; 19 | private final InterpreterClassLoader classLoader; 20 | 21 | public MemoryJavaCompiler(final InterpreterClassLoader classLoader) { 22 | compiler = ToolProvider.getSystemJavaCompiler(); 23 | if (compiler == null) { 24 | throw new IllegalStateException("Error: Java compiler not found. " 25 | + "Java Compiler API, tools.jar should be available on classpath. " 26 | + "Use the JVM that comes with the JDK, not JRE."); 27 | } 28 | fileManager = new MemoryStoreManager(compiler.getStandardFileManager(null, null, null), classLoader); 29 | this.classLoader = classLoader; 30 | } 31 | 32 | public CompilationInfo compile(final Map sources, 33 | final Iterable options) { 34 | final DiagnosticCollector diagnostics = 35 | new DiagnosticCollector<>(); 36 | final Iterable compilationUnits = 37 | toSourceFiles(sources, fileManager); 38 | final CompilationTask task = compiler.getTask(null, fileManager, 39 | diagnostics, options, null, compilationUnits); 40 | final boolean isSuccess = task.call(); 41 | return new CompilationInfo(isSuccess, diagnostics); 42 | } 43 | 44 | public CompilationInfo compile(final Map sources) { 45 | // TODO The version is hardcoded as the Frege compiler for Java 8 is still not available on Maven central 46 | /* 47 | * Sorry, but I need a repl where I can just point to the latest compiler. 48 | * -- Ingo 49 | */ 50 | 51 | final String version = "1.8"; //getJvmVersion(); 52 | List options = new ArrayList<>(); 53 | options.add("-source"); 54 | options.add(version); 55 | options.add("-target"); 56 | options.add(version); 57 | 58 | if (classLoader.getParent() instanceof URLClassLoader) { 59 | URLClassLoader urlClassLoader = (URLClassLoader) classLoader.getParent(); 60 | options.add("-classpath"); 61 | StringBuilder sb = new StringBuilder(); 62 | for (URL url : urlClassLoader.getURLs()) 63 | sb.append(url.getFile()).append(File.pathSeparator); 64 | options.add(sb.toString()); 65 | } 66 | return compile(sources, options); 67 | } 68 | 69 | public CompilationInfo compile( 70 | final String sourceCode, final String className) { 71 | final Map sources = new HashMap<>(); 72 | sources.put(className, sourceCode); 73 | return compile(sources); 74 | } 75 | 76 | public InterpreterClassLoader classLoader() { 77 | return fileManager.getClassLoader(); 78 | } 79 | 80 | private Iterable toSourceFiles( 81 | final Map source, final MemoryStoreManager fileManager) { 82 | final List files = new ArrayList<>(); 83 | for (final Map.Entry entry : source.entrySet()) { 84 | final JavaFileObject sourceFile = MemoryStoreManager.makeStringSource(entry.getKey(), 85 | entry.getValue().toString()); 86 | files.add(sourceFile); 87 | fileManager.putFileForInput(entry.getKey(), sourceFile); 88 | } 89 | return files; 90 | } 91 | } -------------------------------------------------------------------------------- /frege-interpreter-java-support/src/main/java/frege/interpreter/javasupport/MemoryStoreManager.java: -------------------------------------------------------------------------------- 1 | package frege.interpreter.javasupport; 2 | 3 | import javax.tools.FileObject; 4 | import javax.tools.ForwardingJavaFileManager; 5 | import javax.tools.JavaFileManager; 6 | import javax.tools.JavaFileObject; 7 | import javax.tools.JavaFileObject.Kind; 8 | import javax.tools.SimpleJavaFileObject; 9 | import javax.tools.StandardLocation; 10 | import java.io.ByteArrayInputStream; 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.io.OutputStream; 15 | import java.io.Reader; 16 | import java.io.StringReader; 17 | import java.net.URI; 18 | import java.nio.CharBuffer; 19 | import java.util.ArrayList; 20 | import java.util.Collection; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | import java.util.Set; 24 | 25 | public final class MemoryStoreManager extends 26 | ForwardingJavaFileManager { 27 | 28 | private static final String JAVA_EXTENSION = ".java"; 29 | private final Map byteCodeMap; 30 | private final Map sourceMap; 31 | private final InterpreterClassLoader classLoader; 32 | 33 | public MemoryStoreManager(final JavaFileManager fileManager, 34 | final InterpreterClassLoader classLoader) { 35 | super(fileManager); 36 | this.classLoader = classLoader; 37 | this.byteCodeMap = toMemoryJavaClassMap(classLoader.classes()); 38 | sourceMap = new HashMap<>(); 39 | } 40 | 41 | private Map toMemoryJavaClassMap(final Map byteCodeMap) { 42 | Map result = new HashMap<>(); 43 | for (Map.Entry classNameByteCode: byteCodeMap.entrySet()) 44 | result.put(classNameByteCode.getKey(), 45 | new MemoryJavaClass(classNameByteCode.getKey(), classNameByteCode.getValue())); 46 | 47 | return result; 48 | } 49 | 50 | @Override 51 | public String inferBinaryName(final Location location, 52 | final JavaFileObject file) { 53 | if (file instanceof MemoryJavaClass) { 54 | return file.getName(); 55 | } else { 56 | return super.inferBinaryName(location, file); 57 | } 58 | } 59 | 60 | @Override 61 | public Iterable list(final Location location, 62 | final String packageName, final Set kinds, 63 | final boolean recurse) throws IOException { 64 | final Iterable result = super.list(location, 65 | packageName, kinds, recurse); 66 | final ArrayList files = new ArrayList<>(); 67 | if (location == StandardLocation.CLASS_PATH 68 | && kinds.contains(Kind.CLASS)) { 69 | for (final JavaFileObject file : byteCodeMap.values()) { 70 | if (file.getName().startsWith(packageName)) 71 | files.add(file); 72 | } 73 | } else if (location == StandardLocation.SOURCE_PATH 74 | && kinds.contains(Kind.SOURCE)) { 75 | for (final JavaFileObject file : sourceMap.values()) { 76 | if (file.getName().startsWith(packageName)) 77 | files.add(file); 78 | } 79 | } 80 | for (final JavaFileObject file : result) { 81 | files.add(file); 82 | } 83 | return files; 84 | } 85 | 86 | private static class MemoryJavaSource extends SimpleJavaFileObject { 87 | private final String code; 88 | 89 | private MemoryJavaSource(final String name, final String code) { 90 | super(toURI(StandardLocation.SOURCE_PATH, name), Kind.SOURCE); 91 | this.code = code; 92 | } 93 | 94 | @Override 95 | public CharBuffer getCharContent(final boolean ignoreEncodingErrors) { 96 | return CharBuffer.wrap(code); 97 | } 98 | 99 | @Override 100 | public Reader openReader(final boolean ignoreEncodingErrors) 101 | throws IOException { 102 | return new StringReader(code); 103 | } 104 | 105 | @Override 106 | public String toString() { 107 | return String.format("MemoryJavaSource[%s, %s]", getName(), code); 108 | } 109 | } 110 | 111 | private class MemoryJavaClass extends SimpleJavaFileObject { 112 | private final String name; 113 | private ByteArrayOutputStream byteCodeOutputStream; 114 | private byte[] bytecode; 115 | 116 | private MemoryJavaClass(final String name) { 117 | super(toURI(StandardLocation.CLASS_PATH, name), Kind.CLASS); 118 | byteCodeMap.put(name, this); 119 | this.name = name; 120 | } 121 | 122 | private MemoryJavaClass(final String name, final byte[] bytecode) { 123 | super(toURI(StandardLocation.CLASS_PATH, name), Kind.CLASS); 124 | this.name = name; 125 | this.bytecode = bytecode; 126 | } 127 | 128 | @Override 129 | public OutputStream openOutputStream() { 130 | byteCodeOutputStream = new ByteArrayOutputStream(); 131 | return byteCodeOutputStream; 132 | } 133 | 134 | @Override 135 | public InputStream openInputStream() throws IOException { 136 | return new ByteArrayInputStream(getByteCode()); 137 | } 138 | 139 | public byte[] getByteCode() { 140 | return bytecode != null ? bytecode : byteCodeOutputStream.toByteArray(); 141 | } 142 | 143 | @Override 144 | public String getName() { 145 | return name; 146 | } 147 | 148 | @Override 149 | public String toString() { 150 | return String.format("MemoryJavaClass[%s]", name); 151 | } 152 | } 153 | 154 | @Override 155 | public ClassLoader getClassLoader(final Location location) { 156 | return getClassLoader(); 157 | } 158 | 159 | @Override 160 | public void flush() throws IOException { 161 | } 162 | 163 | @Override 164 | public void close() throws IOException { 165 | } 166 | 167 | InterpreterClassLoader getClassLoader() { 168 | Collection bytecodes = byteCodeMap.values(); 169 | Map bytecodeMap = new HashMap<>(); 170 | for (MemoryJavaClass memoryJavaClass: bytecodes) { 171 | bytecodeMap.put(memoryJavaClass.getName(), memoryJavaClass.getByteCode()); 172 | } 173 | return new InterpreterClassLoader(classLoader.getParent(), bytecodeMap); 174 | } 175 | 176 | @Override 177 | public JavaFileObject getJavaFileForOutput(final Location location, 178 | final String name, final Kind kind, final FileObject sibling) 179 | throws IOException { 180 | final String className = toClassName(name); 181 | if (kind == Kind.CLASS) { 182 | return new MemoryJavaClass(className); 183 | } else { 184 | return super.getJavaFileForOutput(location, name, kind, 185 | sibling); 186 | } 187 | } 188 | 189 | private static String toClassName(final String name) { 190 | return name.replaceAll("[/\\\\]", "."); 191 | } 192 | 193 | public void putFileForInput(final Location location, 194 | final String packageName, final String relativeName, 195 | final JavaFileObject file) { 196 | sourceMap.put(toURI(location, packageName, relativeName), file); 197 | } 198 | 199 | public void putFileForInput(final String javaFilePath, 200 | final JavaFileObject file) { 201 | sourceMap.put(toURI(StandardLocation.SOURCE_PATH, javaFilePath), file); 202 | } 203 | 204 | @Override 205 | public FileObject getFileForInput(final Location location, 206 | final String packageName, final String relativeName) 207 | throws IOException { 208 | final URI uri = toURI(location, packageName, relativeName); 209 | if (sourceMap.containsKey(uri)) { 210 | return sourceMap.get(uri); 211 | } else { 212 | return super.getFileForInput(location, packageName, relativeName); 213 | } 214 | } 215 | 216 | public static JavaFileObject makeStringSource(final String name, 217 | final String code) { 218 | return new MemoryJavaSource(name, code); 219 | } 220 | 221 | private URI toURI(final Location location, final String packageName, final String relativeName) { 222 | String name = packageName + "." + relativeName; 223 | return toURI(location, name); 224 | } 225 | 226 | private static URI toURI(final Location location, final String name) { 227 | final String qualifiedClassName; 228 | final String extension; 229 | if (location == StandardLocation.SOURCE_PATH) { 230 | final String noExtPath = name.endsWith(JAVA_EXTENSION) ? name 231 | .substring(0, name.lastIndexOf('.')) : name; 232 | qualifiedClassName = noExtPath.replace('/', '.').replace('\\', '.'); 233 | extension = JAVA_EXTENSION; 234 | } else { // Class Path 235 | qualifiedClassName = name.replace("[/\\\\]", "."); 236 | extension = ""; 237 | } 238 | final String className = className(qualifiedClassName); 239 | final int lastDot = qualifiedClassName.lastIndexOf('.'); 240 | final URI uri; 241 | if (lastDot < 0) { 242 | uri = createUri(location, className, extension); 243 | } else { 244 | final String packName = qualifiedClassName.substring(0, lastDot); 245 | uri = createUri(location, packName, className, extension); 246 | } 247 | return uri; 248 | } 249 | 250 | private static URI createUri(final Location location, final String className, final String extension) { 251 | final String classNameWithSep = className.replace('.', '/'); 252 | final String uriString = String.format("file:///%s%s", classNameWithSep, extension); 253 | return URI.create(uriString); 254 | } 255 | 256 | private static URI createUri(final Location location, 257 | final String packName, 258 | final String className, 259 | final String extension) { 260 | final String classNameWithSep = className.replace('.', '/'); 261 | final String packNameWithSep = packName.replace('.', '/'); 262 | final String uriString = String.format("file:///%s/%s%s", packNameWithSep, 263 | classNameWithSep, extension); 264 | return URI.create(uriString); 265 | } 266 | 267 | private static String className(final String qualifiedClassName) { 268 | return qualifiedClassName.substring(qualifiedClassName.lastIndexOf('.') + 1); 269 | } 270 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | 2 | signingEnabled = false 3 | 4 | -------------------------------------------------------------------------------- /gradle/sonatype.gradle: -------------------------------------------------------------------------------- 1 | 2 | ext { 3 | 4 | sonatypeBaseUrl = "https://oss.sonatype.org" 5 | sonatypeSnapshotUrl = "$sonatypeBaseUrl/content/repositories/snapshots/" 6 | sonatypeRepositoryUrl = "$sonatypeBaseUrl/content/groups/public" 7 | sonatypeReleaseUrl = "$sonatypeBaseUrl/service/local/staging/deploy/maven2/" 8 | sonatypeUploadUrl = isSnapshot ? sonatypeSnapshotUrl : sonatypeReleaseUrl 9 | 10 | sonatypeUsername = project.hasProperty('sonatypeUsername') ? sonatypeUsername : System.getenv('sonatypeUsername') 11 | sonatypePassword = project.hasProperty('sonatypePassword') ? sonatypePassword : System.getenv('sonatypePassword') 12 | 13 | projectUrl ="https://github.com/Frege/frege-interpreter" 14 | projectName = "Frege Interpreter" 15 | pomProjectName = projectName 16 | 17 | groupName = "org.frege-lang" 18 | scmUrl = "git://github.com:Frege/frege-interpreter.git" 19 | scmGitFile = "scm:git@github.com:Frege/frege-interpreter.git" 20 | projectDescription = projectName 21 | 22 | licenseName = "BSD 3-clause license" 23 | licenseUrl = 'http://opensource.org/licenses/BSD-3-Clause' 24 | 25 | organisation = groupName 26 | primaryEmail = "frege-programming-language@googlegroups.com" 27 | } 28 | 29 | Boolean doSigning() { 30 | signingEnabled.trim() == "true" 31 | } 32 | 33 | task javadocJar(type: Jar, dependsOn: "javadoc") { 34 | classifier = 'javadoc' 35 | from "build/docs/javadoc" 36 | } 37 | 38 | task sourcesJar(type: Jar) { 39 | from sourceSets.main.allSource 40 | classifier = 'sources' 41 | } 42 | 43 | artifacts { 44 | archives jar 45 | archives javadocJar 46 | archives sourcesJar 47 | } 48 | 49 | signing { 50 | required { doSigning() } 51 | sign configurations.archives 52 | } 53 | 54 | uploadArchives { 55 | enabled = true 56 | repositories { 57 | mavenDeployer { 58 | if (doSigning()) { 59 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 60 | } 61 | 62 | repository(url: sonatypeUploadUrl) { 63 | authentication(userName: sonatypeUsername, password: sonatypePassword) 64 | } 65 | pom { 66 | groupId = groupName 67 | project { 68 | name pomProjectName 69 | packaging 'jar' 70 | description projectDescription 71 | url projectUrl 72 | organization { 73 | name pomProjectName 74 | url projectUrl 75 | } 76 | scm { 77 | url scmUrl 78 | } 79 | licenses { 80 | license { 81 | name licenseName 82 | url licenseUrl 83 | distribution 'repo' 84 | } 85 | } 86 | developers { 87 | developer { 88 | email primaryEmail 89 | } 90 | } 91 | } 92 | } 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Frege/frege-interpreter/f14bdbe79c13341f4a3e023acfb4f8b15c1fc885/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Mar 14 23:14:57 EDT 2016 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | 2 | include "frege-interpreter-core", "frege-interpreter-java-support" 3 | 4 | --------------------------------------------------------------------------------