元 Lua 抽象语法树

lua-users home
wiki

抽象语法树是表示程序的一种方便的高级方式。 MetaLua 主要通过将 Lua 程序表示为 AST 来处理分析、生成和操作 Lua 程序。 本页介绍了 MetaLua 目前支持的 AST 语法。 它是经过相当长时间的成熟和反馈过程的结果,这种格式被多个工具使用,例如 [ZeroBrane][SciTE] 通过 LuaInspect[Eclipse 的 Lua 开发工具] 或 TypedLua?

符号

树在下面用一些 Metalua 语法糖书写,这提高了它们的易读性。 反引号符号引入一个 `tag`,即存储在表 `"tag"` 字段中的字符串

在使用 Metalua 解释器或编译器时,反引号语法得到支持,可以直接使用。 Metalua 的美化打印助手也尝试在适用时使用反引号语法。

树元素

树元素主要分为语句 stat、表达式 expr 和语句列表 block。 辅助定义包括函数应用/方法调用 apply,既是有效的语句,也是表达式,在赋值语句 lhs 左侧可接受的表达式。

    block: { stat* }

    stat:
      `Do{ stat* }
    | `Set{ {lhs+} {expr+} }                    -- lhs1, lhs2... = e1, e2...
    | `While{ expr block }                      -- while e do b end
    | `Repeat{ block expr }                     -- repeat b until e
    | `If{ (expr block)+ block? }               -- if e1 then b1 [elseif e2 then b2] ... [else bn] end
    | `Fornum{ ident expr expr expr? block }    -- for ident = e, e[, e] do b end
    | `Forin{ {ident+} {expr+} block }          -- for i1, i2... in e1, e2... do b end
    | `Local{ {ident+} {expr+}? }               -- local i1, i2... = e1, e2...
    | `Localrec{ ident expr }                   -- only used for 'local function'
    | `Goto{ <string> }                         -- goto str
    | `Label{ <string> }                        -- ::str::
    | `Return{ <expr*> }                        -- return e1, e2...
    | `Break                                    -- break
    | apply

    expr:
      `Nil  |  `Dots  |  `True  |  `False
    | `Number{ <number> }
    | `String{ <string> }
    | `Function{ { ident* `Dots? } block }
    | `Table{ ( `Pair{ expr expr } | expr )* }
    | `Op{ opid expr expr? }
    | `Paren{ expr }       -- significant to cut multiple values returns
    | apply
    | lhs

    apply:
      `Call{ expr expr* }
    | `Invoke{ expr `String{ <string> } expr* }

    ident: `Id{ <string> }

    lhs: ident | `Index{ expr expr }

    opid: 'add'   | 'sub'   | 'mul'   | 'div'
        | 'mod'   | 'pow'   | 'concat'| 'eq'
        | 'lt'    | 'le'    | 'and'   | 'or'
        | 'not'   | 'len'

元数据 (lineinfo)

AST 还嵌入了一些元数据,允许将它们映射到它们的源表示。 这些信息存储在每个树节点的 "lineinfo" 字段中,该字段指向表示它的源字符串中的字符范围,以及出现在该节点之前或之后的任何注释的内容。

Lineinfo 对象有两个字段,"first""last",分别描述子树在源代码中的开始和结束。 例如,由解析 [[return 123]] 生成的子节点 `Number{123} 将具有描述偏移量 8 的 lineinfo.first 和描述偏移量 10 的 lineinfo.last

    > mlc = require 'metalua.compiler'.new()
    > ast = mlc :src_to_ast "return 123 -- comment"
    > print(ast[1][1].lineinfo)
    <?|L1|C8-10|K8-10|C>
    >

Lineinfo 跟踪相对于源字符串/文件开头(上面的“K8-10”)的字符偏移量、行号(上面的 L1;跨越多行的 lineinfo 将读取类似“L1-10”的内容)、列,即行内的偏移量(上面的“C8-10”),以及如果有的话,文件名(上面的“?”标记表示我们没有文件名,因为 AST 来自字符串)。 最终的“|C>”表示节点之后有一个注释; 最初的“<C|”表示节点之前有一个注释。

位置表示标记的结束和标记间空格的开始("last" 字段),或者标记的开始和标记间空格的结束("first" 字段)。标记间空格可能为空。它们也可以包含注释,这些注释可能有助于与周围的标记和 AST 子树关联。

位置与其“对偶”位置相连:标记间空格开始处的 位置在其 "facing" 字段中保留对该标记间空格结束处的 位置的引用,反之亦然,标记间空格结束处的 位置跟踪标记间空格的开始,也在 "facing" 中。标记间空格可以为空,例如在 "2+2" 中,在这种情况下 lineinfo==lineinfo.facing

注释也保存在 "comments" 字段中。如果存在,该字段包含一个注释列表,其中包含一个 "lineinfo" 字段,描述第一个和最后一个注释之间的跨度。每个注释由一个字符串列表表示,其中包含一个 "lineinfo",描述仅此注释的跨度。连续的 -- 注释行被视为一个注释:"-- foo\n-- bar\n" 解析为一个注释,其文本为 "foo\nbar",而 "-- foo\n\n-- bar\n" 解析为两个注释 "foo""bar"

例如,如果 f 是函数的 AST,并且我想检索函数之前的注释,我会执行以下操作

    f_comment = f.lineinfo.first.comments[1][1]

lineinfo 位置中的信息,即每个 "first""last" 字段中的信息,保存在以下字段中


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2014 年 1 月 31 日下午 5:12 GMT (差异)