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

282
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 (31510L) 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  
  simplyCached byte[] toBytes() {
67  
    ClassMaker classMaker = new(finalClassName(), className(typeToClass(superClass)),
68  
      mapToStringArray(interfaces, i -> className(typeToClass(i))));
69  
    var cp = classMaker.getConstantPool();
70  
    
71  
    for (field : fields) {
72  
      var type = field.type;
73  
      var fg = new FieldGen(
74  
        Const.ACC_PUBLIC, typeToBCELType(type),
75  
        field.name, cp);
76  
      fg.isTransient(field.hasModifier("transient"));
77  
      fg.isStatic(field.isStatic());
78  
      if (type cast ParameterizedType)
79  
        fg.addAttribute(new org.apache.bcel.classfile.Signature(
80  
          cp.addUtf8("Signature"), 2,
81  
          cp.addUtf8(typeToVMSignature(type)),
82  
          cp.getConstantPool()));
83  
      classMaker.addField(fg);
84  
      field.bcel = fg;
85  
    }
86  
    
87  
    if (nempty(initializers)) {
88  
      addMethod(initializerMethod = new FunctionDef("$initFields", new S[0], new Script(initializers)).returnType(void.class));
89  
      
90  
      if (!hasUserDefinedDefaultConstructor())
91  
        addMethod(new FunctionDef("<init>", new S[0], new Script(emptyList())).returnType(void.class));
92  
    }
93  
    
94  
    for (method : methods)
95  
      if (fullCompilation)
96  
        fullyCompileMethod(classMaker, method);
97  
      else
98  
        semiCompileMethod(classMaker, method);
99  
100  
    if (!hasUserDefinedDefaultConstructor())
101  
      classMaker.addDefaultConstructor();
102  
    
103  
    if (srcRef() != null)
104  
      classMaker.addField(new FieldGen(
105  
        Const.ACC_PUBLIC | Const.ACC_STATIC, classToBCELType(TokenRangeWithSrc),
106  
        srcRefField(), classMaker.getConstantPool()));
107  
108  
    ret classMaker.toBytes();
109  
  }
110  
  
111  
  TokenRangeWithSrc srcRef() { ret tokenRangeWithSrc(); }
112  
  
113  
  void addToInitializerMethod(FieldDef field) {
114  
    if (field.isStatic()) ret;
115  
    isFieldInitializer.set(l(initializers));
116  
    initializers.add(
117  
      new Tb.SetField(new Tb.GetVar("this"), field.name, field.initializer));
118  
  }
119  
  
120  
  bool hasUserDefinedDefaultConstructor() {
121  
    ret any(methods, m -> m.isConstructor() && empty(m.args));
122  
  }
123  
  
124  
  // generate interpreted method (slower but always works)
125  
  // like this:
126  
  //
127  
  // new FlexibleVarContext ctx;
128  
  // ctx.put("this", this);
129  
  // ctx.put("arg1", arg1);
130  
  // ctx.put("arg2", arg2);
131  
  // ret methodBody.get(ctx);
132  
  
133  
  void semiCompileMethod(ClassMaker classMaker, FunctionDef method) {
134  
    // make static field for method body later
135  
    int iMethod = l(methodBodies);
136  
    methodBodies.add(method);
137  
    S bodyFieldName = "_body" + iMethod;
138  
    classMaker.addField(new FieldGen(
139  
      Const.ACC_PUBLIC | Const.ACC_STATIC, classToBCELType(Evaluable.class),
140  
      bodyFieldName, classMaker.getConstantPool()));
141  
142  
    int nArgs = l(method.args);
143  
    MethodMaker mm = new(classMaker.cg(), Const.ACC_PUBLIC, typeToBCEL(method.returnType), method.name,
144  
      mapToArray typeToBCEL(method.argTypes));
145  
    
146  
    int iThis = 0, iCtx = mm.frameSize;
147  
    
148  
    // If we are compiling a constructor, call the superclass constructor and $initFields
149  
    if (method.isConstructor()) {
150  
      mm.aload(iThis);
151  
      mm.invokeConstructor(typeToClass(superClass));
152  
      
153  
      if (initializerMethod != null) {
154  
        mm.aload(iThis);
155  
        mm.il.append(mm.factory.createInvoke(classMaker.className(), initializerMethod.name,
156  
          mm.wrapType(void.class),
157  
          mm.wrapTypes(new Class[0]), Const.INVOKESPECIAL));
158  
      }
159  
    }
160  
    
161  
    // new FlexibleVarContext ctx;
162  
    mm.newObject(FlexibleVarContext);
163  
    mm.astore(iCtx);
164  
165  
    // ctx.put("this", this);
166  
    mm.aload(iCtx);
167  
    mm.stringConstant("this");
168  
    mm.aload(iThis);
169  
    mm.invokeVirtual(VarContext, void.class, "put", S, O);
170  
  
171  
    // ctx.put("arg<n>", arg<n>);
172  
    for iArg to nArgs: {
173  
      mm.aload(iCtx);
174  
      mm.stringConstant(method.args[iArg]);
175  
      mm.aloadArgWithAutoboxing(iArg);
176  
      mm.invokeVirtual(VarContext, void.class, "put", S, O);
177  
    }
178  
  
179  
    // ret methodBody.get(ctx);
180  
    mm.getStaticField(classMaker.className(), bodyFieldName, Evaluable.class);
181  
    mm.aload(iCtx);
182  
    mm.invokeInterface(Evaluable.class, O, "get", VarContext);
183  
    
184  
    // cast and return
185  
    
186  
    Type type = method.returnType();
187  
    if (type == void.class)
188  
      mm.return();
189  
    else {
190  
      if (type cast Class && isPrimitiveType(type)) {
191  
        // unbox primitive value
192  
        Class c = type;
193  
        Class boxed = primitiveToBoxedType(c);
194  
        mm.checkCast(typeToBCEL(boxed));
195  
        mm.invokeVirtual(boxed, c, c + "Value");
196  
        mm.returnPrimitive(c);
197  
      } else {
198  
        if (type != O) 
199  
          mm.checkCast(typeToBCEL(type));
200  
        mm.areturn();
201  
      }
202  
    }
203  
    
204  
    mm.done();
205  
    
206  
    //print("Made method " + mm.mg.getMethod());
207  
  }
