Skip to content

Commit

Permalink
Automatically detect dependencies and generate imports
Browse files Browse the repository at this point in the history
  • Loading branch information
mmhelloworld committed Nov 8, 2015
1 parent f005fee commit a4262b1
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 73 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
bin/
target/

dist/

#Gradle application plugin static files
!src/dist

.idea/
.settings/

Expand Down
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,18 +361,21 @@ void=pure,()
##How to run##
1. Download and extract `frege-native-gen-XX.zip` from [releases](https://github.com/Frege/frege-native-gen/releases) where `XX` is the version. The `types.properties` is included in the zip.
2. Mention your class name along with it's purity in **types.properties**.
1. Download and extract `frege-native-gen-<version>.zip` from [releases](https://github.com/Frege/frege-native-gen/releases).
The `types.properties` is included in the zip.
1. Mention your class name along with it's purity in **types.properties**.
For example, to generate for `java.util.HashSet`, add `java.util.HashSet=st`
For example, `java.util.HashSet=st`
or if you want to call it a different name in Frege, add `java.util.HashSet=st,JHashSet`
3. Run `java -jar frege-native-gen-XX.jar java.util.HashSet`
1. Run `java -cp "lib/*:$JAVA_HOME/jre/lib/*" frege.nativegen.Main java.util`
This would convert all the classes in `java.util` package including sub packages and create corresponding Frege modules (one Frege module per package).
The generated sources will be in `generated-sources` folder.
To generate for a third party class (In this example, a class from Guava library):
To generate for classes other than those in JDK, add the respective library in the classpath:
```
java -cp /path/to/guava-15.0.jar:lib/frege-YY.jar:frege-native-gen-XX.jar frege.nativegen.Main com.google.common.collect.ImmutableCollection
java -cp "/path/to/guava.jar:lib/*" frege.nativegen.Main com.google.common.collect
```
where `XX` and `YY` are the versions of the jar files in the downloaded zip.
## Continuous Integration ##
Expand Down
5 changes: 1 addition & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ compileFrege {
}

mainClassName = "frege.nativegen.Main"
applicationName = "fregeffi"

run{
standardInput = System.in
Expand All @@ -50,9 +49,7 @@ ext {
snapshotAppendix = "-SNAPSHOT"
projectVersion = baseVersion + (isSnapshot ? snapshotAppendix : "")

fregeBaseVersion = "3.22.524"
fregeClassifier = "-gcc99d7e"
fregeVersion = "$fregeBaseVersion$fregeClassifier"
fregeVersion = "3.23.370-g898bc8c"

guavaVersion = "18.0"
}
Expand Down
File renamed without changes.
102 changes: 75 additions & 27 deletions src/main/frege/frege/nativegen/Main.fr
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
module frege.nativegen.Main where

import frege.Prelude hiding (Class, ClassLoader)
import frege.nativegen.NativeGen
import frege.nativegen.NativeGen hiding (packageName)
import frege.nativegen.java.Lang
import frege.nativegen.java.Reflect
import Data.TreeMap as M()
import Data.List (intercalate)
import Data.List (intercalate, unique)
import Java.Util (List, Iterator)

abstract data KnownTypesParser = KnownTypesParser
Expand All @@ -17,10 +18,10 @@ abstract data KnownTypesParser = KnownTypesParser

parseKey key = classFor $ packed key

parseValue cls "" = FregeType (classToFregeName cls) cls.getName Pure
parseValue cls "" = FregeType (classToFregeName cls) (Class.asRaw cls) Pure
parseValue cls value = case break (== ',') value.toList of
(purity, []) -> FregeType (classToFregeName cls) cls.getName (parsePurity $ packed purity)
(purity, _:fname) -> FregeType (packed fname) cls.getName (parsePurity $ packed purity)
(purity, []) -> FregeType (classToFregeName cls) (Class.asRaw cls) (parsePurity $ packed purity)
(purity, _:fname) -> FregeType (packed fname) (Class.asRaw cls) (parsePurity $ packed purity)

classToFregeName cls
| cls.isArray = "JArray " ++ cls.getComponentType.getCanonicalName
Expand All @@ -42,37 +43,73 @@ prompt promptStr = do
stdout.flush
getLine

main = do
knownTypes <- KnownTypesParser.parseKnownTypes "types.properties"
classLoader <- ClassLoader.current
packageName <- prompt "Package name: "
outputDir <- prompt "Output directory: "
classes <- classesForPackage packageName >>= List.iterator >>= Iterator.toList
forM_ classes $ convert knownTypes outputDir

convert :: M.Tree String FregeType -> String -> Class a -> IO ()
convert knownTypes outputDir clazz = do
let nmParts = nameParts clazz
fileName <- calculateFileName clazz outputDir nmParts
f <- File.new fileName
exists <- f.exists
writeModule :: M.TreeMap String FregeType -> String -> String -> String -> [RawClass] -> IO ()
writeModule m outputDir moduleName code deps = do
let fileName = calculateFileName outputDir moduleName
exists <- File.new fileName >>= File.exists
pw <- createPrintWriter fileName
let moduleName = intercalate "." nmParts
moduleDecl = "module " ++ moduleName ++ " where\n"
let moduleDecl = "module " ++ moduleName ++ " where\n"
when (not exists) (pw.println moduleDecl)
pw.println $ genFrege knownTypes clazz
writeImports m deps pw
pw.println
pw.println code
pw.flush
pw.close

convert :: M.TreeMap String FregeType -> String -> String -> IO ()
convert knownTypes packageName outputDir = do
classes <- classesForPackage packageName >>= List.iterator >>= Iterator.toList
let clsDeps clazz = do
let deps = genFrege knownTypes clazz
nmParts = nameParts clazz
moduleName = intercalate "." nmParts
return (moduleName, deps)
deps <- mapM clsDeps classes
let mergedDeps = M.each $ M.fromListWith (\(!c1, !d1) \(!c2, !d2) -> (c1 ++ "\n" ++ c2, d1 ++ d2)) deps
forM_ mergedDeps (\(moduleName, (code, deps)) -> writeModule knownTypes outputDir moduleName code deps)

writeImports :: M.TreeMap String FregeType -> [RawClass] -> PrintWriter -> IO ()
writeImports m deps pw = mapM_ write (unique modules) where
write modul = pw.println $ "import " ++ modul
modules = deps >>= (typeToModule m [] . Class.asType . RawClass.asClass)

typeToModule :: M.TreeMap String FregeType -> [String] -> Type -> [String]
typeToModule m acc jtype
| jtype <:? TypeVariable.getClass = acc
| jtype <:? WildcardType.getClass = wildcardToModule m acc $ jtype `asInstanceOf` WildcardType.getClass
| jtype <:? GenericArrayType.getClass = acc
| jtype <:? ParameterizedType.getClass = parameterizedTypeToModule m acc $ jtype `asInstanceOf` ParameterizedType.getClass
| jtype <:? Class.getClass = classToModule m acc $ jtype `asInstanceOf` Class.getClass
| otherwise = acc

wildcardToModule :: M.TreeMap String FregeType -> [String] -> WildcardType -> [String]
wildcardToModule m acc wildcard
| wildcard.getLowerBounds.length != 0 = typeToModule m acc wildcard.getLowerBounds.[0]
| otherwise = typeToModule m acc wildcard.getUpperBounds.[0]

parameterizedTypeToModule :: M.TreeMap String FregeType -> [String] -> ParameterizedType -> [String]
parameterizedTypeToModule m acc ptype =
typeToModule m acc ptype.getRawType ++ (ptype.getActualTypeArguments.toList >>= (\t -> typeToModule m [] t))

classToModule :: M.TreeMap String FregeType -> [String] -> Class a -> [String]
classToModule m acc clazz = (maybe unknown f $ m.lookup clazz.getName): acc
where
unknown = packageName clazz

f :: FregeType -> String
f fregeType = packageName fregeType.jtype.asClass

packageName :: Class a -> String
packageName cls | cls.isArray = packageName cls.getComponentType
packageName cls = intercalate "." $ nameParts cls

createPrintWriter fileName = do
f <- File.new fileName
f.getParentFile >>= (maybe (return false) (File.mkdirs))
FileWriter.new fileName true >>= BufferedWriter.new >>= PrintWriter.new

calculateFileName :: Class a -> String -> [String] -> IO String
calculateFileName clazz outputDir nameParts = do
let relativeFileName = intercalate "/" nameParts
return $ outputDir ++ "/" ++ relativeFileName ++ ".fr"
calculateFileName :: String -> String -> String
calculateFileName outputDir moduleName = outputDir ++ "/" ++ (replace moduleName "." "/") ++ ".fr"

nameParts :: Class a -> [String]
nameParts clazz = init packageNameParts ++ [fileName] where
Expand Down Expand Up @@ -109,4 +146,15 @@ native module where {
}
return classes;
}
}
}

main (packageName: outputDir: _) = do
knownTypes <- KnownTypesParser.parseKnownTypes "types.properties"
classLoader <- ClassLoader.current
convert knownTypes packageName outputDir

main (packageName: _) = main [packageName, "generated-sources"]

main [] = do
packageName <- prompt "Package name: "
main [packageName]
Loading

0 comments on commit a4262b1

Please sign in to comment.