|
@@ -2,26 +2,24 @@ package org.openzen.zenscript.javabytecode.compiler;
|
2
|
2
|
|
3
|
3
|
import java.util.Arrays;
|
4
|
4
|
import java.util.Collection;
|
5
|
|
-import org.objectweb.asm.Label;
|
6
|
|
-import org.objectweb.asm.Type;
|
7
|
|
-import org.openzen.zenscript.codemodel.CompareType;
|
8
|
|
-import org.openzen.zenscript.codemodel.expression.*;
|
9
|
|
-import org.openzen.zenscript.codemodel.type.DefinitionTypeID;
|
10
|
|
-import org.openzen.zenscript.codemodel.type.ITypeID;
|
11
|
|
-import org.openzen.zenscript.implementations.IntRange;
|
12
|
|
-import org.openzen.zenscript.javabytecode.*;
|
13
|
|
-
|
|
5
|
+import java.util.Comparator;
|
14
|
6
|
import java.util.Map;
|
|
7
|
+import java.util.StringJoiner;
|
|
8
|
+import org.objectweb.asm.Label;
|
15
|
9
|
import org.objectweb.asm.Opcodes;
|
|
10
|
+import org.objectweb.asm.Type;
|
16
|
11
|
import org.openzen.zencode.shared.CompileException;
|
17
|
12
|
import org.openzen.zencode.shared.CompileExceptionCode;
|
|
13
|
+import org.openzen.zenscript.codemodel.CompareType;
|
|
14
|
+import org.openzen.zenscript.codemodel.expression.*;
|
18
|
15
|
import org.openzen.zenscript.codemodel.member.ref.ConstMemberRef;
|
19
|
16
|
import org.openzen.zenscript.codemodel.member.ref.DefinitionMemberRef;
|
20
|
17
|
import org.openzen.zenscript.codemodel.member.ref.FieldMemberRef;
|
21
|
|
-import org.openzen.zenscript.codemodel.type.ArrayTypeID;
|
22
|
|
-import org.openzen.zenscript.codemodel.type.AssocTypeID;
|
23
|
|
-import org.openzen.zenscript.codemodel.type.BasicTypeID;
|
|
18
|
+import org.openzen.zenscript.codemodel.statement.ReturnStatement;
|
|
19
|
+import org.openzen.zenscript.codemodel.type.*;
|
24
|
20
|
import org.openzen.zenscript.codemodel.type.member.BuiltinID;
|
|
21
|
+import org.openzen.zenscript.implementations.IntRange;
|
|
22
|
+import org.openzen.zenscript.javabytecode.*;
|
25
|
23
|
|
26
|
24
|
public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
27
|
25
|
private static final int PUBLIC = Opcodes.ACC_PUBLIC;
|
|
@@ -156,9 +154,10 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
156
|
154
|
private static final JavaClassInfo COLLECTION = JavaClassInfo.get(Collection.class);
|
157
|
155
|
private static final JavaMethodInfo COLLECTION_SIZE = new JavaMethodInfo(COLLECTION, "size", "()I", PUBLIC);
|
158
|
156
|
private static final JavaMethodInfo COLLECTION_TOARRAY = new JavaMethodInfo(COLLECTION, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;", PUBLIC);
|
159
|
|
-
|
|
157
|
+
|
160
|
158
|
private final JavaWriter javaWriter;
|
161
|
|
-
|
|
159
|
+ private final JavaCapturedExpressionVisitor capturedExpressionVisitor = new JavaCapturedExpressionVisitor(this);
|
|
160
|
+
|
162
|
161
|
public JavaExpressionVisitor(JavaWriter javaWriter) {
|
163
|
162
|
this.javaWriter = javaWriter;
|
164
|
163
|
}
|
|
@@ -929,27 +928,27 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
929
|
928
|
|
930
|
929
|
@Override
|
931
|
930
|
public Void visitCapturedClosure(CapturedClosureExpression expression) {
|
932
|
|
- return null;
|
|
931
|
+ return expression.accept(capturedExpressionVisitor);
|
933
|
932
|
}
|
934
|
933
|
|
935
|
934
|
@Override
|
936
|
935
|
public Void visitCapturedDirect(CapturedDirectExpression expression) {
|
937
|
|
- return null;
|
|
936
|
+ return expression.accept(capturedExpressionVisitor);
|
938
|
937
|
}
|
939
|
938
|
|
940
|
939
|
@Override
|
941
|
940
|
public Void visitCapturedLocalVariable(CapturedLocalVariableExpression expression) {
|
942
|
|
- return null;
|
|
941
|
+ return expression.accept(capturedExpressionVisitor);
|
943
|
942
|
}
|
944
|
943
|
|
945
|
944
|
@Override
|
946
|
945
|
public Void visitCapturedParameter(CapturedParameterExpression expression) {
|
947
|
|
- return null;
|
948
|
|
- }
|
|
946
|
+ return expression.accept(capturedExpressionVisitor);
|
|
947
|
+ }
|
949
|
948
|
|
950
|
949
|
@Override
|
951
|
950
|
public Void visitCapturedThis(CapturedThisExpression expression) {
|
952
|
|
- return null;
|
|
951
|
+ return expression.accept(capturedExpressionVisitor);
|
953
|
952
|
}
|
954
|
953
|
|
955
|
954
|
@Override
|
|
@@ -1511,15 +1510,13 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
1511
|
1510
|
@Override
|
1512
|
1511
|
public Void visitConstructorThisCall(ConstructorThisCallExpression expression) {
|
1513
|
1512
|
Type type = expression.objectType.accept(JavaTypeVisitor.INSTANCE);
|
1514
|
|
-
|
1515
|
|
- if (javaWriter.method.javaClass.isEnum) {
|
1516
|
|
- javaWriter.loadObject(0);
|
1517
|
|
- javaWriter.loadObject(1);
|
1518
|
|
- javaWriter.loadInt(2);
|
1519
|
|
- } else {
|
1520
|
|
- javaWriter.loadObject(0);
|
1521
|
|
- }
|
1522
|
|
-
|
|
1513
|
+
|
|
1514
|
+ javaWriter.loadObject(0);
|
|
1515
|
+ if (javaWriter.method.javaClass.isEnum) {
|
|
1516
|
+ javaWriter.loadObject(1);
|
|
1517
|
+ javaWriter.loadInt(2);
|
|
1518
|
+ }
|
|
1519
|
+
|
1523
|
1520
|
for (Expression argument : expression.arguments.arguments) {
|
1524
|
1521
|
argument.accept(this);
|
1525
|
1522
|
}
|
|
@@ -1535,8 +1532,8 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
1535
|
1532
|
}
|
1536
|
1533
|
//No super calls in enums possible, and that's already handled in the enum constructor itself.
|
1537
|
1534
|
javaWriter.invokeSpecial(expression.objectType.accept(JavaTypeClassVisitor.INSTANCE), "<init>", CompilerUtils.calcDesc(expression.constructor.header, false));
|
1538
|
|
-
|
1539
|
|
- CompilerUtils.writeDefaultFieldInitializers(javaWriter, javaWriter.forDefinition, false);
|
|
1535
|
+
|
|
1536
|
+ CompilerUtils.writeDefaultFieldInitializers(javaWriter, javaWriter.forDefinition, false);
|
1540
|
1537
|
return null;
|
1541
|
1538
|
}
|
1542
|
1539
|
|
|
@@ -1549,12 +1546,67 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
1549
|
1546
|
|
1550
|
1547
|
@Override
|
1551
|
1548
|
public Void visitFunction(FunctionExpression expression) {
|
|
1549
|
+ if (expression.header.parameters.length == 0 && expression.body instanceof ReturnStatement && expression.body.hasTag(MatchExpression.class) && expression.closure.captures.isEmpty()) {
|
|
1550
|
+ ((ReturnStatement) expression.body).value.accept(this);
|
|
1551
|
+ return null;
|
|
1552
|
+ }
|
|
1553
|
+ final String signature = calcFunctionSignature(expression.closure, expression.header.returnType);
|
|
1554
|
+ final String name = "lambda" + expression.hashCode();
|
|
1555
|
+
|
|
1556
|
+ final JavaMethodInfo methodInfo = new JavaMethodInfo(javaWriter.method.javaClass, name, signature, Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE);
|
|
1557
|
+ JavaWriter functionWriter = new JavaWriter(javaWriter.clazzVisitor, methodInfo, null, signature, null);
|
|
1558
|
+
|
|
1559
|
+ for (CapturedExpression capture : expression.closure.captures) {
|
|
1560
|
+ capture.accept(new JavaCapturedExpressionVisitor(this));
|
|
1561
|
+ }
|
|
1562
|
+
|
|
1563
|
+ javaWriter.invokeStatic(methodInfo);
|
|
1564
|
+
|
|
1565
|
+ functionWriter.start();
|
|
1566
|
+ expression.body.accept(new JavaStatementVisitor(new JavaExpressionVisitor(functionWriter) {
|
|
1567
|
+ @Override
|
|
1568
|
+ public Void visitGetLocalVariable(GetLocalVariableExpression varExpression) {
|
|
1569
|
+ final int position = calculateMemberPosition(varExpression, expression);
|
|
1570
|
+ if (position < 0)
|
|
1571
|
+ throw new CompileException(varExpression.position, CompileExceptionCode.INTERNAL_ERROR, "Captured Statement error");
|
|
1572
|
+ functionWriter.load(varExpression.variable.type.accept(JavaTypeVisitor.INSTANCE), position);
|
|
1573
|
+ return null;
|
|
1574
|
+ }
|
|
1575
|
+ }));
|
|
1576
|
+
|
|
1577
|
+
|
|
1578
|
+ functionWriter.ret();
|
|
1579
|
+ functionWriter.end();
|
|
1580
|
+
|
1552
|
1581
|
return null;
|
1553
|
1582
|
}
|
1554
|
1583
|
|
|
1584
|
+ //TODO replace with visitor?
|
|
1585
|
+ private static int calculateMemberPosition(GetLocalVariableExpression localVariableExpression, FunctionExpression expression) {
|
|
1586
|
+ int h = expression.header.parameters.length;
|
|
1587
|
+ for (CapturedExpression capture : expression.closure.captures) {
|
|
1588
|
+ if (capture instanceof CapturedLocalVariableExpression && ((CapturedLocalVariableExpression) capture).variable == localVariableExpression.variable)
|
|
1589
|
+ return h;
|
|
1590
|
+ if (capture instanceof CapturedClosureExpression && ((CapturedClosureExpression) capture).value instanceof CapturedLocalVariableExpression && ((CapturedLocalVariableExpression) ((CapturedClosureExpression) capture).value).variable == localVariableExpression.variable)
|
|
1591
|
+ return h;
|
|
1592
|
+ h++;
|
|
1593
|
+ }
|
|
1594
|
+ return -1;
|
|
1595
|
+ }
|
|
1596
|
+
|
|
1597
|
+ private String calcFunctionSignature(LambdaClosure closure, ITypeID type) {
|
|
1598
|
+ StringJoiner joiner = new StringJoiner("", "(", ")");
|
|
1599
|
+
|
|
1600
|
+ for (CapturedExpression capture : closure.captures) {
|
|
1601
|
+ String descriptor = capture.type.accept(JavaTypeVisitor.INSTANCE).getDescriptor();
|
|
1602
|
+ joiner.add(descriptor);
|
|
1603
|
+ }
|
|
1604
|
+ return joiner.toString() + type.accept(JavaTypeVisitor.INSTANCE).getDescriptor();
|
|
1605
|
+ }
|
|
1606
|
+
|
1555
|
1607
|
@Override
|
1556
|
1608
|
public Void visitGetField(GetFieldExpression expression) {
|
1557
|
|
- expression.accept(this);
|
|
1609
|
+ expression.accept(this);
|
1558
|
1610
|
if (!checkAndGetFieldInfo(expression.field, false))
|
1559
|
1611
|
throw new IllegalStateException("Missing field info on a field member!");
|
1560
|
1612
|
return null;
|
|
@@ -1562,7 +1614,7 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
1562
|
1614
|
|
1563
|
1615
|
@Override
|
1564
|
1616
|
public Void visitGetFunctionParameter(GetFunctionParameterExpression expression) {
|
1565
|
|
- JavaParameterInfo parameter = expression.parameter.getTag(JavaParameterInfo.class);
|
|
1617
|
+ JavaParameterInfo parameter = expression.parameter.getTag(JavaParameterInfo.class);
|
1566
|
1618
|
javaWriter.load(Type.getType(expression.parameter.type.accept(JavaTypeClassVisitor.INSTANCE)), parameter.index);
|
1567
|
1619
|
return null;
|
1568
|
1620
|
}
|
|
@@ -1772,7 +1824,7 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
1772
|
1824
|
javaWriter.getField(IntRange.class, "to", int.class);
|
1773
|
1825
|
break;
|
1774
|
1826
|
}
|
1775
|
|
-
|
|
1827
|
+
|
1776
|
1828
|
return null;
|
1777
|
1829
|
}
|
1778
|
1830
|
|
|
@@ -1819,11 +1871,65 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
1819
|
1871
|
}
|
1820
|
1872
|
return null;
|
1821
|
1873
|
}
|
1822
|
|
-
|
1823
|
|
- @Override
|
1824
|
|
- public Void visitMatch(MatchExpression expression) {
|
1825
|
|
- throw new UnsupportedOperationException();
|
1826
|
|
- }
|
|
1874
|
+
|
|
1875
|
+ @Override
|
|
1876
|
+ public Void visitMatch(MatchExpression expression) {
|
|
1877
|
+
|
|
1878
|
+ final Label start = new Label();
|
|
1879
|
+ final Label end = new Label();
|
|
1880
|
+
|
|
1881
|
+
|
|
1882
|
+ javaWriter.label(start);
|
|
1883
|
+ expression.value.accept(this);
|
|
1884
|
+ if (expression.value.type == BasicTypeID.STRING)
|
|
1885
|
+ javaWriter.invokeVirtual(new JavaMethodInfo(new JavaClassInfo("java/lang/Object"), "hashCode", "()I", 0));
|
|
1886
|
+
|
|
1887
|
+ final boolean hasNoDefault = hasNoDefault(expression);
|
|
1888
|
+
|
|
1889
|
+ final MatchExpression.Case[] cases = expression.cases;
|
|
1890
|
+ final JavaSwitchLabel[] switchLabels = new JavaSwitchLabel[hasNoDefault ? cases.length : cases.length - 1];
|
|
1891
|
+ final Label defaultLabel = new Label();
|
|
1892
|
+
|
|
1893
|
+ int i = 0;
|
|
1894
|
+ for (final MatchExpression.Case matchCase : cases) {
|
|
1895
|
+ if (matchCase.key != null) {
|
|
1896
|
+ switchLabels[i++] = new JavaSwitchLabel(CompilerUtils.getKeyForSwitch(matchCase.key), new Label());
|
|
1897
|
+ }
|
|
1898
|
+ }
|
|
1899
|
+
|
|
1900
|
+ JavaSwitchLabel[] sortedSwitchLabels = Arrays.copyOf(switchLabels, switchLabels.length);
|
|
1901
|
+ Arrays.sort(sortedSwitchLabels, Comparator.comparingInt(a -> a.key));
|
|
1902
|
+
|
|
1903
|
+ javaWriter.lookupSwitch(defaultLabel, sortedSwitchLabels);
|
|
1904
|
+
|
|
1905
|
+ i = 0;
|
|
1906
|
+ for (final MatchExpression.Case switchCase : cases) {
|
|
1907
|
+ if (hasNoDefault || switchCase.key != null) {
|
|
1908
|
+ javaWriter.label(switchLabels[i++].label);
|
|
1909
|
+ } else {
|
|
1910
|
+ javaWriter.label(defaultLabel);
|
|
1911
|
+ }
|
|
1912
|
+ //switchCase.value.body.setTag(MatchExpression.class, expression);
|
|
1913
|
+ switchCase.value.accept(this);
|
|
1914
|
+ javaWriter.goTo(end);
|
|
1915
|
+ }
|
|
1916
|
+
|
|
1917
|
+ if (hasNoDefault) {
|
|
1918
|
+ javaWriter.label(defaultLabel);
|
|
1919
|
+ }
|
|
1920
|
+
|
|
1921
|
+ javaWriter.label(end);
|
|
1922
|
+
|
|
1923
|
+
|
|
1924
|
+ //throw new UnsupportedOperationException("Not yet implemented!");
|
|
1925
|
+ return null;
|
|
1926
|
+ }
|
|
1927
|
+
|
|
1928
|
+ private static boolean hasNoDefault(MatchExpression switchStatement) {
|
|
1929
|
+ for (MatchExpression.Case switchCase : switchStatement.cases)
|
|
1930
|
+ if (switchCase.key == null) return false;
|
|
1931
|
+ return true;
|
|
1932
|
+ }
|
1827
|
1933
|
|
1828
|
1934
|
@Override
|
1829
|
1935
|
public Void visitNew(NewExpression expression) {
|
|
@@ -1889,16 +1995,16 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
1889
|
1995
|
javaWriter.dup(expression.type.accept(new JavaTypeVisitor()));
|
1890
|
1996
|
if (!checkAndExecuteByteCodeImplementation(expression.member) && !checkAndExecuteMethodInfo(expression.member))
|
1891
|
1997
|
throw new IllegalStateException("Call target has no method info!");
|
1892
|
|
-
|
1893
|
|
- return null;
|
1894
|
|
- }
|
|
1998
|
+
|
|
1999
|
+ return null;
|
|
2000
|
+ }
|
1895
|
2001
|
|
1896
|
2002
|
@Override
|
1897
|
2003
|
public Void visitRange(RangeExpression expression) {
|
1898
|
|
- // TODO: there are other kinds of ranges also; there should be a Range<T, T> type with creation of synthetic types
|
|
2004
|
+ // TODO: there are other kinds of ranges also; there should be a Range<T, T> type with creation of synthetic types
|
1899
|
2005
|
if (expression.from.type.accept(JavaTypeClassVisitor.INSTANCE) != int.class)
|
1900
|
2006
|
throw new CompileException(expression.position, CompileExceptionCode.INTERNAL_ERROR, "Only integer ranges supported");
|
1901
|
|
-
|
|
2007
|
+
|
1902
|
2008
|
javaWriter.newObject(IntRange.class);
|
1903
|
2009
|
javaWriter.dup();
|
1904
|
2010
|
expression.from.accept(this);
|
|
@@ -1908,6 +2014,7 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
1908
|
2014
|
|
1909
|
2015
|
return null;
|
1910
|
2016
|
}
|
|
2017
|
+
|
1911
|
2018
|
|
1912
|
2019
|
@Override
|
1913
|
2020
|
public Void visitSameObject(SameObjectExpression expression) {
|
|
@@ -1942,7 +2049,7 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
1942
|
2049
|
@Override
|
1943
|
2050
|
public Void visitSetFunctionParameter(SetFunctionParameterExpression expression) {
|
1944
|
2051
|
expression.value.accept(this);
|
1945
|
|
- JavaParameterInfo parameter = expression.parameter.getTag(JavaParameterInfo.class);
|
|
2052
|
+ JavaParameterInfo parameter = expression.parameter.getTag(JavaParameterInfo.class);
|
1946
|
2053
|
javaWriter.store(expression.type.accept(JavaTypeVisitor.INSTANCE), parameter.index);
|
1947
|
2054
|
return null;
|
1948
|
2055
|
}
|
|
@@ -2070,11 +2177,11 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
2070
|
2177
|
public Void visitStaticSetter(StaticSetterExpression expression) {
|
2071
|
2178
|
return null;
|
2072
|
2179
|
}
|
2073
|
|
-
|
2074
|
|
- @Override
|
2075
|
|
- public Void visitSupertypeCast(SupertypeCastExpression expression) {
|
2076
|
|
- return null; // nothing to do
|
2077
|
|
- }
|
|
2180
|
+
|
|
2181
|
+ @Override
|
|
2182
|
+ public Void visitSupertypeCast(SupertypeCastExpression expression) {
|
|
2183
|
+ return null; // nothing to do
|
|
2184
|
+ }
|
2078
|
2185
|
|
2079
|
2186
|
@Override
|
2080
|
2187
|
public Void visitThis(ThisExpression expression) {
|
|
@@ -2094,25 +2201,25 @@ public class JavaExpressionVisitor implements ExpressionVisitor<Void> {
|
2094
|
2201
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
2095
|
2202
|
}
|
2096
|
2203
|
|
2097
|
|
- @Override
|
2098
|
|
- public Void visitTryRethrowAsException(TryRethrowAsExceptionExpression expression) {
|
2099
|
|
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
2100
|
|
- }
|
|
2204
|
+ @Override
|
|
2205
|
+ public Void visitTryRethrowAsException(TryRethrowAsExceptionExpression expression) {
|
|
2206
|
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
|
2207
|
+ }
|
2101
|
2208
|
|
2102
|
|
- @Override
|
2103
|
|
- public Void visitTryRethrowAsResult(TryRethrowAsResultExpression expression) {
|
2104
|
|
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
2105
|
|
- }
|
2106
|
|
-
|
2107
|
|
- @Override
|
2108
|
|
- public Void visitVariantValue(VariantValueExpression expression) {
|
2109
|
|
- throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
2110
|
|
- }
|
|
2209
|
+ @Override
|
|
2210
|
+ public Void visitTryRethrowAsResult(TryRethrowAsResultExpression expression) {
|
|
2211
|
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
|
2212
|
+ }
|
|
2213
|
+
|
|
2214
|
+ @Override
|
|
2215
|
+ public Void visitVariantValue(VariantValueExpression expression) {
|
|
2216
|
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
|
2217
|
+ }
|
2111
|
2218
|
|
2112
|
2219
|
@Override
|
2113
|
2220
|
public Void visitWrapOptional(WrapOptionalExpression expression) {
|
2114
|
|
- // TODO: convert basic types (char, int, float, ...) to their boxed (Character, Integer, Float, ...) counterparts
|
2115
|
|
- // -- any object type values can just be passed as-is
|
|
2221
|
+ // TODO: convert basic types (char, int, float, ...) to their boxed (Character, Integer, Float, ...) counterparts
|
|
2222
|
+ // -- any object type values can just be passed as-is
|
2116
|
2223
|
expression.value.accept(this);
|
2117
|
2224
|
return null;
|
2118
|
2225
|
}
|