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).

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