-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathExpressionJavaLambda.java
More file actions
119 lines (93 loc) · 4.5 KB
/
ExpressionJavaLambda.java
File metadata and controls
119 lines (93 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package stanhebben.zenscript.expression;
import org.objectweb.asm.*;
import org.objectweb.asm.Type;
import stanhebben.zenscript.compiler.*;
import stanhebben.zenscript.definitions.ParsedFunctionArgument;
import stanhebben.zenscript.statements.Statement;
import stanhebben.zenscript.symbols.*;
import stanhebben.zenscript.type.ZenType;
import stanhebben.zenscript.util.*;
import java.lang.reflect.*;
import java.util.*;
import static stanhebben.zenscript.util.ZenTypeUtil.*;
/**
* @author Stanneke
*/
public class ExpressionJavaLambda extends Expression {
private final Class<?> interfaceClass;
private final List<ParsedFunctionArgument> arguments;
private final List<Statement> statements;
private final ZenType type;
public ExpressionJavaLambda(ZenPosition position, Class<?> interfaceClass, List<ParsedFunctionArgument> arguments, List<Statement> statements, ZenType type) {
super(position);
this.interfaceClass = interfaceClass;
this.arguments = arguments;
this.statements = statements;
this.type = type;
}
@Override
public ZenType getType() {
return type;
}
@Override
public void compile(boolean result, IEnvironmentMethod environment) {
if(!result)
return;
Method method = interfaceClass.getMethods()[0];
// generate class
String clsName = environment.makeClassNameWithMiddleName(getPosition().getFile().getClassName());
ClassWriter cw = new ZenClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, clsName, null, "java/lang/Object", new String[]{internal(interfaceClass)});
MethodOutput output = new MethodOutput(cw, Opcodes.ACC_PUBLIC, method.getName(), descriptor(method), null, null);
IEnvironmentClass environmentClass = new EnvironmentClass(cw, environment);
EnvironmentMethodLambda environmentMethod = new EnvironmentMethodLambda(output, environmentClass, clsName);
for(int i = 0, j = 0; i < arguments.size(); i++) {
environmentMethod.putValue(arguments.get(i).getName(), new SymbolArgument(i + j + 1, environment.getType(method.getGenericParameterTypes()[i])), getPosition());
if(environment.getType(method.getGenericParameterTypes()[i]).isLarge())
j++;
}
output.start();
for(Statement statement : statements) {
statement.compile(environmentMethod);
}
output.ret();
output.end();
final List<SymbolCaptured> capturedVariables = environmentMethod.getCapturedVariables();
final StringJoiner sj = new StringJoiner("", "(", ")V");
for(SymbolCaptured value : capturedVariables) {
cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL, value.getFieldName(), Type.getDescriptor(value.getType().toJavaClass()), null, null).visitEnd();
sj.add(Type.getDescriptor(value.getType().toJavaClass()));
}
MethodOutput constructor = new MethodOutput(cw, Opcodes.ACC_PUBLIC, "<init>", sj.toString(), null, null);
constructor.start();
constructor.loadObject(0);
constructor.invokeSpecial("java/lang/Object", "<init>", "()V");
{
int i = 1, j = 0;
for(SymbolCaptured capturedVariable : capturedVariables) {
final ZenType type = capturedVariable.getType();
constructor.loadObject(0);
constructor.load(Type.getType(type.toJavaClass()), i + j);
if(type.isLarge()) {
j++;
}
constructor.putField(clsName, capturedVariable.getFieldName(), Type.getDescriptor(capturedVariable.getType().toJavaClass()));
i++;
}
}
constructor.ret();
constructor.end();
environment.putClass(clsName, cw.toByteArray());
// make class instance
environment.getOutput().newObject(clsName);
environment.getOutput().dup();
final String[] arguments = capturedVariables.stream()
.map(SymbolCaptured::getEvaluated)
.peek(expression -> expression.compile(true, environment))
.map(Expression::getType)
.map(ZenType::toASMType)
.map(Type::getDescriptor)
.toArray(String[]::new);
environment.getOutput().construct(clsName, arguments);
}
}