Pegjs: 语义动作的简写

创建于 2018-09-10  ·  13评论  ·  资料来源: pegjs/pegjs

为语义动作添加速记会很好。

比如说,我们不写{ return value } ,而是写,例如{ extract } ,它在初始化程序中定义。

例如:

{
  function extract(value) {
    return value;
  }
  function concat(head, tail) {
    return head ? [head].concat(tail) : [];
  }
  function toAddExpr(head, tail) {
    return { type: 'addExpr', expressions: concat(head, tail) };
  }
}

List
  = '(' _ head:Item? tail:( _ ',' _ value:Item { extract } )* _ ')' { concat }

// Another kind of list
Add
  = '(' _ head:Multiply? tail:( _ '+' _ value:Multiply { extract } )* _ ')' { toAddExpr }

首先,这将使我们能够以更好的方式重用函数…… :smile:
其次,这将使我们的语法更具可读性。

我相信当动作简写中包含的表达式是成员表达式{ foo.bar.baz }而不仅仅是标识符{ foo }时,它也会更有用。 这样语法作者就可以在一个对象甚至一个模块中组织他们的功能。

discussion feature

最有用的评论

实际上,我一直在想,这些更改可能会奏效:

CodeBlock "code block"
  = "=>" _ expession:CallExpression {
       return `return ${ expession };`;
     }
  / "{" <strong i="6">@Code</strong> "}"
  / "{" { error("Unbalanced brace."); }

// Will be based on ECMAScript's CallExpression
CallExpression
  = ...
  / MemberExpression

// Will be based on ECMAScript's MemberExpression
MemberExpression
  = ...
  / ValidIdentifier

// Change `LabelIdentifier` into `ValidIdentifier`

这种方式仍然需要集成一些东西,比如 ECMAScript 的主要表达式(数字、布尔值、数组等)以用作参数,因此需要仔细确定要添加的内容。


平衡支架和大括号

在 PEG.js 解析器中内置适当的 JavaScript 解析器之前,这不会得到修复,但说实话,我对此有点犹豫,因为有一些插件项目可以生成其他语言(C、PHP、TypeScript)的解析器等),我也在研究一种计算机语言,我希望有一天能在其中生成解析器。


除了 _PEG.js v0.12_,我将致力于OpenPEG ,它将提供一个 NPM 包,该包本质上是 PEG.js 的精简版本,不涉及任何 JavaScript 和解析器生成,但具有足够的功能,因此基于 JavaScript 的项目如PEG.js 可以将其用作后端。 当 _v0.12_ 出来时,我将尝试确保生成自定义解析器的任何插件项目都收到 OpenPEG 的通知,并且在 v1 之前将完整的 ECMAScript 2015 解析器实现到 PEG.js 语法解析器中。

所有13条评论

有趣的想法,但我个人认为这不是一个更清晰的方法,因为传递给函数的参数并不明显。 此外,如果您需要传递“自定义”参数 - 您需要将这些参数与常规函数调用混合使用,因此它看起来不像在更简单的情况下那么干净。

#235 中有人建议将语法=>与箭头函数一起使用,我认为它非常简洁明了。

  = '(' expr:some_expression ')' => expr
  ;

我倾向于为速记语法选择以下之一:

  • => expr; _(需要语法支持)_
  • { => expr } _(现在可用,但需要解包)_
  • { > expr } _(需要语法支持)_

还没有决定,所以可以讨论。

至于 OP 想要什么,最好实现一个插件(在决定速记语法之后或之前),它使用 Acorn 或 @babel/parser 来解开标识符或成员表达式,将其转换为调用表达式,同时添加标签作为参数并返回生成的代码。

=> expr;

在我看来最好。

{ => expr }

与 Javascript 语法 IMO 冲突。 因为它在{ }你会期望它是一个完整的箭头函数( () => )。

{ > expr}

与 PegJS 或 Javascript 中的任何其他语法有点正交,不会立即读取“这会返回一个值,速记”IMO - 主要是因为它在花括号中,我认为。 与{=> expr}相同的参数,您希望 Javascript 在那里。


此外,在{}添加非 JS 语法对于语法高亮、linter 等来说是一个问题。我建议不要这样做。

如果我可以建议另一种选择,也许>本身(不在谓词块内)。 当您垂直分隔规则时,这有助于保持对齐:

    = foo:bar qux:(' '+ @qix)+
    > {foo, qux}
    ;

以及内联

some_rule = foo:bar qux:(' '+ @qix)+ > {foo, qux};

为什么“=>”需要分号? 我想在嵌套代码中返回一个值,而不是使用 buildList() 例如:

  = "(" _ head:Expression _ tail:("," _ expr:Expression => expr)* ")" {
      return [head, ...tail]
    }

我发现这比使用魔术索引(如下)更干净。 另一种选择是能够引用嵌套标签。 例如("," _ tail:Expression)* ")"

  = "(" _ head:Expression _ tail:("," _ Expression)* ")" {
      return buildList(head, tail, 2)
    }

