Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JsNative in inner classes; OverlayTypesByExample with support for primitive typed arrays; @ClientBundle.Source problem in ClientBundle #13

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.itemis.xtend.auto.gwt

import org.eclipse.xtend.lib.macro.CodeGenerationContext
import org.eclipse.xtend.lib.macro.declaration.TypeDeclaration
import org.eclipse.xtend.lib.macro.file.Path

class ActiveAnnotationProcessorHelper {
private static def TypeDeclaration topLevelType(TypeDeclaration type) {
return if (type.declaringType == null) type else type.declaringType.topLevelType
}

static def Path getTargetPath(TypeDeclaration type, extension CodeGenerationContext ctx) {
val topLevelType = type.topLevelType
val unit = type.compilationUnit
val targetFolder = unit.filePath.targetFolder
return targetFolder.append(unit.sourceTypeDeclarations.findFirst[sourceType|sourceType==topLevelType].qualifiedName.replace('.','/')+".java")
}
}
14 changes: 12 additions & 2 deletions src/main/java/de/itemis/xtend/auto/gwt/ClientBundle.xtend
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import java.lang.annotation.ElementType
import java.lang.annotation.Target
import java.util.List
import org.eclipse.xtend.lib.macro.Active
import org.eclipse.xtend.lib.macro.CodeGenerationContext
import org.eclipse.xtend.lib.macro.CodeGenerationParticipant
import org.eclipse.xtend.lib.macro.RegisterGlobalsContext
import org.eclipse.xtend.lib.macro.RegisterGlobalsParticipant
import org.eclipse.xtend.lib.macro.TransformationContext
Expand Down Expand Up @@ -47,7 +49,8 @@ annotation ImageResources {
annotation ClientBundle {
}

class CliendBundleProcessor implements RegisterGlobalsParticipant<InterfaceDeclaration>, TransformationParticipant<MutableInterfaceDeclaration> {
class CliendBundleProcessor implements RegisterGlobalsParticipant<InterfaceDeclaration>, TransformationParticipant<MutableInterfaceDeclaration>,
CodeGenerationParticipant<InterfaceDeclaration> {

private static final String INSTANCE = 'INSTANCE'

Expand Down Expand Up @@ -246,5 +249,12 @@ class CliendBundleProcessor implements RegisterGlobalsParticipant<InterfaceDecla
protected def getCssResources(MutableInterfaceDeclaration it) {
annotations.filter[annotationTypeDeclaration.qualifiedName == CssResource.name]
}


override doGenerateCode(List<? extends InterfaceDeclaration> annotatedSourceElements, extension CodeGenerationContext context) {
for(annotatedSourceElement: annotatedSourceElements) {
val path = ActiveAnnotationProcessorHelper::getTargetPath(annotatedSourceElement, context)
val newContents = path.contents.toString.replaceAll("@ClientBundle.Source", "@Source")
path.contents = newContents
}
}
}
45 changes: 30 additions & 15 deletions src/main/java/de/itemis/xtend/auto/gwt/JsNative.xtend
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
*******************************************************************************/
package de.itemis.xtend.auto.gwt

import java.util.HashMap
import java.util.List
import org.eclipse.xtend.lib.macro.AbstractMethodProcessor
import org.eclipse.xtend.lib.macro.Active
import org.eclipse.xtend.lib.macro.CodeGenerationContext
Expand Down Expand Up @@ -51,23 +53,36 @@ class JsNativeProcessor extends AbstractMethodProcessor {
return method.declaringType.simpleName+"#"+method.simpleName+"("+method.parameters.map[type].join(',')+")"
}

override doGenerateCode(MethodDeclaration annotatedMethod, extension CodeGenerationContext context) {
val path = annotatedMethod.declaringType.getTargetPath(context)
val contents = path.contents.toString
val markerStart = contents.indexOf(getUniqueMarkerCode(annotatedMethod))
val startIndex = contents.substring(0, markerStart).lastIndexOf('{')
val endIndex = contents.substring(markerStart).indexOf('}') + markerStart
val jsCode = annotatedMethod.body.toString.trimTripleQuotes
path.contents = contents.substring(0, startIndex)+"/*-{"+jsCode+"}-*/;"+contents.substring(endIndex+1)
override doGenerateCode(List<? extends MethodDeclaration> annotatedMethods, extension CodeGenerationContext context) {
// When the annotation is used multiple times within a single source xtend compilation
// unit, the methods can end up in several different java compilation units due to
// multiple toplevel types in one xtend file. Furthermore, there can be multiple
// annotated methods per java compilation unit.
// We load change all contents first and later save all compilation units only once.
val javaUnits = new HashMap<Path, String>;
for(annotatedMethod: annotatedMethods) {
val path = ActiveAnnotationProcessorHelper::getTargetPath(annotatedMethod.declaringType, context)
if (javaUnits.get(path) == null) {
javaUnits.put(path, path.contents.toString)
}
var contents = javaUnits.get(path)

val markerStart = contents.indexOf(getUniqueMarkerCode(annotatedMethod))
if (markerStart > 0) {
val startIndex = contents.substring(0, markerStart).lastIndexOf('{')
val endIndex = contents.substring(markerStart).indexOf('}') + markerStart
val jsCode = annotatedMethod.body.toString.trimTripleQuotes
val newContents = contents.substring(0, startIndex)+"/*-{"+jsCode+"}-*/;"+contents.substring(endIndex+1)

javaUnits.put(path, newContents)
}
}
for (path: javaUnits.keySet) {
path.contents = javaUnits.get(path)
}
}

private def String trimTripleQuotes(String s) {
s.substring(3, s.length-3)
}

def Path getTargetPath(TypeDeclaration type, extension CodeGenerationContext ctx) {
val unit = type.compilationUnit
val targetFolder = unit.filePath.targetFolder
return targetFolder.append(type.qualifiedName.replace('.','/')+".java")
}
}
}
49 changes: 31 additions & 18 deletions src/main/java/de/itemis/xtend/auto/gwt/OverlayTypeByExample.xtend
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import com.google.gson.JsonParser
import com.google.gson.JsonPrimitive
import com.google.gwt.core.client.JavaScriptObject
import com.google.gwt.core.client.JsArray
import com.google.gwt.core.client.JsArrayBoolean
import com.google.gwt.core.client.JsArrayNumber
import com.google.gwt.core.client.JsArrayString
import java.util.Map.Entry
import java.util.regex.Pattern
import org.eclipse.xtend.lib.macro.AbstractClassProcessor
Expand All @@ -23,8 +26,10 @@ import org.eclipse.xtend.lib.macro.RegisterGlobalsContext
import org.eclipse.xtend.lib.macro.TransformationContext
import org.eclipse.xtend.lib.macro.declaration.ClassDeclaration
import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration
import org.eclipse.xtend.lib.macro.declaration.TypeDeclaration
import org.eclipse.xtend.lib.macro.declaration.TypeReference
import org.eclipse.xtend.lib.macro.declaration.Visibility
import org.eclipse.xtend.lib.macro.file.Path

import static extension de.itemis.xtend.auto.gwt.StaticUtils.*

Expand Down Expand Up @@ -85,20 +90,19 @@ class OverlayTypeByExampleProcessor extends AbstractClassProcessor {
}


val PATTERN = Pattern.compile("public final native (.+) get(\\w+)\\(\\);")
val PATTERN = Pattern.compile("public final native (.+) get(\\w+)\\(\\) \\{\\s*(\\w+)\\s*\\}")

/**
* we add the Java comment containing the javascript code during code generation, since there is no way to add it using the Java model.
*/
override doGenerateCode(ClassDeclaration annotatedClass, extension CodeGenerationContext context) {
val targetFolder = annotatedClass.compilationUnit.filePath.targetFolder
val targetFile = targetFolder.append(annotatedClass.qualifiedName.replace('.','/')+".java")
val contents = targetFile.contents
val path = ActiveAnnotationProcessorHelper::getTargetPath(annotatedClass, context)
val contents = path.contents
val matcher = PATTERN.matcher(contents)
targetFile.contents = matcher.replaceAll("public final native $1 get$2() /*-{ return this.$2; }-*/;")
val newContents = matcher.replaceAll("public final native $1 get$2() /*-{ return this.$3; }-*/;")
path.contents = newContents
}


static class Util {
extension TransformationContext ctx

Expand All @@ -122,6 +126,8 @@ class OverlayTypeByExampleProcessor extends AbstractClassProcessor {
native = true
final = true
returnType = getJavaType(property, classDeclaration)
// save the property key as body for later reference in code generation phase
body = '''«property.key»'''
]
}

Expand All @@ -147,19 +153,26 @@ class OverlayTypeByExampleProcessor extends AbstractClassProcessor {
val type = currentContainer.declaredClasses.findFirst[simpleName == simpleTypeName]
type.newTypeReference
}
JsonPrimitive case element.isString: {
String.newTypeReference
}
JsonPrimitive case element.isBoolean: {
boolean.newTypeReference
}
JsonPrimitive case element.isNumber: {
if (element.asString.indexOf('.') == -1) {
int.newTypeReference
JsonPrimitive:
if (isArray) {
switch (element) {
case element.isString: return JsArrayString.newTypeReference
case element.isBoolean: return JsArrayBoolean.newTypeReference
case element.isNumber: return JsArrayNumber.newTypeReference
}
} else {
double.newTypeReference
}
}
switch (element) {
case element.isString: String.newTypeReference
case element.isBoolean: boolean.newTypeReference
case element.isNumber: {
if (element.asString.indexOf('.') == -1) {
int.newTypeReference
} else {
double.newTypeReference
}
}
}
}
default : {
currentContainer.addError("unknown element "+element)
throw new IllegalStateException
Expand Down