23.0.2 • Published 2 years ago

@tk-tool/lezer-spel v23.0.2

Weekly downloads
-
License
MIT
Repository
-
Last release
2 years ago

@lezer/javascript

This is a JavaScript grammar for the lezer parser system.

It parses ES2020, and supports a "ts" dialect to parse TypeScript, and a "jsx" dialect to parse JSX.

The top option can be set to "SingleExpression" or "SingleClassItem" to parse an expression or class item instead of a full program.

The code is licensed under an MIT license.

相关文档

1.案例 https://github.com/codemirror/lang-example 2.lezer指南 https://lezer.codemirror.net/docs/guide/#writing-a-grammar 用到的工具 生成系统 https://lezer.codemirror.net/docs/ref/#generator 解析系统 https://lezer.codemirror.net/docs/ref/#lr lezer解决方案受启发的来源是 http://tree-sitter.github.io/tree-sitter/ 解析算法来源 https://en.wikipedia.org/wiki/LR_parser 自下而上 自左向右 解析表是很难手工完成的通常需要类似 Bison 这样的解析器生成工具生成 https://en.wikipedia.org/wiki/GNU_Bison Lezer 的解析器生成器定义了自己的语法符号 参考javascript的实现 https://github.com/lezer-parser/javascript/blob/main/src/javascript.grammar 3.接口手册 https://lezer.codemirror.net/docs/ref/

4.案例分析 实现class语法 ClassExpression { kw<"class"> VariableDefinition? (kw<"extends"> expression)? ClassBody } 运算符 运算符规则 语法符号支持重复运算符 (前面的事物重复任意次数) +(一次或多次重复)和 ?(可选,零次或一次重复)。 这些具有高优先级,仅适用于直接在它们前面的元素。 | 管道"|"字符用于表示选择,匹配其两侧的任一表达式。匹配其左侧和右侧的整个表达式 括号可用于分组,如 x (y | z)+。 事物的序列通过简单地将它们并排放置来表达。 a b 表示 a 后接 b。

  该符号借用了扩展的 Backus-Naur 符号和正则表达式语法,
  使用 |表示在几种形式之间进行选择,*(重复任意次) 和 +(1次或多次) 表示重复,而 ?对于可选元素。

语法
  令牌规则中的字符串文字以不同方式工作。它们可以与其他表达式组合以形成更大的令牌。所有标记规则(和文字标记)都被编译为确定性有限自动机,然后可用于将它们与文本流有效匹配。
  因此,在非终结符规则中,像“a”、“b”、“c”这样的表达式是三个标记的序列。在令牌规则中,它完全等同于字符串“abc”
  您可以使用集合表示法来表示字符集,有点类似于正则表达式中的方括号表示法。 $[.,] 表示句号或逗号(没有与 . 相关联的特殊含义)。
  要创建倒置字符集,只匹配集中未提及的字符,您可以在括号前写一个感叹号而不是美元符号。所以 ![x] 匹配任何不是 x 的字符。
  内置字符集
    解析器生成器定义了一些可以使用 @ 符号访问的内置字符集:
      @asciiLetter 匹配 $[a-zA-Z]
      @asciiLowercase 匹配 $[a-z]
      @asciiUppercase 相当于 $[A-Z]
      @digit 匹配 $[0-9]
      @whitespace 匹配 Unicode 标准定义为空白的任何字符。
      @eof 匹配输入的结尾
  命名标记在 @tokens 块中定义。
  Tokens规则不能引用非终结规则。但它们可以相互引用,只要引用不形成非尾递归循环即可。 IE。规则 x 不能直接或间接地包含对 x 的引用,除非该引用出现在规则的最后。
  跳过规则 @skip
    例如: 匹配时跳过 空格 | 空行 | 注释行 | 注释快
      @skip { spaces | newline | LineComment | BlockComment }
    会处理1次或多次

    忽略和不处理 匹配字符串片段之间的空格和注释写法
      @skip {} {
        String {
          stringOpen (stringEscape | stringContent)* stringClose
        }
      }
  定义空格
    spaces[@export] { $[\u0009 \u000b\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]+ }
  定义注空行
    newline[@export] { $[\r\n\u2028\u2029] }
  定义注注释
    LineComment { "//" ![\n]* }
  定义注释快 部分实现代码
    BlockComment { "/*" (blockCommentContent | blockCommentNewline)* blockCommentEnd }
  优先级 定义
    @precedence { times left, plus @left }
    expression { Number | BinaryExpression }
    BinaryExpression {
      expression !times "*" expression |
      expression !plus "+" expression
    }
    这告诉解析器生成器 !times 优先级标记的优先级高于 !plus,并且两者都是左关联的(首选 (a + b) + c 到 a + (b + c))
  顺序问题
    @external
    @external 标记声明和@tokens 块在语法文件中出现的顺序很重要。那些出现较早的将优先于出现较晚的那些,这意味着如果他们返回令牌,则不会尝试其他人。
  语言定义
    @dialects { jsx, ts }
    @dialects 声明提供语法支持的方言列表。
    语言使用
      JSXStartTag[@dialect=jsx] { "<" }
      可以使用 @dialect 伪属性对单个标记(以及通过特殊化其他标记生成的标记)进行注释,以指示它们只能在该方言处于活动状态时出现。多种方言可能同时处于活动状态。

