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

210
LINES

< > BotCompany Repo | #1033976 // GazelleV_LeftArrowScriptParser

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

Libraryless. Click here for Pure Java version (21911L/133K).

/* e.g.

  overlay <- ScreenOverlay
  bounds <- rightScreenBounds
  overlay bounds bounds
  overlay show

Can separate commands with ";" also.
For how to define functions in a script see #1033988.

Note: LeftArrowScriptAutoCompleter uses a lot of this class's internals

*/

sclass GazelleV_LeftArrowScriptParser > SimpleLeftToRightParser {
  replace Toolbox with GazelleV_LeftArrowScript.
  delegate Script to Toolbox.
  delegate Evaluable to Toolbox.
  replace const with _const.
  
  L functionContainers;
  
  new LinkedHashSet<S> knownVars;
  Map<S, Toolbox.FunctionDef> functionDefs = new Map;
  
  // object can be a class
  srecord MethodOnObject(O object, S method) {}
  
  Script parse(S text) {
    setText(text);
    ret parseScript();
  }
  
  Script parseScript() {
    new Script script;
    script.functionDefs = functionDefs;
    try {
      parseScript_2(script);
      ret script;
    } catch e {
      print("Parsed so far:\n" + script);
      
      throw rethrowAndAppendToMessage(e, squareBracketed(str(lineAndColumn())));
    }
  }
  
  void parseScript_2(Script script) {
    while (mainLoop()) {
      if (is(";")) continue with next();
      if (is("}")) break;
      
      S t = token();
      
      if (is("def")) {
        next();
        S functionName = assertIdentifier(tpp());
        new LS args;
        while (isIdentifier())
          args.add(tpp());
        assertEquals("{", tpp());
        temp tempAddAll(knownVars, args);
        //print(+knownVars);
        var functionBody = parseScript();
        assertEquals("}", tpp());
        functionDefs.put(functionName, new Toolbox.FunctionDef(functionName, args, functionBody));
        continue;
      }
      
      if (isIdentifier(t) && eq(token(1), "<") && eq(token(2), "-")) {
        next(3);
        knownVars.add(t);
        script.add(new Toolbox.Assignment(t, parseExpr()));
      } else
        addUnlessNull(script, parseExpr());
    }
  }
  
  Evaluable parseOptionalInnerExpression() {
    if (atCmdEnd()) null;
    ret parseInnerExpr();
  }
  
  Evaluable const(O o) { ret new Toolbox.Const(o); }
  
  Evaluable parseInnerExpr() { ret parseExpr(true); }
  
  Evaluable parseExpr(bool inner default false) {
    if (atEnd()) null;
    if (is(";")) null;
    
    S t = token();
    
    // int or double literal
    if (is("-") && empty(nextSpace()) && startsWithDigit(token(1))
      || startsWithDigit(t)) {
      t = consumeUntilSpaceOrCmdEnd();
      ret isInteger(t) ? const(parseInt(t)) : const(parseDouble(t));
    }

    consume();
      
    if (isQuoted(t))
      ret const(unquote(t));
      
    if (was("true")) ret const(true);
    if (was("false")) ret const(false);
    if (was("null")) ret const(null);
    
    if (was("new")) {
      S className = tpp();
      O o = findExternalObject(className);
      if (o cast Class)
        ret new Toolbox.NewObject(o, parseExpressions());
      fail("Class not found: " + className);
    }

    if (knownVars.contains(t)) {
      var e = new Toolbox.GetVar(t);
      ret inner ? e : parseCall(e);
    }
      
    if (!inner) {
      var fdef = functionDefs.get(t);
      if (fdef != null)
        ret new Toolbox.CallFunction(fdef, parseExpressions());
    }
      
    O o = findExternalObject(t);
    if (o == null)
      fail("Unknown object: " + t);
    else if (inner)
      ret const(o);
    else if (o cast Class) {
      /*if (atCmdEnd())
        ret new Toolbox.NewObject(o);*/
        
      /* old object creation syntax (e.g. Pair new a b)
      if (is("new")) {
        next();
        ret new Toolbox.NewObject(o, parseExpressions());
      } else*/ if (isIdentifier()) {
        S name = tpp();
        
        // look for method first
        
        if (hasMethodNamed(o, name))
          ret new Toolbox.CallMethod(const(o), name, parseExpressions());
          
        // look for field second
        
        var field = getField(o, name);
        if (field != null) {
          assertCmdEnd();
          ret new Toolbox.GetStaticField(field);
        }
        
        fail(name + " not found in " + o + " (looked for method or field)");
      } else
        fail("Method name expected: " + token());
    } else if (o cast MethodOnObject) {
      if (inner) fail("Can't call methods in arguments");
      ret new Toolbox.CallMethod(const(o.object), o.method, parseExpressions());
    } else
      ret parseCall(const(o));
  }
  
  L<Evaluable> parseExpressions() {
    ret collectWhileNotNull(-> parseOptionalInnerExpression());
  }
  
  S consumeUntilSpaceOrCmdEnd() {
    ret consumeUntilSpaceOr(-> atCmdEnd());
  }
  
  bool atCmdEnd() { ret atEndOrLineBreak() || is(";") || is("}"); }
  
  void assertCmdEnd() { if (!atCmdEnd()) fail("Expected end of command"); }
  
  Evaluable parseCall(Evaluable target) {
    if (atCmdEnd()) ret target;
    
    S methodName = tpp();
    var args = parseExpressions();
    ret new Toolbox.CallMethod(target, methodName, args);
  }
  
  // can return MethodOnObject
  swappable O findExternalObject(S name) { null; }
  
  selfType allowTheWorld() { ret allowTheWorld(mc()); }
  
  selfType allowTheWorld(Class... functionContainers) {
    this.functionContainers = asList(functionContainers);
    
    findExternalObject = name -> {
      try object findClassThroughDefaultClassFinder(name);
      try object findClassInStandardImports(name);
      
      fOr (container : functionContainers)
        if (hasMethodNamed(container, name))
          ret new MethodOnObject(container, name);
      null;
    };
    this;
  }
  
  void printFunctionDefs {
    print(values(functionDefs));
  }
}

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1033976
Snippet name: GazelleV_LeftArrowScriptParser
Eternal ID of this version: #1033976/87
Text MD5: 1d26a756b11db150577e83ac61564499
Transpilation MD5: 6d5ab135cf74bb3778722e5ed5c3bbc1
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-01-27 14:52:39
Source code size: 5837 bytes / 210 lines
Pitched / IR pitched: No / No
Views / Downloads: 182 / 512
Version history: 86 change(s)
Referenced in: [show references]