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

401
LINES

< > BotCompany Repo | #1034291 // GazelleV_LeftArrowScriptParser backup before type inference

JavaX fragment (include)

1  
/* e.g.
2  
3  
  overlay <- ScreenOverlay
4  
  bounds <- rightScreenBounds
5  
  overlay bounds bounds
6  
  overlay show
7  
8  
Can separate commands with ";" also.
9  
For how to define functions in a script see #1033988.
10  
11  
Note: LeftArrowScriptAutoCompleter uses a lot of this class's internals
12  
13  
*/
14  
15  
sclass GazelleV_LeftArrowScriptParser > SimpleLeftToRightParser {
16  
  replace Toolbox with GazelleV_LeftArrowScript.
17  
  delegate Script to Toolbox.
18  
  delegate Evaluable to Toolbox.
19  
  replace const with _const.
20  
  
21  
  settable new G22Utils g22utils;
22  
  L functionContainers;
23  
  
24  
  new LinkedHashSet<S> knownVars;
25  
  BuildingScript currentReturnableScript;
26  
  int parenLevels;
27  
  
28  
  // object can be a class
29  
  srecord MethodOnObject(O object, S method) {}
30  
  
31  
  class BuildingScript {
32  
    bool returnable;
33  
    new Script script;
34  
    new L<Evaluable> steps;
35  
    Map<S, Toolbox.FunctionDef> functionDefs = new Map;
36  
    
37  
    *(bool *returnable) {}
38  
    
39  
    void add(Evaluable step) { if (step != null) steps.add(step); }
40  
41  
    Evaluable get() {
42  
      // if the last command is a return from THIS script,
43  
      // convert into a simple expression
44  
      
45  
      var lastStep = last(steps);
46  
      if (lastStep cast Toolbox.ReturnFromScript)
47  
        if (lastStep.script == script)
48  
          replaceLast(steps, lastStep.value);
49  
        
50  
      // if the script is only step, is not returnable
51  
      // and defines no functions, replace it with its only step
52  
      
53  
      if (!returnable && l(steps) == 1 && empty(functionDefs))
54  
        ret first(steps);
55  
        
56  
      // make and return actual script
57  
      
58  
      script.functionDefs = functionDefs;
59  
      script.steps = toTypedArray(Evaluable.class, steps);
60  
      ret script;
61  
    }
62  
    
63  
    S toStringLong() { ret pnlToLines(steps); }
64  
    toString { ret formatRecordVars BuildingScript(+script, +returnable); }
65  
  }
66  
  
67  
  Script parse(S text) {
68  
    setText(text);
69  
    ret (Script) parseScript(true);
70  
  }
71  
  
72  
  // if returnable is true, it's always a Script
73  
  Evaluable parseScript(bool returnable) {
74  
    BuildingScript script = new(returnable);
75  
    var lastReturnableScript = currentReturnableScript;
76  
    if (returnable) currentReturnableScript = script;
77  
    try {
78  
      parseScript_2(script);
79  
      var builtScript = script!;
80  
      currentReturnableScript = lastReturnableScript;
81  
      ret builtScript;
82  
    } catch e {
83  
      print("Parsed so far:\n" + script);
84  
      
85  
      throw rethrowAndAppendToMessage(e, squareBracketed(str(lineAndColumn())));
86  
    }
87  
  }
88  
  
89  
  void parseScript_2(BuildingScript script) {
90  
    while (mainLoop()) {
91  
      if (is(";")) continue with next();
92  
      if (is("}")) break;
93  
      
94  
      S t = token();
95  
      print("First token of command: " + t);
96  
      
97  
      if (is("def"))
98  
        continue with parseFunctionDefinition();
99  
        
100  
      if (is("while"))
101  
        continue with script.add(parseWhileLoop());
102  
103  
      if (is("for"))
104  
        continue with script.add(parseForEach());
105  
106  
      if (is("if"))
107  
        continue with script.add(parseIfStatement());
108  
        
109  
      // return is just ignored for now
110  
      if (is("return")) {
111  
        consume();
112  
        var expr = parseExpr();
113  
        continue with script.add(new Toolbox.ReturnFromScript(currentReturnableScript.script, expr));
114  
      }
115  
116  
      print("next tokens: " + quote(token(1)) + " " + quote(token(2)));
117  
      if (isIdentifier(t) && eq(token(1), "<") && eq(token(2), "-")) {
118  
        print("Found assignment");
119  
        next(3);
120  
        knownVars.add(t);
121  
        script.add(new Toolbox.Assignment(t, parseExpr()));
122  
      } else
123  
        script.add(parseExpr());
124  
    }
125  
  }
126  
  
127  
  Evaluable parseOptionalInnerExpression() {
128  
    printVars parseOptionalInnerExpression(+token());
129  
    if (atCmdEnd() || is("{")) null;
130  
    ret parseInnerExpr();
131  
  }
132  
  
133  
  Evaluable const(O o) { ret new Toolbox.Const(o); }
134  
  
135  
  Evaluable parseInnerExpr() { ret parseExpr(true); }
136  
  
137  
  Evaluable parseExpr(bool inner default false) {
138  
    if (atEnd()) null;
139  
    
140  
    S t = token();
141  
    printVars parseExpr(token := t);
142  
    if (is(";")) null; // empty command
143  
    
144  
    // int or double literal
145  
    if (is("-") && empty(nextSpace()) && startsWithDigit(token(1))
146  
      || startsWithDigit(t)) {
147  
      t = consumeMultiTokenLiteral();
148  
      ret isInteger(t) ? const(parseInt(t)) : const(parseDouble(t));
149  
    }
150  
151  
    if (isQuoted(t)) {
152  
      consume();
153  
      ret const(unquote(t));
154  
    }
155  
      
156  
    if (isIdentifier(t)) {
157  
      consume();
158  
      print("Consumed identifier " + t + ", next token: " + token() + ", inner: " + inner);
159  
      ret parseExprStartingWithIdentifier(t, inner);
160  
    }
161  
    
162  
    // nested expression
163  
    
164  
    if (eq(t, "(")) {
165  
      parenLevels++;
166  
      consume();
167  
      print("Consumed opening parens (level " + parenLevels + ")");
168  
      var e = parseExpr();
169  
      print("Consuming closing parens for expr: " + e + " (closing paren level " + parenLevels + ")");
170  
      consume(")");
171  
      parenLevels--;
172  
      
173  
      ret inner ? e : parseCall(e);
174  
    }
175  
      
176  
    fail("Identifier, literal or opening parentheses expected (got: " + quote(t));
177  
  }
178  
  
179  
  // t is last consumed token (the identifier the expression starts with)
180  
  Evaluable parseExprStartingWithIdentifier(S t, bool inner) {
181  
    if (eq(t, "true")) ret const(true);
182  
    if (eq(t, "false")) ret const(false);
183  
    if (eq(t, "null")) ret const(null);
184  
    
185  
    if (eq(t, "new")) {
186  
      S className = assertIdentifier(tpp());
187  
      O o = findExternalObject(className);
188  
      if (o cast Class)
189  
        ret new Toolbox.NewObject(o, parseArguments());
190  
      fail("Class not found: " + className);
191  
    }
192  
193  
    if (knownVars.contains(t)) {
194  
      var e = new Toolbox.GetVar(t);
195  
      print("Found var acccess: " + e + ", " + (!inner ? "Checking for call" : "Returning expression"));
196  
      ret inner ? e : parseCall(e);
197  
    }
198  
    
199  
    if (!inner) {
200  
      var fdef = currentReturnableScript.functionDefs.get(t);
201  
      if (fdef != null)
202  
        ret new Toolbox.CallFunction(fdef, parseArguments());
203  
    }
204  
      
205  
    O o = findExternalObject(t);
206  
    if (o == null)
207  
      fail("Unknown object: " + t);
208  
    else if (inner)
209  
      ret const(o);
210  
    else if (o cast Class) {
211  
      /*if (atCmdEnd())
212  
        ret new Toolbox.NewObject(o);*/
213  
        
214  
      /* old object creation syntax (e.g. Pair new a b)
215  
      if (is("new")) {
216  
        next();
217  
        ret new Toolbox.NewObject(o, parseArguments());
218  
      } else*/ if (isIdentifier()) {
219  
        S name = tpp();
220  
        
221  
        // look for method first
222  
        
223  
        if (hasMethodNamed(o, name))
224  
          ret new Toolbox.CallMethod(const(o), name, parseArguments());
225  
          
226  
        // look for field second
227  
        
228  
        var field = getField(o, name);
229  
        if (field != null) {
230  
          assertCmdEnd();
231  
          ret new Toolbox.GetStaticField(field);
232  
        }
233  
        
234  
        fail(name + " not found in " + o + " (looked for method or field)");
235  
      } else
236  
        fail("Method name expected: " + token());
237  
    } else if (o cast MethodOnObject) {
238  
      if (inner) fail("Can't call methods in arguments");
239  
      ret new Toolbox.CallMethod(const(o.object), o.method, parseArguments());
240  
    } else
241  
      ret parseCall(const(o));
242  
  }
243  
  
244  
  L<Evaluable> parseArguments() {
245  
    //ret collectWhileNotNull(-> parseOptionalInnerExpression());
246  
    
247  
    new L<Evaluable> l;
248  
    try {
249  
      while (true) {
250  
        Evaluable a = parseOptionalInnerExpression();
251  
        if (a == null) break;
252  
        l.add(a);
253  
      }
254  
      ret l;
255  
    } on fail {
256  
      print("Arguments parsed so far: " + l);
257  
    }
258  
  }
259  
  
260  
  S consumeMultiTokenLiteral() {
261  
    ret consumeUntilSpaceOr(-> atCmdEnd());
262  
  }
263  
  
264  
  bool atCmdEnd() {
265  
    ret
266  
      parenLevels == 0 && atEndOrLineBreak()
267  
      || is(";") || is("}") || is(")");
268  
  }
269  
  
270  
  void assertCmdEnd() { if (!atCmdEnd()) fail("Expected end of command"); }
271  
  
272  
  Evaluable parseCall(Evaluable target) {
273  
    if (atCmdEnd() || !isIdentifier()) ret target;
274  
    
275  
    var start = ptr();
276  
    S methodName = tpp();
277  
    var args = parseArguments();
278  
    
279  
    if (nempty(args))
280  
      ret new Toolbox.CallMethod(target, methodName, args);
281  
    else
282  
      ret src(start, new Toolbox.CallMethodOrGetField(target, methodName));
283  
  }
284  
  
285  
  <A> A src(TokPtr start, A a) {
286  
    if (a cast IHasTokenRangeWithSrc)
287  
      a.setTokenRangeWithSrc(TokenRangeWithSrc(start, ptr()));
288  
    ret a;
289  
  }
290  
  
291  
  // can return MethodOnObject
292  
  swappable O findExternalObject(S name) ctex {
293  
    //try object findClassThroughDefaultClassFinder(name);
294  
    //try object findClassInStandardImports(name);
295  
      
296  
    S fullName = globalClassNames().get(name);
297  
    if (fullName != null)
298  
      ret Class.forName(fullName);
299  
      
300  
    fOr (container : functionContainers)
301  
      if (hasMethodNamed(container, name))
302  
        ret new MethodOnObject(container, name);
303  
    null;
304  
  }
305  
  
306  
  selfType allowTheWorld() { ret allowTheWorld(mc()); }
307  
  
308  
  selfType allowTheWorld(O... functionContainers) {
309  
    this.functionContainers = asList(functionContainers);
310  
    globalClassNames_cache = null; // recalculate
311  
    this;
312  
  }
313  
  
314  
  void printFunctionDefs(Script script) {
315  
    print(values(script.functionDefs));
316  
  }
317  
  
318  
  void parseFunctionDefinition() {
319  
    consume("def");
320  
    S functionName = assertIdentifier(tpp());
321  
    new LS args;
322  
    while (isIdentifier())
323  
      args.add(tpp());
324  
    temp tempAddAll(knownVars, args);
325  
    var functionBody = parseCurlyBlock(true);
326  
    
327  
    currentReturnableScript.functionDefs.put(functionName,
328  
      new Toolbox.FunctionDef(functionName, args, functionBody));
329  
  }
330  
  
331  
  Evaluable parseCurlyBlock(bool returnable) {
332  
    //print(+knownVars);
333  
    consume("{");
334  
    var script = parseScript(returnable);
335  
    consume("}");
336  
    ret script;
337  
  }
338  
  
339  
  Evaluable parseWhileLoop() {
340  
    consume("while");
341  
    var condition = parseExpr();
342  
    var body = parseCurlyBlock(false);
343  
    ret new Toolbox.While(condition, body);
344  
  }
345  
  
346  
  Evaluable parseForEach() {
347  
    consume("for");
348  
    S var = assertIdentifier(tpp());
349  
    print("for var", var);
350  
    consume("in");
351  
    var collection = parseExpr();
352  
    print(+collection);
353  
    temp tempAdd(knownVars, var);
354  
    var body = parseCurlyBlock(false);
355  
    ret new Toolbox.ForEach(collection, var, body);
356  
  }
357  
  
358  
  Evaluable parseIfStatement() {
359  
    consume("if");
360  
    var condition = parseExpr();
361  
    var body = parseCurlyBlock(false);
362  
    ret new Toolbox.IfThen(condition, body);
363  
  }
364  
  
365  
  // declare an external variable
366  
  void addVar(S var) { knownVars.add(var); }
367  
  
368  
  // short name to full name
369  
  simplyCached SS globalClassNames() {
370  
    var packages = mapToTreeSet(importedPackages(), pkg -> pkg + ".");
371  
    
372  
    // add inner classes of function containers
373  
    var classContainers = classContainerPrefixes();
374  
    
375  
    new SS out;
376  
    for (className : g22utils.classNameResolver().allFullyQualifiedClassNames()) {
377  
      if (!contains(className, '$')) {
378  
        S pkg = longestPrefixInTreeSet(className, packages);
379  
        if (pkg != null) {
380  
          S shortName = dropPrefix(pkg, className);
381  
          if (!shortName.contains("."))
382  
            out.put(shortName, className);
383  
        }
384  
      }
385  
        
386  
      S container = longestPrefixInTreeSet(className, classContainers);
387  
      if (container != null)
388  
        out.put(dropPrefix(container, className), className);
389  
    }
390  
        
391  
    ret out;
392  
  }
393  
  
394  
  swappable Cl<S> importedPackages() {
395  
    ret itemPlus("java.lang", standardImports_fullyImportedPackages());
396  
  }
397  
  
398  
  TreeSet<S> classContainerPrefixes() {
399  
    ret mapToTreeSet(functionContainers, fc -> className(fc) + "$");
400  
  }
401  
}

Author comment

Began life as a copy of #1033976

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1034291
Snippet name: GazelleV_LeftArrowScriptParser backup before type inference
Eternal ID of this version: #1034291/1
Text MD5: f561e55965ddeabc63f10b6754735309
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-02-01 03:08:06
Source code size: 11835 bytes / 401 lines
Pitched / IR pitched: No / No
Views / Downloads: 124 / 143
Referenced in: [show references]