lezer 文档2遍阅读 表达式学习

第一条规则表示文档应该被解析为任意数量的表达式,语法树的顶部节点应该被称为 Program。 @top Program { expression } 下一条规则有点复杂。它声明表达式可以是 标识符、字符串、布尔文字或应用程序,它是用括号括起来的任意数量的表达式。 “Application” 分支使用内联规则将规则的定义与其唯一用途结合起来。 expression { Identifier | String | Boolean | Application { "(" expression ")" } } 定义tokens @tokens { Identifier { $a-zA-Z_0-9+ } String { '"' ("\ | "\" _) '"' } Boolean { "#t" | "#f" } LineComment { ";" \n } space { $ \t\n\r+ } "(" ")" } @tokens中定义的字符串的特点 tokens规则中的字符串字面量工作方式不同。它们可以与其他表达式组合以形成更大的令牌。所有的标记规则(和文字标记)都被编译成一个确定性的有限自动机,然后可以使用它有效地将它们与文本流匹配。 顺序问题 事物的序列是通过简单地把它们放在一起来表示的。A b表示A后面跟着b。 @skip { space | Comment } 跳过某些规则匹配的语句 我们最初的示例不允许令牌之间有任何空白。几乎所有真正的语言都定义了某种特殊的标记,通常包括空格和注释,这些标记可能出现在其他标记之间,在匹配语法时被忽略 规则与标记 跳过语法 当你的语法需要一种以上的空白时,例如,当你的字符串不是普通的标记,但需要自己的内部结构,但你不想在字符串之间匹配空白和注释,你可以创建一个这样的跳过块 @skip {} { String { stringOpen (stringEscape | stringContent) stringClose } } 第一个大括号包含跳过表达式(在本例中,我们不希望跳过任何内容,因此它为空),第二对大括号包含使用该跳过表达式的规则。 优先级的使用 Precedence 存在优先级标记概念 左关联@left: 左关联的(偏好(a + b) + c而不是a + (b + c)) 右关联@right: 首先定义 优先级标识符 其次在使用的地方插入定义好的 优先级标识符 比如: 冲突发生在操作符前面时 直接插入标记 ! 必须在冲突发生的地方插入标记。 在这种情况下,冲突直接发生在操作符前面,所以标记就放在那里。
// 定义优先级标识符 @precedence { times @left, plus @left } BinaryExpression { // 使用优先级标识符 expression !times "
" expression | expression !plus "+" expression } 上述规则会把: 1 + 2 3 + 4 正确处理为 ( 1 + ( 2 3 ) ) + 4 "..."的作用 参数化规则 Lezer在参数和参数周围使用尖括号。你可以像这样定义一个参数化规则: commaSep { "" | content ("," content) } 在定义了上述规则之后,您可以使用commaSep来匹配逗号分隔的表达式列表。 可在令牌中使用优先级@tokens / 优先于 // 的配置示例: @tokens { Divide { "/" } Comment { "//" \n } @precedence { Comment, Divide } } 解释:/ 优先于 // 的配置示例 默认情况下,因为Divide是Comment的前缀,所以这些被认为是重叠的。@precedence声明声明当两者匹配时,Comment将覆盖Divide。在@tokens块中可以有多个@precedence声明,每个声明可以包含任意数量的令牌,从而打破这些令牌之间的联系。 Token Specialization 令牌专业化 在Lezer中通过@ specialized操作符得到支持。 该操作符声明一个新令牌,给定一个基令牌和一个字符串字面值。 当为给定的令牌类型定义了专门化后,每次读取时都会查询其专门化表,如果其内容与专门化匹配,则将其替换为专门化令牌。

使用外部tokens 存在调用顺序问题 本地令牌的作用 本地令牌组允许您定义一组可在给定上下文中使用的标记(例如字符串或注释的内容) 以及应该用于其他任何事情的后备令牌 @local tokens { stringEnd@name='"' { '"' } StringEscape { "\" _ } @else stringContent } 存在node props属性列表,用于条件判断 https://lezer.codemirror.net/docs/ref/#common.NodeProp closedBy openedBy group contextHash lookAhead mounted Pseudo-props 位属性 即出现在方括号中间以@开头的名称,用于激活和配置各种类型的附加功能。

关键字 LR parser

生成tree实例 https://lezer.codemirror.net/docs/ref/#common.Parser.parse

codemirror 文档2遍阅读关键api

https://codemirror.net/docs/ref/#view.EditorView.compositionStarted
相关属性
  scrollDOM
  contentDOM
  dom
相关参数
  class EditorView
    dispatch(...specs: TransactionSpec[])
  class EditorState
    update(...specs: readonly TransactionSpec[]) → Transaction
  都使用的参数类型 事物说明
    interface TransactionSpec
插件
  class ViewPlugin<V extends PluginValue>
    static fromClass<V extends PluginValue>(cls: {new (view: EditorView) → V},
    创建一个类的插件,其构造函数以单个编辑器视图作为参数。

写一个文法 Writing a Grammar

Lezer的解析器生成器为语法定义了自己的符号。您可以查看JavaScript语法以查看示例。 https://lezer.codemirror.net/docs/ref/#generator 语法是定义术语的规则的集合。 A grammar is a collection of rules, which define terms. Terms可以是令牌tokens 语法是定义术语的规则的集合。Terms可以是令牌(在这种情况下,它们直接匹配一段输入文本),也可以是非终结符(它匹配由其他Terms组成的表达式)。令牌和非终结符都是使用类似的语法定义的,但它们是显式区分的(令牌必须出现在@tokens块中),而且令牌的匹配范围更有限——例如,它们不能包含任意递归。 大小写问题,涉及是否生成语法树中的节点 您将注意到,示例中有些术语以小写字母开头,有些则以大写字母开头。这种差异是显著的。大写的规则将显示为解析器生成的语法树中的节点,小写的规则则不会。 (如果您在一个没有大小写的脚本中编写规则名称,您可以在名称的开头使用下划线来表示该规则不应该在树中。)

sepl 语法特点

spel文档 http://itmyhome.com/spring/expressions.html https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions 待处理字符项目 and (&&) or (||) not (!) 类型 T() 变量 #variableName Bean 引用 如果已使用 bean 解析器配置求值上下文,则可以使用 @ 符号从表达式中查找 bean。以下示例显示了如何执行此操作: 要访问工厂 bean 本身,您应该在 bean 名称前加上 & 符号。以下示例显示了如何执行此操作: 存在?.运算符 选择语法 以下表达式返回一个新映射,该映射由原始映射中条目值小于 27 的那些元素组成: Map newMap = parser.parseExpression("map.?value<27").getValue(); 嵌套 表达式模板允许将文字文本与一个或多个计算块混合。每个计算块由您可以定义的前缀和后缀字符分隔。一个常见的选择是使用#{}作为分隔符,如下面的例子所示: String randomPhrase = parser.parseExpression( "random number is #{T(java.lang.Math).random()}", new TemplateParserContext()).getValue(String.class); 输出结果: // evaluates to "random number is 0.7038186818312008" AOP概念 Aspect-oriented Programming (面向切面编程)(AOP) complements Object-oriented Programming (OOP) by providing another way of thinking about program structure. The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. Aspects enable the modularization of concerns (such as transaction management) that cut across multiple types and objects. (Such concerns are often termed “crosscutting” concerns in AOP literature.) One of the key components of Spring is the AOP framework. While the Spring IoC container does not depend on AOP (meaning you do not need to use AOP if you don’t want to), AOP complements Spring IoC to provide a very capable middleware solution. 补充面向对象编程的不足 OOP 中模块化的关键单元是类, 而在 AOP 中,模块化的单位是面。 切面支持跨多种类型和对象的关注点(例如事务管理)的模块化 这种关注点在 AOP 文献中通常被称为“横切”关注点

lezer 解析处理后的树

https://lezer.codemirror.net/docs/ref/#common.Tree Trees 应用位置: LanguageSupport language/src/language.ts

解决方案

参考关键字符
TemplateString TemplateType