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

1194
LINES

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

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

Transpiled version (31611L) is out of date.

1  
// See GazelleV_LeftArrowScriptParser
2  
3  
// TODO: decide whether we allow calling methods/getting fields on
4  
// a null reference (just returning null), or whether we throw a
5  
// NullPointerException. Currently we just return null. Probably
6  
// that's pretty cool. Null propagation as a default, just like in
7  
// JavaX. Just more automatic!
8  
9  
sclass GazelleV_LeftArrowScript {
10  
  replace EXITCHECK with if (ctx.exiting()) null; . // Keep the dot in, it belongs there
11  
  
12  
  replace const with _const.
13  
  
14  
  macro HANDLENULLREFERENCE {
15  
    settable bool allowNullReference;
16  
    
17  
    O handleNullReference() {
18  
      if (allowNullReference)
19  
        null;
20  
      else
21  
        throw new NullPointerException();
22  
    }
23  
  }
24  
  
25  
  // Base = any script element with a reference to its source code
26  
  asclass Base > HasTokenRangeWithSrc {
27  
    RuntimeException rethrowWithSrc(S msg default "", Throwable e) {
28  
      if (!e instanceof QuickException && tokenRangeWithSrc() != null)
29  
        /*throw rethrowAndAppendToMessage(e, squareBracketed(
30  
          joinNemptiesWithComma(msg, src)));*/
31  
        throw new ScriptError(tokenRangeWithSrc(), msg, e);
32  
      else
33  
        throw rethrow(e);
34  
    }
35  
    
36  
    S indented() {
37  
      ret indentedScriptStruct(this);
38  
    }
39  
    
40  
    S shortenedSrc() {
41  
      ret shortenSrc(tokenRangeWithSrc());
42  
    }
43  
  }
44  
  
45  
  sclass ScriptError extends RuntimeException is IHasTokenRangeWithSrc {
46  
    *(TokenRangeWithSrc src, Throwable reason) {
47  
      super(reason);
48  
      tokenRangeWithSrc(src);
49  
    }
50  
    
51  
    *(TokenRangeWithSrc src, S msg, Throwable reason) {
52  
      super(msg, reason);
53  
      tokenRangeWithSrc(src); 
54  
    }
55  
    
56  
    !include #1036424 // (I)HasTokenRangeWithSrc Include
57  
    
58  
    TokenRangeWithSrc src() { ret tokenRangeWithSrc(); }
59  
60  
    toString {
61  
      ret super.toString() + "\n  " + src() + " {{ " + shortenSrc(src()) + " }}";
62  
    }
63  
  }
64  
  
65  
  sS shortenSrc(TokenRangeWithSrc src) {
66  
    ret src == null ?: shorten(nlToSpace(src.text()));
67  
  }
68  
  
69  
  // Evaluable = a script element that can be evaluated
70  
  
71  
  interface Evaluable extends IF0, IHasTokenRangeWithSrc {
72  
    public O get(VarContext ctx default new FlexibleVarContext);
73  
    public default LASValueDescriptor returnType() { null; }
74  
    public default Evaluable optimize() { this; }
75  
    
76  
    // informs this object that its return value will not be needed
77  
    // so it can perform appropriate optimizations
78  
    public default Evaluable optimizeForReturnValueNotNeeded() { this; }
79  
    
80  
    public default O getWithParams(O... params) {
81  
      ret get(flexibleVarContextFromParams(params));
82  
    }
83  
  }
84  
  
85  
  // Base + Evaluable + explicitly stored return type
86  
  
87  
  asclass EvaluableBase > Base is Evaluable {
88  
    settable LASValueDescriptor returnType;
89  
    bool returnValueNeeded = true;
90  
    
91  
    public Evaluable optimizeForReturnValueNotNeeded() {
92  
      returnValueNeeded = false;
93  
      ret optimize();
94  
    }
95  
  }
96  
  
97  
  /*interface Cmd {
98  
    // returns true if a return was issued
99  
    public bool run(VarContext ctx default new FlexibleVarContext);
100  
  }*/
101  
  
102  
  static new AtomicLong scriptIDCounter;
103  
  static long scriptID() { ret incAtomicLong(scriptIDCounter); }
104  
  
105  
  srecord noeq ListFromScript(Script script) > EvaluableBase {
106  
    public O get(VarContext ctx) {
107  
      ret script.getAsList(ctx);
108  
    }
109  
  }
110  
  
111  
  sclass Script > EvaluableBase {
112  
    transient long id = scriptID(); // just for printing
113  
    Map<S, FunctionDef> functionDefs;
114  
    Evaluable[] steps;
115  
    //settable LASScope scope;
116  
    Map<S, LASValueDescriptor> params;
117  
    
118  
    *() {}
119  
    *(L<Evaluable> steps) { this.steps = toTypedArray(Evaluable.class, steps); }
120  
121  
    public O get(VarContext ctx) {
122  
      O result = null;
123  
      var pingSource = pingSource();
124  
      for (step : steps) {
125  
        ping(pingSource);
126  
        result = step.get(ctx);
127  
        
128  
        // exiting from anything?
129  
        
130  
        var exiting = ctx.exitFromScript;
131  
        if (exiting != null) {
132  
          printVars ifdef ReturnFromScript_debug("Checking exitFromScript",
133  
            +ctx, +exiting, script := this);
134  
            
135  
          // we're the exit point
136  
          if (exiting == this) {
137  
            ctx.exitFromScript = null;
138  
            result = ctx.returnValue;
139  
            ctx.returnValue(null);
140  
            ret result;
141  
          }
142  
          
143  
          // otherwise exit further
144  
          null;
145  
        }
146  
      }
147  
      ret result;
148  
    }
149  
    
150  
    O getAsList(VarContext ctx) {
151  
      O result = null;
152  
      var pingSource = pingSource();
153  
      new L list;
154  
      for (step : steps) {
155  
        ping(pingSource);
156  
        list.add(step.get(ctx));
157  
        
158  
        // exiting from anything?
159  
        
160  
        var exiting = ctx.exitFromScript;
161  
        if (exiting != null) {
162  
          printVars ifdef ReturnFromScript_debug("Checking exitFromScript",
163  
            +ctx, +exiting, script := this);
164  
            
165  
          // we're the exit point
166  
          if (exiting == this) {
167  
            ctx.exitFromScript = null;
168  
            result = ctx.returnValue;
169  
            ctx.returnValue(null);
170  
            list.add(result);
171  
            ret list;
172  
          }
173  
          
174  
          // otherwise exit further
175  
          null;
176  
        }
177  
      }
178  
      
179  
      ret list;
180  
    }
181  
    
182  
    S toStringLong() { ret pnlToLines(steps); }
183  
    toString { ret "Script " + n2(id); }
184  
    
185  
    FunctionDef getFunction(S name) { ret mapGet(functionDefs, name); }
186  
    
187  
    public Script optimizeScript aka optimize() {
188  
      int n = returnValueNeeded ? steps.length-1 : steps.length;
189  
      for (int i = 0; i < n; i++)
190  
        steps[i] = steps[i].optimizeForReturnValueNotNeeded();
191  
        
192  
      for (f : values(functionDefs))
193  
        f.optimize();
194  
        
195  
      this;
196  
    }
197  
  } // end of Script
198  
  
199  
  srecord noeq FunctionDef(S name, S[] args, Script body) > Base {
200  
    //settable LASScope scope;
201  
    settable Type returnType = O.class;
202  
    settable LASValueDescriptor[] argTypes;
203  
    settable bool synthetic;
204  
    settable bool varargs; // Is last argument varargs ("...")
205  
206  
    *(S *name, LS args, Script *body) {
207  
      this.args = toStringArray(args);
208  
    }
209  
    
210  
    public O callFromOutside(O... args) {
211  
      ret call(new FlexibleVarContext, args);
212  
    }
213  
    
214  
    public O call(VarContext ctx, O... args) {
215  
      VarContext ctx2 = /*scope != null && scope.useFixedVars
216  
        ? new FixedVarContext(ctx, scope.names) :*/ new FlexibleVarContext(ctx);
217  
        
218  
      int n = min(l(args), l(this.args));
219  
      
220  
      if (varargs && n == l(this.args)) {
221  
        --n;
222  
        ctx2.put(this.args[n], subArray(args, n));
223  
      }
224  
      for i to n:
225  
        ctx2.put(this.args[i], args[i]);
226  
      print ifdef GazelleV_LeftArrowScript_debug(ctx2 := ctx2.vars);
227  
      ret body.get(ctx2);
228  
    }
229  
    
230  
    void optimize {
231  
      body = body.optimize();
232  
    }
233  
    
234  
    bool isConstructor() { ret eq(name, "<init>"); }
235  
  }
236  
  
237  
  srecord noeq Assignment(S var, Evaluable expression) > EvaluableBase {
238  
    public O get(VarContext ctx) {
239  
      O o = expression.get(ctx);
240  
      ctx.set(var, o);
241  
      ret o;
242  
    }
243  
    
244  
    toString { ret var + " <- " + expression; }
245  
  }
246  
  
247  
  /*asclass FixedVarBase > EvaluableBase {
248  
    settable LASScope scope;
249  
    S var;
250  
    int varIdx;
251  
    
252  
    S varToStr() { ret var + " [" + varIdx + "]"; }
253  
    
254  
    void assertResolved {
255  
      if (varIdx < 0)
256  
        fail("Unresolved variable access: " + var);
257  
    }
258  
    
259  
    void resolve {
260  
      varIdx = scope.resolveVar(var);
261  
    }
262  
  }
263  
  
264  
  persistable sclass FixedVarAssignment > FixedVarBase {
265  
    Evaluable expression;
266  
    *(LASScope *scope, S *var, Evaluable *expression) {}
267  
    
268  
    public O get(VarContext ctx) {
269  
      O o = expression.get(ctx);
270  
      ctx/FixedVarContext.set(varIdx, o);
271  
      ret o;
272  
    }
273  
    
274  
    toString { ret varToStr() + " <- " + expression; }
275  
  }*/
276  
  
277  
  // type isn't used yet
278  
  srecord noeq VarDeclaration(S var, Class type, Evaluable expression) > EvaluableBase {
279  
    public O get(VarContext ctx) {
280  
      try {
281  
        O o = expression?.get(ctx);
282  
        ctx.set(var, o);
283  
        ret o;
284  
      } catch e {
285  
        throw rethrowWithSrc(e);
286  
      }
287  
    }
288  
    
289  
    toString { ret "var " + var + " <- " + expression; }
290  
  }
291  
  
292  
  srecord noeq AssignmentToOuterVar(S var, Evaluable expression) > EvaluableBase {
293  
    public O get(VarContext ctx) {
294  
      var parent = ctx.parent();
295  
      assertNotNull("No outer variable context", parent);
296  
      O o = expression.get(ctx);
297  
      parent.set(var, o);
298  
      ret o;
299  
    }
300  
    
301  
    toString { ret "outer " + var + " <- " + expression; }
302  
  }
303  
  
304  
  persistable sclass NewObject > EvaluableBase {
305  
    Class c;
306  
    Evaluable[] args;
307  
    
308  
    *(Class c) { this(c, null); }
309  
    *(Class *c, Evaluable[] *args) {
310  
      returnType(new LASValueDescriptor.Exact(c, false));
311  
    }
312  
    
313  
    public O get(VarContext ctx) {
314  
      try {
315  
        ret preciseNuObject(c, evalArgs(args, ctx));
316  
      } catch e {
317  
        throw rethrowWithSrc(e);
318  
      }
319  
    }
320  
    
321  
    toString { ret "new " + formatFunctionCall(className(c), args); }
322  
  }
323  
  
324  
  // new object of a script-defined class
325  
  // (we don't generate/resolve these classes until after the complete
326  
  // parse is done so parsing stays lightweight)
327  
  persistable sclass NewObject_LASClass > NewObject {
328  
    ResolvableLASClass lasClass;
329  
    
330  
    *(ResolvableLASClass *lasClass) {}
331  
    *(ResolvableLASClass *lasClass, Evaluable[] *args) {}
332  
    
333  
    void resolve {
334  
      if (c == null)
335  
        c = lasClass!;
336  
    }
337  
    
338  
    public O get(VarContext ctx) {
339  
      resolve();
340  
      ret super.get(ctx);
341  
    }
342  
    
343  
    toString { ret "new " + formatFunctionCall(str(lasClass), args); }
344  
  }
345  
  
346  
  // new object of a class defined in expression
347  
  srecord noeq NewObject_UnknownClass(Evaluable classExpr, Evaluable[] args) > NewObject {
348  
349  
    public O get(VarContext ctx) {
350  
      try {
351  
        Class c = cast classExpr.get(ctx);
352  
        ret preciseNuObject(c, evalArgs(args, ctx));
353  
      } catch e {
354  
        throw rethrowWithSrc(e);
355  
      }
356  
    }
357  
    
358  
    toString { ret "new " + formatFunctionCall(classExpr, args); }
359  
  }
360  
  
361  
  srecord noeq CallFunction(FunctionDef f, Evaluable[] args) > EvaluableBase {
362  
    public O get(VarContext ctx) {
363  
      var evaledArgs = evalArgs(args, ctx);
364  
      EXITCHECK
365  
      ret f.call(ctx, evaledArgs); 
366  
    }
367  
    
368  
    toString { ret formatFunctionCall(f.name, args); }
369  
    
370  
    public LASValueDescriptor returnType() {
371  
      ret LASValueDescriptor.fromType(f.getReturnType());
372  
    }
373  
  }
374  
  
375  
  srecord noeq GetVar(S var) > EvaluableBase {
376  
    public O get(VarContext ctx) {
377  
      ret ctx.get(var);
378  
    }
379  
    
380  
    toString { ret var; }
381  
  }
382  
  
383  
  /*persistable sclass GetFixedVar > FixedVarBase {
384  
    *(LASScope *scope, S *var) {}
385  
    
386  
    public O get(VarContext ctx) {
387  
      assertResolved();
388  
      try {
389  
        ret ctx/FixedVarContext.get(varIdx);
390  
      } catch ArrayIndexOutOfBoundsException e {
391  
        assertResolved();
392  
        throw e;
393  
      }
394  
    }
395  
    
396  
    toString { ret var + " [" + varIdx + "]"; }
397  
  }*/
398  
  
399  
  srecord noeq Const(O value) > EvaluableBase {
400  
    public O get(VarContext ctx) {
401  
      ret value;
402  
    }
403  
    
404  
    toString { ret strOrClassName(value); }
405  
    
406  
    public LASValueDescriptor returnType() {
407  
      ret new LASValueDescriptor.KnownValue(value);
408  
    }
409  
    
410  
    // Structuring this object is only done to make a class def hash,
411  
    // or to show a parsed script to a user.
412  
    // So the structure just has to be unique, not serializable.
413  
    // As the contents of "value" could be an unpersistable object,
414  
    // we just stringify it.
415  
    O _serialize() {
416  
      bool ok = isUnproblematicValue(value);
417  
      printVars ifdef g22const_debug("Const._serialize",
418  
        className := value?.getClass(), +ok);
419  
      ret ok
420  
        ? this 
421  
        : toStringWithClass(value);
422  
    }
423  
  }
424  
  
425  
  srecord noeq GetStaticField(Field field) > EvaluableBase {
426  
    public O get(VarContext ctx) ctex {
427  
      ret field.get(null);
428  
    }
429  
    
430  
    // See Const._serialize
431  
    S _serialize() { ret str(field); }
432  
  }
433  
  
434  
  abstract srecord noeq CallOnTarget(Evaluable target) > EvaluableBase {
435  
    HANDLENULLREFERENCE
436  
    
437  
    abstract O evalOnTarget(VarContext ctx, O object);
438  
    
439  
    public O get(VarContext ctx) {
440  
      try {
441  
        O object = target.get(ctx);
442  
        if (object == null)
443  
          ret handleNullReference();
444  
            
445  
        ret evalOnTarget(ctx, object);
446  
      } catch e {
447  
        throw rethrowWithSrc(e);
448  
      }
449  
    }
450  
  }
451  
  
452  
  persistable sclass CallMethodOrGetField > CallOnTarget {
453  
    S name;
454  
    
455  
    *(Evaluable *target, S *name) {}
456  
    
457  
    O evalOnTarget(VarContext ctx, O object) {
458  
      try {
459  
        ret preciseGetOrCallMethod(object, name);
460  
      } catch e {
461  
        throw rethrowWithSrc("Was getting " + name, e);
462  
      }
463  
    }
464  
  }
465  
  
466  
  persistable sclass GetField > CallOnTarget {
467  
    S name;
468  
    
469  
    *(Evaluable *target, S *name) {}
470  
    
471  
    O evalOnTarget(VarContext ctx, O object) {
472  
      try {
473  
        ret _get(object, name);
474  
      } catch e {
475  
        throw rethrowWithSrc("Was getting " + name, e);
476  
      }
477  
    }
478  
  }
479  
  
480  
  sclass GetVarContext > EvaluableBase {
481  
    public O get(VarContext ctx) { ret ctx; }
482  
  }
483  
  
484  
  srecord noeq ThrowMethodNotFoundException(CallMethod instruction) > EvaluableBase {
485  
    public O get(VarContext ctx) {
486  
      fail("Method not found: " + instruction);
487  
    }
488  
  }
489  
  
490  
  srecord noeq ThrowNullPointerException(CallMethod instruction) > EvaluableBase {
491  
    public O get(VarContext ctx) {
492  
      fail("Null pointer exception: " + instruction);
493  
    }
494  
  }
495  
  
496  
  persistable sclass CallMethod > CallOnTarget {
497  
    S methodName;
498  
    Evaluable[] args;
499  
    
500  
    *(Evaluable *target, S *methodName, Evaluable[] *args) {}
501  
    
502  
    O evalOnTarget(VarContext ctx, O object) {
503  
      ret /*call*/newPreciseCall(object, methodName, evalArgs(args, ctx));
504  
    }
505  
    
506  
    toString { ret target + "." + formatFunctionCall(methodName, args); }
507  
    
508  
    // optimize to DirectMethodCallOnKnownTarget if target type
509  
    // and all argument types are known exactly
510  
    public Evaluable optimize() {
511  
      var targetType = target.returnType();
512  
      if (targetType != null && targetType.knownValue()) {
513  
        O o = targetType.value();
514  
        if (o == null)
515  
          ret allowNullReference
516  
            ? const(null)
517  
            : new ThrowNullPointerException(this);
518  
        
519  
        Class[] argTypes = new[l(args)];
520  
        for i over args: {
521  
          var type = args[i].returnType();
522  
          if (type == null || !type.javaClassIsExact())
523  
            this;
524  
          argTypes[i] = type.javaClass();
525  
        }
526  
        
527  
        // can't optimize varargs
528  
        L<Method> methods = findMethodsNamed_cached(o, methodName);
529  
        if (any(methods, m -> m.isVarArgs())) this;
530  
        
531  
        var method, widening = unpair findMethod_withPrimitiveWidening_onTypes(o, methodName, argTypes);
532  
        if (method == null) ret new ThrowMethodNotFoundException(this);
533  
        
534  
        ret new DirectMethodCallOnKnownTarget(widening, o instanceof Class ? null : o, method, args);
535  
      }
536  
      
537  
      this;
538  
    }
539  
  }
540  
  
541  
  static O[] evalArgs(Evaluable[] args, VarContext ctx) {
542  
    ret mapToArrayOrNull(args, arg -> arg.get(ctx));
543  
  }
544  
  
545  
  // method invocation on unknown object with "magic switch"
546  
  persistable sclass CallMethodOrGlobalFunction > CallMethod {
547  
    MethodOnObject globalFunction;
548  
    
549  
    static final new O methodNotFoundSentinel;
550  
    
551  
    *(Evaluable *target, S *methodName, MethodOnObject *globalFunction, Evaluable[] *args) {}
552  
      
553  
    // mark "magic switch" with +
554  
    toString { ret target + "." + formatFunctionCall(methodName + "+", args); }
555  
    
556  
    O evalOnTarget(VarContext ctx, O o) {
557  
      O[] realArgs = evalArgs(args, ctx);
558  
      O result = newPreciseCall_sentinel(o, methodName, methodNotFoundSentinel, realArgs);
559  
      if (result != methodNotFoundSentinel)
560  
        ret result;
561  
      print ifdef sentinelDebug("Sentinel triggered: " + globalFunction);
562  
      ret newPreciseCall(
563  
        globalFunction.object,
564  
        globalFunction.method,
565  
        itemPlusArray(o, realArgs));
566  
    }
567  
  }
568  
    
569  
  // method invocation/field get on unknown object with "magic switch"
570  
  persistable sclass CallMethodOrGetFieldOrGlobalFunction > CallMethodOrGetField {
571  
    MethodOnObject globalFunction;
572  
    
573  
    static final new O notFoundSentinel;
574  
    
575  
    *(Evaluable *target, S *name, MethodOnObject *globalFunction) {}
576  
      
577  
    // mark "magic switch" with +
578  
    toString { ret target + "." + name + "+"; }
579  
    
580  
    O evalOnTarget(VarContext ctx, O o) {
581  
      try {
582  
        O result = preciseGetOrCallMethod_sentinel(o, name, notFoundSentinel);
583  
        if (result != notFoundSentinel)
584  
          ret result;
585  
        print ifdef sentinelDebug("Sentinel triggered: " + globalFunction);
586  
        ret newPreciseCall(
587  
          globalFunction.object,
588  
          globalFunction.method,
589  
          o);
590  
      } catch e {
591  
        throw rethrowWithSrc("Was getting " + name, e);
592  
      }
593  
    }
594  
  }
595  
  
596  
  abstract srecord noeq LambdaBase(Class intrface) > EvaluableBase {
597  
    transient Method implementedMethod;
598  
      
599  
    // !customConstructor
600  
    *(Class *intrface) {
601  
      implementedMethod = findSingleInterfaceMethodOrFail(intrface);
602  
    }
603  
  }
604  
  
605  
  // expects the interface method to have exactly one argument
606  
  sclass LambdaMethodOnArgument > LambdaBase {
607  
    S methodName;
608  
    Evaluable[] args;
609  
    
610  
    *(Class intrface, S *methodName, Evaluable[] *args) {
611  
      super(intrface);
612  
    }
613  
    
614  
    public O get(VarContext ctx) {
615  
      ret proxyFromInvocationHandler(intrface, (proxy, method, actualArgs) -> {
616  
        if (method.getDeclaringClass() == intrface)
617  
          ret forwardCall(actualArgs[0], ctx);
618  
        else
619  
          ret handleObjectMethodsInProxyInvocationHandler(
620  
            this, implementedMethod, method, proxy, actualArgs);
621  
      });
622  
    }
623  
    
624  
    O forwardCall(O target, VarContext ctx) {
625  
      ret call(target, methodName, evalArgs(args, ctx));
626  
    }
627  
  }
628  
    
629  
  srecord noeq LambdaDef(Class intrface, S[] args, Evaluable body) > EvaluableBase {
630  
    new Map<S, LASValueDescriptor> argTypes;
631  
    transient Method implementedMethod;
632  
    
633  
    // !customConstructor
634  
    *(Class *intrface, S[] *args, Evaluable *body) {
635  
      implementedMethod = findSingleInterfaceMethodOrFail(intrface);
636  
      if (implementedMethod.getParameterCount() != l(args))
637  
        fail("Bad parameter count for lambda: " + implementedMethod + " vs: " + joinWithComma(args));
638  
    }
639  
    
640  
    // We have to create the proxy when the lambda definition is
641  
    // evaluated since we have to put the context in there
642  
    public O get(VarContext ctx) {
643  
      ret proxyFromInvocationHandler(intrface, (proxy, method, actualArgs) -> {
644  
        ping();
645  
        
646  
        if (method.getDeclaringClass() == intrface) {
647  
          var ctx2 = new FlexibleVarContext(ctx);
648  
          var argNames = args;
649  
          // We already know that the count matches.
650  
          for i over args:
651  
            ctx2.put(argNames[i], actualArgs[i]);
652  
  
653  
          ret body.get(ctx2);
654  
        } else
655  
          ret handleObjectMethodsInProxyInvocationHandler(
656  
            this, implementedMethod, method, proxy, actualArgs);
657  
      });
658  
    }
659  
    
660  
    toString { ret "Lambda(" + shortenedSrc() + ")"; }
661  
  }
662  
    
663  
  abstract srecord noeq CurriedLambdaBase(Class intrface, Evaluable[] curriedArgs) > EvaluableBase {
664  
    transient Method implementedMethod;
665  
      
666  
    // !customConstructor
667  
    *(Class *intrface, Evaluable[] *curriedArgs) {
668  
      implementedMethod = findSingleInterfaceMethodOrFail(intrface);
669  
    }
670  
    
671  
    public O get(VarContext ctx) {
672  
      try {
673  
        O[] curriedArguments = evalArgs(curriedArgs, ctx);
674  
        
675  
        ret proxyFromInvocationHandler(intrface, (proxy, method, actualArgs) -> {
676  
          // Comparing a Method is more expensive than just
677  
          // comparing the class (should be enough to distinguish
678  
          // methods since we are dealing with a single-method class).
679  
          // tl;dr So far we are getting away with this so all is good ^^
680  
          try {
681  
            if (method.getDeclaringClass() == intrface)
682  
              ret forwardCall(ctx, concatMethodArgs(curriedArguments, actualArgs));
683  
            else
684  
              ret handleObjectMethodsInProxyInvocationHandler(
685  
                this, implementedMethod, method, proxy, actualArgs);            } catch e {
686  
            throw rethrowWithSrc(e);
687  
          }
688  
        });
689  
      } catch e {
690  
        throw rethrowWithSrc(e);
691  
      }
692  
    }
693  
    
694  
    abstract O forwardCall(VarContext ctx, O[] args);
695  
  }
696  
  
697  
  persistable sclass CurriedMethodLambda > CurriedLambdaBase {
698  
    O target;
699  
    S targetMethod;
700  
701  
    *(Class intrface, O *target, S *targetMethod, Evaluable[] curriedArgs) {
702  
      super(intrface, curriedArgs);
703  
    }
704  
    
705  
    O forwardCall(VarContext ctx, O[] args) {
706  
      ret newPreciseCall(target, targetMethod, args);
707  
    }
708  
  }
709  
  
710  
  sclass CurriedScriptFunctionLambda > CurriedLambdaBase {
711  
    FunctionDef f;
712  
    
713  
    *(Class intrface, FunctionDef *f, Evaluable[] curriedArgs) {
714  
      super(intrface, curriedArgs);
715  
    }
716  
    
717  
    O forwardCall(VarContext ctx, O[] args) {
718  
      ret f.call(ctx, args);
719  
    }
720  
  }
721  
  
722  
  sclass CurriedConstructorLambda > CurriedLambdaBase {
723  
    Constructor[] ctors;
724  
    
725  
    *(Class intrface, Constructor[] *ctors, Evaluable[] curriedArgs) {
726  
      super(intrface, curriedArgs);
727  
    }
728  
    
729  
    O forwardCall(VarContext ctx, O[] args) {
730  
      ret preciseNuObject(ctors, args);
731  
    }
732  
  }
733  
  
734  
  srecord noeq DirectMethodCallOnKnownTarget(bool widening, O target, Method method, Evaluable[] args) > EvaluableBase {
735  
    public O get(VarContext ctx) {
736  
      var evaluatedArgs = evalArgs(args, ctx);
737  
      ret widening
738  
        ? invokeMethodWithWidening(method, target, evaluatedArgs)
739  
        : invokeMethod(method, target, evaluatedArgs);
740  
    }
741  
    
742  
    toString { ret (target == null ? "" : target + ".") + formatFunctionCall(str(method), args); }
743  
    
744  
    public LASValueDescriptor returnType() {
745  
      ret LASValueDescriptor.fromClass(method.getReturnType());
746  
    }
747  
  }
748  
  
749  
  srecord noeq While(Evaluable condition, Evaluable body) > EvaluableBase {
750  
    public O get(VarContext ctx) {
751  
      while (!ctx.exiting() && (Bool) condition.get(ctx)) {
752  
        body.get(ctx);
753  
      }
754  
      
755  
      // while loops don't return anything
756  
      null;
757  
    }
758  
  }
759  
  
760  
  srecord noeq DoWhile(Evaluable condition, Evaluable body) > EvaluableBase {
761  
    public O get(VarContext ctx) {
762  
      do {
763  
        body.get(ctx);
764  
      } while (!ctx.exiting() && (Bool) condition.get(ctx));
765  
      
766  
      // while loops don't return anything
767  
      null;
768  
    }
769  
  }
770  
  
771  
  // collection is an Iterable, an array etc.
772  
  abstract srecord noeq ForEachBase(Evaluable collection, Evaluable body) > EvaluableBase {
773  
    macro ITERATE_ARRAY {
774  
      out = emptyList(array.length);
775  
      for (element : array) {
776  
        EXITCHECK
777  
        processElement(ctx, out, element);
778  
      }
779  
    }
780  
    
781  
    public O get(VarContext ctx) {
782  
      var coll = collection.get(ctx);
783  
      Iterator iterator;
784  
      L out;
785  
      try {
786  
        if (coll == null)
787  
          out = new L;
788  
        else if (coll.getClass().isArray()) {
789  
          if (coll cast O[]) { var array = coll; ITERATE_ARRAY }
790  
          else if (coll cast byte[]) { var array = coll; ITERATE_ARRAY }
791  
          else if (coll cast short[]) { var array = coll; ITERATE_ARRAY }
792  
          else if (coll cast double[]) { var array = coll; ITERATE_ARRAY }
793  
          else if (coll cast float[]) { var array = coll; ITERATE_ARRAY }
794  
          else if (coll cast int[]) { var array = coll; ITERATE_ARRAY }
795  
          else if (coll cast long[]) { var array = coll; ITERATE_ARRAY }
796  
          else if (coll cast char[]) { var array = coll; ITERATE_ARRAY }
797  
          else if (coll cast bool[]) { var array = coll; ITERATE_ARRAY }
798  
          else fail("todo for each with: " + coll);
799  
        } else if (coll cast Iterable) {
800  
          out = emptyList(coll);
801  
          iterator = coll.iterator();
802  
          try {
803  
            while (iterator.hasNext()) {
804  
              EXITCHECK
805  
              var element = iterator.next();
806  
              processElement(ctx, out, element);
807  
            }
808  
          } finally {
809  
            if (iterator cast AutoCloseable) ctex {
810  
              iterator.close();
811  
            }
812  
          }
813  
        } else
814  
          fail("Not iterable: " + className(coll));
815  
      } finally {
816  
        loopDone(ctx);
817  
      }
818  
      
819  
      ret out;
820  
    }
821  
    
822  
    abstract void processElement(VarContext ctx, L out, O o);
823  
    abstract void loopDone(VarContext ctx);
824  
  }
825  
  
826  
  persistable sclass ForEach > ForEachBase {
827  
    S var;
828  
    settable LASValueDescriptor varType;
829  
    
830  
    *(Evaluable *collection, S *var, Evaluable *body) {}
831  
    
832  
    void processElement(VarContext ctx, L out, O o) {
833  
      ctx.set(var, o);
834  
      out.add(body.get(ctx));
835  
    }
836  
    
837  
    void loopDone(VarContext ctx) {
838  
      ctx.unset(var);
839  
    }
840  
  }
841  
  
842  
  srecord ForIterator(Evaluable iterable, S var, Evaluable body) > EvaluableBase {
843  
    public O get(VarContext ctx) {
844  
      VarContext subContext = new FlexibleVarContext(ctx);
845  
      
846  
      var iterable = this.iterable.get(ctx);
847  
      Iterator iterator = iterator_gen(iterable);
848  
        
849  
      ret new MapI(value -> {
850  
        subContext.set(var, value);
851  
        ret body.get(subContext);
852  
      }, iterator);
853  
    }
854  
  }
855  
856  
  srecord ForNested(Evaluable iterable, S var, Evaluable body) > EvaluableBase {
857  
    public O get(VarContext ctx) {
858  
      VarContext subContext = new FlexibleVarContext(ctx);
859  
      
860  
      var iterable = this.iterable.get(ctx);
861  
      Iterator iterator = iterator_gen(iterable);
862  
863  
      ret nestedIterator(iterator, value -> {
864  
        subContext.set(var, value);
865  
        ret iterator_gen(body.get(subContext));
866  
      });
867  
    }
868  
  }
869  
870  
  persistable sclass ForPairs > ForEachBase {
871  
    S varA, varB;
872  
    
873  
    *(Evaluable *collection, Evaluable *body, S *varA, S *varB) {}
874  
    
875  
    void processElement(VarContext ctx, L out, O o) {
876  
      Pair p = cast o;
877  
      ctx.set(varA, p.a);
878  
      ctx.set(varB, p.b);
879  
      out.add(body.get(ctx));
880  
    }
881  
    
882  
    void loopDone(VarContext ctx) {
883  
      ctx.unset(varA);
884  
      ctx.unset(varB);
885  
    }
886  
  }
887  
  
888  
  srecord noeq ForKeyValue(Evaluable map, Evaluable body, S varA, S varB) > EvaluableBase {
889  
    public O get(VarContext ctx) {
890  
      Map<?, ?> theMap = (Map) map.get(ctx);
891  
      L out;
892  
      try {
893  
        if (theMap != null) {
894  
          out = emptyList(theMap.size());
895  
          for (entry : theMap.entrySet()) {
896  
            EXITCHECK
897  
            ctx.set(varA, entry.getKey());
898  
            ctx.set(varB, entry.getValue());
899  
            out.add(body.get(ctx));
900  
          }
901  
        } else
902  
          out = new L;
903  
      } finally {
904  
        ctx.unset(varA);
905  
        ctx.unset(varB);
906  
      }
907  
      
908  
      ret out;
909  
    }
910  
  }
911  
912  
  srecord noeq ForIntTo(Evaluable endValue, S var, Evaluable body) > EvaluableBase {
913  
    public Evaluable optimize() {
914  
      if (!returnValueNeeded)
915  
        body = body.optimizeForReturnValueNotNeeded();
916  
      this;
917  
    }
918  
    
919  
    public O get(VarContext ctx) {
920  
      int n = (Int) endValue.get(ctx), i = 0;
921  
      L out = returnValueNeeded ? new L : null;
922  
      
923  
      try {
924  
        ctx.put(var, i);
925  
        
926  
        while (i < n) {
927  
          EXITCHECK
928  
          O o = body.get(ctx);
929  
          out?.add(o);
930  
          ctx.set(var, i = (Int) ctx.get(var)+1);
931  
        }
932  
      } finally {
933  
        ctx.unset(var);
934  
      }
935  
      
936  
      ret out;
937  
    }
938  
  }
939  
  
940  
  persistable sclass ForIndex > EvaluableBase {
941  
    Evaluable collection, body;
942  
    S varIndex, varElement;
943  
    
944  
    *(Evaluable *collection, Evaluable *body, S *varIndex, S *varElement) {}
945  
    
946  
    public O get(VarContext ctx) {
947  
      ret new ForIndex_instance(collection, body, varIndex, varElement).get(ctx);
948  
    }
949  
  }
950  
  
951  
  sclass ForIndex_instance > ForEachBase {
952  
    S varIndex, varElement;
953  
    int index;
954  
    
955  
    *(Evaluable *collection, Evaluable *body, S *varIndex, S *varElement) {}
956  
957  
    void processElement(VarContext ctx, L out, O o) {
958  
      ctx.set(varIndex, index++);
959  
      ctx.set(varElement, o);
960  
      out.add(body.get(ctx));
961  
    }
962  
    
963  
    void loopDone(VarContext ctx) {
964  
      ctx.unset(varIndex);
965  
      ctx.unset(varElement);
966  
    }
967  
  }
968  
  
969  
  srecord noeq IfThen(Evaluable condition, Evaluable body,
970  
    Evaluable elseBranch) > EvaluableBase {
971  
    
972  
    IfThen(Evaluable condition, Evaluable body) {
973  
      this.condition = condition;
974  
      this.body = body;
975  
    }
976  
    
977  
    public O get(VarContext ctx) {
978  
      if ((Bool) condition.get(ctx))
979  
        ret body.get(ctx);
980  
      else if (elseBranch != null)
981  
        ret elseBranch.get(ctx);
982  
      else
983  
        null;
984  
    }
985  
  }
986  
  
987  
  srecord noeq ReturnFromScript(Script script, Evaluable value) > EvaluableBase {
988  
    public O get(VarContext ctx) {
989  
      O result = value.get(ctx);
990  
      printVars ifdef ReturnFromScript_debug("ReturnFromScript",
991  
        +result, +ctx, +script);
992  
      ctx.exitFromScript(script);
993  
      ctx.returnValue(result);
994  
      null;
995  
    }
996  
    
997  
    toString {
998  
      ret formatFunctionCall ReturnFromScript(script, value);
999  
    }
1000  
  }
1001  
  
1002  
  srecord noeq Continue(Script loopBody) > EvaluableBase {
1003  
    public O get(VarContext ctx) {
1004  
      ctx.exitFromScript(loopBody);
1005  
      ctx.returnValue(null);
1006  
      null;
1007  
    }
1008  
    
1009  
    toString {
1010  
      ret formatFunctionCall Continue(loopBody);
1011  
    }
1012  
  }
1013  
  
1014  
  srecord noeq RepeatN(Evaluable n, Evaluable body) > EvaluableBase {
1015  
    public O get(VarContext ctx) {
1016  
      long count = ((Number) n.get(ctx)).longValue();
1017  
      
1018  
      repeat count {
1019  
        EXITCHECK
1020  
        body.get(ctx);
1021  
      }
1022  
      
1023  
      null;
1024  
    }
1025  
  }
1026  
  
1027  
  persistable srecord BoolAnd(Evaluable a, Evaluable b) > EvaluableBase {
1028  
    public O get(VarContext ctx) {
1029  
      if (!((Bool) a.get(ctx))) false;
1030  
      ret b.get(ctx);
1031  
    }
1032  
  }
1033  
  
1034  
  persistable srecord BoolOr(Evaluable a, Evaluable b) > EvaluableBase {
1035  
    public O get(VarContext ctx) {
1036  
      if (((Bool) a.get(ctx))) true;
1037  
      ret b.get(ctx);
1038  
    }
1039  
  }
1040  
  
1041  
  srecord noeq TempBlock(Evaluable tempExpr,
1042  
    Evaluable body) > EvaluableBase {
1043  
    
1044  
    public O get(VarContext ctx) {
1045  
      temp (AutoCloseable) tempExpr.get(ctx);
1046  
      ret body.get(ctx);
1047  
    }
1048  
  }
1049  
  
1050  
  srecord noeq WillReturn(Evaluable exp, Evaluable body) > EvaluableBase {
1051  
    public O get(VarContext ctx) {
1052  
      body.get(ctx);
1053  
      ret exp.get(ctx);
1054  
    }
1055  
  }
1056  
  
1057  
  srecord ClassDef(ResolvableLASClass lasClass) > EvaluableBase {
1058  
    public O get(VarContext ctx) {
1059  
      ret lasClass!;
1060  
    }
1061  
  }
1062  
  
1063  
  srecord noeq SetField(Evaluable target, S name, Evaluable expr) > EvaluableBase {
1064  
    HANDLENULLREFERENCE
1065  
  
1066  
    public O get(VarContext ctx) {
1067  
      try {
1068  
        O value = expr.get(ctx);
1069  
        
1070  
        O object = target.get(ctx);
1071  
        if (object == null)
1072  
          handleNullReference();
1073  
        else
1074  
          set(object, name, value);
1075  
          
1076  
        ret value;
1077  
      } catch e {
1078  
        throw rethrowWithSrc(e);
1079  
      }
1080  
    }
1081  
  }
1082  
  
1083  
  srecord noeq SetStaticField(Field field, Evaluable expr) > EvaluableBase {
1084  
    public O get(VarContext ctx) {
1085  
      try {
1086  
        O value = expr.get(ctx);
1087  
        field.set(null, value);
1088  
        ret value;
1089  
      } catch e {
1090  
        throw rethrowWithSrc(e);
1091  
      }
1092  
    }
1093  
  }
1094  
  
1095  
  srecord noeq Throw(Evaluable expr) > EvaluableBase {
1096  
    public O get(VarContext ctx) {
1097  
      throw asRuntimeException((Throwable) expr.get(ctx));
1098  
    }
1099  
  }
1100  
  
1101  
  srecord noeq TryCatch(Evaluable body, S var, Evaluable catchBlock) > EvaluableBase {
1102  
    public O get(VarContext ctx) {
1103  
      try {
1104  
        ret body.get(ctx);
1105  
      } catch e {
1106  
        var addVar = var == null ?: ctx.tempPut(var, e);
1107  
        temp addVar;
1108  
        ret catchBlock.get(ctx);
1109  
      }
1110  
    }
1111  
  }
1112  
1113  
  srecord noeq TryFinally(Evaluable body, Evaluable finallyBlock) > EvaluableBase {
1114  
    public O get(VarContext ctx) {
1115  
      try {
1116  
        ret body.get(ctx);
1117  
      } finally {
1118  
        finallyBlock.get(ctx);
1119  
      }
1120  
    }
1121  
  }
1122  
1123  
  static structure_Data structureDataForLAS() {
1124  
    new structure_Data d;
1125  
    d.skipDefaultValues(true);
1126  
    
1127  
    d.shouldIncludeField = field -> {
1128  
      S c = shortClassName(field.getDeclaringClass());
1129  
      S f = field.getName();
1130  
      bool shouldInclude = !(eq(c, "HasTokenRangeWithSrc") && eq(f, "src"));
1131  
      //printVars("shouldIncludeField", +c, +f, +shouldInclude);
1132  
      ret shouldInclude;
1133  
    };
1134  
      
1135  
    ret d;
1136  
  }
1137  
  
1138  
  // with respect to serialization
1139  
  sbool isUnproblematicValue(O o) {
1140  
    ret o == null || o instanceof Number || o instanceof S
1141  
      || o instanceof Bool || o instanceof Class;
1142  
  }
1143  
  
1144  
  // These structs are a. for the user to see the parsed script
1145  
  // and b. for checking if two class defs are equal.
1146  
  //
1147  
  // (The resulting struct string doesn't have to unstructure()-able,
1148  
  // which is why we can e.g. shorten class names.)
1149  
  sS scriptStruct(O o) {
1150  
    S s = struct(o, structureDataForLAS());
1151  
    LS tok = structTok(s);
1152  
    S prefix = shortName(GazelleV_LeftArrowScript) + "$";
1153  
    for (int i = 1; i < l(tok); i += 2)
1154  
      tok.set(i, replacePrefix(prefix, "$", tok.get(i)));
1155  
    ret join(tok);
1156  
  }
1157  
  
1158  
  sS indentedScriptStruct(O o) {
1159  
    ret indentStructureString(scriptStruct(o));
1160  
  }
1161  
  
1162  
  static Evaluable const(O o) {
1163  
    ret new Const(o);
1164  
  }
1165  
  
1166  
  sclass Then > CallOnTarget {
1167  
    CallOnTarget call1, call2;
1168  
    
1169  
    *(CallOnTarget *call1, CallOnTarget *call2) {
1170  
      target = call1.target;
1171  
      call1.target = null;
1172  
    }
1173  
    
1174  
    O evalOnTarget(VarContext ctx, O object) {
1175  
      call1.evalOnTarget(ctx, object);
1176  
      ret call2.evalOnTarget(ctx, object);
1177  
    }
1178  
  }
1179  
1180  
  srecord noeq Synchronized(Evaluable target, Evaluable body) > EvaluableBase {
1181  
    public Evaluable optimize() {
1182  
      if (!returnValueNeeded)
1183  
        body = body.optimizeForReturnValueNotNeeded();
1184  
      this;
1185  
    }
1186  
    
1187  
    public O get(VarContext ctx) {
1188  
      synchronized(target.get(ctx)) {
1189  
        ret body.get(ctx);
1190  
      }
1191  
    }
1192  
  }
1193  
  
1194  
} // 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/307
Text MD5: 320cfff0069602d4e5e829dbc8a3c21b
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2025-01-03 20:40:01
Source code size: 34857 bytes / 1194 lines
Pitched / IR pitched: No / No
Views / Downloads: 1085 / 3404
Version history: 306 change(s)
Referenced in: [show references]