Skip to content
Snippets Groups Projects
Verified Commit 42906dd5 authored by Rico Bergmann's avatar Rico Bergmann
Browse files

[WIP] Invoke compiler to create .class files

parent 4e86bea9
No related branches found
No related tags found
2 merge requests!2Publish v0.1,!1Move away from experimental changes
val emfcommonVersion = "2.12.0" val emfcommonVersion = "2.12.0"
val emfecoreVersion = "2.12.0" val emfecoreVersion = "2.12.0"
val scrollVersion = "1.6"
name := "CodeGenerator" name := "CodeGenerator"
...@@ -11,7 +12,8 @@ libraryDependencies ++= Seq( ...@@ -11,7 +12,8 @@ libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value, "org.scala-lang" % "scala-reflect" % scalaVersion.value,
"org.scala-lang" % "scala-compiler" % scalaVersion.value, "org.scala-lang" % "scala-compiler" % scalaVersion.value,
"org.eclipse.emf" % "org.eclipse.emf.common" % emfcommonVersion, "org.eclipse.emf" % "org.eclipse.emf.common" % emfcommonVersion,
"org.eclipse.emf" % "org.eclipse.emf.ecore" % emfecoreVersion "org.eclipse.emf" % "org.eclipse.emf.ecore" % emfecoreVersion,
"com.github.max-leuthaeuser" %% "scroll" % scrollVersion
) )
scalacOptions ++= Seq( scalacOptions ++= Seq(
......
...@@ -9,7 +9,7 @@ import org.rosi_project.model_sync.generator.sync_model.SModelVisitor ...@@ -9,7 +9,7 @@ import org.rosi_project.model_sync.generator.sync_model.SModelVisitor
class SClass(val name: String, class SClass(val name: String,
val attributes: Seq[SAttribute], val attributes: Seq[SAttribute],
val sPackage: String = "", val sPackage: String = "",
val parent: SClass = null, var parent: STypedElement = null,
var methods: Seq[SMethod] = Seq.empty) var methods: Seq[SMethod] = Seq.empty)
extends STypedElement { extends STypedElement {
...@@ -18,7 +18,7 @@ class SClass(val name: String, ...@@ -18,7 +18,7 @@ class SClass(val name: String,
def isRootClass: Boolean = parent == null def isRootClass: Boolean = parent == null
def collectImports: Set[String] = { def collectImports: Set[String] = {
val parentImport: List[String] = if (isRootClass) List() else includeImportIfNecessary(parent.sPackage, parent.name) val parentImport: List[String] = if (isRootClass) List() else includeImportIfNecessary(parent.getPackage, parent.getName)
val attrTypeImports: List[String] = val attrTypeImports: List[String] =
attributes attributes
...@@ -48,18 +48,22 @@ class SClass(val name: String, ...@@ -48,18 +48,22 @@ class SClass(val name: String,
(parentImport ++ attrTypeImports ++ methodResultImports ++ methodParamImports ++ methodImplImports).toSet (parentImport ++ attrTypeImports ++ methodResultImports ++ methodParamImports ++ methodImplImports).toSet
} }
def getConstructorParameters: Seq[SMethodParameter] = {
val ownParams = attributes.map(attr => SMethodParameter(attr.name, attr.attrType))
val parentParams = if (isRootClass) List() else parent.getConstructorParameters
ownParams ++ parentParams
}
def addMethod(m: SMethod): Unit = methods = methods :+ m def addMethod(m: SMethod): Unit = methods = methods :+ m
def setParent(parent: STypedElement): Unit = this.parent = parent
override def getName: String = name override def getName: String = name
override def getPackage: String = sPackage override def getPackage: String = sPackage
override def getConstructorParameters: Seq[SMethodParameter] = {
val ownParams = attributes.map(attr => SMethodParameter(attr.name, attr.attrType))
val parentParams = if (isRootClass) List() else parent.getConstructorParameters
ownParams ++ parentParams
}
override def getInheritanceHierarchy: Seq[STypedElement] = if (isRootClass) List(this) else this +: parent.getInheritanceHierarchy
override def accept(visitor: SModelVisitor): Unit = { override def accept(visitor: SModelVisitor): Unit = {
attributes.foreach(_.accept(visitor)) attributes.foreach(_.accept(visitor))
methods.foreach(_.accept(visitor)) methods.foreach(_.accept(visitor))
...@@ -67,7 +71,9 @@ class SClass(val name: String, ...@@ -67,7 +71,9 @@ class SClass(val name: String,
} }
private def includeImportIfNecessary(sPackage: String, sClass: String): List[String] = { private def includeImportIfNecessary(sPackage: String, sClass: String): List[String] = {
if (sPackage != sPackage && sPackage != "") List(s"$sPackage.$sClass") else List() if (sPackage != this.sPackage && sPackage != "") List(s"$sPackage.$sClass") else List()
} }
override def toString: String = s"$name"
} }
...@@ -9,4 +9,8 @@ trait STypedElement extends SModelElement { ...@@ -9,4 +9,8 @@ trait STypedElement extends SModelElement {
def getPackage: String def getPackage: String
def getConstructorParameters: Seq[SMethodParameter] = Seq.empty
def getInheritanceHierarchy: Seq[STypedElement] = Seq.empty
} }
...@@ -58,7 +58,7 @@ class SClassWriter(val modelClass: SClass) { ...@@ -58,7 +58,7 @@ class SClassWriter(val modelClass: SClass) {
val constructor = s"(${params.mkString(", ")})" val constructor = s"(${params.mkString(", ")})"
var baseFixture = s"${modelClass.getName}$constructor" var baseFixture = s"${modelClass.getName}$constructor"
if (modelClass.isRootClass) baseFixture else s"$baseFixture extends ${modelClass.parent.name}$parentConstructor" if (modelClass.isRootClass) baseFixture else s"$baseFixture extends ${modelClass.parent.getName}$parentConstructor"
} }
private def firstLetterToUpperCase(str: String): String = { private def firstLetterToUpperCase(str: String): String = {
......
package org.rosi_project.model_sync.generator.io package org.rosi_project.model_sync.generator.io
import java.io.{FileOutputStream, PrintWriter}
import java.net.URLClassLoader
import java.nio.file.Files import java.nio.file.Files
import java.util.jar.{Attributes, JarOutputStream, Manifest}
import org.rosi_project.model_sync.generator.acr.{SAttribute, SClass, SMethod, SType} import org.rosi_project.model_sync.generator.acr.{SAttribute, SClass, SMethod, SType}
import org.rosi_project.model_sync.generator.sync_model.{SModel, SModelVisitor} import org.rosi_project.model_sync.generator.sync_model.{SModel, SModelVisitor}
import scala.reflect.io.{File, Path} import scala.reflect.io.{File, Path}
import scala.tools.nsc.Main import scala.tools.nsc.reporters.ConsoleReporter
import scala.tools.nsc.{GenericRunnerSettings, Global, Settings}
/** /**
* @author Rico Bergmann * @author Rico Bergmann
...@@ -20,19 +24,37 @@ class SModelFSWriter extends SModelVisitor { ...@@ -20,19 +24,37 @@ class SModelFSWriter extends SModelVisitor {
override def visit(sModel: SModel): Unit = { override def visit(sModel: SModel): Unit = {
println(s"... Wrote files (sources) $sFilesToCompile") println(s"... Wrote files (sources) $sFilesToCompile")
println("... Starting compilation")
val compiler = Main.newCompiler()
println("... Starting compilation")
val out = new PrintWriter(System.out)
val compilationSettings: Settings = new GenericRunnerSettings(out.println)
// TODO do we want to reuse the whole classpath? Or just the parts we _actually_ need
compilationSettings.classpath.value = adaptClassPathToOSEnv(fetchCurrentClassPath).distinct.mkString(File.pathSeparator)
println(s"Using classpath ${compilationSettings.classpath.value}")
compilationSettings.outdir.value = baseOutputDir.toAbsolute.toString
val reporter = new ConsoleReporter(compilationSettings)
val compiler = new Global(compilationSettings, reporter)
val runner = new compiler.Run
runner.compile(sFilesToCompile.map(_.toAbsolute.toString))
println("... Compilation done") println("... Compilation done")
println("... Cleaning up") println("... Cleaning up")
sFilesToCompile.foreach{_.delete}
println("... Generating JAR") println("... Generating JAR")
// see: https://stackoverflow.com/questions/1281229/how-to-use-jaroutputstream-to-create-a-jar-file
val mf = new Manifest
mf.getMainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0")
val targetJar = new JarOutputStream(new FileOutputStream("model.jar"), mf)
// TODO fill the JAR
targetJar.close()
println("... Done") println("... Done")
} }
override def visit(sClass: SClass): Unit = { override def visit(sClass: SClass): Unit = {
println(s"Writing class $sClass")
val classNameWithPath = baseOutputDir.toAbsolute.toString() + pckg2Path(sClass.getPackage) + File.separator + s"${sClass.name}.scala" val classNameWithPath = baseOutputDir.toAbsolute.toString() + pckg2Path(sClass.getPackage) + File.separator + s"${sClass.name}.scala"
val writer = new SClassWriter(sClass) val writer = new SClassWriter(sClass)
val classFile = File(classNameWithPath) val classFile = File(classNameWithPath)
...@@ -55,4 +77,29 @@ class SModelFSWriter extends SModelVisitor { ...@@ -55,4 +77,29 @@ class SModelFSWriter extends SModelVisitor {
private def pckg2Path(pckg: String): Path = Path(pckg.replace(".", File.separator)) private def pckg2Path(pckg: String): Path = Path(pckg.replace(".", File.separator))
private def fetchCurrentClassPath: List[String] = {
val ctxLoader = Thread.currentThread().getContextClassLoader
ctxLoader match {
case urlCL: URLClassLoader =>
urlCL.getURLs.toList.map{_.toString}
case wrappedCL =>
wrappedCL.getParent match {
case urlCL: URLClassLoader =>
urlCL.getURLs.toList.map{_.toString}
case something => sys.error(s"Could not unwrap class loader: $something")
}
}
}
private def adaptClassPathToOSEnv(cp: List[String]): List[String] = {
// TODO adapt for UNIX systems (only works on windows right now)
cp.map(entry => {
val UrlRegex = """file:/(.*)""".r
entry match {
case UrlRegex(path) => path
case p => p
}
}).map(_.replaceAll("/", "\\\\").replaceAll("%20", " "))
}
} }
package org.rosi_project.model_sync.generator.sync_model package org.rosi_project.model_sync.generator.sync_model
import org.rosi_project.model_sync.generator.acr._ import org.rosi_project.model_sync.generator.acr._
import scroll.internal.Compartment
/** /**
* @author Rico Bergmann * @author Rico Bergmann
...@@ -12,6 +13,14 @@ class SyncEnhancingVisitor extends SModelVisitor { ...@@ -12,6 +13,14 @@ class SyncEnhancingVisitor extends SModelVisitor {
override def visit(sClass: SClass): Unit = { override def visit(sClass: SClass): Unit = {
// TODO extend PlayerSync and call setup method in constructor // TODO extend PlayerSync and call setup method in constructor
sClass.getInheritanceHierarchy.reverse.headOption.foreach{
case root: SClass => root.setParent(SyncEnhancingVisitor.COMPARTMENT_STYPE)
case tp => sys.error(s"May not enhance $tp as it is a type and not a class")
}
println(s"Class hierarchy for $sClass : ${sClass.getInheritanceHierarchy}")
} }
override def visit(sAttr: SAttribute): Unit = { override def visit(sAttr: SAttribute): Unit = {
...@@ -42,4 +51,9 @@ object SyncEnhancingVisitor { ...@@ -42,4 +51,9 @@ object SyncEnhancingVisitor {
private val SetterRegex = """set([A-Z][a-zA-z0-9]*)""".r private val SetterRegex = """set([A-Z][a-zA-z0-9]*)""".r
private val COMPARTMENT_CLASS = classOf[Compartment]
// TODO enhance with player sync instead of compartment! (where to get the class from?)
private val COMPARTMENT_STYPE = SType(COMPARTMENT_CLASS.getSimpleName, COMPARTMENT_CLASS.getPackage.getName)
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment