Transpiled version (31971L) is out of date.
1  | sclass LASClassDef extends HasTokenRangeWithSrc {
 | 
2  | settable S userGivenName;  | 
3  | settable S classDefPrefix = "userCode.";  | 
4  | settable bool fullCompilation;  | 
5  | settable bool verbose = true;  | 
6  | |
7  | replace Tb with GazelleV_LeftArrowScript.  | 
8  | delegate FunctionDef, Evaluable, Script to Tb.  | 
9  | |
10  | transient Class resolvedClass;  | 
11  | |
12  | settable Type superClass = O.class;  | 
13  | |
14  | new L<FieldDef> fields;  | 
15  | new Map<S, FieldDef> fieldsByName;  | 
16  | |
17  | new L<FunctionDef> methods;  | 
18  | new MultiMap<S, FunctionDef> methodsByName;  | 
19  | |
20  | new L<FunctionDef> methodBodies;  | 
21  | |
22  | new L<Type> interfaces;  | 
23  | |
24  | FunctionDef initializerMethod;  | 
25  | |
26  | new L<Evaluable> initializers;  | 
27  | new BitSet isFieldInitializer;  | 
28  | |
29  | //new L<Evaluable> staticInitializers;  | 
30  | new LPair<S, Evaluable> staticFieldInitializers;  | 
31  | |
32  |   sclass FieldDef {
 | 
33  | settable S name;  | 
34  | settable Type type;  | 
35  | settable Evaluable initializer;  | 
36  | Set<S> modifiers;  | 
37  | |
38  | transient FieldGen bcel;  | 
39  | |
40  |     bool hasModifier(S modifier) { ret contains(modifiers, modifier); }
 | 
41  |     void addModifier(S modifier) { modifiers = createOrAddToSet(modifiers, modifier); }
 | 
42  | |
43  |     bool isStatic() { ret hasModifier("static"); }
 | 
44  | }  | 
45  | |
46  |   S structForHash() {
 | 
47  | ret Tb.scriptStruct(litorderedmap(  | 
48  | +userGivenName, +fields, +methods, +fullCompilation  | 
49  | ));  | 
50  | }  | 
51  | |
52  |   simplyCached S classHash() {
 | 
53  | S struct = structForHash();  | 
54  | if (verbose) print(structForHash := struct);  | 
55  | ret md5(struct);  | 
56  | }  | 
57  | |
58  |   S finalClassName() {
 | 
59  | ret classDefPrefix() + finalClassNameWithoutPrefix();  | 
60  | }  | 
61  | |
62  |   S finalClassNameWithoutPrefix() {
 | 
63  | ret or2(userGivenName, "C") + "_" + classHash();  | 
64  | }  | 
65  | |
66  |   Class typeToClassNonNull(Type t) {
 | 
67  | Class c = typeToClass(t);  | 
68  | if (t != null && c == null)  | 
69  |       fail("Can't resolve type to class: " + toStringWithClassName(t));
 | 
70  | ret c;  | 
71  | }  | 
72  | |
73  |   simplyCached byte[] toBytes() {
 | 
74  | ClassMaker classMaker = new(finalClassName(), className(typeToClassNonNull(superClass)),  | 
75  | mapToStringArray(interfaces, i -> className(typeToClassNonNull(i))));  | 
76  | var cp = classMaker.getConstantPool();  | 
77  | |
78  |     for (field : fields) {
 | 
79  | var type = field.type;  | 
80  | assertNotNull(+type);  | 
81  | var bcelType = typeToBCELType(type);  | 
82  | assertNotNull(+bcelType);  | 
83  | var fg = new FieldGen(  | 
84  | Const.ACC_PUBLIC, bcelType,  | 
85  | field.name, cp);  | 
86  |       fg.isTransient(field.hasModifier("transient"));
 | 
87  | fg.isStatic(field.isStatic());  | 
88  | if (type cast ParameterizedType)  | 
89  | fg.addAttribute(new org.apache.bcel.classfile.Signature(  | 
90  |           cp.addUtf8("Signature"), 2,
 | 
91  | cp.addUtf8(typeToVMSignature(type)),  | 
92  | cp.getConstantPool()));  | 
93  | classMaker.addField(fg);  | 
94  | field.bcel = fg;  | 
95  | }  | 
96  | |
97  |     if (nempty(initializers)) {
 | 
98  |       addMethod(initializerMethod = new FunctionDef("$initFields", new S[0], new Script(initializers)).returnType(void.class));
 | 
99  | |
100  | if (!hasUserDefinedDefaultConstructor())  | 
101  |         addMethod(new FunctionDef("<init>", new S[0], new Script(emptyList())).returnType(void.class));
 | 
102  | }  | 
103  | |
104  | for (method : methods)  | 
105  | if (fullCompilation)  | 
106  | fullyCompileMethod(classMaker, method);  | 
107  | else  | 
108  | semiCompileMethod(classMaker, method);  | 
109  | |
110  | if (!hasUserDefinedDefaultConstructor())  | 
111  | classMaker.addDefaultConstructor();  | 
112  | |
113  | if (srcRef() != null)  | 
114  | classMaker.addField(new FieldGen(  | 
115  | Const.ACC_PUBLIC | Const.ACC_STATIC, classToBCELType(TokenRangeWithSrc),  | 
116  | srcRefField(), classMaker.getConstantPool()));  | 
117  | |
118  | ret classMaker.toBytes();  | 
119  | }  | 
120  | |
121  |   TokenRangeWithSrc srcRef() { ret tokenRangeWithSrc(); }
 | 
122  | |
123  |   void addToInitializerMethod(FieldDef field) {
 | 
124  | if (field.isStatic()) ret;  | 
125  | isFieldInitializer.set(l(initializers));  | 
126  | initializers.add(  | 
127  |       new Tb.SetField(new Tb.GetVar("this"), field.name, field.initializer));
 | 
128  | }  | 
129  | |
130  |   bool hasUserDefinedDefaultConstructor() {
 | 
131  | ret any(methods, m -> m.isConstructor() && empty(m.args));  | 
132  | }  | 
133  | |
134  | // generate interpreted method (slower but always works)  | 
135  | // like this:  | 
136  | //  | 
137  | // new FlexibleVarContext ctx;  | 
138  |   // ctx.put("this", this);
 | 
139  |   // ctx.put("arg1", arg1);
 | 
140  |   // ctx.put("arg2", arg2);
 | 
141  | // ret methodBody.get(ctx);  | 
142  | |
143  |   void semiCompileMethod(ClassMaker classMaker, FunctionDef method) {
 | 
144  | // make static field for method body later  | 
145  | int iMethod = l(methodBodies);  | 
146  | methodBodies.add(method);  | 
147  | S bodyFieldName = "_body" + iMethod;  | 
148  | classMaker.addField(new FieldGen(  | 
149  | Const.ACC_PUBLIC | Const.ACC_STATIC, classToBCELType(Evaluable.class),  | 
150  | bodyFieldName, classMaker.getConstantPool()));  | 
151  | |
152  | int nArgs = l(method.args);  | 
153  | MethodMaker mm = new(classMaker.cg(), Const.ACC_PUBLIC, typeToBCEL(method.returnType), method.name,  | 
154  | mapToArray typeToBCEL(method.argTypes));  | 
155  | |
156  | int iThis = 0, iCtx = mm.frameSize;  | 
157  | |
158  | // If we are compiling a constructor, call the superclass constructor and $initFields  | 
159  |     if (method.isConstructor()) {
 | 
160  | mm.aload(iThis);  | 
161  | mm.invokeConstructor(typeToClass(superClass));  | 
162  | |
163  |       if (initializerMethod != null) {
 | 
164  | mm.aload(iThis);  | 
165  | mm.il.append(mm.factory.createInvoke(classMaker.className(), initializerMethod.name,  | 
166  | mm.wrapType(void.class),  | 
167  | mm.wrapTypes(new Class[0]), Const.INVOKESPECIAL));  | 
168  | }  | 
169  | }  | 
170  | |
171  | // new FlexibleVarContext ctx;  | 
172  | mm.newObject(FlexibleVarContext);  | 
173  | mm.astore(iCtx);  | 
174  | |
175  |     // ctx.put("this", this);
 | 
176  | mm.aload(iCtx);  | 
177  |     mm.stringConstant("this");
 | 
178  | mm.aload(iThis);  | 
179  | mm.invokeVirtual(VarContext, void.class, "put", S, O);  | 
180  | |
181  |     // ctx.put("arg<n>", arg<n>);
 | 
182  |     for iArg to nArgs: {
 | 
183  | mm.aload(iCtx);  | 
184  | mm.stringConstant(method.args[iArg]);  | 
185  | mm.aloadArgWithAutoboxing(iArg);  | 
186  | mm.invokeVirtual(VarContext, void.class, "put", S, O);  | 
187  | }  | 
188  | |
189  | // ret methodBody.get(ctx);  | 
190  | mm.getStaticField(classMaker.className(), bodyFieldName, Evaluable.class);  | 
191  | mm.aload(iCtx);  | 
192  | mm.invokeInterface(Evaluable.class, O, "get", VarContext);  | 
193  | |
194  | // cast and return  | 
195  | |
196  | Type type = method.returnType();  | 
197  | if (type == void.class)  | 
198  | mm.return();  | 
199  |     else {
 | 
200  |       if (type cast Class && isPrimitiveType(type)) {
 | 
201  | // unbox primitive value  | 
202  | Class c = type;  | 
203  | Class boxed = primitiveToBoxedType(c);  | 
204  | mm.checkCast(typeToBCEL(boxed));  | 
205  | mm.invokeVirtual(boxed, c, c + "Value");  | 
206  | mm.returnPrimitive(c);  | 
207  |       } else {
 | 
208  | if (type != O)  | 
209  | mm.checkCast(typeToBCEL(type));  | 
210  | mm.areturn();  | 
211  | }  | 
212  | }  | 
213  | |
214  | mm.done();  | 
215  | |
216  |     //print("Made method " + mm.mg.getMethod());
 | 
217  | }  | 
218  | |
219  | // fully compile method to byte code (this works only for very simple methods)  | 
220  |   void fullyCompileMethod(ClassMaker classMaker, FunctionDef method) {
 | 
221  | MethodMaker mm = new(classMaker, typeToClass(method.returnType()), method.name,  | 
222  | repArray(Class.class, O.class, l(method.args)));  | 
223  | |
224  |     var tbc = LASToByteCode(mm) {
 | 
225  |       JVMStackCellType compileGetVar(Tb.GetVar code) {
 | 
226  | // load "this"  | 
227  | |
228  |         if (eq(code.var, "this")) {
 | 
229  | mm.aload(0);  | 
230  | ret JVMStackCellType.objValue;  | 
231  | }  | 
232  | |
233  | // load method argument  | 
234  | |
235  | int iArg = indexOf(method.args, code.var);  | 
236  |         if (iArg >= 0) {
 | 
237  | mm.aload(iArg+1);  | 
238  | ret JVMStackCellType.objValue;  | 
239  | }  | 
240  | |
241  | ret super.compileGetVar(code);  | 
242  | }  | 
243  | };  | 
244  | tbc.postConversion = stackTop -> mm.convertToObject(stackTop);  | 
245  | tbc.compileScript(method.body);  | 
246  | mm.areturn();  | 
247  | mm.done();  | 
248  | }  | 
249  | |
250  |   void init(Class c) {
 | 
251  | if (resolvedClass != null) ret;  | 
252  | resolvedClass = c;  | 
253  | |
254  |     for iMethod over methodBodies: {
 | 
255  | S bodyFieldName = "_body" + iMethod;  | 
256  | set(c, bodyFieldName, methodBodies.get(iMethod).body);  | 
257  | }  | 
258  | |
259  | for (field : fields)  | 
260  | if (field.isStatic() && field.initializer != null)  | 
261  | set(c, field.name, field.initializer.get());  | 
262  | |
263  | setOpt(c, srcRefField(), srcRef());  | 
264  | }  | 
265  | |
266  |   ResolvableLASClass resolvable(ILASClassLoader lasClassLoader) {
 | 
267  | ret new ResolvableLASClass(lasClassLoader, this);  | 
268  | }  | 
269  | |
270  |   O typeToBCEL(LASValueDescriptor descriptor) {
 | 
271  | ret or(descriptor?.javaClass(), O);  | 
272  | }  | 
273  | |
274  |   O typeToBCEL(Type type) {
 | 
275  | try object resolvableClassToName(type);  | 
276  | ret typeToClass(type);  | 
277  | }  | 
278  | |
279  |   void addField(FieldDef field) {
 | 
280  | fields.add(field);  | 
281  | fieldsByName.put(field.name, field);  | 
282  | if (field.initializer != null)  | 
283  | addToInitializerMethod(field);  | 
284  | }  | 
285  | |
286  |   void addMethod(FunctionDef method) {
 | 
287  | methods.add(method);  | 
288  | methodsByName.put(method.name, method);  | 
289  | }  | 
290  | |
291  |   S srcRefField() { ret "__srcRef"; }
 | 
292  | }  | 
download show line numbers debug dex old transpilations
Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj
No comments. add comment
| Snippet ID: | #1035078 | 
| Snippet name: | LASClassDef - a custom class defined in a left-arrow script. also contains the byte code generator | 
| Eternal ID of this version: | #1035078/103 | 
| Text MD5: | 85c20f308cf81fde6bfd0c787c9ee52b | 
| Author: | stefan | 
| Category: | javax / left arrow script | 
| Type: | JavaX fragment (include) | 
| Public (visible to everyone): | Yes | 
| Archived (hidden from active list): | No | 
| Created/modified: | 2025-10-22 17:13:37 | 
| Source code size: | 8853 bytes / 292 lines | 
| Pitched / IR pitched: | No / No | 
| Views / Downloads: | 3031 / 3751 | 
| Version history: | 102 change(s) | 
| Referenced in: | [show references] |