我正在查看 parser.pegjs,我看到第 434 行附近有 CodeBlock。 需要做什么才能试用它? 规则代码只是读取 SourceCharacter,它只是 '.'

CodeBlock "code block"
  = "=>" __ <strong i="13">@Code</strong> // this?
  / "{" <strong i="14">@Code</strong> "}"

@mikeaustin是的,这是正确的,但是它无法知道该序列的结束位置,因此将在=>之后消耗所有内容

也许“代码”可以更聪明一点,平衡括号和大括号,并处理 LineTerminator? 它不需要了解完整的 JavaScript,但这可能比听起来更难。

实际上,我一直在想,这些更改可能会奏效:

CodeBlock "code block"
  = "=>" _ expession:CallExpression {
       return `return ${ expession };`;
     }
  / "{" <strong i="6">@Code</strong> "}"
  / "{" { error("Unbalanced brace."); }

// Will be based on ECMAScript's CallExpression
CallExpression
  = ...
  / MemberExpression

// Will be based on ECMAScript's MemberExpression
MemberExpression
  = ...
  / ValidIdentifier

// Change `LabelIdentifier` into `ValidIdentifier`

这种方式仍然需要集成一些东西,比如 ECMAScript 的主要表达式(数字、布尔值、数组等)以用作参数,因此需要仔细确定要添加的内容。


平衡支架和大括号

在 PEG.js 解析器中内置适当的 JavaScript 解析器之前,这不会得到修复,但说实话,我对此有点犹豫,因为有一些插件项目可以生成其他语言(C、PHP、TypeScript)的解析器等),我也在研究一种计算机语言,我希望有一天能在其中生成解析器。


除了 _PEG.js v0.12_,我将致力于OpenPEG ,它将提供一个 NPM 包,该包本质上是 PEG.js 的精简版本,不涉及任何 JavaScript 和解析器生成,但具有足够的功能,因此基于 JavaScript 的项目如PEG.js 可以将其用作后端。 当 _v0.12_ 出来时,我将尝试确保生成自定义解析器的任何插件项目都收到 OpenPEG 的通知,并且在 v1 之前将完整的 ECMAScript 2015 解析器实现到 PEG.js 语法解析器中。

FWIW,我已经开始为此使用模板文字。 它还可以帮助我通过文本编辑器突出显示 JS 的语法...

exports = module.exports = functionBodies`${grammarScript}
...
objectText =
    head:word
    rest:(_txt_ word)*
    ${f=>{
        return new Txt(rest.reduce((a,b)=>([...a,...b]),[head]))
        }}
word = ch:(wordCharacter/escapedCharacter)+ ${chJoin}
...
`
function functionBodies(glue, ...fns){
    return glue.map( (str,i) => str + (fns[i]||'').toString().replace(/^[^{]*/,'').replace(/[^}]*$/, '') ).join('')
    }

function chJoin(ch){return ch.join('')}

如何使用建议的管道操作符(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Pipeline_operator)? 因为,基本上,您要求通过管道传输数据?

{
  function extract(value) {
    return value;
  }
  function concat(head, tail) {
    return head ? [head].concat(tail) : [];
  }
  function toAddExpr(head, tail) {
    return { type: 'addExpr', expressions: concat(head, tail) };
  }
}

List
  = '(' _ head:Item? tail:( _ ',' _ value:Item |> extract )* _ ')' |> concat

// Another kind of list
Add
  = '(' _ head:Multiply? tail:( _ '+' _ value:Multiply |> extract  )* _ ')' |> toAddExpr

这一切都不应该发生。 不应该有简短的语法。

如果我们只是正常解析箭头,而不是尝试横向填充它们,则这些都不是必需的。

虽然这是一个巧妙的想法,但它与 JavaScript 相比设置了大量的语法歧义。 任何解析过 JS 并记得with是多么糟糕的人都知道,这基本上会扼杀解析器。

我们应该只支持 Javascript,而不是试图创建花哨的新东西。 箭头函数比 ES6 更旧,而 ES6 是 2015 年的。这个问题在六年前就解决了。 这里不应该发生任何发明。

