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

1188
LINES

< > BotCompany Repo | #1033981 // GazelleV_LeftArrowScript [LIVE]

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

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

// 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 {
  replace EXITCHECK with if (ctx.exiting()) null; . // Keep the dot in, it belongs there
  
  replace const with _const.
  
  macro HANDLENULLREFERENCE {
    settable bool allowNullReference;
    
    O handleNullReference() {
      if (allowNullReference)
        null;
      else
        throw new NullPointerException();
    }
  }
  
  // Base = any script element with a reference to its source code
  asclass Base > HasTokenRangeWithSrc {
    RuntimeException rethrowWithSrc(S msg default "", Throwable e) {
      if (tokenRangeWithSrc() != null)
        /*throw rethrowAndAppendToMessage(e, squareBracketed(
          joinNemptiesWithComma(msg, src)));*/
        throw new ScriptError(tokenRangeWithSrc(), msg, e);
      else
        throw rethrow(e);
    }
    
    S indented() {
      ret indentedScriptStruct(this);
    }
    
    S shortenedSrc() {
      ret shortenSrc(tokenRangeWithSrc());
    }
  }
  
  sclass ScriptError extends RuntimeException is IHasTokenRangeWithSrc {
    *(TokenRangeWithSrc src, Throwable reason) {
      super(reason);
      tokenRangeWithSrc(src);
    }
    
    *(TokenRangeWithSrc src, S msg, Throwable reason) {
      super(msg, reason);
      tokenRangeWithSrc(src); 
    }
    
    !include #1036424 // (I)HasTokenRangeWithSrc Include
    
    TokenRangeWithSrc src() { ret tokenRangeWithSrc(); }

    toString {
      ret super.toString() + "\n  " + src() + " {{ " + shortenSrc(src()) + " }}";
    }
  }
  
  sS shortenSrc(TokenRangeWithSrc src) {
    ret src == null ?: shorten(nlToSpace(src.text()));
  }
  
  // Evaluable = a script element that can be evaluated
  
  interface Evaluable extends IF0, IHasTokenRangeWithSrc {
    public O get(VarContext ctx default new FlexibleVarContext);
    public default LASValueDescriptor returnType() { null; }
    public default Evaluable optimize() { this; }
    
    // informs this object that its return value will not be needed
    // so it can perform appropriate optimizations
    public default Evaluable optimizeForReturnValueNotNeeded() { this; }
    
    public default O getWithParams(O... params) {
      ret get(flexibleVarContextFromParams(params));
    }
  }
  
  // Base + Evaluable + explicitly stored return type
  
  asclass EvaluableBase > Base is Evaluable {
    settable LASValueDescriptor returnType;
    bool returnValueNeeded = true;
    
    public Evaluable optimizeForReturnValueNotNeeded() {
      returnValueNeeded = false;
      ret optimize();
    }
  }
  
  /*interface Cmd {
    // returns true if a return was issued
    public bool run(VarContext ctx default new FlexibleVarContext);
  }*/
  
  static new AtomicLong scriptIDCounter;
  static long scriptID() { ret incAtomicLong(scriptIDCounter); }
  
  srecord noeq ListFromScript(Script script) > EvaluableBase {
    public O get(VarContext ctx) {
      ret script.getAsList(ctx);
    }
  }
  
  sclass Script > EvaluableBase {
    transient long id = scriptID(); // just for printing
    Map<S, FunctionDef> functionDefs;
    Evaluable[] steps;
    //settable LASScope scope;
    Map<S, LASValueDescriptor> params;
    
    *() {}
    *(L<Evaluable> steps) { this.steps = toTypedArray(Evaluable.class, steps); }

    public O get(VarContext ctx) {
      O result = null;
      var pingSource = pingSource();
      for (step : steps) {
        ping(pingSource);
        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;
            result = ctx.returnValue;
            ctx.returnValue(null);
            ret result;
          }
          
          // otherwise exit further
          null;
        }
      }
      ret result;
    }
    
    O getAsList(VarContext ctx) {
      O result = null;
      var pingSource = pingSource();
      new L list;
      for (step : steps) {
        ping(pingSource);
        list.add(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;
            result = ctx.returnValue;
            ctx.returnValue(null);
            list.add(result);
            ret list;
          }
          
          // otherwise exit further
          null;
        }
      }
      
      ret list;
    }
    
    S toStringLong() { ret pnlToLines(steps); }
    toString { ret "Script " + n2(id); }
    
    FunctionDef getFunction(S name) { ret mapGet(functionDefs, name); }
    
    public Script optimizeScript aka optimize() {
      int n = returnValueNeeded ? steps.length-1 : steps.length;
      for (int i = 0; i < n; i++)
        steps[i] = steps[i].optimizeForReturnValueNotNeeded();
        
      for (f : values(functionDefs))
        f.optimize();
        
      this;
    }
  } // end of Script
  
  srecord noeq FunctionDef(S name, S[] args, Script body) > Base {
    //settable LASScope scope;
    settable Type returnType = O.class;
    settable LASValueDescriptor[] argTypes;
    settable bool synthetic;

    *(S *name, LS args, Script *body) {
      this.args = toStringArray(args);
    }
    
    public O callFromOutside(O... args) {
      ret call(new FlexibleVarContext, args);
    }
    
    public O call(VarContext ctx, O... args) {
      VarContext ctx2 = /*scope != null && scope.useFixedVars
        ? new FixedVarContext(ctx, scope.names) :*/ new FlexibleVarContext(ctx);
        
      int n = min(l(args), l(this.args));
      for i to n:
        ctx2.put(this.args[i], args[i]);
      print ifdef GazelleV_LeftArrowScript_debug(ctx2 := ctx2.vars);
      ret body.get(ctx2);
    }
    
    void optimize {
      body = body.optimize();
    }
    
    bool isConstructor() { ret eq(name, "<init>"); }
  }
  
  srecord noeq Assignment(S var, Evaluable expression) > EvaluableBase {
    public O get(VarContext ctx) {
      O o = expression.get(ctx);
      ctx.set(var, o);
      ret o;
    }
    
    toString { ret var + " <- " + expression; }
  }
  
  /*asclass FixedVarBase > EvaluableBase {
    settable LASScope scope;
    S var;
    int varIdx;
    
    S varToStr() { ret var + " [" + varIdx + "]"; }
    
    void assertResolved {
      if (varIdx < 0)
        fail("Unresolved variable access: " + var);
    }
    
    void resolve {
      varIdx = scope.resolveVar(var);
    }
  }
  
  persistable sclass FixedVarAssignment > FixedVarBase {
    Evaluable expression;
    *(LASScope *scope, S *var, Evaluable *expression) {}
    
    public O get(VarContext ctx) {
      O o = expression.get(ctx);
      ctx/FixedVarContext.set(varIdx, o);
      ret o;
    }
    
    toString { ret varToStr() + " <- " + expression; }
  }*/
  
  // type isn't used yet
  srecord noeq VarDeclaration(S var, Class type, Evaluable expression) > EvaluableBase {
    public O get(VarContext ctx) {
      try {
        O o = expression?.get(ctx);
        ctx.set(var, o);
        ret o;
      } catch e {
        throw rethrowWithSrc(e);
      }
    }
    
    toString { ret "var " + var + " <- " + expression; }
  }
  
  srecord noeq AssignmentToOuterVar(S var, Evaluable expression) > EvaluableBase {
    public O get(VarContext ctx) {
      var parent = ctx.parent();
      assertNotNull("No outer variable context", parent);
      O o = expression.get(ctx);
      parent.set(var, o);
      ret o;
    }
    
    toString { ret "outer " + var + " <- " + expression; }
  }
  
  persistable sclass NewObject > EvaluableBase {
    Class c;
    Evaluable[] args;
    
    *(Class c) { this(c, null); }
    *(Class *c, Evaluable[] *args) {
      returnType(new LASValueDescriptor.Exact(c, false));
    }
    
    public O get(VarContext ctx) {
      try {
        ret preciseNuObject(c, evalArgs(args, ctx));
      } catch e {
        throw rethrowWithSrc(e);
      }
    }
    
    toString { ret "new " + formatFunctionCall(className(c), args); }
  }
  
  // new object of a script-defined class
  // (we don't generate/resolve these classes until after the complete
  // parse is done so parsing stays lightweight)
  persistable sclass NewObject_LASClass > NewObject {
    ResolvableLASClass lasClass;
    
    *(ResolvableLASClass *lasClass) {}
    *(ResolvableLASClass *lasClass, Evaluable[] *args) {}
    
    void resolve {
      if (c == null)
        c = lasClass!;
    }
    
    public O get(VarContext ctx) {
      resolve();
      ret super.get(ctx);
    }
    
    toString { ret "new " + formatFunctionCall(str(lasClass), args); }
  }
  
  // new object of a class defined in expression
  srecord noeq NewObject_UnknownClass(Evaluable classExpr, Evaluable[] args) > NewObject {

    public O get(VarContext ctx) {
      try {
        Class c = cast classExpr.get(ctx);
        ret preciseNuObject(c, evalArgs(args, ctx));
      } catch e {
        throw rethrowWithSrc(e);
      }
    }
    
    toString { ret "new " + formatFunctionCall(classExpr, args); }
  }
  
  srecord noeq CallFunction(FunctionDef f, Evaluable[] args) > EvaluableBase {
    public O get(VarContext ctx) {
      var evaledArgs = evalArgs(args, ctx);
      EXITCHECK
      ret f.call(ctx, evaledArgs); 
    }
    
    toString { ret formatFunctionCall(f.name, args); }
    
    public LASValueDescriptor returnType() {
      ret LASValueDescriptor.fromType(f.getReturnType());
    }
  }
  
  srecord noeq GetVar(S var) > EvaluableBase {
    public O get(VarContext ctx) {
      ret ctx.get(var);
    }
    
    toString { ret var; }
  }
  
  /*persistable sclass GetFixedVar > FixedVarBase {
    *(LASScope *scope, S *var) {}
    
    public O get(VarContext ctx) {
      assertResolved();
      try {
        ret ctx/FixedVarContext.get(varIdx);
      } catch ArrayIndexOutOfBoundsException e {
        assertResolved();
        throw e;
      }
    }
    
    toString { ret var + " [" + varIdx + "]"; }
  }*/
  
  srecord noeq Const(O value) > EvaluableBase {
    public O get(VarContext ctx) {
      ret value;
    }
    
    toString { ret strOrClassName(value); }
    
    public LASValueDescriptor returnType() {
      ret new LASValueDescriptor.KnownValue(value);
    }
    
    // Structuring this object is only done to make a class def hash,
    // or to show a parsed script to a user.
    // So the structure just has to be unique, not serializable.
    // As the contents of "value" could be an unpersistable object,
    // we just stringify it.
    O _serialize() {
      bool ok = isUnproblematicValue(value);
      printVars ifdef g22const_debug("Const._serialize",
        className := value?.getClass(), +ok);
      ret ok
        ? this 
        : toStringWithClass(value);
    }
  }
  
  srecord noeq GetStaticField(Field field) > EvaluableBase {
    public O get(VarContext ctx) ctex {
      ret field.get(null);
    }
    
    // See Const._serialize
    S _serialize() { ret str(field); }
  }
  
  abstract srecord noeq CallOnTarget(Evaluable target) > EvaluableBase {
    HANDLENULLREFERENCE
    
    abstract O evalOnTarget(VarContext ctx, O object);
    
    public O get(VarContext ctx) {
      try {
        O object = target.get(ctx);
        if (object == null)
          ret handleNullReference();
            
        ret evalOnTarget(ctx, object);
      } catch e {
        throw rethrowWithSrc(e);
      }
    }
  }
  
  persistable sclass CallMethodOrGetField > CallOnTarget {
    S name;
    
    *(Evaluable *target, S *name) {}
    
    O evalOnTarget(VarContext ctx, O object) {
      try {
        ret preciseGetOrCallMethod(object, name);
      } catch e {
        throw rethrowWithSrc("Was getting " + name, e);
      }
    }
  }
  
  persistable sclass GetField > CallOnTarget {
    S name;
    
    *(Evaluable *target, S *name) {}
    
    O evalOnTarget(VarContext ctx, O object) {
      try {
        ret _get(object, name);
      } catch e {
        throw rethrowWithSrc("Was getting " + name, e);
      }
    }
  }
  
  sclass GetVarContext > EvaluableBase {
    public O get(VarContext ctx) { ret ctx; }
  }
  
  srecord noeq ThrowMethodNotFoundException(CallMethod instruction) > EvaluableBase {
    public O get(VarContext ctx) {
      fail("Method not found: " + instruction);
    }
  }
  
  srecord noeq ThrowNullPointerException(CallMethod instruction) > EvaluableBase {
    public O get(VarContext ctx) {
      fail("Null pointer exception: " + instruction);
    }
  }
  
  persistable sclass CallMethod > CallOnTarget {
    S methodName;
    Evaluable[] args;
    
    *(Evaluable *target, S *methodName, Evaluable[] *args) {}
    
    O evalOnTarget(VarContext ctx, O object) {
      ret /*call*/newPreciseCall(object, methodName, evalArgs(args, ctx));
    }
    
    toString { ret target + "." + formatFunctionCall(methodName, args); }
    
    // optimize to DirectMethodCallOnKnownTarget if target type
    // and all argument types are known exactly
    public Evaluable optimize() {
      var targetType = target.returnType();
      if (targetType != null && targetType.knownValue()) {
        O o = targetType.value();
        if (o == null)
          ret allowNullReference
            ? const(null)
            : new ThrowNullPointerException(this);
        
        Class[] argTypes = new[l(args)];
        for i over args: {
          var type = args[i].returnType();
          if (type == null || !type.javaClassIsExact())
            this;
          argTypes[i] = type.javaClass();
        }
        
        // can't optimize varargs
        L<Method> methods = findMethodsNamed_cached(o, methodName);
        if (any(methods, m -> m.isVarArgs())) this;
        
        var method, widening = unpair findMethod_withPrimitiveWidening_onTypes(o, methodName, argTypes);
        if (method == null) ret new ThrowMethodNotFoundException(this);
        
        ret new DirectMethodCallOnKnownTarget(widening, o instanceof Class ? null : o, method, args);
      }
      
      this;
    }
  }
  
  static O[] evalArgs(Evaluable[] args, VarContext ctx) {
    ret mapToArrayOrNull(args, arg -> arg.get(ctx));
  }
  
  // method invocation on unknown object with "magic switch"
  persistable sclass CallMethodOrGlobalFunction > CallMethod {
    MethodOnObject globalFunction;
    
    static final new O methodNotFoundSentinel;
    
    *(Evaluable *target, S *methodName, MethodOnObject *globalFunction, Evaluable[] *args) {}
      
    // mark "magic switch" with +
    toString { ret target + "." + formatFunctionCall(methodName + "+", args); }
    
    O evalOnTarget(VarContext ctx, O o) {
      O[] realArgs = evalArgs(args, ctx);
      O result = newPreciseCall_sentinel(o, methodName, methodNotFoundSentinel, realArgs);
      if (result != methodNotFoundSentinel)
        ret result;
      print ifdef sentinelDebug("Sentinel triggered: " + globalFunction);
      ret newPreciseCall(
        globalFunction.object,
        globalFunction.method,
        itemPlusArray(o, realArgs));
    }
  }
    
  // method invocation/field get on unknown object with "magic switch"
  persistable sclass CallMethodOrGetFieldOrGlobalFunction > CallMethodOrGetField {
    MethodOnObject globalFunction;
    
    static final new O notFoundSentinel;
    
    *(Evaluable *target, S *name, MethodOnObject *globalFunction) {}
      
    // mark "magic switch" with +
    toString { ret target + "." + name + "+"; }
    
    O evalOnTarget(VarContext ctx, O o) {
      try {
        O result = preciseGetOrCallMethod_sentinel(o, name, notFoundSentinel);
        if (result != notFoundSentinel)
          ret result;
        print ifdef sentinelDebug("Sentinel triggered: " + globalFunction);
        ret newPreciseCall(
          globalFunction.object,
          globalFunction.method,
          o);
      } catch e {
        throw rethrowWithSrc("Was getting " + name, e);
      }
    }
  }
  
  abstract srecord noeq LambdaBase(Class intrface) > EvaluableBase {
    transient Method implementedMethod;
      
    // !customConstructor
    *(Class *intrface) {
      implementedMethod = findSingleInterfaceMethodOrFail(intrface);
    }
  }
  
  // expects the interface method to have exactly one argument
  sclass LambdaMethodOnArgument > LambdaBase {
    S methodName;
    Evaluable[] args;
    
    *(Class intrface, S *methodName, Evaluable[] *args) {
      super(intrface);
    }
    
    public O get(VarContext ctx) {
      ret proxyFromInvocationHandler(intrface, (proxy, method, actualArgs) -> {
        if (method.getDeclaringClass() == intrface)
          ret forwardCall(actualArgs[0], ctx);
        else
          ret handleObjectMethodsInProxyInvocationHandler(
            this, implementedMethod, method, proxy, actualArgs);
      });
    }
    
    O forwardCall(O target, VarContext ctx) {
      ret call(target, methodName, evalArgs(args, ctx));
    }
  }
    
  srecord noeq LambdaDef(Class intrface, S[] args, Evaluable body) > EvaluableBase {
    new Map<S, LASValueDescriptor> argTypes;
    transient Method implementedMethod;
    
    // !customConstructor
    *(Class *intrface, S[] *args, Evaluable *body) {
      implementedMethod = findSingleInterfaceMethodOrFail(intrface);
      if (implementedMethod.getParameterCount() != l(args))
        fail("Bad parameter count for lambda: " + implementedMethod + " vs: " + joinWithComma(args));
    }
    
    // We have to create the proxy when the lambda definition is
    // evaluated since we have to put the context in there
    public O get(VarContext ctx) {
      ret proxyFromInvocationHandler(intrface, (proxy, method, actualArgs) -> {
        ping();
        
        if (method.getDeclaringClass() == intrface) {
          var ctx2 = new FlexibleVarContext(ctx);
          var argNames = args;
          // We already know that the count matches.
          for i over args:
            ctx2.put(argNames[i], actualArgs[i]);
  
          ret body.get(ctx2);
        } else
          ret handleObjectMethodsInProxyInvocationHandler(
            this, implementedMethod, method, proxy, actualArgs);
      });
    }
    
    toString { ret "Lambda(" + shortenedSrc() + ")"; }
  }
    
  abstract srecord noeq CurriedLambdaBase(Class intrface, Evaluable[] curriedArgs) > EvaluableBase {
    transient Method implementedMethod;
      
    // !customConstructor
    *(Class *intrface, Evaluable[] *curriedArgs) {
      implementedMethod = findSingleInterfaceMethodOrFail(intrface);
    }
    
    public O get(VarContext ctx) {
      try {
        O[] curriedArguments = evalArgs(curriedArgs, ctx);
        
        ret proxyFromInvocationHandler(intrface, (proxy, method, actualArgs) -> {
          // Comparing a Method is more expensive than just
          // comparing the class (should be enough to distinguish
          // methods since we are dealing with a single-method class).
          // tl;dr So far we are getting away with this so all is good ^^
          try {
            if (method.getDeclaringClass() == intrface)
              ret forwardCall(ctx, concatMethodArgs(curriedArguments, actualArgs));
            else
              ret handleObjectMethodsInProxyInvocationHandler(
                this, implementedMethod, method, proxy, actualArgs);            } catch e {
            throw rethrowWithSrc(e);
          }
        });
      } catch e {
        throw rethrowWithSrc(e);
      }
    }
    
    abstract O forwardCall(VarContext ctx, O[] args);
  }
  
  persistable sclass CurriedMethodLambda > CurriedLambdaBase {
    O target;
    S targetMethod;

    *(Class intrface, O *target, S *targetMethod, Evaluable[] curriedArgs) {
      super(intrface, curriedArgs);
    }
    
    O forwardCall(VarContext ctx, O[] args) {
      ret newPreciseCall(target, targetMethod, args);
    }
  }
  
  sclass CurriedScriptFunctionLambda > CurriedLambdaBase {
    FunctionDef f;
    
    *(Class intrface, FunctionDef *f, Evaluable[] curriedArgs) {
      super(intrface, curriedArgs);
    }
    
    O forwardCall(VarContext ctx, O[] args) {
      ret f.call(ctx, args);
    }
  }
  
  sclass CurriedConstructorLambda > CurriedLambdaBase {
    Constructor[] ctors;
    
    *(Class intrface, Constructor[] *ctors, Evaluable[] curriedArgs) {
      super(intrface, curriedArgs);
    }
    
    O forwardCall(VarContext ctx, O[] args) {
      ret preciseNuObject(ctors, args);
    }
  }
  
  srecord noeq DirectMethodCallOnKnownTarget(bool widening, O target, Method method, Evaluable[] args) > EvaluableBase {
    public O get(VarContext ctx) {
      var evaluatedArgs = evalArgs(args, ctx);
      ret widening
        ? invokeMethodWithWidening(method, target, evaluatedArgs)
        : invokeMethod(method, target, evaluatedArgs);
    }
    
    toString { ret (target == null ? "" : target + ".") + formatFunctionCall(str(method), args); }
    
    public LASValueDescriptor returnType() {
      ret LASValueDescriptor.fromClass(method.getReturnType());
    }
  }
  
  srecord noeq While(Evaluable condition, Evaluable body) > EvaluableBase {
    public O get(VarContext ctx) {
      while (!ctx.exiting() && (Bool) condition.get(ctx)) {
        body.get(ctx);
      }
      
      // while loops don't return anything
      null;
    }
  }
  
  srecord noeq DoWhile(Evaluable condition, Evaluable body) > EvaluableBase {
    public O get(VarContext ctx) {
      do {
        body.get(ctx);
      } while (!ctx.exiting() && (Bool) condition.get(ctx));
      
      // while loops don't return anything
      null;
    }
  }
  
  // collection is an Iterable, an array etc.
  abstract srecord noeq ForEachBase(Evaluable collection, Evaluable body) > EvaluableBase {
    macro ITERATE_ARRAY {
      out = emptyList(array.length);
      for (element : array) {
        EXITCHECK
        processElement(ctx, out, element);
      }
    }
    
    public O get(VarContext ctx) {
      var coll = collection.get(ctx);
      Iterator iterator;
      L out;
      try {
        if (coll == null)
          out = new L;
        else if (coll.getClass().isArray()) {
          if (coll cast O[]) { var array = coll; ITERATE_ARRAY }
          else if (coll cast byte[]) { var array = coll; ITERATE_ARRAY }
          else if (coll cast short[]) { var array = coll; ITERATE_ARRAY }
          else if (coll cast double[]) { var array = coll; ITERATE_ARRAY }
          else if (coll cast float[]) { var array = coll; ITERATE_ARRAY }
          else if (coll cast int[]) { var array = coll; ITERATE_ARRAY }
          else if (coll cast long[]) { var array = coll; ITERATE_ARRAY }
          else if (coll cast char[]) { var array = coll; ITERATE_ARRAY }
          else if (coll cast bool[]) { var array = coll; ITERATE_ARRAY }
          else fail("todo for each with: " + coll);
        } else if (coll cast Iterable) {
          out = emptyList(coll);
          iterator = coll.iterator();
          try {
            while (iterator.hasNext()) {
              EXITCHECK
              var element = iterator.next();
              processElement(ctx, out, element);
            }
          } finally {
            if (iterator cast AutoCloseable) ctex {
              iterator.close();
            }
          }
        } else
          fail("Not iterable: " + className(coll));
      } finally {
        loopDone(ctx);
      }
      
      ret out;
    }
    
    abstract void processElement(VarContext ctx, L out, O o);
    abstract void loopDone(VarContext ctx);
  }
  
  persistable sclass ForEach > ForEachBase {
    S var;
    settable LASValueDescriptor varType;
    
    *(Evaluable *collection, S *var, Evaluable *body) {}
    
    void processElement(VarContext ctx, L out, O o) {
      ctx.set(var, o);
      out.add(body.get(ctx));
    }
    
    void loopDone(VarContext ctx) {
      ctx.unset(var);
    }
  }
  
  srecord ForIterator(Evaluable iterable, S var, Evaluable body) > EvaluableBase {
    public O get(VarContext ctx) {
      VarContext subContext = new FlexibleVarContext(ctx);
      
      var iterable = this.iterable.get(ctx);
      Iterator iterator = iterator_gen(iterable);
        
      ret new MapI(value -> {
        subContext.set(var, value);
        ret body.get(subContext);
      }, iterator);
    }
  }

  srecord ForNested(Evaluable iterable, S var, Evaluable body) > EvaluableBase {
    public O get(VarContext ctx) {
      VarContext subContext = new FlexibleVarContext(ctx);
      
      var iterable = this.iterable.get(ctx);
      Iterator iterator = iterator_gen(iterable);

      ret nestedIterator(iterator, value -> {
        subContext.set(var, value);
        ret iterator_gen(body.get(subContext));
      });
    }
  }

  persistable sclass ForPairs > ForEachBase {
    S varA, varB;
    
    *(Evaluable *collection, Evaluable *body, S *varA, S *varB) {}
    
    void processElement(VarContext ctx, L out, O o) {
      Pair p = cast o;
      ctx.set(varA, p.a);
      ctx.set(varB, p.b);
      out.add(body.get(ctx));
    }
    
    void loopDone(VarContext ctx) {
      ctx.unset(varA);
      ctx.unset(varB);
    }
  }
  
  srecord noeq ForKeyValue(Evaluable map, Evaluable body, S varA, S varB) > EvaluableBase {
    public O get(VarContext ctx) {
      Map<?, ?> theMap = (Map) map.get(ctx);
      L out;
      try {
        if (theMap != null) {
          out = emptyList(theMap.size());
          for (entry : theMap.entrySet()) {
            EXITCHECK
            ctx.set(varA, entry.getKey());
            ctx.set(varB, entry.getValue());
            out.add(body.get(ctx));
          }
        } else
          out = new L;
      } finally {
        ctx.unset(varA);
        ctx.unset(varB);
      }
      
      ret out;
    }
  }

  srecord noeq ForIntTo(Evaluable endValue, S var, Evaluable body) > EvaluableBase {
    public Evaluable optimize() {
      if (!returnValueNeeded)
        body = body.optimizeForReturnValueNotNeeded();
      this;
    }
    
    public O get(VarContext ctx) {
      int n = (Int) endValue.get(ctx), i = 0;
      L out = returnValueNeeded ? new L : null;
      
      try {
        ctx.put(var, i);
        
        while (i < n) {
          EXITCHECK
          O o = body.get(ctx);
          out?.add(o);
          ctx.set(var, i = (Int) ctx.get(var)+1);
        }
      } finally {
        ctx.unset(var);
      }
      
      ret out;
    }
  }
  
  persistable sclass ForIndex > EvaluableBase {
    Evaluable collection, body;
    S varIndex, varElement;
    
    *(Evaluable *collection, Evaluable *body, S *varIndex, S *varElement) {}
    
    public O get(VarContext ctx) {
      ret new ForIndex_instance(collection, body, varIndex, varElement).get(ctx);
    }
  }
  
  sclass ForIndex_instance > ForEachBase {
    S varIndex, varElement;
    int index;
    
    *(Evaluable *collection, Evaluable *body, S *varIndex, S *varElement) {}

    void processElement(VarContext ctx, L out, O o) {
      ctx.set(varIndex, index++);
      ctx.set(varElement, o);
      out.add(body.get(ctx));
    }
    
    void loopDone(VarContext ctx) {
      ctx.unset(varIndex);
      ctx.unset(varElement);
    }
  }
  
  srecord noeq IfThen(Evaluable condition, Evaluable body,
    Evaluable elseBranch) > EvaluableBase {
    
    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) > EvaluableBase {
    public O get(VarContext ctx) {
      O result = value.get(ctx);
      printVars ifdef ReturnFromScript_debug("ReturnFromScript",
        +result, +ctx, +script);
      ctx.exitFromScript(script);
      ctx.returnValue(result);
      null;
    }
    
    toString {
      ret formatFunctionCall ReturnFromScript(script, value);
    }
  }
  
  srecord noeq Continue(Script loopBody) > EvaluableBase {
    public O get(VarContext ctx) {
      ctx.exitFromScript(loopBody);
      ctx.returnValue(null);
      null;
    }
    
    toString {
      ret formatFunctionCall Continue(loopBody);
    }
  }
  
  srecord noeq RepeatN(Evaluable n, Evaluable body) > EvaluableBase {
    public O get(VarContext ctx) {
      long count = ((Number) n.get(ctx)).longValue();
      
      repeat count {
        EXITCHECK
        body.get(ctx);
      }
      
      null;
    }
  }
  
  persistable srecord BoolAnd(Evaluable a, Evaluable b) > EvaluableBase {
    public O get(VarContext ctx) {
      if (!((Bool) a.get(ctx))) false;
      ret b.get(ctx);
    }
  }
  
  persistable srecord BoolOr(Evaluable a, Evaluable b) > EvaluableBase {
    public O get(VarContext ctx) {
      if (((Bool) a.get(ctx))) true;
      ret b.get(ctx);
    }
  }
  
  srecord noeq TempBlock(Evaluable tempExpr,
    Evaluable body) > EvaluableBase {
    
    public O get(VarContext ctx) {
      temp (AutoCloseable) tempExpr.get(ctx);
      ret body.get(ctx);
    }
  }
  
  srecord noeq WillReturn(Evaluable exp, Evaluable body) > EvaluableBase {
    public O get(VarContext ctx) {
      body.get(ctx);
      ret exp.get(ctx);
    }
  }
  
  srecord ClassDef(ResolvableLASClass lasClass) > EvaluableBase {
    public O get(VarContext ctx) {
      ret lasClass!;
    }
  }
  
  srecord noeq SetField(Evaluable target, S name, Evaluable expr) > EvaluableBase {
    HANDLENULLREFERENCE
  
    public O get(VarContext ctx) {
      try {
        O value = expr.get(ctx);
        
        O object = target.get(ctx);
        if (object == null)
          handleNullReference();
        else
          set(object, name, value);
          
        ret value;
      } catch e {
        throw rethrowWithSrc(e);
      }
    }
  }
  
  srecord noeq SetStaticField(Field field, Evaluable expr) > EvaluableBase {
    public O get(VarContext ctx) {
      try {
        O value = expr.get(ctx);
        field.set(null, value);
        ret value;
      } catch e {
        throw rethrowWithSrc(e);
      }
    }
  }
  
  srecord noeq Throw(Evaluable expr) > EvaluableBase {
    public O get(VarContext ctx) {
      throw asRuntimeException((Throwable) expr.get(ctx));
    }
  }
  
  srecord noeq TryCatch(Evaluable body, S var, Evaluable catchBlock) > EvaluableBase {
    public O get(VarContext ctx) {
      try {
        ret body.get(ctx);
      } catch e {
        var addVar = var == null ?: ctx.tempPut(var, e);
        temp addVar;
        ret catchBlock.get(ctx);
      }
    }
  }

  srecord noeq TryFinally(Evaluable body, Evaluable finallyBlock) > EvaluableBase {
    public O get(VarContext ctx) {
      try {
        ret body.get(ctx);
      } finally {
        finallyBlock.get(ctx);
      }
    }
  }

  static structure_Data structureDataForLAS() {
    new structure_Data d;
    d.skipDefaultValues(true);
    
    d.shouldIncludeField = field -> {
      S c = shortClassName(field.getDeclaringClass());
      S f = field.getName();
      bool shouldInclude = !(eq(c, "HasTokenRangeWithSrc") && eq(f, "src"));
      //printVars("shouldIncludeField", +c, +f, +shouldInclude);
      ret shouldInclude;
    };
      
    ret d;
  }
  
  // with respect to serialization
  sbool isUnproblematicValue(O o) {
    ret o == null || o instanceof Number || o instanceof S
      || o instanceof Bool || o instanceof Class;
  }
  
  // These structs are a. for the user to see the parsed script
  // and b. for checking if two class defs are equal.
  //
  // (The resulting struct string doesn't have to unstructure()-able,
  // which is why we can e.g. shorten class names.)
  sS scriptStruct(O o) {
    S s = struct(o, structureDataForLAS());
    LS tok = structTok(s);
    S prefix = shortName(GazelleV_LeftArrowScript) + "$";
    for (int i = 1; i < l(tok); i += 2)
      tok.set(i, replacePrefix(prefix, "$", tok.get(i)));
    ret join(tok);
  }
  
  sS indentedScriptStruct(O o) {
    ret indentStructureString(scriptStruct(o));
  }
  
  static Evaluable const(O o) {
    ret new Const(o);
  }
  
  sclass Then > CallOnTarget {
    CallOnTarget call1, call2;
    
    *(CallOnTarget *call1, CallOnTarget *call2) {
      target = call1.target;
      call1.target = null;
    }
    
    O evalOnTarget(VarContext ctx, O object) {
      call1.evalOnTarget(ctx, object);
      ret call2.evalOnTarget(ctx, object);
    }
  }

  srecord noeq Synchronized(Evaluable target, Evaluable body) > EvaluableBase {
    public Evaluable optimize() {
      if (!returnValueNeeded)
        body = body.optimizeForReturnValueNotNeeded();
      this;
    }
    
    public O get(VarContext ctx) {
      synchronized(target.get(ctx)) {
        ret body.get(ctx);
      }
    }
  }
  
} // end of GazelleV_LeftArrowScript

Author comment

Began life as a copy of #1033976

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1033981
Snippet name: GazelleV_LeftArrowScript [LIVE]
Eternal ID of this version: #1033981/304
Text MD5: 17091ce9277d3574af69046ff4c908ba
Transpilation MD5: 33e2f0df7797aedd87aede6799338fdd
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2023-09-22 17:58:37
Source code size: 34635 bytes / 1188 lines
Pitched / IR pitched: No / No
Views / Downloads: 876 / 3092
Version history: 303 change(s)
Referenced in: #1034040 - GazelleV_LeftArrowScript backup
#1034041 - GazelleV_LeftArrowScript (rewrite rejected by Java compiler)
#1034167 - Standard Classes + Interfaces (LIVE, continuation of #1003674)
#1034292 - GazelleV_LeftArrowScript backup before type inference
#1034737 - GazelleV_LeftArrowScript [backup]