Uses 679K of libraries. Click here for Pure Java version (27908L/137K).
1 | set flag AllPublic. // so we can access main call() |
2 | |
3 | // functions used in the generated code |
4 | please include functions call preciseGetOrCallMethod set. |
5 | |
6 | srecord noeq LASToByteCode(MethodMaker m) { |
7 | bool callPing = true; |
8 | |
9 | replace Tb with GazelleV_LeftArrowScript. // Short for "Toolbox" |
10 | delegate Evaluable to Tb. |
11 | |
12 | // parameter index of VarContext |
13 | settable int iVarContext = -1; |
14 | |
15 | delegate none, objValue, intValue, doubleValue to JVMStackCellType. |
16 | |
17 | delegate convertToObject, discardStackTop, here, loadNull to m. |
18 | |
19 | Tb.Script returnableScript; |
20 | |
21 | settable IF1<JVMStackCellType> postConversion; |
22 | |
23 | JVMStackCellType compileScript(Tb.Script script) { |
24 | returnableScript = script; |
25 | var stackTop = compile(script); |
26 | if (postConversion != null) |
27 | stackTop = postConversion.get(stackTop); |
28 | ret stackTop; |
29 | } |
30 | |
31 | void compileToObject(Tb.Evaluable code) { |
32 | convertToObject(compile(code)); |
33 | } |
34 | |
35 | JVMStackCellType compile(Tb.Evaluable code) { |
36 | if (code cast Tb.Const) { |
37 | O o = code.value; |
38 | if (o == null) { |
39 | m.add(new ACONST_NULL); |
40 | ret objValue; |
41 | } else if (o cast S) { |
42 | m.stringConstant(o); |
43 | ret objValue; |
44 | } else if (o cast Int) { m.intConstant(o); ret intValue; } |
45 | else if (o cast Double) { m.doubleConstant(o); ret doubleValue; } |
46 | else if (o cast Class) { |
47 | m.classConstant(o); |
48 | ret objValue; |
49 | } else if (o cast Bool) { |
50 | m.boolConstant(o); |
51 | ret intValue; |
52 | } else |
53 | fail("Can't compile const value: " + toStringWithClass(o)); |
54 | } else if (code cast Tb.Script) { |
55 | var stackTop = none; |
56 | for (step : code.steps) { |
57 | // pop result of last instruction if any |
58 | if (stackTop != none) |
59 | m.add(new POP); |
60 | |
61 | stackTop = compile(step); |
62 | } |
63 | ret stackTop; |
64 | } else if (code cast Tb.CallMethod) { |
65 | // push target |
66 | compileToObject(code.target); |
67 | |
68 | // push method name |
69 | m.stringConstant(code.methodName); |
70 | |
71 | // push argument array |
72 | argumentsAsArray(code.args); |
73 | |
74 | // call call() |
75 | m.invokeStatic(mainFunctionHolder call, O, "call", O, S, O[].class); |
76 | ret objValue; |
77 | } else if (code cast Tb.CallMethodOrGetField) { |
78 | // push target |
79 | compileToObject(code.target); |
80 | |
81 | // push method/field name |
82 | m.stringConstant(code.name); |
83 | |
84 | // call call() |
85 | m.invokeStatic(mainFunctionHolder call, O, "preciseGetOrCallMethod", O, S); |
86 | ret objValue; |
87 | } else if (code cast Tb.SetField) { |
88 | // push target |
89 | compileToObject(code.target); |
90 | |
91 | // push field name |
92 | m.stringConstant(code.name); |
93 | |
94 | // push value |
95 | compileToObject(code.expr); |
96 | |
97 | // call set() |
98 | m.invokeStatic(mainFunctionHolder set, O, "set", O, S, O); |
99 | ret none; |
100 | } else if (code cast Tb.NewObject) { |
101 | // push class |
102 | m.classConstant(code.c); |
103 | |
104 | argumentsAsArray(code.args); |
105 | |
106 | // call nuObject() |
107 | m.invokeStatic(mainFunctionHolder nuObject, O, "nuObject", Class.class, O[].class); |
108 | ret objValue; |
109 | } else if (code cast Tb.Assignment) { |
110 | // evaluate expression, store in temporary variable |
111 | compileToObject(code.expression); |
112 | m.astore(iTemp()); |
113 | |
114 | // Call VarContext.set() |
115 | loadVarContext(); |
116 | m.stringConstant(code.var); |
117 | m.aload(iTemp()); |
118 | m.invokeVirtual(VarContext, void.class, "set", S, O); |
119 | |
120 | m.aload(iTemp()); |
121 | ret objValue; |
122 | } else if (code cast Tb.While) { |
123 | |
124 | /* Simulating this: |
125 | |
126 | while (ping() && (Bool) condition.get(ctx)) { |
127 | body.get(ctx); |
128 | } |
129 | null; |
130 | */ |
131 | |
132 | // Mark loop start as jump target |
133 | var loopStart = m.il.append(new NOP); |
134 | |
135 | // Call ping() unless disabled |
136 | BranchInstruction branch1 = null; |
137 | if (callPing) { |
138 | m.invokeStatic(mainFunctionHolder ping, bool.class, "ping"); |
139 | branch1 = new IFEQ(null); |
140 | m.add(branch1); |
141 | } |
142 | |
143 | // Evaluate condition |
144 | compileToBool(code.condition); |
145 | var branch2 = new IFEQ(null); |
146 | m.add(branch2); |
147 | |
148 | // Evaluate body |
149 | discardStackTop(compile(code.body)); |
150 | |
151 | // Jump to loop start |
152 | m.add(new GOTO(loopStart)); |
153 | |
154 | // Update forward branches |
155 | var loopEnd = m.il.append(new NOP); |
156 | branch1?.setTarget(loopEnd); |
157 | branch2.setTarget(loopEnd); |
158 | |
159 | ret none; |
160 | } else if (code cast Tb.IfThen) { |
161 | compileToBool(code.condition); |
162 | var branch1 = new IFEQ(null); |
163 | m.add(branch1); |
164 | |
165 | // Evaluate body |
166 | var stackTop = compile(code.body); |
167 | |
168 | // body returns nothing? then we don't need an else branch |
169 | if (stackTop == none) { |
170 | branch1.setTarget(here()); |
171 | ret stackTop; |
172 | } else { |
173 | // otherwise, convert to object and return null in else branch |
174 | convertToObject(stackTop); |
175 | var jumpToEnd = m.forwardGoto(); |
176 | branch1.setTarget(here()); |
177 | loadNull(); |
178 | jumpToEnd.setTarget(m.here()); |
179 | ret objValue; |
180 | } |
181 | } else if (code cast Tb.GetVar) { |
182 | ret compileGetVar(code); |
183 | } else if (code cast Tb.ReturnFromScript) { |
184 | if (code.script != returnableScript) |
185 | fail("Can only return from current script"); |
186 | |
187 | var stackTop = compile(code.value); |
188 | if (postConversion != null) |
189 | stackTop = postConversion.get(stackTop); |
190 | m.returnWithType(stackTop); |
191 | ret none; |
192 | } |
193 | |
194 | fail("Can't compile yet: " + className(code)); |
195 | } |
196 | |
197 | void argumentsAsArray(Evaluable[] args) { |
198 | int n = l(args); |
199 | m.intConst(n); |
200 | m.add(new ANEWARRAY(m.classRef(O))); |
201 | for iArg to n: { |
202 | m.dup(); // get array again |
203 | m.intConst(iArg); |
204 | compileToObject(args[iArg]); |
205 | m.add(new AASTORE); |
206 | } |
207 | } |
208 | |
209 | void loadVarContext { |
210 | assertTrue("Need VarContext", iVarContext >= 0); |
211 | m.aload(iVarContext); |
212 | } |
213 | |
214 | // index of a temporary variable, created on demand |
215 | simplyCached int iTemp() { |
216 | ret m.newLocalVar(); |
217 | } |
218 | |
219 | void compileToBool(Evaluable condition) { |
220 | var stackTop = compile(condition); |
221 | if (stackTop == objValue) { |
222 | // cast to Boolean |
223 | m.checkCast(Bool.class); |
224 | |
225 | // call Boolean.booleanValue() |
226 | m.invokeVirtual(Bool.class, bool.class, "booleanValue"); |
227 | } else if (stackTop == intValue) {} // ok |
228 | else fail("Can't convert to bool: " + stackTop); |
229 | } |
230 | |
231 | JVMStackCellType compileGetVar(Tb.GetVar code) { |
232 | // Prepare VarContext.get() |
233 | loadVarContext(); |
234 | m.stringConstant(code.var); |
235 | |
236 | // call VarContext.get() |
237 | m.invokeVirtual(VarContext, O, "get", S); |
238 | ret objValue; |
239 | } |
240 | } |
download show line numbers debug dex old transpilations
Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1034318 |
Snippet name: | LASToByteCode [works for many language constructs already!] |
Eternal ID of this version: | #1034318/60 |
Text MD5: | 45a3c6205c10b2da44e97aff01b3db9a |
Transpilation MD5: | b3cc75795f4f4ba4052728b91b2b6b06 |
Author: | stefan |
Category: | javax / left arrow script |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-04-02 17:23:10 |
Source code size: | 6955 bytes / 240 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 249 / 604 |
Version history: | 59 change(s) |
Referenced in: | [show references] |