管道运算符存在严重缺陷,可能实际上不会使其成为 Javascript,并且它最初来自的语言 (F#) 和普及它的语言 (Elixir) 都在远离它。 此外,这在任何意义上都不是管道。

PEG 如此成功的原因在于它是最小的,并且与语言保持紧密联系,使其快速、小巧和可预测。

箭头函数比 ES6 更旧,而 ES6 是 2015 年的。这个问题在六年前就解决了。 这里不应该发生任何发明。

呃。 这对我来说是个新闻。 关心扩展?

PEG 如此成功的原因在于它是最小的,并且与语言保持紧密联系,使其快速、小巧和可预测。

PEG(作为一个概念,而不是这个库)之所以成功,是因为它能够以简单的方式表示复杂的语法(递归等)。 Packrat 不是用这个库发明的; 它不是一种语法。 这是一个算法。

箭头函数比 ES6 更旧,而 ES6 是 2015 年的。这个问题在六年前就解决了。 这里不应该发生任何发明。

呃。 这对我来说是个新闻。 关心扩展?

我真的不知道你在问什么。

箭头函数早于 ES6。 这是 ES6 中的第二大斗争,是什么让 ES4 脱轨了,也是什么让 ES5+ 脱轨了。 从 90 年代中期开始,每个人都在要求它们,因为它们实际上已经存在于 E4X 中,并且因为 Google 和 Apple 向 Hixie 抱怨微软曾经发明过任何东西而被拿走。

你现在知道 E4X 就是 React,并认为 Facebook 发明了它。 Facebook 认为他们抄袭了 Hyperscript。 Hyperscript 的家伙很清楚他只是从旧的 IE 中重新实现了一个有用的东西。

他们将被完全排除在 ES6 之外,就像模板字符串一样,但后来 Coffeescript 出现并给了 JS 社区,然后 JS 社区大喊大叫,直到 ECMA 的人让步。 只用了18个月

箭头函数可以完成这里需要发生的一切。 早在 2018 年,您似乎就是在此线程中提出这些问题的人,这让您的分歧令人震惊; 我试图支持你。

对我来说更重要的是,如果它是用箭头函数完成的,那么什么都没有添加。

Peg 与 JS 的差异绝对是最小的。 通过只做 ES6 的东西来支持这一点意味着列表不会改变。

这是极其宝贵的。


PEG(作为一个概念,而不是这个库)之所以成功,是因为它能够以简单的方式表示复杂的语法(递归等)。

我不同意。 许多解析器在这方面做得更好,甚至没有一点受欢迎,即使是了解它们的人(如 Earley)。

传统的解释是错误消息质量和速度的结合,但我也不同意这一点,因为许多解析器有更好的错误消息更快(再次,像 Earley,),甚至没有一点流行,即使是人们谁知道他们

另外,请注意 PEG 具有三个严重的复杂性上限。

一,任何你想通过 peg 语法的东西都必须有一个组合表达式,不会压倒本地机器的缓存和评估吞吐量(示例 #623)

二,许多常见的工作,例如解析 BNF,在 peg 中经常非常困难(例如 #489)

第三,值得注意的是,所有其他 JS PEG 库,甚至更强大的库,都失败了。 我试图离开,然后又回来了很多次。 特别是,我多次尝试切换到canopy ,因为它允许我另外定位crubypythonjavascript

当然,我只能代表我认识的大约两打人在使用它。 我可以,因为我几天前问过,当我意识到新的非维护人员正在丢弃软件并用他从头开始制作的东西替换它时,经过多年没有发布的更改

但是他们中的每一个人都对我说,他们需要一个没有很多原生概念开销的解析器,或者他们需要一些快速而小巧的东西,其行为是可靠的

未发布的 0.11 在 node 与 chrome 中的行为显着不同,并且 node 由 chrome 组成。 尝试针对它编写一些属性测试。 老实说,这有点可怕。

.

Packrat 不是用这个库发明的; 它不是一种语法。 这是一个算法。

我没有说任何关于 Packrat 的事,朋友。 我不确定你想纠正什么。

然而,Packrat 解析不是一种算法,因为排序不是一种算法。 Packrat 解析是一项任务,有很多方法可以完成。

事实上,大多数介绍 Haskell 的书籍都会让你做三到四个不同的 Packrat 解析器,因为它们是真正沉迷于 Haskell 的 monad 方法的性能问题的好方法,并且它们想向你展示如何改变写作方法packrats(即更改算法)会产生更好的结果。

.

请重新考虑不赞成。 这个图书馆已经死了三年了,现在我想把它复活。

该库已死的部分原因是人们一直试图创造新功能,而不是执行简单的维护,例如添加已在开发中使用了两年的es()模块功能

我必须通过剪切线条并将手写的 javascript 装订到它们的末尾来手动修改我的 PEG 解析器

繁星点点的眼睛应该闭上一会儿,一些实用的油腻肘部应该开始。 PEG 是我见过的唯一一个使用率下降的主要 NPM 库。 鉴于我不知道一个合理的替代品,这对我来说很奇怪而且很困惑。

image

我现在想贡献一些错误修正,但我不能,因为

  1. 0.10自从 dmajda 离开后就没有发布过,
  2. 0.11三年了,从来没有发表过,一个月前宣布永远不会发表,而且
  3. 替代品0.12根本不是挂钩,而是另一个人用不同的编程语言从头开始编写的东西,我们都看不到

我知道这是不礼貌的,但我们需要面对这个图书馆正在被杀死

如果这个库要再次看到更新,是时候面对我们需要接受正常的开发过程了。 现在是 2020 年。自 2017 年以来我们什么也没看到。

不,开发分支不算数。 而且新的维护者将不得不重新打开一大堆问题,因为0.11的质量不够,而且从10比修复11工作要少得多

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

dmajda picture dmajda  ·  20评论

vldmr1986 picture vldmr1986  ·  12评论

futagoza picture futagoza  ·  6评论

dmajda picture dmajda  ·  15评论

dmajda picture dmajda  ·  7评论