|
@@ -6,7 +6,10 @@
|
6
|
6
|
package org.openzen.zenscript.javabytecode;
|
7
|
7
|
|
8
|
8
|
import java.util.ArrayList;
|
|
9
|
+import java.util.HashMap;
|
9
|
10
|
import java.util.List;
|
|
11
|
+import java.util.Map;
|
|
12
|
+
|
10
|
13
|
import org.objectweb.asm.ClassWriter;
|
11
|
14
|
import org.objectweb.asm.Opcodes;
|
12
|
15
|
import org.openzen.zenscript.codemodel.HighLevelDefinition;
|
|
@@ -15,6 +18,7 @@ import org.openzen.zenscript.codemodel.member.DefinitionMember;
|
15
|
18
|
import org.openzen.zenscript.codemodel.statement.Statement;
|
16
|
19
|
import static org.openzen.zenscript.codemodel.type.member.BuiltinTypeMembers.*;
|
17
|
20
|
|
|
21
|
+import org.openzen.zenscript.javabytecode.compiler.JavaClassWriter;
|
18
|
22
|
import org.openzen.zenscript.javabytecode.compiler.definitions.JavaDefinitionVisitor;
|
19
|
23
|
import org.openzen.zenscript.javabytecode.compiler.JavaStatementVisitor;
|
20
|
24
|
import org.openzen.zenscript.javabytecode.compiler.JavaWriter;
|
|
@@ -127,8 +131,8 @@ public class JavaCompiler {
|
127
|
131
|
}
|
128
|
132
|
|
129
|
133
|
private final JavaModule target;
|
130
|
|
- private final List<String> scriptBlockNames = new ArrayList<>();
|
131
|
|
- private final ClassWriter scriptsClassWriter;
|
|
134
|
+ private final Map<String, JavaClassWriter> scriptBlocks = new HashMap<>();
|
|
135
|
+ private final JavaClassWriter scriptsClassWriter;
|
132
|
136
|
private int generatedScriptBlockCounter = 0;
|
133
|
137
|
private boolean finished = false;
|
134
|
138
|
|
|
@@ -139,19 +143,29 @@ public class JavaCompiler {
|
139
|
143
|
public JavaCompiler(boolean debug) {
|
140
|
144
|
target = new JavaModule();
|
141
|
145
|
|
142
|
|
- scriptsClassWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
|
146
|
+ scriptsClassWriter = new JavaClassWriter(ClassWriter.COMPUTE_FRAMES, true);
|
143
|
147
|
scriptsClassWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Scripts", null, "java/lang/Object", null);
|
144
|
148
|
}
|
145
|
149
|
|
146
|
150
|
public void addDefinition(HighLevelDefinition definition) {
|
147
|
151
|
// convert definition into java class
|
148
|
|
- target.register(definition.name, definition.accept(new JavaDefinitionVisitor()));
|
|
152
|
+
|
|
153
|
+ final String methodName = definition.position.filename.substring(0, definition.position.filename.lastIndexOf('.')).replace("/", "_");
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+ if(!scriptBlocks.containsKey(methodName)) {
|
|
157
|
+ JavaClassWriter scriptFileWriter = new JavaClassWriter(ClassWriter.COMPUTE_FRAMES);
|
|
158
|
+ scriptFileWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, methodName, null, "java/lang/Object", null);
|
|
159
|
+ scriptBlocks.put(methodName, scriptFileWriter);
|
|
160
|
+ }
|
|
161
|
+
|
|
162
|
+ target.register(definition.name, definition.accept(new JavaDefinitionVisitor(scriptBlocks.get(definition.position.filename))));
|
149
|
163
|
|
150
|
164
|
}
|
151
|
165
|
|
152
|
166
|
public void addScriptBlock(ScriptBlock script) {
|
153
|
|
- SourceFile sourceFile = script.getTag(SourceFile.class);
|
154
|
|
- String methodName;
|
|
167
|
+ final SourceFile sourceFile = script.getTag(SourceFile.class);
|
|
168
|
+ final String methodName;
|
155
|
169
|
if (sourceFile == null) {
|
156
|
170
|
methodName = "generatedBlock" + (generatedScriptBlockCounter++);
|
157
|
171
|
} else {
|
|
@@ -160,11 +174,17 @@ public class JavaCompiler {
|
160
|
174
|
methodName = sourceFile.filename.substring(0, sourceFile.filename.lastIndexOf('.')).replace("/", "_");
|
161
|
175
|
}
|
162
|
176
|
|
163
|
|
- scriptBlockNames.add(methodName);
|
|
177
|
+ if(!scriptBlocks.containsKey(methodName)) {
|
|
178
|
+ JavaClassWriter scriptFileWriter = new JavaClassWriter(ClassWriter.COMPUTE_FRAMES, true);
|
|
179
|
+ scriptFileWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, methodName, null, "java/lang/Object", null);
|
|
180
|
+ scriptBlocks.put(methodName, scriptFileWriter);
|
|
181
|
+ }
|
164
|
182
|
|
165
|
183
|
// convert scripts into methods (add them to a Scripts class?)
|
166
|
184
|
// (TODO: can we break very long scripts into smaller methods? for the extreme scripts)
|
167
|
|
- final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(new JavaWriter(scriptsClassWriter, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, methodName, "()V", null, null));
|
|
185
|
+ final JavaClassWriter visitor = scriptBlocks.get(methodName);
|
|
186
|
+ visitor.hasRun = true;
|
|
187
|
+ final JavaStatementVisitor statementVisitor = new JavaStatementVisitor(new JavaWriter(visitor, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "run", "()V", null, null));
|
168
|
188
|
statementVisitor.start();
|
169
|
189
|
for (Statement statement : script.statements) {
|
170
|
190
|
statement.accept(statementVisitor);
|
|
@@ -180,8 +200,13 @@ public class JavaCompiler {
|
180
|
200
|
|
181
|
201
|
final JavaWriter runWriter = new JavaWriter(scriptsClassWriter, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "run", "()V", null, null);
|
182
|
202
|
runWriter.start();
|
183
|
|
- for (String scriptBlockName : scriptBlockNames) {
|
184
|
|
- runWriter.invokeStatic("Scripts", scriptBlockName, "()V");
|
|
203
|
+ for (Map.Entry<String, JavaClassWriter> entry : scriptBlocks.entrySet()) {
|
|
204
|
+ final String owner = entry.getKey();
|
|
205
|
+ final JavaClassWriter classWriter = entry.getValue();
|
|
206
|
+ if(classWriter.hasRun)
|
|
207
|
+ runWriter.invokeStatic(owner, "run", "()V");
|
|
208
|
+ classWriter.visitEnd();
|
|
209
|
+ target.register(owner, classWriter.toByteArray());
|
185
|
210
|
}
|
186
|
211
|
runWriter.ret();
|
187
|
212
|
runWriter.end();
|