繁体   English   中英

如何将关键字添加到 acorn 或 esprima 解析器

[英]How to add keyword to acorn or esprima parser

我正在研究一种可以转换为 javascript 并具有类似语法的语言。 但是我想包含一些新类型的块语句。 出于语法目的,它们与 IfStatement 相同。 我怎样才能让 esprima 或 acorn 解析这个程序MyStatement {a=1;}而不抛出错误? 如果将其称为 IfStatement,则很好。 我不想分叉esprima。

事实证明,acorn 的插件功能并未真正记录在案。 似乎分叉橡子将是最简单的路线。 在这种情况下,它就像搜索_if并遵循类似的_MyStatement模式一样简单。

但是,可以编写一个插件来完成我想要做的事情。 这似乎有点黑客,但这里是代码。 基本步骤是:

  1. 扩展Parse并添加到第一遍识别的关键字列表中

  2. 为新关键字创建一个 TokenType 并将其添加到Parser.acorn.keywordTypes ,扩展parseStatement以便它处理新的 TokenType

  3. 为新的 TokenType 创建一个处理程序,它将根据关键字功能的要求将信息添加到抽象语法树中,并使用像this.expect(tt.parenR)这样的命令来消耗令牌以吃掉 '(' 或this.parseExpression()到处理整个表达式。

这是代码:

var program = 
`
  MyStatement {
    MyStatement(true) {
      MyStatement() {
        var a = 1;
      }
    }
    if (1) {
      var c = 0;
    }
  }
`;

const acorn = require("acorn");

const Parser = acorn.Parser;
const tt = acorn.tokTypes; //used to access standard token types like "("
const TokenType = acorn.TokenType; //used to create new types of Tokens.

//add a new keyword to Acorn.
Parser.acorn.keywordTypes["MyStatement"] = new TokenType("MyStatement",{keyword: "MyStatement"});

//const isIdentifierStart = acorn.isIdentifierStart;

function wordsRegexp(words) {
  return new RegExp("^(?:" + words.replace(/ /g, "|") + ")$")
}

var bruceware = function(Parser) {
  return class extends Parser {
    parse(program) {
      console.log("hooking parse.");

      //it appears it is necessary to add keywords here also.
      var newKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this const class extends export import super";
      newKeywords += " MyStatement";
      this.keywords = wordsRegexp(newKeywords);

      return(super.parse(program));
    }

    parseStatement(context, topLevel, exports) {
      var starttype = this.type;
      console.log("!!!hooking parseStatement", starttype);

      if (starttype == Parser.acorn.keywordTypes["MyStatement"]) {
        console.log("Parse MyStatement");
        var node = this.startNode();
        return this.parseMyStatement(node);
      }
      else {
        return(super.parseStatement(context, topLevel, exports));
      }
    }

    parseMyStatement(node) {
      console.log("parse MyStatement");
      this.next();

      //In my language, MyStatement doesn't have to have a parameter. It could be called as `MyStatement { ... }`
      if (this.type == tt.parenL) {
        node.test = this.parseOptionalParenExpression();
      }
      else {
        node.test = 0; //If there is no test, just make it 0 for now (note that this may break code generation later).
      }

      node.isMyStatement = true; //set a flag so we know that this if a "MyStatement" instead of an if statement.

      //process the body of the block just like a normal if statement for now.

      // allow function declarations in branches, but only in non-strict mode
      node.consequent = this.parseStatement("if");
      //node.alternate = this.eat(acornTypes["else"]) ? this.parseStatement("if") : null;
      return this.finishNode(node, "IfStatement")
    };

    //In my language, MyStatement, optionally has a parameter. It can also by called as MyStatement() { ... }
    parseOptionalParenExpression() {
      this.expect(tt.parenL);

      //see what type it is
      console.log("Type: ", this.type);

      //allow it to be blank.
      var val = 0; //for now just make the condition 0. Note that this may break code generation later.
      if (this.type == tt.parenR) {
        this.expect(tt.parenR);
      }
      else { 
        val = this.parseExpression();
        this.expect(tt.parenR);
      }

      return val
    };

  }
}

process.stdout.write('\033c'); //cls

var result2 = Parser.extend(bruceware).parse(program); //attempt to parse

console.log(JSON.stringify(result2,null,' ')); //show the results.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM