Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

292
LINES

< > BotCompany Repo | #1035078 // LASClassDef - a custom class defined in a left-arrow script. also contains the byte code generator

JavaX fragment (include) [tags: use-pretranspiled]

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]