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

300
LINES

< > BotCompany Repo | #1034737 // GazelleV_LeftArrowScript [backup]

JavaX fragment (include)

// See GazelleV_LeftArrowScriptParser

// TODO: decide whether we allow calling methods/getting fields on
// a null reference (just returning null), or whether we throw a
// NullPointerException. Currently we just return null. Probably
// that's pretty cool. Null propagation as a default, just like in
// JavaX. Just more automatic!

sclass GazelleV_LeftArrowScript {
  // Base = any script element with a reference to its source code
  
  asclass Base is IHasTokenRangeWithSrc {
    TokenRangeWithSrc src;
    
    public void setTokenRangeWithSrc(TokenRangeWithSrc src) { this.src = src; }
    public TokenRangeWithSrc tokenRangeWithSrc() { ret src; }
    
    RuntimeException rethrowWithSrc(Throwable e) {
      if (src != null)
        throw rethrowAndAppendToMessage(e, squareBracketed(str(src)));
      else
        throw rethrow(e);
    }
  }
  
  // Evaluable = a script element that can be evaluated
  
  interface Evaluable extends IF0 {
    public O get(VarContext ctx default new);
    public default LASValueDescriptor returnType() { null; }
    public default Evaluable optimize() { this; }
  }
  
  // Base + Evaluable + explicitly stored return type
  
  asclass BaseEvaluable > Base is Evaluable {
    settable LASValueDescriptor returnType;
  }
  
  /*interface Cmd {
    // returns true if a return was issued
    public bool run(VarContext ctx default new);
  }*/
  
  static new AtomicLong scriptIDCounter;
  static long scriptID() { ret incAtomicLong(scriptIDCounter); }
  
  sclass Script > Base is Evaluable {
    long id = scriptID(); // just for printing
    Map<S, FunctionDef> functionDefs;
    Evaluable[] steps;
    
    public O get(VarContext ctx) {
      O result = null;
      for (step : steps) {
        ping();
        result = step.get(ctx);
        
        // exiting from anything?
        
        var exiting = ctx.exitFromScript;
        if (exiting != null) {
          printVars ifdef ReturnFromScript_debug("Checking exitFromScript",
            +ctx, +exiting, script := this);
            
          // we're the exit point
          if (exiting == this)
            ctx.exitFromScript = null;
            
          // exit further
          break;
        }
      }
      ret result;
    }
    
    S toStringLong() { ret pnlToLines(steps); }
    toString { ret "Script " + n2(id); }
    
    FunctionDef getFunction(S name) { ret mapGet(functionDefs, name); }
  } // end of Script
  
  srecord noeq FunctionDef(S name, LS args, Evaluable body) > Base {
    public O call(VarContext ctx, O... args) {
      var ctx2 = new VarContext(ctx);
      int n = min(l(args), l(this.args));
      for i to n:
        ctx2.put(this.args.get(i), args[i]);
      print ifdef GazelleV_LeftArrowScript_debug(ctx2 := ctx2.vars);
      ret body.get(ctx2);
    }
  }
  
  srecord noeq Assignment(S var, Evaluable expression) > Base is Evaluable {
    public O get(VarContext ctx) {
      O o = expression.get(ctx);
      ctx.set(var, o);
      ret o;
    }
    
    toString { ret var + " <- " + expression; }
  }
  
  persistable sclass NewObject > Base is Evaluable {
    Class c;
    L<Evaluable> args;
    
    *(Class *c) {}
    *(Class *c, L<Evaluable> *args) {}
    
    public O get(VarContext ctx) {
      ret callConstructor(c, mapToArray(args, arg -> arg.get(ctx)));
    }
    
    toString { ret "new " + formatFunctionCall(className(c), args); }
  }
  
  srecord noeq CallFunction(FunctionDef f, L<Evaluable> args) > Base is Evaluable {
    public O get(VarContext ctx) {
      //ping();
      ret f.call(ctx, mapToArray(args, a -> a.get(ctx));
    }
    
    toString { ret formatFunctionCall(f.name, args); }
  }
  
  srecord noeq GetVar(S var) > BaseEvaluable {
    public O get(VarContext ctx) {
      ret ctx.get(var);
    }
    
    toString { ret var; }
  }
  
  srecord noeq Const(O value) > Base is Evaluable {
    public O get(VarContext ctx) {
      ret value;
    }
    
    toString { ret strOrClassName(value); }
    
    public LASValueDescriptor returnType() {
      ret new LASValueDescriptor.KnownValue(value);
    }
  }
  
  srecord noeq GetStaticField(Field field) > Base is Evaluable {
    public O get(VarContext ctx) ctex {
      ret field.get(null);
    }
  }
  
  srecord noeq CallMethodOrGetField(Evaluable target, S name) > Base is Evaluable {
    public O get(VarContext ctx) {
      try {
        O object = target.get(ctx);
        if (object == null)
          null; // throw new NullPointerException();
          
        // could optimize more for sure
        if (canCallWithVarargs(object, name))
          ret call(object, name);
          
        // TODO: better error message when neither field nor method found
        ret _get(object, name);
      } catch e {
        throw rethrowWithSrc(e);
      }
    }
  }
  
  sclass GetVarContext > Base is Evaluable {
    public O get(VarContext ctx) { ret ctx; }
  }
  
  srecord noeq ThrowMethodNotFoundException(CallMethod instruction) > Base is Evaluable {
    public O get(VarContext ctx) {
      fail("Method not found: " + instruction);
    }
  }
  
  srecord noeq ThrowNullPointerException(CallMethod instruction) > Base is Evaluable {
    public O get(VarContext ctx) {
      fail("Null pointer exception: " + instruction);
    }
  }
  
  srecord noeq CallMethod(Evaluable target, S methodName, L<Evaluable> args) > Base is Evaluable {
    public O get(VarContext ctx) {
      ret call(target.get(ctx), methodName, mapToArray(args, arg -> arg.get(ctx)));
    }
    
    toString { ret target + "." + formatFunctionCall(methodName, args); }
    
    public Evaluable optimize() {
      var targetType = target.returnType();
      if (targetType.knownValue()) {
        O o = targetType.value();
        if (o == null) ret new ThrowNullPointerException(this);
        
        Class[] argTypes = new[l(args)];
        for i over args: {
          var type = args.get(i).returnType();
          if (!type.javaClassIsExact())
            this;
          argTypes[i] = type.javaClass();
        }
        
        // TODO: varargs
        var method = findMethod_precise_onTypes(o, methodName, argTypes);
        if (method == null) ret new ThrowMethodNotFoundException(this);
        
        ret new DirectMethodCallOnKnownTarget(o instanceof Class ? null : o, method, args);
      }
      
      this;
    }
  }
  
  srecord noeq DirectMethodCallOnKnownTarget(O target, Method method, L<Evaluable> args) > Base is Evaluable {
    public O get(VarContext ctx) {
      ret invokeMethod(method, target, mapToArray(args, arg -> arg.get(ctx)));
    }
    
    toString { ret (target == null ? "" : target + ".") + formatFunctionCall(str(method), args); }
    
    public LASValueDescriptor returnType() {
      ret LASValueDescriptor.fromClass(method.getReturnType());
    }
  }
  
  srecord noeq While(Evaluable condition, Evaluable body) > Base is Evaluable {
    public O get(VarContext ctx) {
      while (ping() && (Bool) condition.get(ctx)) {
        body.get(ctx);
      }
      
      // while loops don't return anything
      null;
    }
  }
  
  srecord noeq ForEach(Evaluable collection, S var, Evaluable body) > Base is Evaluable {
    public O get(VarContext ctx) {
      var coll = collection.get(ctx);
      Iterator iterator;
      new L out;
      if (coll cast O[])
        for (element : coll) {
          ping();
          ctx.set(var, element);
          out.add(body.get(ctx));
        }
      else if (coll cast Iterable) {
        for (element : coll) {
          ping();
          ctx.set(var, element);
          out.add(body.get(ctx));
        }
      } else if (coll == null) {} // ok
      else
        fail("Not iterable: " + className(coll));

      ctx.unset(var);
      ret out;
    }
  }
  
  srecord noeq IfThen(Evaluable condition, Evaluable body,
    Evaluable elseBranch) > Base is Evaluable {
    
    IfThen(Evaluable condition, Evaluable body) {
      this.condition = condition;
      this.body = body;
    }
    
    public O get(VarContext ctx) {
      if ((Bool) condition.get(ctx))
        ret body.get(ctx);
      else if (elseBranch != null)
        ret elseBranch.get(ctx);
      else
        null;
    }
  }
  
  srecord noeq ReturnFromScript(Script script, Evaluable value) > Base is Evaluable {
    public O get(VarContext ctx) {
      O result = value.get(ctx);
      printVars ifdef ReturnFromScript_debug("ReturnFromScript",
        +result, +ctx, +script);
      ctx.exitFromScript(script);
      ret result;
    }
    
    toString {
      ret formatFunctionCall ReturnFromScript(script, value);
    }
  }
}

Author comment

Began life as a copy of #1033981

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1034737
Snippet name: GazelleV_LeftArrowScript [backup]
Eternal ID of this version: #1034737/1
Text MD5: 3b48664fc921e99eafe8c78903369d21
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-03-08 00:42:43
Source code size: 8898 bytes / 300 lines
Pitched / IR pitched: No / No
Views / Downloads: 146 / 153
Referenced in: [show references]