208  
209  
  // fully compile method to byte code (this works only for very simple methods)
210  
  void fullyCompileMethod(ClassMaker classMaker, FunctionDef method) {
211  
    MethodMaker mm = new(classMaker, typeToClass(method.returnType()), method.name,
212  
      repArray(Class.class, O.class, l(method.args)));
213  
          
214  
    var tbc = LASToByteCode(mm) {
215  
      JVMStackCellType compileGetVar(Tb.GetVar code) {
216  
        // load "this"
217  
        
218  
        if (eq(code.var, "this")) {
219  
          mm.aload(0);
220  
          ret JVMStackCellType.objValue;
221  
        }
222  
        
223  
        // load method argument
224  
        
225  
        int iArg = indexOf(method.args, code.var);
226  
        if (iArg >= 0) {
227  
          mm.aload(iArg+1);
228  
          ret JVMStackCellType.objValue;
229  
        }
230  
          
231  
        ret super.compileGetVar(code);
232  
      }
233  
    };
234  
    tbc.postConversion = stackTop -> mm.convertToObject(stackTop);
235  
    tbc.compileScript(method.body);
236  
    mm.areturn();
237  
    mm.done();
238  
  }
239  
  
240  
  void init(Class c) {
241  
    if (resolvedClass != null) ret;
242  
    resolvedClass = c;
243  
    
244  
    for iMethod over methodBodies: {
245  
      S bodyFieldName = "_body" + iMethod;
246  
      set(c, bodyFieldName, methodBodies.get(iMethod).body);
247  
    }
248  
    
249  
    for (field : fields)
250  
      if (field.isStatic() && field.initializer != null)
251  
        set(c, field.name, field.initializer.get());
252  
253  
    setOpt(c, srcRefField(), srcRef());
254  
  }
255  
  
256  
  ResolvableLASClass resolvable(ILASClassLoader lasClassLoader) {
257  
    ret new ResolvableLASClass(lasClassLoader, this);
258  
  }
259  
  
260  
  O typeToBCEL(LASValueDescriptor descriptor) {
261  
    ret or(descriptor?.javaClass(), O);
262  
  }
263  
  
264  
  O typeToBCEL(Type type) {
265  
    try object resolvableClassToName(type);
266  
    ret typeToClass(type);
267  
  }
268  
  
269  
  void addField(FieldDef field) {
270  
    fields.add(field);
271  
    fieldsByName.put(field.name, field);
272  
    if (field.initializer != null)
273  
      addToInitializerMethod(field);
274  
  }
275  
  
276  
  void addMethod(FunctionDef method) {
277  
    methods.add(method);
278  
    methodsByName.put(method.name, method);
279  
  }
280  
  
281  
  S srcRefField() { ret "__srcRef"; }
282  
}

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/99
Text MD5: c77c85326ed42763140d4105243e3662
Author: stefan
Category: javax / left arrow script
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2023-04-29 23:59:57
Source code size: 8549 bytes / 282 lines
Pitched / IR pitched: No / No
Views / Downloads: 319 / 695
Version history: 98 change(s)
Referenced in: [show references]