Skip to content

Commit 0cff071

Browse files
committed
Merge pull request #261 from NumberFour/IDE-2470
IDE-2470: Add temporary JSX transpilation support to N4JS transpiler
2 parents c49207c + 560dfb5 commit 0cff071

File tree

19 files changed

+25975
-25786
lines changed

19 files changed

+25975
-25786
lines changed

plugins/eu.numberfour.n4js.transpiler.es/META-INF/MANIFEST.MF

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ Require-Bundle: eu.numberfour.n4js,
1616
org.eclipse.emf.ecore.xcore;bundle-version="1.3.1",
1717
eu.numberfour.n4js.releng.utils;bundle-version="0.0.1",
1818
it.xsemantics.runtime,
19-
com.google.guava
19+
com.google.guava,
20+
eu.numberfour.n4jsx.model
2021
Export-Package: eu.numberfour.n4js.transpiler.es

plugins/eu.numberfour.n4js.transpiler.es/src/eu/numberfour/n4js/transpiler/es/EcmaScriptTranspiler.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import eu.numberfour.n4js.transpiler.es.transform.FormalParameterTransformation;
3939
import eu.numberfour.n4js.transpiler.es.transform.FunctionDeclarationTransformation;
4040
import eu.numberfour.n4js.transpiler.es.transform.InterfaceDeclarationTransformation;
41+
import eu.numberfour.n4js.transpiler.es.transform.JSXTransformation;
4142
import eu.numberfour.n4js.transpiler.es.transform.MemberPatchingTransformation;
4243
import eu.numberfour.n4js.transpiler.es.transform.ModuleWrappingTransformation;
4344
import eu.numberfour.n4js.transpiler.es.transform.SanitizeImportsTransformation;
@@ -92,6 +93,8 @@ public class EcmaScriptTranspiler extends AbstractTranspiler {
9293
private Provider<ArrowFunction_Part1_Transformation> arrowFunction_Part1_TransformationProvider;
9394
@Inject
9495
private Provider<ArrowFunction_Part2_Transformation> arrowFunction_Part2_TransformationProvider;
96+
@Inject
97+
private Provider<JSXTransformation> jsxTransformationProvider;
9598

9699
@Inject
97100
private ProjectUtils projectUtils;
@@ -108,6 +111,7 @@ public class EcmaScriptTranspiler extends AbstractTranspiler {
108111
@Override
109112
protected Transformation[] computeTransformationsToBeExecuted(TranspilerState state) {
110113
return new Transformation[] {
114+
jsxTransformationProvider.get(),
111115
staticPolyfillTransformationProvider.get(),
112116
memberPatchingTransformationProvider.get(),
113117
apiImplStubGenerationTransformationProvider.get(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/**
2+
* Copyright (c) 2016 NumberFour AG.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* NumberFour AG - Initial API and implementation
10+
*/
11+
package eu.numberfour.n4js.transpiler.es.transform
12+
13+
import eu.numberfour.n4js.n4JS.Expression
14+
import eu.numberfour.n4js.n4JS.ParameterizedCallExpression
15+
import eu.numberfour.n4js.n4JS.PropertyNameValuePair
16+
import eu.numberfour.n4js.transpiler.Transformation
17+
import eu.numberfour.n4js.transpiler.im.IdentifierRef_IM
18+
import eu.numberfour.n4jsx.n4JSX.JSXAttribute
19+
import eu.numberfour.n4jsx.n4JSX.JSXChild
20+
import eu.numberfour.n4jsx.n4JSX.JSXElement
21+
import eu.numberfour.n4jsx.n4JSX.JSXExpression
22+
import eu.numberfour.n4jsx.n4JSX.JSXPropertyAttribute
23+
import eu.numberfour.n4jsx.n4JSX.JSXSpreadAttribute
24+
25+
import static eu.numberfour.n4js.transpiler.TranspilerBuilderBlocks.*
26+
import eu.numberfour.n4js.utils.N4JSLanguageUtils
27+
28+
/**
29+
*
30+
*/
31+
class JSXTransformation extends Transformation {
32+
33+
34+
override assertPreConditions() {
35+
}
36+
37+
override assertPostConditions() {
38+
}
39+
40+
override analyze() {
41+
// ignore
42+
}
43+
44+
override transform() {
45+
collectNodes(state.im, JSXElement, false).forEach[transformJSXElement];
46+
}
47+
48+
def private void transformJSXElement(JSXElement elem) {
49+
replace(elem, convertJSXElement(elem));
50+
}
51+
def private ParameterizedCallExpression convertJSXElement(JSXElement elem) {
52+
return _CallExpr(
53+
_PropertyAccessExpr(steFor_React, steFor_createElement),
54+
(
55+
#[
56+
elem.tagNameFromElement,
57+
if(elem.jsxAttributes.isEmpty) {
58+
_NULL
59+
} else {
60+
_ObjLit(elem.jsxAttributes.map[convertJSXAttribute])
61+
}
62+
]
63+
+ elem.jsxChildren.map[convertJSXChild]
64+
)
65+
);
66+
}
67+
68+
def private Expression convertJSXChild(JSXChild child) {
69+
switch(child) {
70+
JSXElement:
71+
convertJSXElement(child)
72+
JSXExpression:
73+
child.expression
74+
}
75+
}
76+
77+
def private PropertyNameValuePair convertJSXAttribute(JSXAttribute attr) {
78+
switch(attr) {
79+
JSXPropertyAttribute: {
80+
_PropertyNameValuePair(
81+
attr.nameFromPropertyAttribute,
82+
attr.valueExpressionFromPropertyAttribute)
83+
}
84+
JSXSpreadAttribute:
85+
_PropertyNameValuePair(N4JSLanguageUtils.SPREAD_IN_OJECT_LITERAL_WORK_AROUND, attr.expression)
86+
}
87+
}
88+
89+
def private Expression getTagNameFromElement(JSXElement elem) {
90+
val nameExpr = elem.jsxElementName.expression;
91+
if(nameExpr instanceof IdentifierRef_IM) {
92+
val id = nameExpr.id_IM;
93+
if(id===null) {
94+
return _StringLiteral(nameExpr.idAsText);
95+
}
96+
}
97+
return nameExpr;
98+
}
99+
100+
def private String getNameFromPropertyAttribute(JSXPropertyAttribute attr) {
101+
val prop = attr.property;
102+
if(prop!==null && !prop.eIsProxy) {
103+
return prop.name;
104+
}
105+
return attr.propertyAsText;
106+
}
107+
def private Expression getValueExpressionFromPropertyAttribute(JSXPropertyAttribute attr) {
108+
return attr.jsxAttributeValue ?: _TRUE;
109+
}
110+
}

plugins/eu.numberfour.n4js.transpiler/src/eu/numberfour/n4js/transpiler/TranspilerBuilderBlocks.xtend

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ import eu.numberfour.n4js.ts.types.TSetter
9292
import eu.numberfour.n4js.ts.utils.TypeUtils
9393
import java.math.BigDecimal
9494
import java.util.List
95+
import eu.numberfour.n4js.n4JS.NullLiteral
9596

9697
/**
9798
* Builder methods for intermediate elements.
@@ -590,6 +591,10 @@ public class TranspilerBuilderBlocks
590591
return result;
591592
}
592593

594+
public static def NullLiteral _NULL() {
595+
return N4JSFactory.eINSTANCE.createNullLiteral;
596+
}
597+
593598
public static def BooleanLiteral _TRUE() {
594599
return _BooleanLiteral(true);
595600
}

plugins/eu.numberfour.n4js.transpiler/src/eu/numberfour/n4js/transpiler/TranspilerComponent.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,4 +658,18 @@ public SymbolTableEntryInternal steFor_require() {
658658
return getSymbolTableEntryInternal("require", true);
659659
}
660660

661+
// ################################################################################################################
662+
// JSX RELATED THINGS (TODO IDE-2416 remove this from n4js transpiler)
663+
664+
/** "React" - retrieve the internal symbol table entry for the symbol "React" */
665+
public SymbolTableEntryInternal steFor_React() {
666+
667+
return getSymbolTableEntryInternal("React", true);
668+
}
669+
670+
/** "createElement" - retrieve the internal symbol table entry for the symbol "createElement" */
671+
public SymbolTableEntryInternal steFor_createElement() {
672+
673+
return getSymbolTableEntryInternal("createElement", true);
674+
}
661675
}

plugins/eu.numberfour.n4js.transpiler/src/eu/numberfour/n4js/transpiler/print/PrettyPrinterSwitch.java

Lines changed: 5 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import java.util.Collection;
1717
import java.util.Collections;
1818
import java.util.Iterator;
19-
import java.util.List;
2019

2120
import org.eclipse.emf.common.util.EList;
2221
import org.eclipse.emf.common.util.WrappedException;
@@ -122,15 +121,6 @@
122121
import eu.numberfour.n4js.ts.typeRefs.TypeRef;
123122
import eu.numberfour.n4js.ts.types.TypeVariable;
124123
import eu.numberfour.n4js.utils.N4JSLanguageUtils;
125-
import eu.numberfour.n4jsx.n4JSX.JSXAttribute;
126-
import eu.numberfour.n4jsx.n4JSX.JSXChild;
127-
import eu.numberfour.n4jsx.n4JSX.JSXElement;
128-
import eu.numberfour.n4jsx.n4JSX.JSXElementName;
129-
import eu.numberfour.n4jsx.n4JSX.JSXExpression;
130-
import eu.numberfour.n4jsx.n4JSX.JSXPropertyAttribute;
131-
import eu.numberfour.n4jsx.n4JSX.JSXSpreadAttribute;
132-
import eu.numberfour.n4jsx.n4JSX.JSXText;
133-
import eu.numberfour.n4jsx.n4JSX.N4JSXPackage;
134124

135125
/**
136126
* Traverses an intermediate model and serializes it to a {@link SourceMapAwareAppendable}. Client code should only use
@@ -180,9 +170,6 @@ protected Boolean doSwitch(int classifierID, EObject elemInIM) {
180170

181171
@Override
182172
public Boolean defaultCase(EObject object) {
183-
if (object.eClass().getEPackage() == N4JSXPackage.eINSTANCE) { // TODO IDE-2416 remove this
184-
return caseJSX(object);
185-
}
186173
throw new IllegalStateException(
187174
"PrettyPrinterSwitch missing a case for objects of type " + object.eClass().getName());
188175
}
@@ -659,6 +646,11 @@ public Boolean casePropertyAssignmentAnnotationList(PropertyAssignmentAnnotation
659646

660647
@Override
661648
public Boolean casePropertyNameValuePair(PropertyNameValuePair original) {
649+
if (N4JSLanguageUtils.SPREAD_IN_OJECT_LITERAL_WORK_AROUND.equals(original.getName())) {
650+
write("... ");
651+
process(original.getExpression());
652+
return DONE;
653+
}
662654
processPropertyName(original);
663655
write(": ");
664656
process(original.getExpression());
@@ -932,102 +924,6 @@ public Boolean caseSnippet(Snippet original) {
932924
return DONE;
933925
}
934926

935-
// ###############################################################################################################
936-
// JSX support
937-
// TODO IDE-2416
938-
939-
private Boolean caseJSX(EObject object) {
940-
if (object instanceof JSXElement) {
941-
return caseJSXElement((JSXElement) object);
942-
} else if (object instanceof JSXText) {
943-
return caseJSXText((JSXText) object);
944-
} else if (object instanceof JSXExpression) {
945-
return caseJSXExpression((JSXExpression) object);
946-
} else if (object instanceof JSXElementName) {
947-
return caseJSXElementName((JSXElementName) object);
948-
} else if (object instanceof JSXPropertyAttribute) {
949-
return caseJSXPropertyAttribute((JSXPropertyAttribute) object);
950-
} else if (object instanceof JSXSpreadAttribute) {
951-
return caseJSXSpreadAttribute((JSXSpreadAttribute) object);
952-
} else {
953-
throw new UnsupportedOperationException("unsupported type of object: " + object.eClass().getName());
954-
}
955-
}
956-
957-
private Boolean caseJSXElement(JSXElement object) {
958-
write("<");
959-
if (object.getJsxElementName() == null)
960-
throw new IllegalStateException(
961-
"JSX element has no name " + object.eClass().getName());
962-
963-
doSwitch(object.getJsxElementName());
964-
965-
if (!object.getJsxAttributes().isEmpty()) {
966-
for (JSXAttribute attr : object.getJsxAttributes()) {
967-
doSwitch(attr);
968-
}
969-
}
970-
971-
JSXElementName jsxClosingName = object.getJsxClosingName();
972-
if (jsxClosingName == null) {
973-
write("/>");
974-
} else {
975-
write(">");
976-
List<JSXChild> jsxChildren = object.getJsxChildren();
977-
if (jsxChildren.isEmpty() == false) {
978-
for (JSXChild child : jsxChildren) {
979-
doSwitch(child);
980-
}
981-
}
982-
write("</");
983-
doSwitch(object.getJsxClosingName());
984-
write(">");
985-
}
986-
987-
return DONE;
988-
}
989-
990-
private Boolean caseJSXText(@SuppressWarnings("unused") JSXText object) {
991-
write("/* TODO JSXText not supported */");
992-
return DONE;
993-
}
994-
995-
private Boolean caseJSXExpression(JSXExpression object) {
996-
write("{");
997-
doSwitch(object.getExpression());
998-
write("}");
999-
return DONE;
1000-
}
1001-
1002-
private Boolean caseJSXElementName(JSXElementName object) {
1003-
write(((IdentifierRef_IM) object.getExpression()).getIdAsText());
1004-
return DONE;
1005-
}
1006-
1007-
private Boolean caseJSXPropertyAttribute(JSXPropertyAttribute object) {
1008-
write(' ');
1009-
write(object.getPropertyAsText());
1010-
write("=");
1011-
final Expression value = object.getJsxAttributeValue();
1012-
final boolean requiresCurlyBraces = !(value instanceof StringLiteral);
1013-
if (requiresCurlyBraces) {
1014-
write('{');
1015-
doSwitch(value);
1016-
write('}');
1017-
} else {
1018-
doSwitch(value);
1019-
}
1020-
return DONE;
1021-
}
1022-
1023-
private Boolean caseJSXSpreadAttribute(JSXSpreadAttribute object) {
1024-
write("{");
1025-
write("... ");
1026-
doSwitch(object.getExpression());
1027-
write("}");
1028-
return DONE;
1029-
}
1030-
1031927
// ###############################################################################################################
1032928
// UTILITY AND CONVENIENCE METHODS
1033929

plugins/eu.numberfour.n4js/src/eu/numberfour/n4js/utils/N4JSLanguageUtils.xtend

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ class N4JSLanguageUtils {
102102
*/
103103
public static final String SYMBOL_IDENTIFIER_PREFIX = ComputedPropertyNameValueConverter.SYMBOL_IDENTIFIER_PREFIX;
104104

105+
/**
106+
* Temporary hack to be able to support spread operator in the JSX transpiler support.
107+
* This is required, because the ES6 spread operator is not yet supported in the N4JS grammar.
108+
* TODO IDE-2471 remove this and add proper support for spread in object literals to grammar/parser
109+
*/
110+
public static final String SPREAD_IN_OJECT_LITERAL_WORK_AROUND = "MISSING_SPREAD_WORK_AROUND";
111+
105112
/**
106113
* If the given function definition is asynchronous, will wrap given return type into a Promise.
107114
* Otherwise, returns given return type unchanged. A return type of <code>void</code> is changed to

plugins/eu.numberfour.n4jsx.ui/src-gen/eu/numberfour/n4jsx/ui/contentassist/antlr/N4JSXParser.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ protected String getRuleName(AbstractElement element) {
4141
put(grammarAccess.getJSXElementAccess().getAlternatives_3(), "rule__JSXElement__Alternatives_3");
4242
put(grammarAccess.getJSXChildAccess().getAlternatives(), "rule__JSXChild__Alternatives");
4343
put(grammarAccess.getJSXAttributeAccess().getAlternatives(), "rule__JSXAttribute__Alternatives");
44-
put(grammarAccess.getJSXPropertyAttributeAccess().getAlternatives_2(), "rule__JSXPropertyAttribute__Alternatives_2");
44+
put(grammarAccess.getJSXPropertyAttributeAccess().getAlternatives_1_1(), "rule__JSXPropertyAttribute__Alternatives_1_1");
4545
put(grammarAccess.getScriptElementAccess().getAlternatives(), "rule__ScriptElement__Alternatives");
4646
put(grammarAccess.getAnnotatedScriptElementAccess().getAlternatives_1(), "rule__AnnotatedScriptElement__Alternatives_1");
4747
put(grammarAccess.getAnnotatedScriptElementAccess().getAlternatives_1_3_0(), "rule__AnnotatedScriptElement__Alternatives_1_3_0");
@@ -151,7 +151,8 @@ protected String getRuleName(AbstractElement element) {
151151
put(grammarAccess.getJSXElementNameExpressionAccess().getGroup_1(), "rule__JSXElementNameExpression__Group_1__0");
152152
put(grammarAccess.getJSXSpreadAttributeAccess().getGroup(), "rule__JSXSpreadAttribute__Group__0");
153153
put(grammarAccess.getJSXPropertyAttributeAccess().getGroup(), "rule__JSXPropertyAttribute__Group__0");
154-
put(grammarAccess.getJSXPropertyAttributeAccess().getGroup_2_1(), "rule__JSXPropertyAttribute__Group_2_1__0");
154+
put(grammarAccess.getJSXPropertyAttributeAccess().getGroup_1(), "rule__JSXPropertyAttribute__Group_1__0");
155+
put(grammarAccess.getJSXPropertyAttributeAccess().getGroup_1_1_1(), "rule__JSXPropertyAttribute__Group_1_1_1__0");
155156
put(grammarAccess.getScriptAccess().getGroup(), "rule__Script__Group__0");
156157
put(grammarAccess.getAnnotatedScriptElementAccess().getGroup(), "rule__AnnotatedScriptElement__Group__0");
157158
put(grammarAccess.getAnnotatedScriptElementAccess().getGroup_1_0(), "rule__AnnotatedScriptElement__Group_1_0__0");
@@ -628,8 +629,8 @@ protected String getRuleName(AbstractElement element) {
628629
put(grammarAccess.getJSXAttributesAccess().getJsxAttributesAssignment(), "rule__JSXAttributes__JsxAttributesAssignment");
629630
put(grammarAccess.getJSXSpreadAttributeAccess().getExpressionAssignment_2(), "rule__JSXSpreadAttribute__ExpressionAssignment_2");
630631
put(grammarAccess.getJSXPropertyAttributeAccess().getPropertyAssignment_0(), "rule__JSXPropertyAttribute__PropertyAssignment_0");
631-
put(grammarAccess.getJSXPropertyAttributeAccess().getJsxAttributeValueAssignment_2_0(), "rule__JSXPropertyAttribute__JsxAttributeValueAssignment_2_0");
632-
put(grammarAccess.getJSXPropertyAttributeAccess().getJsxAttributeValueAssignment_2_1_1(), "rule__JSXPropertyAttribute__JsxAttributeValueAssignment_2_1_1");
632+
put(grammarAccess.getJSXPropertyAttributeAccess().getJsxAttributeValueAssignment_1_1_0(), "rule__JSXPropertyAttribute__JsxAttributeValueAssignment_1_1_0");
633+
put(grammarAccess.getJSXPropertyAttributeAccess().getJsxAttributeValueAssignment_1_1_1_1(), "rule__JSXPropertyAttribute__JsxAttributeValueAssignment_1_1_1_1");
633634
put(grammarAccess.getScriptAccess().getAnnotationsAssignment_1(), "rule__Script__AnnotationsAssignment_1");
634635
put(grammarAccess.getScriptAccess().getScriptElementsAssignment_2(), "rule__Script__ScriptElementsAssignment_2");
635636
put(grammarAccess.getAnnotatedScriptElementAccess().getDeclaredModifiersAssignment_1_2_1_0_0(), "rule__AnnotatedScriptElement__DeclaredModifiersAssignment_1_2_1_0_0");

0 commit comments

Comments
 (0)