简体   繁体   English

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

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

I am working on a language that transpiles to javascript and has a similar syntax.我正在研究一种可以转换为 javascript 并具有类似语法的语言。 However I want to include some new type of block statements.但是我想包含一些新类型的块语句。 For syntax purposes they are the same as an IfStatement.出于语法目的,它们与 IfStatement 相同。 How can I get esprima or acorn to parse this program MyStatement {a=1;} without throwing an error?我怎样才能让 esprima 或 acorn 解析这个程序MyStatement {a=1;}而不抛出错误? Its fine if it calls it an IfStatement.如果将其称为 IfStatement,则很好。 I would prefer not to fork esprima.我不想分叉esprima。

It turns out, that the plugin capabilities of acorn are not really documented.事实证明,acorn 的插件功能并未真正记录在案。 It seems like forking acorn would be the easiest route.似乎分叉橡子将是最简单的路线。 In this case, it is as simple as searching for occurances of _if and following a similar pattern for _MyStatement .在这种情况下,它就像搜索_if并遵循类似的_MyStatement模式一样简单。

However it is possible to write a plugin to accomplish what I was trying to do.但是,可以编写一个插件来完成我想要做的事情。 It seems a bit of a hack, but here is the code.这似乎有点黑客,但这里是代码。 The basic steps are:基本步骤是:

  1. To exend Parse and add to the list of keywords that will be recognized by the first pass扩展Parse并添加到第一遍识别的关键字列表中

  2. Create a TokenType for the new keyword and add it to the Parser.acorn.keywordTypes , extend parseStatement so that it processes the new TokenType为新关键字创建一个 TokenType 并将其添加到Parser.acorn.keywordTypes ,扩展parseStatement以便它处理新的 TokenType

  3. Create a handler for the new TokenType which will add information to the Abstract Syntax Tree as required by the keyword functionality and also consume tokens using commands like this.expect(tt.parenR) to eat a '(' or this.parseExpression() to process an entire expression.为新的 TokenType 创建一个处理程序,它将根据关键字功能的要求将信息添加到抽象语法树中,并使用像this.expect(tt.parenR)这样的命令来消耗令牌以吃掉 '(' 或this.parseExpression()到处理整个表达式。

Here is the code:这是代码:

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.

相关问题 无法使用Esprima / Acorn解析函数:意外令牌'(' - Unable to parse function with Esprima/Acorn: unexpected token '(' Javascript解析器本身是用ESPRIMA这样的javascript编写的,它是如何工作的? 然后谁来解析ESPRIMA的javascript - How it works that Javascript parser is itself written in javascript like ESPRIMA ? Then who parses the javascript of ESPRIMA 橡子的插件loose_parser? - Plugins for acorn loose_parser? 如何检测是否使用分号终止由Esprima生成的Mozilla Parser AST中的表达式? - How does one detect whether a semicolon is used to terminate an expression in the Mozilla Parser AST as generated by Esprima? 如何使用acorn.js 或类似库向ast 树添加新节点? - How to use acorn.js or similar library to add a new node to the ast tree? 如何在另一个.js文件中利用acorn.js? - How to go about utilizing acorn.js in another .js file? 用JavaScript(Esprima.JS)开发解析器,以Mozilla AST格式解析Haskell语言 - Developing a parser in JavaScript(Esprima.JS) that parses Haskell Language in Mozilla AST format 如何使用 esprima 从 Java 解析 javascript 文件? - How to use esprima to parse a javascript file, from Java? 如何使用recast / esprima创建await表达式 - How do i create an await expression using recast/esprima 找不到模块'esprima' - Cannot find module 'esprima'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM