Home > Blockchain >  ANTLR4 how to wait for processing all rules?
ANTLR4 how to wait for processing all rules?

Time:04-27

I have created my own Xtext based DSL and vscode based editor with language server protocol. I parse the model from the current TextDocument with antlr4ts. Below is the code snippet for the listener

class TreeShapeListener implements DebugInternalModelListener {

  public async enterRuleElem1(ctx: RuleElem1Context): Promise<void> {
    ...
    // by the time the response is received, 'walk' function returns
    var resp = await this.client.sendRequest(vscode_languageserver_protocol_1.DefinitionRequest.type,
            this.client.code2ProtocolConverter.asTextDocumentPositionParams(this.document, position))
                .then(this.client.protocol2CodeConverter.asDefinitionResult, (error) => {
                    return this.client.handleFailedRequest(vscode_languageserver_protocol_1.DefinitionRequest.type, error, null);
            });
    ...
    this.model.addElem1(elem1);
  }

  public async enterRuleElem2(ctx: RuleElem2Context): void {
    ...
    this.model.addElem2(elem2);
  }

and here I create the parser and the tree walker.

  // Create the lexer and parser
  let inputStream = antlr4ts.CharStreams.fromString(document.getText());
  let lexer = new DebugInternaModelLexer(inputStream);
  let tokenStream = new antlr4ts.CommonTokenStream(lexer);
  let parser = new DebugInternalModelParser(tokenStream);
    
  parser.buildParseTree = true;
  let tree = parser.ruleModel();

  let model = new Model();
  ParseTreeWalker.DEFAULT.walk(new TreeShapeListener(model, client, document) as ParseTreeListener, tree);
  console.log(model);
 

The problem is that while processing one of the rules (enterRuleElem1), I have an async function (client.sendRequest) which is returned after ParseTreeWalker.DEFAULT.walk returns. How can I make walk wait till all the rules are completed?

Edit 1: Not sure if this is how walk function works, but tried to recreate the above scenario with a minimal code below

function setTimeoutPromise(delay) {
    return new Promise((resolve, reject) => {
      if (delay < 0) return reject("Delay must be greater than 0")
  
      setTimeout(() => {
        resolve(`You waited ${delay} milliseconds`)
      }, delay)
    })
}

async function enterRuleBlah() {
    let resp = await setTimeoutPromise(2500);
    console.log(resp);
}

function enterRuleBlub() {
    console.log('entered blub');
}

function walk() {
    enterRuleBlah();
    enterRuleBlub();
}

walk();

console.log('finished parsing');

and the output is

entered blub
finished parsing
You waited 2500 milliseconds

Edit 2: I tried the suggestion from the answer and now it works! My solution looks like:

    public async doStuff() {
        ...
        return new Promise((resolve)=> {
            resolve(0);
        })
    }

    let listener = new TreeShapeListener(model, client, document);
    ParseTreeWalker.DEFAULT.walk(listener as ParseTreeListener, tree);

    await listener.doStuff();

CodePudding user response:

The tree walk is entirely synchronous, regardless whether you make your listener/visitor rules async or not. Better separate the requests from the walk, which should only collect all the information need to know what to send and after that process this collection and actually send the requests, for which you then can wait.

  • Related