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

240
LINES

< > BotCompany Repo | #1034318 // LASToByteCode [works for many language constructs already!]

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

Uses 679K of libraries. Click here for Pure Java version (27908L/137K).

set flag AllPublic. // so we can access main call()

// functions used in the generated code
please include functions call preciseGetOrCallMethod set.

srecord noeq LASToByteCode(MethodMaker m) {
  bool callPing = true;
  
  replace Tb with GazelleV_LeftArrowScript. // Short for "Toolbox"
  delegate Evaluable to Tb.
  
  // parameter index of VarContext
  settable int iVarContext = -1;
  
  delegate none, objValue, intValue, doubleValue to JVMStackCellType.
  
  delegate convertToObject, discardStackTop, here, loadNull to m.
  
  Tb.Script returnableScript;
  
  settable IF1<JVMStackCellType> postConversion;
  
  JVMStackCellType compileScript(Tb.Script script) {
    returnableScript = script;
    var stackTop = compile(script);
    if (postConversion != null)
      stackTop = postConversion.get(stackTop);
    ret stackTop;
  }
  
  void compileToObject(Tb.Evaluable code) {
    convertToObject(compile(code));
  }

  JVMStackCellType compile(Tb.Evaluable code) {
    if (code cast Tb.Const) {
      O o = code.value;
      if (o == null) {
        m.add(new ACONST_NULL);
        ret objValue;
      } else if (o cast S) {
        m.stringConstant(o);
        ret objValue;
      } else if (o cast Int) { m.intConstant(o); ret intValue; }
      else if (o cast Double) { m.doubleConstant(o); ret doubleValue; }
      else if (o cast Class) {
        m.classConstant(o);
        ret objValue;
      } else if (o cast Bool) {
        m.boolConstant(o);
        ret intValue;
      } else
        fail("Can't compile const value: " + toStringWithClass(o));
    } else if (code cast Tb.Script) {
      var stackTop = none;
      for (step : code.steps) {
        // pop result of last instruction if any
        if (stackTop != none)
          m.add(new POP);
          
        stackTop = compile(step);
      }
      ret stackTop;
    } else if (code cast Tb.CallMethod) {
      // push target
      compileToObject(code.target);
      
      // push method name
      m.stringConstant(code.methodName);
      
      // push argument array
      argumentsAsArray(code.args);
      
      // call call()
      m.invokeStatic(mainFunctionHolder call, O, "call", O, S, O[].class);
      ret objValue;
    } else if (code cast Tb.CallMethodOrGetField) {
      // push target
      compileToObject(code.target);
      
      // push method/field name
      m.stringConstant(code.name);
      
      // call call()
      m.invokeStatic(mainFunctionHolder call, O, "preciseGetOrCallMethod", O, S);
      ret objValue;
    } else if (code cast Tb.SetField) {
      // push target
      compileToObject(code.target);
      
      // push field name
      m.stringConstant(code.name);
      
      // push value
      compileToObject(code.expr);
      
      // call set()
      m.invokeStatic(mainFunctionHolder set, O, "set", O, S, O);
      ret none;
    } else if (code cast Tb.NewObject) {
      // push class
      m.classConstant(code.c);
      
      argumentsAsArray(code.args);
      
      // call nuObject()
      m.invokeStatic(mainFunctionHolder nuObject, O, "nuObject", Class.class, O[].class);
      ret objValue;
    } else if (code cast Tb.Assignment) {
      // evaluate expression, store in temporary variable
      compileToObject(code.expression);
      m.astore(iTemp());
      
      // Call VarContext.set()
      loadVarContext();
      m.stringConstant(code.var);
      m.aload(iTemp());
      m.invokeVirtual(VarContext, void.class, "set", S, O);
      
      m.aload(iTemp());
      ret objValue;
    } else if (code cast Tb.While) {
    
    /* Simulating this:
      
       while (ping() && (Bool) condition.get(ctx)) {
         body.get(ctx);
       }
       null;
    */
    
      // Mark loop start as jump target
      var loopStart = m.il.append(new NOP);

      // Call ping() unless disabled
      BranchInstruction branch1 = null;
      if (callPing) {
        m.invokeStatic(mainFunctionHolder ping, bool.class, "ping");
        branch1 = new IFEQ(null);
        m.add(branch1);
      }
      
      // Evaluate condition
      compileToBool(code.condition);
      var branch2 = new IFEQ(null);
      m.add(branch2);
      
      // Evaluate body
      discardStackTop(compile(code.body));
      
      // Jump to loop start
      m.add(new GOTO(loopStart));
      
      // Update forward branches
      var loopEnd = m.il.append(new NOP);
      branch1?.setTarget(loopEnd);
      branch2.setTarget(loopEnd);
      
      ret none;
    } else if (code cast Tb.IfThen) {
      compileToBool(code.condition);
      var branch1 = new IFEQ(null);
      m.add(branch1);
      
      // Evaluate body
      var stackTop = compile(code.body);
      
      // body returns nothing? then we don't need an else branch
      if (stackTop == none) {
        branch1.setTarget(here());
        ret stackTop;
      } else {
        // otherwise, convert to object and return null in else branch
        convertToObject(stackTop);
        var jumpToEnd = m.forwardGoto();
        branch1.setTarget(here());
        loadNull();
        jumpToEnd.setTarget(m.here());
        ret objValue;
      }
    } else if (code cast Tb.GetVar) {
      ret compileGetVar(code);
    } else if (code cast Tb.ReturnFromScript) {
      if (code.script != returnableScript)
        fail("Can only return from current script");
        
      var stackTop = compile(code.value);
      if (postConversion != null)
        stackTop = postConversion.get(stackTop);
      m.returnWithType(stackTop);
      ret none;
    }
    
    fail("Can't compile yet: " + className(code));
  }

  void argumentsAsArray(Evaluable[] args) {  
    int n = l(args);
    m.intConst(n);
    m.add(new ANEWARRAY(m.classRef(O)));
    for iArg to n: {
      m.dup(); // get array again
      m.intConst(iArg);
      compileToObject(args[iArg]);
      m.add(new AASTORE);
    }
  }
  
  void loadVarContext {
    assertTrue("Need VarContext", iVarContext >= 0);
    m.aload(iVarContext);
  }
  
  // index of a temporary variable, created on demand
  simplyCached int iTemp() {
    ret m.newLocalVar();
  }
  
  void compileToBool(Evaluable condition) {
    var stackTop = compile(condition);
    if (stackTop == objValue) {
      // cast to Boolean
      m.checkCast(Bool.class);
      
      // call Boolean.booleanValue()
      m.invokeVirtual(Bool.class, bool.class, "booleanValue");
    } else if (stackTop == intValue) {} // ok
    else fail("Can't convert to bool: " + stackTop);
  }

  JVMStackCellType compileGetVar(Tb.GetVar code) {
    // Prepare VarContext.get()
    loadVarContext();
    m.stringConstant(code.var);
    
    // call VarContext.get()
    m.invokeVirtual(VarContext, O, "get", S);
    ret objValue;
  }
}

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: 190 / 511
Version history: 59 change(s)
Referenced in: [show references]