Skip to content

Commit

Permalink
Merge pull request #28 from Frege/feature/command-line-options
Browse files Browse the repository at this point in the history
Option to generate for either class or package, ability to run via gradle, remove fj dependency
  • Loading branch information
mmhelloworld committed Nov 22, 2015
2 parents cb64135 + 3b8ff93 commit 7adcbd5
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 84 deletions.
35 changes: 23 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,21 +366,32 @@ void=pure,()
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, `java.util.HashSet=st`
or if you want to call it a different name in Frege, add `java.util.HashSet=st,JHashSet`
For example, `java.util.HashSet=st`
or if you want to call it a different name in Frege, add `java.util.HashSet=st,JHashSet`
1. Run `java -cp "lib/*:$JAVA_HOME/jre/lib/*" frege.nativegen.Main -p 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.
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.
* Run `java -cp "lib/*:$JAVA_HOME/jre/lib/*" frege.nativegen.Main -c java.util.List` for a specific class.
* To generate for classes other than those in JDK, add the respective library in the classpath:
`java -cp "/path/to/guava.jar:lib/*" frege.nativegen.Main -p com.google.common.collect`
* Run `java -cp "lib/*:$JAVA_HOME/jre/lib/*" frege.nativegen.Main -h` for help.
###How to run with Gradle###
From project source root,
* For all the classes in a package: `./gradlew run -Poptions="-p java.util"`
* For a specific class: `./gradlew run -Poptions="-c java.util.List"`
* To run with different *types.properties*: `./gradlew run -Poptions="-c java.util.List -t /path/to/types.properties"`
* For help: `./gradlew run -Poptions="-h"`
To generate for classes other than those in JDK, add the respective library in the classpath:
```
java -cp "/path/to/guava.jar:lib/*" frege.nativegen.Main com.google.common.collect
```
## Continuous Integration ##
The Travis CI build of this repository is at https://travis-ci.org/Frege/frege-native-gen.
The Travis CI build of this repository is at [https://travis-ci.org/Frege/frege-native-gen](https://travis-ci.org/Frege/frege-native-gen).
The snapshot builds are automatically deploy to Sonatype at https://oss.sonatype.org/content/groups/public/org/frege-lang/frege-native-gen/.
The snapshot builds are automatically deploy to Sonatype at [https://oss.sonatype.org/content/groups/public/org/frege-lang/frege-native-gen/](https://oss.sonatype.org/content/groups/public/org/frege-lang/frege-native-gen/).
20 changes: 3 additions & 17 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ buildscript {
mavenCentral()
}
dependencies {
// classpath "org.frege-lang:frege-gradle-plugin:0.4.1"
classpath "gradle.plugin.org.frege-lang:frege-gradle-plugin:0.5"
classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.5.3"
}
Expand All @@ -20,31 +19,19 @@ buildscript {
apply plugin: "java"
apply plugin: "maven"
apply plugin: "signing"
//apply plugin: "frege"
apply plugin: "org.frege-lang"
apply plugin: 'io.codearte.nexus-staging'
apply plugin: "application"

//tasks.compileFrege.dependsOn "compileJava"
//
//compileFrege {
// verbose = true
// hints = true
// make = true
// inline = false
//}

mainClassName = "frege.nativegen.Main"

run {
standardInput = System.in
standardOutput = System.out

args = ["fj"]
// args = ["java.util.HashSet"]
// args = ["java.util"]
if (hasProperty("args")) {
// args project.args.split()
if (project.hasProperty("options")) {
String noptions = "-t $rootDir/src/dist/types.properties " + options
args noptions.split(' ')
}
}

Expand Down Expand Up @@ -83,7 +70,6 @@ compileTestFrege {
dependencies {
compile "org.frege-lang:frege:$fregeVersion"
compile "com.google.guava:guava:$guavaVersion"
compile "org.functionaljava:functionaljava:4.4"
}

nexusStaging {
Expand Down
141 changes: 86 additions & 55 deletions src/main/frege/frege/nativegen/Main.fr
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,25 @@ writeModule m outputDir moduleName code deps = do
pw.flush
pw.close

convert :: M.TreeMap String FregeType -> String -> String -> IO ()
convert knownTypes packageName outputDir = do
convertPackage :: M.TreeMap String FregeType -> String -> String -> IO ()
convertPackage 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)
let moduleDeps = map (classDeps knownTypes) classes
mergedDeps = M.each $ M.fromListWith (\(!c1, !d1) \(!c2, !d2) -> (c1 ++ "\n" ++ c2, d1 ++ d2)) moduleDeps
for mergedDeps (\(moduleName, (code, deps)) -> writeModule knownTypes outputDir moduleName code deps)

classDeps knownTypes clazz =
let deps = genFrege knownTypes clazz
nmParts = nameParts clazz
moduleName = intercalate "." nmParts
in (moduleName, deps)

convertClass :: M.TreeMap String FregeType -> String -> String -> IO ()
convertClass knownTypes className outputDir = do
clazzEither <- Class.forName className
let clazz = either throw id clazzEither
(moduleName, (code, deps)) = classDeps knownTypes clazz
writeModule knownTypes outputDir moduleName code deps

writeImports :: M.TreeMap String FregeType -> String -> [RawClass] -> PrintWriter -> IO ()
writeImports m moduleName deps pw = mapM_ write (unique modules) where
Expand All @@ -90,7 +98,7 @@ wildcardToModule m acc wildcard

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

classToModule :: M.TreeMap String FregeType -> [String] -> Class a -> [String]
classToModule m acc clazz = (maybe unknown f $ m.lookup clazz.getName): acc
Expand Down Expand Up @@ -127,62 +135,85 @@ capitalize :: String -> String
capitalize s | (h:t) <- s.toList = packed $ h.toUpperCase : t
capitalize s = s

pure native toString :: a -> String
pure native split :: String -> String -> JArray String

native classesForPackage frege.nativegen.Main.packageClasses :: String -> STMutable s (List (Class a))

native module where {
public static java.util.List<Class<?>> packageClasses(String packageName) {
java.util.List<Class<?>> classes;
java.util.List<Class<?>> classes = new java.util.ArrayList<>();
try {

/*
classes = fj.control.parallel.parMap(
com.google.common.reflect.ClassPath.from(Thread.currentThread().getContextClassLoader()).getTopLevelClassesRecursive(packageName),
new fj.F<com.google.common.reflect.ClassPath.ClassInfo, Class<?>>(){
public Class<?> f(com.google.common.reflect.ClassPath.ClassInfo a) {
return a.load();
}
}
)
*/

classes = fj.data.List.list(
com.google.common.reflect.ClassPath.from(Thread.currentThread().getContextClassLoader())
.getTopLevelClassesRecursive(packageName)
).map(new fj.F<com.google.common.reflect.ClassPath.ClassInfo, Class<?>>(){
public Class<?> f(com.google.common.reflect.ClassPath.ClassInfo a) {
return a.load();
}
}).filter(new fj.F<Class<?>, Boolean>(){
public Boolean f(Class<?> cls) {
return !cls.isSynthetic() && !cls.isAnonymousClass() && !cls.isLocalClass();
}
}).toJavaList();

/*
classes = com.google.common.reflect.ClassPath.from(Thread.currentThread().getContextClassLoader())
.getTopLevelClassesRecursive(packageName)
.parallelStream()
.map(com.google.common.reflect.ClassPath.ClassInfo::load)
.filter(cls -> !cls.isSynthetic() && !cls.isAnonymousClass() && !cls.isLocalClass())
.collect(java.util.stream.Collectors.toList());
*/
com.google.common.collect.ImmutableSet<com.google.common.reflect.ClassPath.ClassInfo> clsInfos =
com.google.common.reflect.ClassPath.from(Thread.currentThread().getContextClassLoader())
.getTopLevelClassesRecursive(packageName);
for (com.google.common.reflect.ClassPath.ClassInfo clsInfo: clsInfos) {
Class<?> cls = clsInfo.load();
if (!cls.isSynthetic() && !cls.isAnonymousClass() && !cls.isLocalClass())
classes.add(cls);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return classes;
}
}

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

main (packageName: _) = main [packageName, "generated-sources"]
parseArgs :: [String] -> Either String Options
parseArgs args = go optDefault args where
optDefault = Options
{ name = ""
, category = Package
, typesFilePath = "types.properties"
, outputDir="generated-sources" }

go optSoFar [] = Options.validate optSoFar
go optSoFar ("-p" : packageName : rest)
= go optSoFar.{name = packageName, category = Package} rest
go optSoFar ("-c" : className : rest)
= go optSoFar.{name = className, category = Class} rest
go optSoFar ("-d" : directory : rest)
= go optSoFar.{outputDir = directory} rest
go optSoFar ("-t" : typesFilePath : rest)
= go optSoFar.{typesFilePath = typesFilePath} rest
go _ (invalidOption:_) = Left $ "Invalid option: " ++ invalidOption

data Category = Package | Class
derive Show Category
derive Eq Category

data Options = Options
{ name :: String
, category :: Category
, typesFilePath :: String
, outputDir :: String }
where

main [] = do
packageName <- prompt "Package name: "
main [packageName]
validate :: Options -> Either String Options
validate options
| null options.name = Left "Missing class or package name"
| null options.typesFilePath = Left "Missing types.properties file path"
| otherwise = Right options

derive Show Options

usage =
[ ("-c", "Class name")
, ("-p", "Package name")
, ("-t", "types.properties file path [Default: ./types.properties]")
, ("-d", "Output directory [Default: ./generated-sources]")
, ("-h", "Show this help")]

printUsage = do
println "Options:"
for usage (\(name, desc) -> println $ name ++ " <" ++ desc ++ ">")

main ("-h": _) = printUsage
main args = do
let handle opts = do
knownTypes <- KnownTypesParser.parseKnownTypes opts.typesFilePath
let converter = if opts.category == Class then convertClass else convertPackage
converter knownTypes opts.name opts.outputDir
err message = do
stderr.println message
printUsage
either err handle $ parseArgs args

0 comments on commit 7adcbd5

Please sign in to comment.