|
| 1 | +local class = require 'class' |
| 2 | +local lexer = require 'parser.lexer' |
| 3 | +local util = require 'utility' |
| 4 | + |
| 5 | +require 'parser.ast.base' |
| 6 | +require 'parser.ast.error' |
| 7 | +require 'parser.ast.list' |
| 8 | +require 'parser.ast.nil' |
| 9 | +require 'parser.ast.boolean' |
| 10 | +require 'parser.ast.number' |
| 11 | +require 'parser.ast.string' |
| 12 | +require 'parser.ast.comment' |
| 13 | +require 'parser.ast.exp' |
| 14 | +require 'parser.ast.id' |
| 15 | +require 'parser.ast.var' |
| 16 | +require 'parser.ast.call' |
| 17 | +require 'parser.ast.table' |
| 18 | +require 'parser.ast.block' |
| 19 | +require 'parser.ast.field' |
| 20 | +require 'parser.ast.unary' |
| 21 | +require 'parser.ast.binary' |
| 22 | +require 'parser.ast.state.state' |
| 23 | +require 'parser.ast.main' |
| 24 | +require 'parser.ast.cats.cat' |
| 25 | + |
| 26 | +---@class LuaParser.Ast |
| 27 | +---@field envMode 'fenv' | '_ENV' |
| 28 | +---@field main LuaParser.Node.Main |
| 29 | +---@overload fun(code: string, version: LuaParser.LuaVersion, options: LuaParser.CompileOptions): LuaParser.Ast |
| 30 | +local M = class.get 'LuaParser.Ast' |
| 31 | + |
| 32 | +---@alias LuaParser.Status |
| 33 | +---| 'Lua' # Lua代码 |
| 34 | +---| 'ShortCats' # 单行的注解 |
| 35 | +---| 'LongCats' # 多行的注解 |
| 36 | +---| 'InLineCats' # 内联的注解 |
| 37 | +---| 'ShortLua' # 单行注解内的Lua代码 |
| 38 | +---| 'LongLua' # 多行注释内的Lua代码 |
| 39 | + |
| 40 | +---@param code string # lua代码 |
| 41 | +---@param version? LuaParser.LuaVersion |
| 42 | +---@param options? LuaParser.CompileOptions |
| 43 | +function M:__init(code, version, options) |
| 44 | + -- 代码内容 |
| 45 | + self.code = code |
| 46 | + -- Lua版本 |
| 47 | + ---@type LuaParser.LuaVersion |
| 48 | + self.version = version or 'Lua 5.4' |
| 49 | + -- 非标准符号的映射表 |
| 50 | + ---@type table<string, true> |
| 51 | + self.nssymbolMap = {} |
| 52 | + -- 词法分析结果 |
| 53 | + self.lexer = lexer.parseLua(code) |
| 54 | + -- 错误信息 |
| 55 | + ---@type LuaParser.Node.Error[] |
| 56 | + self.errors = {} |
| 57 | + -- 注释 |
| 58 | + ---@type LuaParser.Node.Comment[] |
| 59 | + self.comments = {} |
| 60 | + -- 代码块 |
| 61 | + ---@private |
| 62 | + ---@type LuaParser.Node.Block[] |
| 63 | + self.blocks = {} |
| 64 | + -- 当前代码块 |
| 65 | + ---@private |
| 66 | + ---@type LuaParser.Node.Block? |
| 67 | + self.curBlock = nil |
| 68 | + -- 按类型存放的节点 |
| 69 | + ---@private |
| 70 | + ---@type table<string, LuaParser.Node.Base[]> |
| 71 | + self.nodesMap = util.multiTable(2) |
| 72 | + -- 存放所有的block |
| 73 | + ---@private |
| 74 | + ---@type LuaParser.Node.Block[] |
| 75 | + self.blockList = {} |
| 76 | + -- 当前的局部变量计数(最大只能存在200个局部变量) |
| 77 | + ---@private |
| 78 | + self.localCount = 0 |
| 79 | + -- 当前解析状态 |
| 80 | + ---@private |
| 81 | + ---@type LuaParser.Status |
| 82 | + self.status = 'Lua' |
| 83 | + -- 未绑定的注解 |
| 84 | + ---@private |
| 85 | + self.cats = {} |
| 86 | + |
| 87 | + local major, minor = self.version:match 'Lua (%d+)%.(%d+)' |
| 88 | + ---@type integer |
| 89 | + self.versionNum = major * 10 + minor |
| 90 | + |
| 91 | + local envMode = 'auto' |
| 92 | + if options then |
| 93 | + if options.nonestandardSymbols then |
| 94 | + for _, s in ipairs(options.nonestandardSymbols) do |
| 95 | + self.nssymbolMap[s] = true |
| 96 | + end |
| 97 | + end |
| 98 | + -- 是否为LuaJIT |
| 99 | + self.jit = options.jit |
| 100 | + -- 是否支持Unicode标识符 |
| 101 | + self.unicodeName = options.unicodeName |
| 102 | + |
| 103 | + envMode = options.envMode |
| 104 | + end |
| 105 | + |
| 106 | + if envMode == '_ENV' |
| 107 | + or envMode == 'fenv' then |
| 108 | + ---@cast envMode '_ENV' | 'fenv' |
| 109 | + self.envMode = envMode |
| 110 | + else |
| 111 | + if self.versionNum >= 52 then |
| 112 | + self.envMode = '_ENV' |
| 113 | + else |
| 114 | + self.envMode = 'fenv' |
| 115 | + end |
| 116 | + end |
| 117 | +end |
| 118 | + |
| 119 | +-- 跳过换行符 |
| 120 | +---@private |
| 121 | +---@return boolean # 是否成功跳过换行符 |
| 122 | +function M:skipNL() |
| 123 | + local status = self.status |
| 124 | + if status == 'Lua' |
| 125 | + or status == 'LongCats' |
| 126 | + or status == 'LongLua' then |
| 127 | + return self.lexer:consumeType 'NL' ~= nil |
| 128 | + else |
| 129 | + return false |
| 130 | + end |
| 131 | +end |
| 132 | + |
| 133 | +-- 跳过注释 |
| 134 | +---@private |
| 135 | +---@param inExp? boolean # 在表达式中 |
| 136 | +---@return boolean # 是否成功跳过注释 |
| 137 | +function M:skipComment(inExp) |
| 138 | + local comment = self:parseComment(inExp) |
| 139 | + if comment then |
| 140 | + self.comments[#self.comments+1] = comment |
| 141 | + return true |
| 142 | + end |
| 143 | + return false |
| 144 | +end |
| 145 | + |
| 146 | +-- 跳过未知符号 |
| 147 | +---@private |
| 148 | +---@return boolean |
| 149 | +function M:skipUnknown() |
| 150 | + local token, pos = self.lexer:consumeType 'Unknown' |
| 151 | + if not token then |
| 152 | + return false |
| 153 | + end |
| 154 | + |
| 155 | + ---@cast pos -? |
| 156 | + self:throw('UNKNOWN_SYMBOL', pos, pos + #token) |
| 157 | + |
| 158 | + return true |
| 159 | +end |
| 160 | + |
| 161 | +-- 跳过空白符 |
| 162 | +---@private |
| 163 | +---@param inExp? boolean # 在表达式中 |
| 164 | +function M:skipSpace(inExp) |
| 165 | + if self.lexer.ci ~= self.lastSpaceCI then |
| 166 | + self.lastRightCI = self.lexer.ci |
| 167 | + end |
| 168 | + repeat until not self:skipNL() |
| 169 | + and not self:skipCat() |
| 170 | + and not self:skipComment(inExp) |
| 171 | + and not self:skipUnknown() |
| 172 | + self.lastSpaceCI = self.lexer.ci |
| 173 | +end |
| 174 | + |
| 175 | +-- 获取上个词的右侧位置(不包括换行符和注释) |
| 176 | +---@private |
| 177 | +---@return integer |
| 178 | +function M:getLastPos() |
| 179 | + local ci = self.lexer.ci |
| 180 | + if ci == self.lastSpaceCI then |
| 181 | + ci = self.lastRightCI |
| 182 | + end |
| 183 | + local token = self.lexer.tokens[ci - 1] |
| 184 | + local pos = self.lexer.poses[ci - 1] |
| 185 | + return pos + #token |
| 186 | +end |
| 187 | + |
| 188 | +-- 创建一个节点 |
| 189 | +---@private |
| 190 | +---@generic T: string |
| 191 | +---@param type `T` |
| 192 | +---@param data table |
| 193 | +---@return T |
| 194 | +function M:createNode(type, data) |
| 195 | + data.ast = self |
| 196 | + local node = class.new(type, data) |
| 197 | + |
| 198 | + local nodeMap = self.nodesMap[node.type] |
| 199 | + nodeMap[#nodeMap+1] = node |
| 200 | + |
| 201 | + if node.isBlock then |
| 202 | + self.blockList[#self.blockList+1] = node |
| 203 | + end |
| 204 | + |
| 205 | + return node |
| 206 | +end |
| 207 | + |
| 208 | +-- 获取当前函数 |
| 209 | +---@private |
| 210 | +---@return LuaParser.Node.Function | LuaParser.Node.Main | nil |
| 211 | +function M:getCurrentFunction() |
| 212 | + local blocks = self.blocks |
| 213 | + for i = #blocks, 1, -1 do |
| 214 | + local block = blocks[i] |
| 215 | + if block.type == 'Function' |
| 216 | + or block.type == 'Main' then |
| 217 | + ---@cast block LuaParser.Node.Function | LuaParser.Node.Main |
| 218 | + return block |
| 219 | + end |
| 220 | + end |
| 221 | + return nil |
| 222 | +end |
| 223 | + |
| 224 | +return M |
0 commit comments