From 2a29458c86628a2af20da4ebeb39a8f81d4ea53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Tue, 14 Sep 2021 16:59:55 +0800 Subject: update parser --- script/parser/compile.lua | 17 +- script/parser/grammar.lua | 2 +- script/parser/guide.lua | 4 +- script/parser/init.lua | 1 + script/parser/lines.lua | 2 +- script/parser/luadoc.lua | 4 +- script/parser/newparser.lua | 3528 +++++++++++++++++++++++++++++++++++++++++++ script/parser/parse.lua | 17 +- script/parser/tokens.lua | 38 + 9 files changed, 3595 insertions(+), 18 deletions(-) create mode 100644 script/parser/newparser.lua create mode 100644 script/parser/tokens.lua (limited to 'script') diff --git a/script/parser/compile.lua b/script/parser/compile.lua index 207664cc..d6c6a526 100644 --- a/script/parser/compile.lua +++ b/script/parser/compile.lua @@ -1,4 +1,6 @@ local guide = require 'parser.guide' +local parse = require 'parser.parse' +local newparser = require 'parser.newparser' local type = type local tableInsert = table.insert local pairs = pairs @@ -566,8 +568,12 @@ local function PostCompile() end end -return function (self, lua, mode, version, options) - local state, err = self:parse(lua, mode, version, options) +return function (lua, mode, version, options) + do + local state, err = newparser(lua, mode, version, options) + return state, err + end + local state, err = parse(lua, mode, version, options) if not state then return nil, err end @@ -576,11 +582,7 @@ return function (self, lua, mode, version, options) --end local clock = os.clock() pushError = state.pushError - if version == 'Lua 5.1' or version == 'LuaJIT' then - ENVMode = '@fenv' - else - ENVMode = '_ENV' - end + ENVMode = state.ENVMode Compiled = {} GoToTag = {} LocalCount = 0 @@ -590,7 +592,6 @@ return function (self, lua, mode, version, options) Root.state = state end Options = options - state.ENVMode = ENVMode if type(state.ast) == 'table' then Compile(state.ast) end diff --git a/script/parser/grammar.lua b/script/parser/grammar.lua index 1a3913e0..154bd7ba 100644 --- a/script/parser/grammar.lua +++ b/script/parser/grammar.lua @@ -557,7 +557,7 @@ Lua <- Head? Head <- '#' (!%nl .)* ]] -return function (self, lua, mode) +return function (lua, mode) local gram = compiled[mode] or compiled['Lua'] local r, _, pos = gram:match(lua) if not r then diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 6dcfbf95..e5e9ead1 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -85,6 +85,7 @@ local breakBlockTypes = { ['in'] = true, ['loop'] = true, ['repeat'] = true, + ['for'] = true, } local childMap = { @@ -722,9 +723,6 @@ function m.eachSource(ast, callback) end --- 获取指定的 special ----@param ast parser.guide.object ----@param name string ----@param callback fun(source: parser.guide.object) function m.eachSpecialOf(ast, name, callback) local root = m.getRoot(ast) if not root.specials then diff --git a/script/parser/init.lua b/script/parser/init.lua index ba40d145..219f8900 100644 --- a/script/parser/init.lua +++ b/script/parser/init.lua @@ -7,6 +7,7 @@ local api = { lines = require 'parser.lines', guide = require 'parser.guide', luadoc = require 'parser.luadoc', + tokens = require 'parser.tokens', } return api diff --git a/script/parser/lines.lua b/script/parser/lines.lua index 1aba0ae5..06023df1 100644 --- a/script/parser/lines.lua +++ b/script/parser/lines.lua @@ -2,7 +2,7 @@ local sfind = string.find local ssub = string.sub ---@param text string -return function (self, text) +return function (text) local current = 1 local lines = {} local i = 1 diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index da612e60..26341571 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -1375,7 +1375,7 @@ local function bindDocs(state) bindDoc(sources, Lines, binded) end -return function (_, state) +return function (state) local ast = state.ast local comments = state.comms table.sort(comments, function (a, b) @@ -1389,7 +1389,7 @@ return function (_, state) pushError = state.pushError - Lines = lines(nil, state.lua) + Lines = lines(state.lua) local ci = 1 NextComment = function (offset, peek) diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua new file mode 100644 index 00000000..7fd0ec31 --- /dev/null +++ b/script/parser/newparser.lua @@ -0,0 +1,3528 @@ +local tokens = require 'parser.tokens' +local guide = require 'parser.guide' + +local sbyte = string.byte +local sfind = string.find +local smatch = string.match +local sgsub = string.gsub +local ssub = string.sub +local schar = string.char +local supper = string.upper +local uchar = utf8.char +local tconcat = table.concat +local tinsert = table.insert +local tointeger = math.tointeger +local mtype = math.type +local tonumber = tonumber +local maxinteger = math.maxinteger +local assert = assert +local next = next + +_ENV = nil + +---@alias parser.position integer + +---@param str string +---@return table +local function stringToCharMap(str) + local map = {} + local pos = 1 + while pos <= #str do + local byte = sbyte(str, pos, pos) + map[schar(byte)] = true + pos = pos + 1 + if ssub(str, pos, pos) == '-' + and pos < #str then + pos = pos + 1 + local byte2 = sbyte(str, pos, pos) + assert(byte < byte2) + for b = byte + 1, byte2 do + map[schar(b)] = true + end + pos = pos + 1 + end + end + return map +end + +local CharMapNumber = stringToCharMap '0-9' +local CharMapN16 = stringToCharMap 'xX' +local CharMapN2 = stringToCharMap 'bB' +local CharMapE10 = stringToCharMap 'eE' +local CharMapE16 = stringToCharMap 'pP' +local CharMapSign = stringToCharMap '+-' +local CharMapSB = stringToCharMap 'ao|~&=<>.*/%^+-' +local CharMapSU = stringToCharMap 'n#~!-' +local CharMapSimple = stringToCharMap '.:([\'"{' +local CharMapStrSH = stringToCharMap '\'"' +local CharMapStrLH = stringToCharMap '[' +local CharMapTSep = stringToCharMap ',;' +local CharMapWord = stringToCharMap '_a-zA-Z\x80-\xff' + +local EscMap = { + ['a'] = '\a', + ['b'] = '\b', + ['f'] = '\f', + ['n'] = '\n', + ['r'] = '\r', + ['t'] = '\t', + ['v'] = '\v', + ['\\'] = '\\', + ['\''] = '\'', + ['\"'] = '\"', +} + +local NLMap = { + ['\n'] = true, + ['\r'] = true, + ['\r\n'] = true, +} + +local LineMulti = 10000 + +-- goto 单独处理 +local KeyWord = { + ['and'] = true, + ['break'] = true, + ['do'] = true, + ['else'] = true, + ['elseif'] = true, + ['end'] = true, + ['false'] = true, + ['for'] = true, + ['function'] = true, + ['if'] = true, + ['in'] = true, + ['local'] = true, + ['nil'] = true, + ['not'] = true, + ['or'] = true, + ['repeat'] = true, + ['return'] = true, + ['then'] = true, + ['true'] = true, + ['until'] = true, + ['while'] = true, +} + +local Specials = { + ['_G'] = true, + ['rawset'] = true, + ['rawget'] = true, + ['setmetatable'] = true, + ['require'] = true, + ['dofile'] = true, + ['loadfile'] = true, + ['pcall'] = true, + ['xpcall'] = true, + ['pairs'] = true, + ['ipairs'] = true, +} + +local UnarySymbol = { + ['not'] = 11, + ['#'] = 11, + ['~'] = 11, + ['-'] = 11, +} + +local BinarySymbol = { + ['or'] = 1, + ['and'] = 2, + ['<='] = 3, + ['>='] = 3, + ['<'] = 3, + ['>'] = 3, + ['~='] = 3, + ['=='] = 3, + ['|'] = 4, + ['~'] = 5, + ['&'] = 6, + ['<<'] = 7, + ['>>'] = 7, + ['..'] = 8, + ['+'] = 9, + ['-'] = 9, + ['*'] = 10, + ['//'] = 10, + ['/'] = 10, + ['%'] = 10, + ['^'] = 12, +} + +local BinaryAlias = { + ['&&'] = 'and', + ['||'] = 'or', + ['!='] = '~=', +} + +local BinaryActionAlias = { + ['='] = '==', +} + +local UnaryAlias = { + ['!'] = 'not', +} + +local SymbolForward = { + [01] = true, + [02] = true, + [03] = true, + [04] = true, + [05] = true, + [06] = true, + [07] = true, + [08] = false, + [09] = true, + [10] = true, + [11] = true, + [12] = false, +} + +local GetToSetMap = { + ['getglobal'] = 'setglobal', + ['getlocal'] = 'setlocal', + ['getfield'] = 'setfield', + ['getindex'] = 'setindex', + ['getmethod'] = 'setmethod', +} + +local ChunkFinishMap = { + ['end'] = true, + ['else'] = true, + ['elseif'] = true, + ['in'] = true, + ['do'] = true, + ['then'] = true, + ['until'] = true, + [';'] = true, + [']'] = true, + [')'] = true, + ['}'] = true, +} + +local State, Lua, Line, LineOffset, Chunk, Tokens, Index, LastTokenFinish, Mode, LocalCount + +local LocalLimit = 200 + +local parseExp, parseAction + +local function pushError(err) + local errs = State.errs + if err.finish < err.start then + err.finish = err.start + end + local last = errs[#errs] + if last then + if last.start <= err.start and last.finish >= err.finish then + return + end + end + err.level = err.level or 'error' + errs[#errs+1] = err + return err +end + +local function addSpecial(name, obj) + local root = State.ast + if not root.specials then + root.specials = {} + end + if not root.specials[name] then + root.specials[name] = {} + end + root.specials[name][#root.specials[name]+1] = obj + obj.special = name +end + +---@param offset integer +---@param leftOrRight '"left"'|'"right"' +local function getPosition(offset, leftOrRight) + if not offset or offset > #Lua then + return LineMulti * Line + #Lua - LineOffset + 1 + end + if leftOrRight == 'left' then + return LineMulti * Line + offset - LineOffset + else + return LineMulti * Line + offset - LineOffset + 1 + end +end + +---@return string word +---@return parser.position startPosition +---@return parser.position finishPosition +---@return integer newOffset +local function peekWord() + local word = Tokens[Index + 1] + if not word then + return nil + end + if not CharMapWord[ssub(word, 1, 1)] then + return nil + end + local startPos = getPosition(Tokens[Index] , 'left') + local finishPos = getPosition(Tokens[Index] + #word - 1, 'right') + return word, startPos, finishPos +end + +local function lastRightPosition() + if Index < 2 then + return 0 + end + local token = Tokens[Index - 1] + if NLMap[token] then + return LastTokenFinish + elseif token then + return getPosition(Tokens[Index - 2] + #token - 1, 'right') + else + return getPosition(#Lua, 'right') + end +end + +local function missSymbol(symbol, start, finish) + pushError { + type = 'MISS_SYMBOL', + start = start or lastRightPosition(), + finish = finish or start or lastRightPosition(), + info = { + symbol = symbol, + } + } +end + +local function missExp() + pushError { + type = 'MISS_EXP', + start = lastRightPosition(), + finish = lastRightPosition(), + } +end + +local function missName(pos) + pushError { + type = 'MISS_NAME', + start = pos or lastRightPosition(), + finish = pos or lastRightPosition(), + } +end + +local function missEnd(relatedStart, relatedFinish) + pushError { + type = 'MISS_SYMBOL', + start = lastRightPosition(), + finish = lastRightPosition(), + info = { + symbol = 'end', + related = { + { + start = relatedStart, + finish = relatedFinish, + } + } + } + } + pushError { + type = 'MISS_END', + start = relatedStart, + finish = relatedFinish, + } +end + +local function unknownSymbol(start, finish, word) + local token = word or Tokens[Index + 1] + if not token then + return false + end + pushError { + type = 'UNKNOWN_SYMBOL', + start = start or getPosition(Tokens[Index], 'left'), + finish = finish or getPosition(Tokens[Index] + #token - 1, 'right'), + info = { + symbol = token, + } + } + return true +end + +local function skipUnknownSymbol(stopSymbol) + if unknownSymbol() then + Index = Index + 2 + return true + end + return false +end + +local function skipNL() + local token = Tokens[Index + 1] + if NLMap[token] then + if Index >= 2 and not NLMap[Tokens[Index - 1]] then + LastTokenFinish = getPosition(Tokens[Index - 2] + #Tokens[Index - 1] - 1, 'right') + end + Line = Line + 1 + LineOffset = Tokens[Index] + #token + Index = Index + 2 + return true + end + return false +end + +local function fastForwardToken(offset) + while true do + local myOffset = Tokens[Index] + if not myOffset + or myOffset >= offset then + break + end + Index = Index + 2 + end +end + +local function resolveLongString(finishMark) + skipNL() + local miss + local start = Tokens[Index] + local finishOffset = sfind(Lua, finishMark, start, true) + if not finishOffset then + finishOffset = #Lua + 1 + miss = true + end + local stringResult = ssub(Lua, start, finishOffset - 1) + local lastLN = stringResult:find '[\r\n][^\r\n]*$' + if lastLN then + local result, count = stringResult + : gsub('\r\n', '\n') + : gsub('[\r\n]', '\n') + Line = Line + count + LineOffset = lastLN + start + stringResult = result + end + fastForwardToken(finishOffset + #finishMark) + if miss then + local pos = getPosition(finishOffset - 1, 'right') + pushError { + type = 'MISS_SYMBOL', + start = pos, + finish = pos, + info = { + symbol = finishMark, + }, + fix = { + title = 'ADD_LSTRING_END', + { + start = pos, + finish = pos, + text = finishMark, + } + }, + } + end + return stringResult, getPosition(finishOffset + #finishMark - 1, 'right') +end + +local function parseLongString() + local start, finish, mark = sfind(Lua, '^(%[%=*%[)', Tokens[Index]) + if not mark then + return nil + end + fastForwardToken(finish + 1) + local startPos = getPosition(start, 'left') + local finishMark = sgsub(mark, '%[', ']') + local stringResult, finishOffset = resolveLongString(finishMark) + return { + type = 'string', + start = startPos, + finish = getPosition(finishOffset, 'right'), + [1] = stringResult, + [2] = mark, + } +end + +local function pushCommentHeadError(left) + if State.options.nonstandardSymbol and State.options.nonstandardSymbol['//'] then + return + end + pushError { + type = 'ERR_COMMENT_PREFIX', + start = left, + finish = left + 2, + fix = { + title = 'FIX_COMMENT_PREFIX', + { + start = left, + finish = left + 2, + text = '--', + }, + } + } +end + +local function pushLongCommentError(left, right) + if State.options.nonstandardSymbol and State.options.nonstandardSymbol['/**/'] then + return + end + pushError { + type = 'ERR_C_LONG_COMMENT', + start = left, + finish = right, + fix = { + title = 'FIX_C_LONG_COMMENT', + { + start = left, + finish = left + 2, + text = '--[[', + }, + { + start = right - 2, + finish = right, + text = '--]]' + }, + } + } +end + +local function skipComment(isAction) + local token = Tokens[Index + 1] + if token == '--' + or (token == '//' and isAction) then + local left = getPosition(Tokens[Index], 'left') + if token == '//' then + pushCommentHeadError(left) + end + Index = Index + 2 + local longComment = parseLongString() + if longComment then + return true + end + while true do + local nl = Tokens[Index + 1] + if not nl or NLMap[nl] then + break + end + Index = Index + 2 + end + return true + end + if token == '/*' then + local left = getPosition(Tokens[Index], 'left') + Index = Index + 2 + local result, right = resolveLongString '*/' + pushLongCommentError(left, right) + return true + end + return false +end + +local function skipSpace(isAction) + repeat until not skipNL() + and not skipComment(isAction) +end + +local function expectAssign() + local token = Tokens[Index + 1] + if token == '=' then + Index = Index + 2 + return true + end + if token == '==' then + local left = getPosition(Tokens[Index], 'left') + local right = getPosition(Tokens[Index] + #token - 1, 'right') + pushError { + type = 'ERR_ASSIGN_AS_EQ', + start = left, + finish = right, + fix = { + title = 'FIX_ASSIGN_AS_EQ', + { + start = left, + finish = right, + text = '=', + } + } + } + Index = Index + 2 + return true + end + return false +end + +local function parseLocalAttrs() + local attrs + while true do + skipSpace() + local token = Tokens[Index + 1] + if token ~= '<' then + break + end + if not attrs then + attrs = {} + end + local attr = { + type = 'localattr', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index], 'right'), + } + attrs[#attrs+1] = attr + Index = Index + 2 + skipSpace() + local word, wstart, wfinish = peekWord() + if word then + attr[1] = word + attr.finish = wfinish + Index = Index + 2 + else + missName() + end + attr.finish = lastRightPosition() + skipSpace() + if Tokens[Index + 1] == '>' then + attr.finish = getPosition(Tokens[Index], 'right') + Index = Index + 2 + elseif Tokens[Index + 1] == '>=' then + attr.finish = getPosition(Tokens[Index], 'right') + pushError { + type = 'MISS_SPACE_BETWEEN', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + 1, 'right'), + } + Index = Index + 2 + else + missSymbol '>' + end + if State.version ~= 'Lua 5.4' then + pushError { + type = 'UNSUPPORT_SYMBOL', + start = attr.start, + finish = attr.finish, + version = 'Lua 5.4', + info = { + version = State.version + } + } + end + end + return attrs +end + +local function createLocal(obj, attrs) + if not obj then + return nil + end + obj.type = 'local' + obj.effect = obj.finish + + if attrs then + obj.attrs = attrs + for i = 1, #attrs do + local attr = attrs[i] + attr.parent = obj + end + end + + local chunk = Chunk[#Chunk] + if chunk then + local locals = chunk.locals + if not locals then + locals = {} + chunk.locals = locals + end + locals[#locals+1] = obj + LocalCount = LocalCount + 1 + if LocalCount > LocalLimit then + pushError { + type = 'LOCAL_LIMIT', + start = obj.start, + finish = obj.finish, + } + end + end + return obj +end + +local function pushChunk(chunk) + Chunk[#Chunk+1] = chunk +end + +local function resolveLable(label, obj) + if not label.ref then + label.ref = {} + end + label.ref[#label.ref+1] = obj + obj.node = label + + -- 如果有局部变量在 goto 与 label 之间声明, + -- 并在 label 之后使用,则算作语法错误 + + -- 如果 label 在 goto 之前声明,那么不会有中间声明的局部变量 + if obj.start > label.start then + return + end + + local block = guide.getBlock(obj) + local locals = block and block.locals + if not locals then + return + end + + for i = 1, #locals do + local loc = locals[i] + -- 检查局部变量声明位置为 goto 与 label 之间 + if loc.start < obj.start or loc.finish > label.finish then + goto CONTINUE + end + -- 检查局部变量的使用位置在 label 之后 + local refs = loc.ref + if not refs then + goto CONTINUE + end + for j = 1, #refs do + local ref = refs[j] + if ref.finish > label.finish then + pushError { + type = 'JUMP_LOCAL_SCOPE', + start = obj.start, + finish = obj.finish, + info = { + loc = loc[1], + }, + relative = { + { + start = label.start, + finish = label.finish, + }, + { + start = loc.start, + finish = loc.finish, + } + }, + } + return + end + end + ::CONTINUE:: + end +end + +local function resolveGoTo(gotos) + for i = 1, #gotos do + local action = gotos[i] + local label = guide.getLabel(action, action[1]) + if label then + resolveLable(label, action) + else + pushError { + type = 'NO_VISIBLE_LABEL', + start = action.start, + finish = action.finish, + info = { + label = action[1], + } + } + end + end +end + +local function popChunk() + local chunk = Chunk[#Chunk] + if chunk.gotos then + resolveGoTo(chunk.gotos) + chunk.gotos = nil + end + local lastAction = chunk[#chunk] + if lastAction then + chunk.finish = lastAction.finish + end + Chunk[#Chunk] = nil +end + +local function parseNil() + if Tokens[Index + 1] ~= 'nil' then + return nil + end + local offset = Tokens[Index] + Index = Index + 2 + return { + type = 'nil', + start = getPosition(offset, 'left'), + finish = getPosition(offset + 2, 'right'), + } +end + +local function parseBoolean() + local word = Tokens[Index+1] + if word ~= 'true' + and word ~= 'false' then + return nil + end + local start = getPosition(Tokens[Index], 'left') + local finish = getPosition(Tokens[Index] + #word - 1, 'right') + Index = Index + 2 + return { + type = 'boolean', + start = start, + finish = finish, + [1] = word == 'true' and true or false, + } +end + +local function parseStringUnicode() + local offset = Tokens[Index] + 1 + if ssub(Lua, offset, offset) ~= '{' then + local pos = getPosition(offset, 'left') + missSymbol('{', pos) + return nil, offset + end + local leftPos = getPosition(offset, 'left') + local x16 = smatch(Lua, '^%w*', offset + 1) + local rightPos = getPosition(offset + #x16, 'right') + offset = offset + #x16 + 1 + if ssub(Lua, offset, offset) == '}' then + offset = offset + 1 + rightPos = rightPos + 1 + else + missSymbol('}', rightPos) + end + offset = offset + 1 + if #x16 == 0 then + pushError { + type = 'UTF8_SMALL', + start = leftPos, + finish = rightPos, + } + return '', offset + end + if State.version ~= 'Lua 5.3' + and State.version ~= 'Lua 5.4' + and State.version ~= 'LuaJIT' + then + pushError { + type = 'ERR_ESC', + start = leftPos - 2, + finish = rightPos, + version = {'Lua 5.3', 'Lua 5.4', 'LuaJIT'}, + info = { + version = State.version, + } + } + return nil, offset + end + local byte = tonumber(x16, 16) + if not byte then + for i = 1, #x16 do + if not tonumber(ssub(x16, i, i), 16) then + pushError { + type = 'MUST_X16', + start = leftPos + i, + finish = leftPos + i + 1, + } + end + end + return nil, offset + end + if State.version == 'Lua 5.4' then + if byte < 0 or byte > 0x7FFFFFFF then + pushError { + type = 'UTF8_MAX', + start = leftPos, + finish = rightPos, + info = { + min = '00000000', + max = '7FFFFFFF', + } + } + return nil, offset + end + else + if byte < 0 or byte > 0x10FFFF then + pushError { + type = 'UTF8_MAX', + start = leftPos, + finish = rightPos, + version = byte <= 0x7FFFFFFF and 'Lua 5.4' or nil, + info = { + min = '000000', + max = '10FFFF', + } + } + end + end + if byte >= 0 and byte <= 0x10FFFF then + return uchar(byte), offset + end + return '', offset +end + +local stringPool = {} +local function parseShortString() + local mark = Tokens[Index+1] + local startOffset = Tokens[Index] + local startPos = getPosition(startOffset, 'left') + Index = Index + 2 + -- empty string + if Tokens[Index+1] == mark then + local finishPos = getPosition(Tokens[Index], 'right') + Index = Index + 2 + return { + type = 'string', + start = startPos, + finish = finishPos, + [1] = '', + [2] = mark, + } + end + local stringIndex = 0 + local currentOffset = startOffset + 1 + while true do + local token = Tokens[Index + 1] + if token == mark then + stringIndex = stringIndex + 1 + stringPool[stringIndex] = ssub(Lua, currentOffset, Tokens[Index] - 1) + Index = Index + 2 + break + end + if not token + or NLMap[token] then + missSymbol(mark) + break + end + if token == '\\' then + stringIndex = stringIndex + 1 + stringPool[stringIndex] = ssub(Lua, currentOffset, Tokens[Index] - 1) + currentOffset = Tokens[Index] + Index = Index + 2 + -- has space? + if Tokens[Index] - currentOffset > 1 then + pushError { + type = 'ERR_ESC', + start = getPosition(currentOffset, 'left'), + finish = getPosition(currentOffset + 1, 'right'), + } + goto CONTINUE + end + local nextToken = ssub(Tokens[Index + 1], 1, 1) + if EscMap[nextToken] then + stringIndex = stringIndex + 1 + stringPool[stringIndex] = EscMap[nextToken] + currentOffset = Tokens[Index] + #nextToken + Index = Index + 2 + goto CONTINUE + end + if nextToken == mark then + stringIndex = stringIndex + 1 + stringPool[stringIndex] = mark + currentOffset = Tokens[Index] + #nextToken + Index = Index + 2 + goto CONTINUE + end + if nextToken == 'z' then + Index = Index + 2 + repeat until not skipNL() + currentOffset = Tokens[Index] + goto CONTINUE + end + if CharMapNumber[nextToken] then + local numbers = smatch(Tokens[Index + 1], '^%d+') + if #numbers > 3 then + numbers = ssub(numbers, 1, 3) + end + currentOffset = Tokens[Index] + #numbers + fastForwardToken(currentOffset) + local byte = tointeger(numbers) + if byte <= 255 then + stringIndex = stringIndex + 1 + stringPool[stringIndex] = schar(byte) + else + -- TODO pushError + end + goto CONTINUE + end + if nextToken == 'x' then + local left = getPosition(Tokens[Index] - 1, 'left') + local x16 = ssub(Tokens[Index + 1], 2, 3) + local byte = tonumber(x16, 16) + if byte then + currentOffset = Tokens[Index] + 3 + stringIndex = stringIndex + 1 + stringPool[stringIndex] = schar(byte) + else + currentOffset = Tokens[Index] + 1 + pushError { + type = 'MISS_ESC_X', + start = getPosition(currentOffset, 'left'), + finish = getPosition(currentOffset + 1, 'right'), + } + end + if State.version == 'Lua 5.1' then + pushError { + type = 'ERR_ESC', + start = left, + finish = left + 4, + version = {'Lua 5.2', 'Lua 5.3', 'Lua 5.4', 'LuaJIT'}, + info = { + version = State.version, + } + } + end + Index = Index + 2 + goto CONTINUE + end + if nextToken == 'u' then + local str, newOffset = parseStringUnicode() + if str then + stringIndex = stringIndex + 1 + stringPool[stringIndex] = str + end + currentOffset = newOffset + fastForwardToken(currentOffset - 1) + goto CONTINUE + end + if NLMap[nextToken] then + stringPool[stringIndex] = '\n' + currentOffset = Tokens[Index] + #nextToken + Index = Index + 2 + goto CONTINUE + end + pushError { + type = 'ERR_ESC', + start = getPosition(currentOffset, 'left'), + finish = getPosition(currentOffset + 1, 'right'), + } + end + Index = Index + 2 + ::CONTINUE:: + end + local stringResult = tconcat(stringPool, '', 1, stringIndex) + return { + type = 'string', + start = startPos, + finish = lastRightPosition(), + [1] = stringResult, + [2] = mark, + } +end + +local function parseString() + local c = Tokens[Index + 1] + if CharMapStrSH[c] then + return parseShortString() + end + if CharMapStrLH[c] then + return parseLongString() + end + return nil +end + +local function parseNumber10(start) + local integer = true + local integerPart = smatch(Lua, '^%d*', start) + local offset = start + #integerPart + -- float part + if ssub(Lua, offset, offset) == '.' then + local floatPart = smatch(Lua, '^%d*', offset + 1) + integer = false + offset = offset + #floatPart + 1 + end + -- exp part + local echar = ssub(Lua, offset, offset) + if CharMapE10[echar] then + integer = false + offset = offset + 1 + local nextChar = ssub(Lua, offset, offset) + if CharMapSign[nextChar] then + offset = offset + 1 + end + local exp = smatch(Lua, '^%d*', offset) + offset = offset + #exp + if #exp == 0 then + pushError { + type = 'MISS_EXPONENT', + start = getPosition(offset - 1, 'right'), + finish = getPosition(offset - 1, 'right'), + } + end + end + return tonumber(ssub(Lua, start, offset - 1)), offset, integer +end + +local function parseNumber16(start) + local integerPart = smatch(Lua, '^[%da-fA-F]*', start) + local offset = start + #integerPart + local integer = true + -- float part + if ssub(Lua, offset, offset) == '.' then + local floatPart = smatch(Lua, '^[%da-fA-F]*', offset + 1) + integer = false + offset = offset + #floatPart + 1 + if #integerPart == 0 and #floatPart == 0 then + pushError { + type = 'MUST_X16', + start = getPosition(offset - 1, 'right'), + finish = getPosition(offset - 1, 'right'), + } + end + else + if #integerPart == 0 then + pushError { + type = 'MUST_X16', + start = getPosition(offset - 1, 'right'), + finish = getPosition(offset - 1, 'right'), + } + return 0, offset + end + end + -- exp part + local echar = ssub(Lua, offset, offset) + if CharMapE16[echar] then + integer = false + offset = offset + 1 + local nextChar = ssub(Lua, offset, offset) + if CharMapSign[nextChar] then + offset = offset + 1 + end + local exp = smatch(Lua, '^%d*', offset) + offset = offset + #exp + end + local n = tonumber(ssub(Lua, start - 2, offset - 1)) + return n, offset, integer +end + +local function parseNumber2(start) + local bins = smatch(Lua, '^[01]*', start) + local offset = start + #bins + if State.version ~= 'LuaJIT' then + pushError { + type = 'UNSUPPORT_SYMBOL', + start = getPosition(start - 2, 'left'), + finish = getPosition(offset - 1, 'right'), + version = 'LuaJIT', + info = { + version = 'Lua 5.4', + } + } + end + return tonumber(bins, 2), offset +end + +local function dropNumberTail(offset, integer) + local _, finish, word = sfind(Lua, '^([%.%w_\x80-\xff]+)', offset) + if not finish then + return offset + end + if integer then + if supper(ssub(word, 1, 2)) == 'LL' then + if State.version ~= 'LuaJIT' then + pushError { + type = 'UNSUPPORT_SYMBOL', + start = getPosition(offset, 'left'), + finish = getPosition(offset + 1, 'right'), + version = 'LuaJIT', + info = { + version = State.version, + } + } + end + offset = offset + 2 + word = ssub(word, offset) + elseif supper(ssub(word, 1, 3)) == 'ULL' then + if State.version ~= 'LuaJIT' then + pushError { + type = 'UNSUPPORT_SYMBOL', + start = getPosition(offset, 'left'), + finish = getPosition(offset + 2, 'right'), + version = 'LuaJIT', + info = { + version = State.version, + } + } + end + offset = offset + 3 + word = ssub(word, offset) + end + end + if supper(ssub(word, 1, 1)) == 'I' then + if State.version ~= 'LuaJIT' then + pushError { + type = 'UNSUPPORT_SYMBOL', + start = getPosition(offset, 'left'), + finish = getPosition(offset, 'right'), + version = 'LuaJIT', + info = { + version = State.version, + } + } + end + offset = offset + 1 + word = ssub(word, offset) + end + if #word > 0 then + pushError { + type = 'MALFORMED_NUMBER', + start = getPosition(offset, 'left'), + finish = getPosition(finish, 'right'), + } + end + return finish + 1 +end + +local function parseNumber() + local offset = Tokens[Index] + if not offset then + return nil + end + local startPos = getPosition(offset, 'left') + local neg + if ssub(Lua, offset, offset) == '-' then + neg = true + offset = offset + 1 + end + local number, integer + local firstChar = ssub(Lua, offset, offset) + if firstChar == '.' then + number, offset = parseNumber10(offset) + integer = false + elseif firstChar == '0' then + local nextChar = ssub(Lua, offset + 1, offset + 1) + if CharMapN16[nextChar] then + number, offset, integer = parseNumber16(offset + 2) + elseif CharMapN2[nextChar] then + number, offset = parseNumber2(offset + 2) + integer = true + else + number, offset, integer = parseNumber10(offset) + end + elseif CharMapNumber[firstChar] then + number, offset, integer = parseNumber10(offset) + else + return nil + end + if not number then + number = 0 + end + if neg then + number = - number + end + local result = { + type = integer and 'integer' or 'number', + start = startPos, + finish = getPosition(offset - 1, 'right'), + [1] = number, + } + offset = dropNumberTail(offset, integer) + fastForwardToken(offset) + return result +end + +local function isKeyWord(word) + if KeyWord[word] then + return true + end + if word == 'goto' then + return State.version ~= 'Lua 5.1' + end + return false +end + +local function parseName() + local word = peekWord() + if not word then + return nil + end + if ChunkFinishMap[word] then + return nil + end + local startPos = getPosition(Tokens[Index], 'left') + local finishPos = getPosition(Tokens[Index] + #word - 1, 'right') + Index = Index + 2 + if not State.options.unicodeName and word:find '[\x80-\xff]' then + pushError { + type = 'UNICODE_NAME', + start = startPos, + finish = finishPos, + } + end + if isKeyWord(word) then + pushError { + type = 'KEYWORD', + start = startPos, + finish = finishPos, + } + end + return { + type = 'name', + start = startPos, + finish = finishPos, + [1] = word, + } +end + +local function parseNameOrList() + local first = parseName() + if not first then + return nil + end + skipSpace() + local list + while true do + if Tokens[Index + 1] ~= ',' then + break + end + Index = Index + 2 + skipSpace() + local name = parseName() + if not name then + missName() + break + end + if not list then + list = { + type = 'list', + start = first.start, + finish = first.finish, + [1] = first + } + end + list[#list+1] = name + list.finish = name.finish + end + return list or first +end + +local function dropTail() + local token = Tokens[Index + 1] + if token ~= '?' + and token ~= ':' then + return + end + local pl, pt, pp = 0, 0, 0 + while true do + local token = Tokens[Index + 1] + if not token then + break + end + if NLMap[token] then + break + end + if token == ',' then + if pl > 0 + or pt > 0 + or pp > 0 then + goto CONTINUE + else + break + end + end + if token == '<' then + pl = pl + 1 + goto CONTINUE + end + if token == '{' then + pt = pt + 1 + goto CONTINUE + end + if token == '(' then + pp = pp + 1 + goto CONTINUE + end + if token == '>' then + if pl <= 0 then + break + end + pl = pl - 1 + goto CONTINUE + end + if token == '}' then + if pt <= 0 then + break + end + pt = pt - 1 + goto CONTINUE + end + if token == ')' then + if pp <= 0 then + break + end + pp = pp - 1 + goto CONTINUE + end + ::CONTINUE:: + Index = Index + 2 + end +end + +local function parseExpList(mini) + local list + local wantSep = false + while true do + skipSpace() + local token = Tokens[Index + 1] + if not token then + break + end + if ChunkFinishMap[token] then + break + end + if token == ',' then + local sepPos = getPosition(Tokens[Index], 'right') + if not wantSep then + pushError { + type = 'UNEXPECT_SYMBOL', + start = getPosition(Tokens[Index], 'left'), + finish = sepPos, + info = { + symbol = ',', + } + } + end + wantSep = false + Index = Index + 2 + goto CONTINUE + else + if mini then + if wantSep then + break + end + local nextToken = peekWord() + if isKeyWord(nextToken) + and nextToken ~= 'function' then + break + end + end + local exp = parseExp() + if not exp then + break + end + dropTail() + if wantSep then + missSymbol(',', list[#list].finish, exp.start) + end + wantSep = true + if not list then + list = { + type = 'list', + start = exp.start, + } + end + list[#list+1] = exp + list.finish = exp.finish + exp.parent = list + end + ::CONTINUE:: + end + if not list then + return nil + end + if not wantSep then + missExp() + end + return list +end + +local function parseIndex() + local bstart = getPosition(Tokens[Index], 'left') + Index = Index + 2 + skipSpace() + local exp = parseExp() + local index = { + type = 'index', + start = bstart, + finish = exp and exp.finish or (bstart + 1), + index = exp + } + if exp then + exp.parent = index + else + missExp() + end + skipSpace() + if Tokens[Index + 1] == ']' then + index.finish = getPosition(Tokens[Index], 'right') + Index = Index + 2 + else + missSymbol ']' + end + return index +end + +local function parseTable() + local tbl = { + type = 'table', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index], 'right'), + } + Index = Index + 2 + local index = 0 + local wantSep = false + while true do + skipSpace() + local token = Tokens[Index + 1] + if token == '}' then + Index = Index + 2 + break + end + if CharMapTSep[token] then + if not wantSep then + missExp() + end + wantSep = false + Index = Index + 2 + goto CONTINUE + end + local lastRight = lastRightPosition() + if token == '[' then + if wantSep then + pushError { + type = 'MISS_SEP_IN_TABLE', + start = lastRight, + finish = getPosition(Tokens[Index], 'left'), + } + end + wantSep = true + index = index + 1 + local tindex = parseIndex() + skipSpace() + if expectAssign() then + skipSpace() + local ivalue = parseExp() + tindex.type = 'tableindex' + tindex.parent = tbl + if ivalue then + ivalue.parent = tindex + tindex.finish = ivalue.finish + tindex.value = ivalue + else + missExp() + end + tbl[index] = tindex + else + missSymbol '=' + end + goto CONTINUE + end + + local exp = parseExp(true) + if exp then + if wantSep then + pushError { + type = 'MISS_SEP_IN_TABLE', + start = lastRight, + finish = exp.start, + } + end + wantSep = true + index = index + 1 + if exp.type == 'varargs' then + tbl[index] = exp + exp.parent = tbl + goto CONTINUE + end + if exp.type == 'getlocal' + or exp.type == 'getglobal' then + skipSpace() + if expectAssign() then + local eqRight = lastRightPosition() + skipSpace() + local fvalue = parseExp() + local tfield = { + type = 'tablefield', + start = exp.start, + finish = fvalue and fvalue.finish or eqRight, + parent = tbl, + field = exp, + value = fvalue, + } + exp.type = 'field' + exp.parent = tfield + if fvalue then + fvalue.parent = tfield + else + missExp() + end + tbl[index] = tfield + goto CONTINUE + end + end + local texp = { + type = 'tableexp', + start = exp.start, + finish = exp.finish, + tindex = index, + parent = tbl, + value = exp, + } + exp.parent = texp + tbl[index] = texp + goto CONTINUE + end + missSymbol '}' + break + ::CONTINUE:: + end + tbl.finish = getPosition(Tokens[Index - 2], 'right') + return tbl +end + +local function parseSimple(node, funcName) + local lastMethod + while true do + if lastMethod and node.node == lastMethod then + if node.type ~= 'call' then + missSymbol('(', node.node.finish, node.node.finish) + end + lastMethod = nil + end + skipSpace() + local token = Tokens[Index + 1] + if token == '.' then + local dot = { + type = token, + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index], 'right'), + } + Index = Index + 2 + skipSpace() + local field = parseName() + local getfield = { + type = 'getfield', + start = node.start, + finish = lastRightPosition(), + node = node, + dot = dot, + field = field + } + if field then + field.parent = node + field.type = 'field' + else + pushError { + type = 'MISS_FIELD', + start = lastRightPosition(), + finish = lastRightPosition(), + } + end + node.next = getfield + node = getfield + elseif token == ':' then + local colon = { + type = token, + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index], 'right'), + } + Index = Index + 2 + skipSpace() + local method = parseName() + local getmethod = { + type = 'getmethod', + start = node.start, + finish = lastRightPosition(), + node = node, + colon = colon, + method = method + } + if method then + method.parent = node + method.type = 'method' + else + pushError { + type = 'MISS_METHOD', + start = lastRightPosition(), + finish = lastRightPosition(), + } + end + node.next = getmethod + node = getmethod + if lastMethod then + missSymbol('(', node.node.finish, node.node.finish) + end + lastMethod = getmethod + elseif token == '(' then + if funcName then + break + end + local startPos = getPosition(Tokens[Index], 'left') + local call = { + type = 'call', + start = node.start, + node = node, + } + Index = Index + 2 + local args = parseExpList() + if Tokens[Index + 1] == ')' then + call.finish = getPosition(Tokens[Index], 'right') + Index = Index + 2 + else + missSymbol ')' + end + if args then + args.type = 'callargs' + args.start = startPos + args.finish = call.finish + args.parent = call + call.args = args + end + if node.type == 'getmethod' then + -- dummy param `self` + if not call.args then + call.args = { + type = 'callargs', + start = call.start, + finish = call.finish, + parent = call, + } + end + local newNode = {} + for k, v in next, call.node.node do + newNode[k] = v + end + newNode.mirror = call.node.node + newNode.dummy = true + newNode.parent = call.args + call.node.node.mirror = newNode + tinsert(call.args, 1, newNode) + end + node = call + elseif token == '{' then + if funcName then + break + end + local str = parseTable() + local call = { + type = 'call', + start = node.start, + finish = str.finish, + node = node, + } + local args = { + type = 'callargs', + start = str.start, + finish = str.finish, + parent = call, + [1] = str, + } + call.args = args + str.parent = args + return call + elseif CharMapStrSH[token] then + if funcName then + break + end + local str = parseShortString() + local call = { + type = 'call', + start = node.start, + finish = str.finish, + node = node, + } + local args = { + type = 'callargs', + start = str.start, + finish = str.finish, + parent = call, + [1] = str, + } + call.args = args + str.parent = args + return call + elseif CharMapStrLH[token] then + local str = parseLongString() + if str then + if funcName then + break + end + local call = { + type = 'call', + start = node.start, + finish = str.finish, + node = node, + } + local args = { + type = 'callargs', + start = str.start, + finish = str.finish, + parent = call, + [1] = str, + } + call.args = args + str.parent = args + return call + else + local index = parseIndex() + index.type = 'getindex' + index.bstart = index.start + index.start = node.start + index.node = node + node.next = index + node = index + if funcName then + pushError { + type = 'INDEX_IN_FUNC_NAME', + start = index.bstart, + finish = index.finish, + } + end + end + else + break + end + end + if node.type == 'call' + and node.node == lastMethod then + lastMethod = nil + end + if node == lastMethod then + if funcName then + lastMethod = nil + end + end + if lastMethod then + missSymbol('(', lastMethod.finish) + end + return node +end + +local function parseVarargs() + local varargs = { + type = 'varargs', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + 2, 'right'), + } + Index = Index + 2 + for i = #Chunk, 1, -1 do + local chunk = Chunk[i] + if chunk.vararg then + if not chunk.vararg.ref then + chunk.vararg.ref = {} + end + chunk.vararg.ref[#chunk.vararg.ref+1] = varargs + varargs.node = chunk.vararg + break + end + if chunk.type == 'function' then + break + end + end + if not varargs.node and Mode == 'Lua' then + pushError { + type = 'UNEXPECT_DOTS', + start = varargs.start, + finish = varargs.finish, + } + end + return varargs +end + +local function parseParen() + local pl = Tokens[Index] + local paren = { + type = 'paren', + start = getPosition(pl, 'left'), + finish = getPosition(pl, 'right') + } + Index = Index + 2 + skipSpace() + local exp = parseExp() + if exp then + paren.exp = exp + paren.finish = exp.finish + exp.parent = paren + else + missExp() + end + skipSpace() + if Tokens[Index + 1] == ')' then + paren.finish = getPosition(Tokens[Index], 'right') + Index = Index + 2 + else + missSymbol ')' + end + return paren +end + +local function getLocal(name, pos) + for i = #Chunk, 1, -1 do + local chunk = Chunk[i] + local locals = chunk.locals + if locals then + local res + for n = 1, #locals do + local loc = locals[n] + if loc.effect > pos then + break + end + if loc[1] == name then + if not res or res.effect < loc.effect then + res = loc + end + end + end + if res then + return res + end + end + end +end + +local function resolveName(node) + if not node then + return nil + end + local loc = getLocal(node[1], node.start) + if loc then + node.type = 'getlocal' + node.node = loc + if not loc.ref then + loc.ref = {} + end + loc.ref[#loc.ref+1] = node + else + node.type = 'getglobal' + local env = getLocal(State.ENVMode, node.start) + if env then + node.node = env + if not env.ref then + env.ref = {} + end + env.ref[#env.ref+1] = node + end + end + local name = node[1] + if Specials[name] then + addSpecial(name, node) + else + local ospeicals = State.options.special + if ospeicals and ospeicals[name] then + addSpecial(name, node) + end + end + return node +end + +local function isChunkFinishToken(token) + local currentChunk = Chunk[#Chunk] + if not currentChunk then + return false + end + local tp = currentChunk.type + if tp == 'main' then + return false + end + if tp == 'for' + or tp == 'in' + or tp == 'loop' then + return token == 'do' + or token == 'end' + end + if tp == 'if' + or tp == 'ifblock' + or tp == 'elseifblock' + or tp == 'elseblock' then + return token == 'then' + or token == 'end' + or token == 'else' + or token == 'elseif' + end + return token ~= 'do' +end + +local function parseActions() + local rtn, last + while true do + skipSpace(true) + local token = Tokens[Index + 1] + if token == ';' then + Index = Index + 2 + goto CONTINUE + end + if ChunkFinishMap[token] + and isChunkFinishToken(token) then + break + end + local action, failed = parseAction() + if failed then + break + end + if action then + if action.type == 'return' then + rtn = action + end + last = action + end + ::CONTINUE:: + end + if rtn and rtn ~= last then + pushError { + type = 'ACTION_AFTER_RETURN', + start = rtn.start, + finish = rtn.finish, + } + end +end + +local function parseParams(params) + local lastSep + local hasDots + while true do + skipSpace() + local token = Tokens[Index + 1] + if not token or token == ')' then + if lastSep then + missName() + end + break + end + if token == ',' then + if lastSep or lastSep == nil then + missName() + else + lastSep = true + end + Index = Index + 2 + goto CONTINUE + end + if token == '...' then + if lastSep == false then + missSymbol ',' + end + lastSep = false + if not params then + params = {} + end + local vararg = { + type = '...', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + 2, 'right'), + parent = params, + } + local chunk = Chunk[#Chunk] + chunk.vararg = vararg + params[#params+1] = vararg + if hasDots then + pushError { + type = 'ARGS_AFTER_DOTS', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + 2, 'right'), + } + end + hasDots = true + Index = Index + 2 + goto CONTINUE + end + if CharMapWord[ssub(token, 1, 1)] then + if lastSep == false then + missSymbol ',' + end + lastSep = false + if not params then + params = {} + end + params[#params+1] = createLocal { + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + #token - 1, 'right'), + parent = params, + [1] = token, + } + if hasDots then + pushError { + type = 'ARGS_AFTER_DOTS', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + #token - 1, 'right'), + } + end + Index = Index + 2 + goto CONTINUE + end + skipUnknownSymbol '%,%)%.' + ::CONTINUE:: + end + return params +end + +local function parseFunction(isLocal, isAction) + local funcLeft = getPosition(Tokens[Index], 'left') + local funcRight = getPosition(Tokens[Index] + 7, 'right') + local func = { + type = 'function', + start = funcLeft, + finish = funcRight, + keyword = { + [1] = funcLeft, + [2] = funcRight, + }, + } + Index = Index + 2 + local LastLocalCount = LocalCount + LocalCount = 0 + skipSpace() + local hasLeftParen = Tokens[Index + 1] == '(' + if not hasLeftParen then + local name = parseName() + if name then + local simple = parseSimple(name, true) + if isLocal then + if simple == name then + createLocal(name) + else + resolveName(name) + pushError { + type = 'UNEXPECT_LFUNC_NAME', + start = simple.start, + finish = simple.finish, + } + end + else + resolveName(name) + end + func.name = simple + func.finish = simple.finish + if not isAction then + pushError { + type = 'UNEXPECT_EFUNC_NAME', + start = simple.start, + finish = simple.finish, + } + end + skipSpace() + hasLeftParen = Tokens[Index + 1] == '(' + end + end + pushChunk(func) + local params + if func.name and func.name.type == 'getmethod' then + if func.name.type == 'getmethod' then + params = {} + params[1] = createLocal { + start = funcRight, + finish = funcRight, + method = func.name, + parent = params, + tag = 'self', + dummy = true, + [1] = 'self', + } + end + end + if hasLeftParen then + local parenLeft = getPosition(Tokens[Index], 'left') + Index = Index + 2 + params = parseParams(params) + if params then + params.type = 'funcargs' + params.start = parenLeft + params.finish = lastRightPosition() + params.parent = func + func.args = params + func.finish = params.finish + end + skipSpace() + if Tokens[Index + 1] == ')' then + local parenRight = getPosition(Tokens[Index], 'right') + func.finish = parenRight + if params then + params.finish = parenRight + end + Index = Index + 2 + skipSpace() + else + if params then + params.finish = func.finish + end + missSymbol ')' + end + else + missSymbol '(' + end + parseActions() + popChunk() + if Tokens[Index + 1] == 'end' then + local endLeft = getPosition(Tokens[Index], 'left') + local endRight = getPosition(Tokens[Index] + 2, 'right') + func.keyword[3] = endLeft + func.keyword[4] = endRight + func.finish = endRight + Index = Index + 2 + else + missEnd(funcLeft, funcRight) + end + LocalCount = LastLocalCount + return func +end + +local function parseExpUnit() + local token = Tokens[Index + 1] + if token == '(' then + local paren = parseParen() + return parseSimple(paren, false) + end + + if token == '...' then + local varargs = parseVarargs() + return varargs + end + + if token == '{' then + local table = parseTable() + return table + end + + if CharMapStrSH[token] then + local string = parseShortString() + return string + end + + if CharMapStrLH[token] then + local string = parseLongString() + return string + end + + local number = parseNumber() + if number then + return number + end + + if ChunkFinishMap[token] then + return nil + end + + if token == 'nil' then + return parseNil() + end + + if token == 'true' + or token == 'false' then + return parseBoolean() + end + + if token == 'function' then + return parseFunction() + end + + local node = parseName() + if node then + return parseSimple(resolveName(node), false) + end + + return nil +end + +local function parseUnaryOP(level) + local token = Tokens[Index + 1] + local symbol = UnarySymbol[token] and token or UnaryAlias[token] + if not symbol then + return nil + end + local myLevel = UnarySymbol[symbol] + if level and myLevel < level then + return nil + end + local op = { + type = symbol, + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + #symbol - 1, 'right'), + } + Index = Index + 2 + return op, myLevel +end + +---@param level integer # op level must greater than this level +local function parseBinaryOP(asAction, level) + local token = Tokens[Index + 1] + local symbol = (BinarySymbol[token] and token) + or BinaryAlias[token] + or (not asAction and BinaryActionAlias[token]) + if not symbol then + return nil + end + local myLevel = BinarySymbol[symbol] + if level and myLevel < level then + return nil + end + local op = { + type = symbol, + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + #token - 1, 'right'), + } + if not asAction then + if token == '=' then + pushError { + type = 'ERR_EQ_AS_ASSIGN', + start = op.start, + finish = op.finish, + fix = { + title = 'FIX_EQ_AS_ASSIGN', + { + start = op.start, + finish = op.finish, + text = '==', + } + } + } + end + end + if BinaryAlias[token] then + if State.options.nonstandardSymbol and State.options.nonstandardSymbol[token] then + else + pushError { + type = 'ERR_NONSTANDARD_SYMBOL', + start = op.start, + finish = op.finish, + info = { + symbol = symbol, + }, + fix = { + title = 'FIX_NONSTANDARD_SYMBOL', + symbol = symbol, + { + start = op.start, + finish = op.finish, + text = symbol, + }, + } + } + end + end + if token == '//' + or token == '<<' + or token == '>>' then + if State.version ~= 'Lua 5.3' + and State.version ~= 'Lua 5.4' then + pushError { + type = 'UNSUPPORT_SYMBOL', + version = {'Lua 5.3', 'Lua 5.4'}, + start = op.start, + finish = op.finish, + info = { + version = State.version, + } + } + end + end + Index = Index + 2 + return op, myLevel +end + +function parseExp(asAction, level) + local exp + local uop, uopLevel = parseUnaryOP(level) + if uop then + skipSpace() + local child = parseExp(asAction, uopLevel) + exp = { + type = 'unary', + op = uop, + start = uop.start, + finish = child and child.finish or uop.finish, + [1] = child, + } + if child then + child.parent = exp + else + missExp() + end + else + exp = parseExpUnit() + if not exp then + return nil + end + end + + while true do + skipSpace() + local bop, bopLevel = parseBinaryOP(asAction, level) + if not bop then + break + end + + ::AGAIN:: + skipSpace() + local isForward = SymbolForward[bopLevel] + local child = parseExp(asAction, isForward and (bopLevel + 0.5) or bopLevel) + if not child then + if skipUnknownSymbol() then + goto AGAIN + else + missExp() + end + end + local bin = { + type = 'binary', + start = exp.start, + finish = child and child.finish or bop.finish, + op = bop, + [1] = exp, + [2] = child + } + exp.parent = bin + if child then + child.parent = bin + end + exp = bin + end + + return exp +end + +local function skipSeps() + while true do + skipSpace() + if Tokens[Index + 1] == ',' then + missExp() + Index = Index + 2 + else + break + end + end +end + +---@return parser.guide.object first +---@return parser.guide.object second +---@return parser.guide.object[] rest +local function parseSetValues() + skipSpace() + local first = parseExp() + if not first then + return nil + end + skipSpace() + if Tokens[Index + 1] ~= ',' then + return first + end + Index = Index + 2 + skipSeps() + local second = parseExp() + if not second then + missExp() + return first + end + skipSpace() + if Tokens[Index + 1] ~= ',' then + return first, second + end + Index = Index + 2 + skipSeps() + local third = parseExp() + if not third then + missExp() + return first, second + end + + local rest = { third } + while true do + skipSpace() + if Tokens[Index + 1] ~= ',' then + return first, second, rest + end + Index = Index + 2 + skipSeps() + local exp = parseExp() + if not exp then + missExp() + return first, second, rest + end + rest[#rest+1] = exp + end +end + +local function pushActionIntoCurrentChunk(action) + local chunk = Chunk[#Chunk] + if chunk then + chunk[#chunk+1] = action + action.parent = chunk + end +end + +---@return parser.guide.object second +---@return parser.guide.object[] rest +local function parseVarTails(parser, isLocal) + if Tokens[Index + 1] ~= ',' then + return + end + Index = Index + 2 + skipSpace() + local second = parser(true) + if not second then + missName() + return + end + if isLocal then + createLocal(second, parseLocalAttrs()) + second.effect = maxinteger + end + skipSpace() + if Tokens[Index + 1] ~= ',' then + return second + end + Index = Index + 2 + skipSeps() + local third = parser(true) + if not third then + missName() + return second + end + if isLocal then + createLocal(third, parseLocalAttrs()) + third.effect = maxinteger + end + local rest = { third } + while true do + skipSpace() + if Tokens[Index + 1] ~= ',' then + return second, rest + end + Index = Index + 2 + skipSeps() + local name = parser(true) + if not name then + missName() + return second, rest + end + if isLocal then + createLocal(name, parseLocalAttrs()) + name.effect = maxinteger + end + rest[#rest+1] = name + end +end + +local function bindValue(n, v, index, lastValue, isLocal, isSet) + if isLocal then + n.effect = lastRightPosition() + elseif isSet then + n.type = GetToSetMap[n.type] or n.type + if n.type == 'setlocal' then + local loc = n.node + if loc.attrs then + pushError { + type = 'SET_CONST', + start = n.start, + finish = n.finish, + } + end + end + end + if not v and lastValue then + if lastValue.type == 'call' + or lastValue.type == 'varargs' then + v = lastValue + if not v.extParent then + v.extParent = {} + end + end + end + if v then + if v.type == 'call' + or v.type == 'varargs' then + local select = { + type = 'select', + sindex = index, + start = v.start, + finish = v.finish, + vararg = v + } + if v.parent then + v.extParent[#v.extParent+1] = select + else + v.parent = select + end + v = select + end + n.value = v + n.range = v.finish + v.parent = n + if isLocal then + n.effect = lastRightPosition() + end + end +end + +local function parseMultiVars(n1, parser, isLocal) + local n2, nrest = parseVarTails(parser, isLocal) + skipSpace() + local v1, v2, vrest + local isSet + if expectAssign() then + v1, v2, vrest = parseSetValues() + isSet = true + if not v1 then + missExp() + end + end + bindValue(n1, v1, 1, nil, isLocal, isSet) + local lastValue = v1 + if n2 then + bindValue(n2, v2, 2, lastValue, isLocal, isSet) + lastValue = v2 or lastValue + pushActionIntoCurrentChunk(n2) + end + if nrest then + for i = 1, #nrest do + local n = nrest[i] + local v = vrest and vrest[i] + bindValue(n, v, i + 2, lastValue, isLocal, isSet) + lastValue = v or lastValue + pushActionIntoCurrentChunk(n) + end + end + + if v2 and not n2 then + v2.redundant = true + pushActionIntoCurrentChunk(v2) + end + if vrest then + for i = 1, #vrest do + local v = vrest[i] + if not nrest or not nrest[i] then + v.redundant = true + pushActionIntoCurrentChunk(v) + end + end + end + + return n1, isSet +end + +local function compileExpAsAction(exp) + pushActionIntoCurrentChunk(exp) + if GetToSetMap[exp.type] then + skipSpace() + local action, isSet = parseMultiVars(exp, parseExp) + if isSet + or action.type == 'getmethod' then + return action + end + end + + if exp.type == 'call' then + return exp + end + + if exp.type == 'binary' then + if GetToSetMap[exp[1].type] then + local op = exp.op + if op.type == '==' then + pushError { + type = 'ERR_ASSIGN_AS_EQ', + start = op.start, + finish = op.finish, + fix = { + title = 'FIX_ASSIGN_AS_EQ', + { + start = op.start, + finish = op.finish, + text = '=', + } + } + } + return + end + end + end + + pushError { + type = 'EXP_IN_ACTION', + start = exp.start, + finish = exp.finish, + } +end + +local function parseLocal() + Index = Index + 2 + skipSpace() + local word = peekWord() + if not word then + missName() + return nil + end + + if word == 'function' then + local func = parseFunction(true, true) + local name = func.name + if name then + func.name = nil + name.value = func + name.vstart = func.start + name.range = func.finish + func.parent = name + pushActionIntoCurrentChunk(name) + return name + else + missName(func.keyword[2]) + pushActionIntoCurrentChunk(func) + return func + end + end + + local name = parseName() + if not name then + missName() + return nil + end + local loc = createLocal(name, parseLocalAttrs()) + loc.effect = maxinteger + pushActionIntoCurrentChunk(loc) + skipSpace() + parseMultiVars(loc, parseName, true) + loc.effect = lastRightPosition() + + return loc +end + +local function parseDo() + local doLeft = getPosition(Tokens[Index], 'left') + local doRight = getPosition(Tokens[Index] + 1, 'right') + local obj = { + type = 'do', + start = doLeft, + finish = doRight, + keyword = { + [1] = doLeft, + [2] = doRight, + }, + } + Index = Index + 2 + pushActionIntoCurrentChunk(obj) + pushChunk(obj) + parseActions() + popChunk() + if Tokens[Index + 1] == 'end' then + obj.finish = getPosition(Tokens[Index] + 2, 'right') + obj.keyword[3] = getPosition(Tokens[Index], 'left') + obj.keyword[4] = getPosition(Tokens[Index] + 2, 'right') + Index = Index + 2 + else + missEnd(doLeft, doRight) + end + if obj.locals then + LocalCount = LocalCount - #obj.locals + end + + return obj +end + +local function parseReturn() + local returnLeft = getPosition(Tokens[Index], 'left') + local returnRight = getPosition(Tokens[Index] + 5, 'right') + Index = Index + 2 + skipSpace() + local rtn = parseExpList(true) + if rtn then + rtn.type = 'return' + rtn.start = returnLeft + else + rtn = { + type = 'return', + start = returnLeft, + finish = returnRight, + } + end + pushActionIntoCurrentChunk(rtn) + for i = #Chunk, 1, -1 do + local func = Chunk[i] + if func.type == 'function' + or func.type == 'main' then + if not func.returns then + func.returns = {} + end + func.returns[#func.returns+1] = rtn + break + end + end + + return rtn +end + +local function parseLabel() + local left = getPosition(Tokens[Index], 'left') + Index = Index + 2 + skipSpace() + local label = parseName() + skipSpace() + + if not label then + missName() + end + + if Tokens[Index + 1] == '::' then + Index = Index + 2 + else + if label then + missSymbol '::' + end + end + + if not label then + return nil + end + + label.type = 'label' + pushActionIntoCurrentChunk(label) + + local block = guide.getBlock(label) + if block then + if not block.labels then + block.labels = {} + end + local name = label[1] + local olabel = guide.getLabel(block, name) + if olabel then + if State.version == 'Lua 5.4' + or block == guide.getBlock(olabel) then + pushError { + type = 'REDEFINED_LABEL', + start = label.start, + finish = label.finish, + relative = { + { + olabel.start, + olabel.finish, + } + } + } + end + end + block.labels[name] = label + end + + if State.version == 'Lua 5.1' then + pushError { + type = 'UNSUPPORT_SYMBOL', + start = left, + finish = lastRightPosition(), + version = {'Lua 5.2', 'Lua 5.3', 'Lua 5.4', 'LuaJIT'}, + info = { + version = State.version, + } + } + return + end + return label +end + +local function parseGoTo() + Index = Index + 2 + skipSpace() + + local action = parseName() + if not action then + missName() + return nil + end + + action.type = 'goto' + + for i = #Chunk, 1, -1 do + local chunk = Chunk[i] + if chunk.type == 'function' + or chunk.type == 'main' then + if not chunk.gotos then + chunk.gotos = {} + end + chunk.gotos[#chunk.gotos+1] = action + break + end + end + + pushActionIntoCurrentChunk(action) + return action +end + +local function parseIfBlock(parent) + local ifLeft = getPosition(Tokens[Index], 'left') + local ifRight = getPosition(Tokens[Index] + 1, 'right') + Index = Index + 2 + local ifblock = { + type = 'ifblock', + parent = parent, + start = ifLeft, + finish = ifRight, + keyword = { + [1] = ifLeft, + [2] = ifRight, + } + } + skipSpace() + local filter = parseExp() + if filter then + ifblock.filter = filter + ifblock.finish = filter.finish + filter.parent = ifblock + else + missExp() + end + skipSpace() + local thenToken = Tokens[Index + 1] + if thenToken == 'then' + or thenToken == 'do' then + ifblock.finish = getPosition(Tokens[Index] + #thenToken - 1, 'right') + ifblock.keyword[3] = getPosition(Tokens[Index], 'left') + ifblock.keyword[4] = ifblock.finish + if thenToken == 'do' then + pushError { + type = 'ERR_THEN_AS_DO', + start = ifblock.keyword[3], + finish = ifblock.keyword[4], + fix = { + title = 'FIX_THEN_AS_DO', + { + start = ifblock.keyword[3], + finish = ifblock.keyword[4], + text = 'then', + } + } + } + end + Index = Index + 2 + else + missSymbol 'then' + end + pushChunk(ifblock) + parseActions() + popChunk() + if ifblock.locals then + LocalCount = LocalCount - #ifblock.locals + end + return ifblock +end + +local function parseElseIfBlock(parent) + local ifLeft = getPosition(Tokens[Index], 'left') + local ifRight = getPosition(Tokens[Index] + 5, 'right') + local elseifblock = { + type = 'elseifblock', + parent = parent, + start = ifLeft, + finish = ifRight, + keyword = { + [1] = ifLeft, + [2] = ifRight, + } + } + Index = Index + 2 + skipSpace() + local filter = parseExp() + if filter then + elseifblock.filter = filter + elseifblock.finish = filter.finish + filter.parent = elseifblock + else + missExp() + end + skipSpace() + local thenToken = Tokens[Index + 1] + if thenToken == 'then' + or thenToken == 'do' then + elseifblock.finish = getPosition(Tokens[Index] + #thenToken - 1, 'right') + elseifblock.keyword[3] = getPosition(Tokens[Index], 'left') + elseifblock.keyword[4] = elseifblock.finish + if thenToken == 'do' then + pushError { + type = 'ERR_THEN_AS_DO', + start = elseifblock.keyword[3], + finish = elseifblock.keyword[4], + fix = { + title = 'FIX_THEN_AS_DO', + { + start = elseifblock.keyword[3], + finish = elseifblock.keyword[4], + text = 'then', + } + } + } + end + Index = Index + 2 + else + missSymbol 'then' + end + pushChunk(elseifblock) + parseActions() + popChunk() + if elseifblock.locals then + LocalCount = LocalCount - #elseifblock.locals + end + return elseifblock +end + +local function parseElseBlock(parent) + local ifLeft = getPosition(Tokens[Index], 'left') + local ifRight = getPosition(Tokens[Index] + 3, 'right') + local elseblock = { + type = 'elseblock', + parent = parent, + start = ifLeft, + finish = ifRight, + keyword = { + [1] = ifLeft, + [2] = ifRight, + } + } + Index = Index + 2 + skipSpace() + pushChunk(elseblock) + parseActions() + popChunk() + if elseblock.locals then + LocalCount = LocalCount - #elseblock.locals + end + return elseblock +end + +local function parseIf() + local token = Tokens[Index + 1] + local left = getPosition(Tokens[Index], 'left') + local action = { + type = 'if', + start = left, + finish = getPosition(Tokens[Index] + #token - 1, 'right'), + } + pushActionIntoCurrentChunk(action) + if token ~= 'if' then + missSymbol('if', left, left) + end + local hasElse + while true do + local word = Tokens[Index + 1] + local child + if word == 'if' then + child = parseIfBlock(action) + elseif word == 'elseif' then + child = parseElseIfBlock(action) + elseif word == 'else' then + child = parseElseBlock(action) + end + if not child then + break + end + if hasElse then + pushError { + type = 'BLOCK_AFTER_ELSE', + start = child.start, + finish = child.finish, + } + end + if word == 'else' then + hasElse = true + end + action[#action+1] = child + action.finish = child.finish + skipSpace() + end + + if Tokens[Index + 1] == 'end' then + action.finish = getPosition(Tokens[Index] + 2, 'right') + Index = Index + 2 + else + missEnd(action[1].keyword[1], action[1].keyword[2]) + end + + return action +end + +local function parseFor() + local action = { + type = 'for', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + 2, 'right'), + keyword = {}, + } + action.keyword[1] = action.start + action.keyword[2] = action.finish + Index = Index + 2 + pushActionIntoCurrentChunk(action) + pushChunk(action) + skipSpace() + local nameOrList = parseNameOrList() + if not nameOrList then + missName() + end + skipSpace() + -- for i = + if expectAssign() then + action.type = 'loop' + + skipSpace() + local expList = parseExpList() + local name + if nameOrList then + if nameOrList.type == 'name' then + name = nameOrList + else + name = nameOrList[1] + end + end + if name then + local loc = createLocal(name) + loc.parent = action + action.finish = name.finish + action.loc = loc + end + if expList then + local value = expList[1] + if value then + value.parent = action + action.init = value + action.finish = expList[#expList].finish + end + local max = expList[2] + if max then + max.parent = action + action.max = max + action.finish = max.finish + else + pushError { + type = 'MISS_LOOP_MAX', + start = lastRightPosition(), + finish = lastRightPosition(), + } + end + local step = expList[3] + if step then + step.parent = action + action.step = step + action.finish = step.finish + end + else + pushError { + type = 'MISS_LOOP_MIN', + start = lastRightPosition(), + finish = lastRightPosition(), + } + end + + if action.loc then + action.loc.effect = action.finish + end + elseif Tokens[Index + 1] == 'in' then + action.type = 'in' + local inLeft = getPosition(Tokens[Index], 'left') + local inRight = getPosition(Tokens[Index] + 1, 'right') + Index = Index + 2 + skipSpace() + + local exps = parseExpList() + + action.finish = inRight + action.keyword[3] = inLeft + action.keyword[4] = inRight + + local list + if nameOrList and nameOrList.type == 'name' then + list = { + type = 'list', + start = nameOrList.start, + finish = nameOrList.finish, + [1] = nameOrList, + } + else + list = nameOrList + end + + if exps then + local lastExp = exps[#exps] + if lastExp then + action.finish = lastExp.finish + end + + action.exps = exps + for i = 1, #exps do + local exp = exps[i] + exp.parent = action + end + else + missExp() + end + + if list then + local lastName = list[#list] + list.range = lastName and lastName.range or inRight + action.keys = list + for i = 1, #list do + local loc = createLocal(list[i]) + loc.parent = action + loc.effect = action.finish + end + end + else + missSymbol 'in' + end + + skipSpace() + local doToken = Tokens[Index + 1] + if doToken == 'do' + or doToken == 'then' then + local left = getPosition(Tokens[Index], 'left') + local right = getPosition(Tokens[Index] + #doToken - 1, 'right') + action.finish = left + action.keyword[#action.keyword+1] = left + action.keyword[#action.keyword+1] = right + if doToken == 'then' then + pushError { + type = 'ERR_DO_AS_THEN', + start = left, + finish = right, + fix = { + title = 'FIX_DO_AS_THEN', + { + start = left, + finish = right, + text = 'do', + } + } + } + end + Index = Index + 2 + else + missSymbol 'do' + end + + skipSpace() + parseActions() + popChunk() + + skipSpace() + if Tokens[Index + 1] == 'end' then + action.finish = getPosition(Tokens[Index] + 2, 'right') + action.keyword[#action.keyword+1] = getPosition(Tokens[Index], 'left') + action.keyword[#action.keyword+1] = action.finish + Index = Index + 2 + else + missEnd(action.keyword[1], action.keyword[2]) + end + + if action.locals then + LocalCount = LocalCount - #action.locals + end + + return action +end + +local function parseWhile() + local action = { + type = 'while', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + 4, 'right'), + keyword = {}, + } + action.keyword[1] = action.start + action.keyword[2] = action.finish + Index = Index + 2 + + skipSpace() + local filter = parseExp() + if filter then + action.filter = filter + action.finish = filter.finish + filter.parent = action + else + missExp() + end + + skipSpace() + local doToken = Tokens[Index + 1] + if doToken == 'do' + or doToken == 'then' then + local left = getPosition(Tokens[Index], 'left') + local right = getPosition(Tokens[Index] + #doToken - 1, 'right') + action.finish = left + action.keyword[#action.keyword+1] = left + action.keyword[#action.keyword+1] = right + if doToken == 'then' then + pushError { + type = 'ERR_DO_AS_THEN', + start = left, + finish = right, + fix = { + title = 'FIX_DO_AS_THEN', + { + start = left, + finish = right, + text = 'do', + } + } + } + end + Index = Index + 2 + else + missSymbol 'do' + end + + pushActionIntoCurrentChunk(action) + pushChunk(action) + skipSpace() + parseActions() + popChunk() + + skipSpace() + if Tokens[Index + 1] == 'end' then + action.finish = getPosition(Tokens[Index] + 2, 'right') + action.keyword[#action.keyword+1] = getPosition(Tokens[Index], 'left') + action.keyword[#action.keyword+1] = action.finish + Index = Index + 2 + else + missEnd(action.keyword[1], action.keyword[2]) + end + + if action.locals then + LocalCount = LocalCount - #action.locals + end + + return action +end + +local function parseRepeat() + local action = { + type = 'repeat', + start = getPosition(Tokens[Index], 'left'), + finish = getPosition(Tokens[Index] + 5, 'right'), + keyword = {}, + } + action.keyword[1] = action.start + action.keyword[2] = action.finish + Index = Index + 2 + + pushActionIntoCurrentChunk(action) + pushChunk(action) + skipSpace() + parseActions() + + skipSpace() + if Tokens[Index + 1] == 'until' then + action.finish = getPosition(Tokens[Index] + 4, 'right') + action.keyword[#action.keyword+1] = getPosition(Tokens[Index], 'left') + action.keyword[#action.keyword+1] = action.finish + Index = Index + 2 + + skipSpace() + local filter = parseExp() + if filter then + action.filter = filter + filter.parent = action + else + missExp() + end + + else + missSymbol 'until' + end + + popChunk() + if action.filter then + action.finish = action.filter.finish + end + + if action.locals then + LocalCount = LocalCount - #action.locals + end + + return action +end + +local function parseBreak() + local returnLeft = getPosition(Tokens[Index], 'left') + local returnRight = getPosition(Tokens[Index] + 4, 'right') + Index = Index + 2 + skipSpace() + local action = { + type = 'break', + start = returnLeft, + finish = returnRight, + } + + local ok + for i = #Chunk, 1, -1 do + local chunk = Chunk[i] + if chunk.type == 'function' then + break + end + if chunk.type == 'while' + or chunk.type == 'in' + or chunk.type == 'loop' + or chunk.type == 'repeat' + or chunk.type == 'for' then + if not chunk.breaks then + chunk.breaks = {} + end + chunk.breaks[#chunk.breaks+1] = action + ok = true + break + end + end + if not ok and Mode == 'Lua' then + pushError { + type = 'BREAK_OUTSIDE', + start = action.start, + finish = action.finish, + } + end + + pushActionIntoCurrentChunk(action) + return action +end + +function parseAction() + local token = Tokens[Index + 1] + + if token == '::' then + return parseLabel() + end + + if token == 'local' then + return parseLocal() + end + + if token == 'if' + or token == 'elseif' + or token == 'else' then + return parseIf() + end + + if token == 'for' then + return parseFor() + end + + if token == 'do' then + return parseDo() + end + + if token == 'return' then + return parseReturn() + end + + if token == 'break' then + return parseBreak() + end + + if token == 'while' then + return parseWhile() + end + + if token == 'repeat' then + return parseRepeat() + end + + if token == 'goto' then + return parseGoTo() + end + + if token == 'function' then + local exp = parseFunction(false, true) + local name = exp.name + if name then + exp.name = nil + name.type = GetToSetMap[name.type] + name.value = exp + name.vstart = exp.start + name.range = exp.finish + exp.parent = name + pushActionIntoCurrentChunk(name) + return name + else + pushActionIntoCurrentChunk(exp) + missName(exp.keyword[2]) + return exp + end + end + + local exp = parseExp(true) + if exp then + local action = compileExpAsAction(exp) + if action then + return action + end + end + return nil, true +end + +local function skipFirstComment() + if Tokens[Index + 1] ~= '#' then + return + end + while true do + Index = Index + 2 + local token = Tokens[Index + 1] + if not token then + break + end + if NLMap[token] then + skipNL() + break + end + end +end + +local function parseLua() + local main = { + type = 'main', + start = 0, + finish = 0, + } + pushChunk(main) + createLocal{ + type = 'local', + start = 0, + finish = 0, + effect = 0, + tag = '_ENV', + special= '_G', + [1] = State.ENVMode, + } + LocalCount = 0 + skipFirstComment() + while true do + parseActions() + if Index <= #Tokens then + unknownSymbol() + Index = Index + 2 + else + break + end + end + popChunk() + main.finish = getPosition(#Lua, 'right') + + return main +end + +local function initState(lua, version, options) + Lua = lua + Line = 0 + LineOffset = 1 + LastTokenFinish = 0 + LocalCount = 0 + Chunk = {} + Tokens = tokens(lua) + Index = 1 + State = { + version = version, + lua = lua, + ast = {}, + errs = {}, + diags = {}, + comms = {}, + options = options or {}, + } + if version == 'Lua 5.1' or version == 'LuaJIT' then + State.ENVMode = '@fenv' + else + State.ENVMode = '_ENV' + end +end + +return function (lua, mode, version, options) + Mode = mode + initState(lua, version, options) + skipSpace() + if mode == 'Lua' then + State.ast = parseLua() + elseif mode == 'Nil' then + State.ast = parseNil() + elseif mode == 'Boolean' then + State.ast = parseBoolean() + elseif mode == 'String' then + State.ast = parseString() + elseif mode == 'Number' then + State.ast = parseNumber() + elseif mode == 'Exp' then + State.ast = parseExp() + elseif mode == 'Action' then + State.ast = parseAction() + end + + return State +end diff --git a/script/parser/parse.lua b/script/parser/parse.lua index 9b8d5496..e7c7d177 100644 --- a/script/parser/parse.lua +++ b/script/parser/parse.lua @@ -1,6 +1,7 @@ -local ast = require 'parser.ast' +local ast = require 'parser.ast' +local grammar = require 'parser.grammar' -return function (self, lua, mode, version, options) +local function buildState(lua, version, options) local errs = {} local diags = {} local comms = {} @@ -36,9 +37,19 @@ return function (self, lua, mode, version, options) comms[#comms+1] = comment end } + if version == 'Lua 5.1' or version == 'LuaJIT' then + state.ENVMode = '@fenv' + else + state.ENVMode = '_ENV' + end + return state +end + +return function (lua, mode, version, options) + local state = buildState(lua, version, options) local clock = os.clock() ast.init(state) - local suc, res, err = xpcall(self.grammar, debug.traceback, self, lua, mode) + local suc, res, err = xpcall(grammar, debug.traceback, lua, mode) ast.close() if not suc then return nil, res diff --git a/script/parser/tokens.lua b/script/parser/tokens.lua new file mode 100644 index 00000000..958f292e --- /dev/null +++ b/script/parser/tokens.lua @@ -0,0 +1,38 @@ +local m = require 'lpeglabel' + +local Sp = m.S' \t' +local Nl = m.P'\r\n' + m.S'\r\n' +local Number = m.R'09'^1 +local Word = m.R('AZ', 'az', '__', '\x80\xff') * m.R('AZ', 'az', '09', '__', '\x80\xff')^0 +local Symbol = m.P'==' + + m.P'~=' + + m.P'--' + + m.P'<<' + + m.P'>>' + + m.P'<=' + + m.P'>=' + + m.P'//' + + m.P'...' + + m.P'..' + + m.P'::' + -- incorrect + + m.P'!=' + + m.P'&&' + + m.P'||' + + m.P'/*' + + m.P'*/' + + m.P'+=' + + m.P'-=' + + m.P'*=' + + m.P'/=' + -- singles + + m.S'+-*/!#%^&()={}[]|\\\'":;<>,.?~`' +local Unknown = (1 - Number - Word - Symbol - Sp - Nl)^1 +local Token = m.Cp() * m.C(Nl + Number + Word + Symbol + Unknown) + +local Parser = m.Ct((Sp^1 + Token)^0) + +return function (lua) + local results = Parser:match(lua) + return results +end -- cgit v1.2.3 From 5a43c5f78a9d13b9d18ba58bd45c85e7521d9f08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Tue, 14 Sep 2021 17:23:50 +0800 Subject: fix --- script/brave/work.lua | 4 ++-- script/core/completion.lua | 2 +- script/files.lua | 11 +++++------ script/parser/newparser.lua | 46 ++++++++++++++++++++++++++------------------- 4 files changed, 35 insertions(+), 28 deletions(-) (limited to 'script') diff --git a/script/brave/work.lua b/script/brave/work.lua index 907f78cf..ee7b4acd 100644 --- a/script/brave/work.lua +++ b/script/brave/work.lua @@ -26,12 +26,12 @@ brave.on('timer', function (time) end) brave.on('compile', function (text) - local state, err = parser:compile(text, 'lua', 'Lua 5.4') + local state, err = parser.compile(text, 'lua', 'Lua 5.4') if not state then log.error(err) return end - local lines = parser:lines(text) + local lines = parser.lines(text) return { root = state.root, value = state.value, diff --git a/script/core/completion.lua b/script/core/completion.lua index fb7b2eb4..f81f8179 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -1049,7 +1049,7 @@ local function tryLabelInString(label, source) if not source or source.type ~= 'string' then return label end - local str = parser:grammar(label, 'String') + local str = parser.grammar(label, 'String') if not str then return label end diff --git a/script/files.lua b/script/files.lua index fa5474ef..ecaaa5a5 100644 --- a/script/files.lua +++ b/script/files.lua @@ -446,14 +446,13 @@ function m.compileState(uri, text) local prog = progress.create(lang.script.WINDOW_COMPILING, 0.5) prog:setMessage(ws.getRelativePath(uri)) local clock = os.clock() - local state, err = parser:compile(text - , 'lua' + local state, err = parser.compile(text + , 'Lua' , config.get 'Lua.runtime.version' , { special = config.get 'Lua.runtime.special', unicodeName = config.get 'Lua.runtime.unicodeName', nonstandardSymbol = config.get 'Lua.runtime.nonstandardSymbol', - delay = await.delay, } ) local passed = os.clock() - clock @@ -465,7 +464,7 @@ function m.compileState(uri, text) state.uri = uri state.ast.uri = uri local clock = os.clock() - parser:luadoc(state) + parser.luadoc(state) local passed = os.clock() - clock if passed > 0.1 then log.warn(('Parse LuaDoc of [%s] takes [%.3f] sec, size [%.3f] kb.'):format(uri, passed, #text / 1000)) @@ -548,7 +547,7 @@ function m.getLines(uri) end local lines = m.linesMap[uri] if not lines then - lines = parser:lines(file.text) + lines = parser.lines(file.text) m.linesMap[uri] = lines end return lines @@ -561,7 +560,7 @@ function m.getOriginLines(uri) end local lines = m.originLinesMap[uri] if not lines then - lines = parser:lines(file.originText) + lines = parser.lines(file.originText) m.originLinesMap[uri] = lines end return lines diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 7fd0ec31..e1d98d87 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -1598,8 +1598,9 @@ local function parseSimple(node, funcName) finish = lastRightPosition(), } end - node.next = getfield - node = getfield + node.parent = getfield + node.next = getfield + node = getfield elseif token == ':' then local colon = { type = token, @@ -1627,8 +1628,9 @@ local function parseSimple(node, funcName) finish = lastRightPosition(), } end - node.next = getmethod - node = getmethod + node.parent = getmethod + node.next = getmethod + node = getmethod if lastMethod then missSymbol('(', node.node.finish, node.node.finish) end @@ -1678,28 +1680,30 @@ local function parseSimple(node, funcName) call.node.node.mirror = newNode tinsert(call.args, 1, newNode) end + node.parent = call node = call elseif token == '{' then if funcName then break end - local str = parseTable() + local tbl = parseTable() local call = { type = 'call', start = node.start, - finish = str.finish, + finish = tbl.finish, node = node, } local args = { type = 'callargs', - start = str.start, - finish = str.finish, + start = tbl.start, + finish = tbl.finish, parent = call, - [1] = str, + [1] = tbl, } - call.args = args - str.parent = args - return call + call.args = args + tbl.parent = args + node.parent = call + node = call elseif CharMapStrSH[token] then if funcName then break @@ -1718,9 +1722,10 @@ local function parseSimple(node, funcName) parent = call, [1] = str, } - call.args = args - str.parent = args - return call + call.args = args + str.parent = args + node.parent = args + node = call elseif CharMapStrLH[token] then local str = parseLongString() if str then @@ -1740,9 +1745,10 @@ local function parseSimple(node, funcName) parent = call, [1] = str, } - call.args = args - str.parent = args - return call + call.args = args + str.parent = args + node.parent = call + node = call else local index = parseIndex() index.type = 'getindex' @@ -1750,7 +1756,8 @@ local function parseSimple(node, funcName) index.start = node.start index.node = node node.next = index - node = index + node.parent = index + node = index if funcName then pushError { type = 'INDEX_IN_FUNC_NAME', @@ -3458,6 +3465,7 @@ local function parseLua() start = 0, finish = 0, effect = 0, + parent = main, tag = '_ENV', special= '_G', [1] = State.ENVMode, -- cgit v1.2.3 From 5a072004414ff1f8de416c62a4067774f72e7097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Tue, 14 Sep 2021 20:43:33 +0800 Subject: cleanup --- script/core/code-action.lua | 2 +- script/core/completion.lua | 2 +- script/core/diagnostics/newfield-call.lua | 4 +- script/core/diagnostics/newline-call.lua | 4 +- script/core/find-source.lua | 6 +-- script/core/keyword.lua | 4 +- script/core/reference.lua | 4 +- script/core/type-formatting.lua | 2 +- script/files.lua | 2 +- script/parser/guide.lua | 88 +++++++++---------------------- script/parser/luadoc.lua | 12 ++--- script/vm/getDocs.lua | 2 +- 12 files changed, 46 insertions(+), 86 deletions(-) (limited to 'script') diff --git a/script/core/code-action.lua b/script/core/code-action.lua index 64f862f9..1bac9359 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -57,7 +57,7 @@ end local function disableDiagnostic(uri, code, start, results) local lines = files.getLines(uri) - local row = guide.positionOf(lines, start) + local row = guide.positionOf(start) results[#results+1] = { title = lang.script('ACTION_DISABLE_DIAG', code), kind = 'quickfix', diff --git a/script/core/completion.lua b/script/core/completion.lua index f81f8179..59dc19f3 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -176,7 +176,7 @@ local function getSnip(source) if vm.isMetaFile(uri) then goto CONTINUE end - local row = guide.positionOf(lines, def.start) + local row = guide.positionOf(def.start) local firstRow = lines[row] local lastRow = lines[math.min(row + context - 1, #lines)] local snip = text:sub(firstRow.start, lastRow.finish) diff --git a/script/core/diagnostics/newfield-call.lua b/script/core/diagnostics/newfield-call.lua index fe86ad66..61d52dd2 100644 --- a/script/core/diagnostics/newfield-call.lua +++ b/script/core/diagnostics/newfield-call.lua @@ -27,8 +27,8 @@ return function (uri, callback) local func = call.node local args = call.args if args then - local funcLine = guide.positionOf(lines, func.finish) - local argsLine = guide.positionOf(lines, args.start) + local funcLine = guide.positionOf(func.finish) + local argsLine = guide.positionOf(args.start) if argsLine > funcLine then callback { start = call.start, diff --git a/script/core/diagnostics/newline-call.lua b/script/core/diagnostics/newline-call.lua index 71dc33e2..69bf948f 100644 --- a/script/core/diagnostics/newline-call.lua +++ b/script/core/diagnostics/newline-call.lua @@ -26,8 +26,8 @@ return function (uri, callback) return end - local nodeRow = guide.positionOf(lines, node.finish) - local argRow = guide.positionOf(lines, args.start) + local nodeRow = guide.positionOf(node.finish) + local argRow = guide.positionOf(args.start) if nodeRow == argRow then return end diff --git a/script/core/find-source.lua b/script/core/find-source.lua index edbb1e2c..26a411e5 100644 --- a/script/core/find-source.lua +++ b/script/core/find-source.lua @@ -11,12 +11,12 @@ local function isValidFunctionPos(source, offset) return false end -return function (ast, offset, accept) +return function (ast, position, accept) local len = math.huge local result - guide.eachSourceContain(ast.ast, offset, function (source) + guide.eachSourceContain(ast.ast, position, function (source) if source.type == 'function' then - if not isValidFunctionPos(source, offset) then + if not isValidFunctionPos(source, position) then return end end diff --git a/script/core/keyword.lua b/script/core/keyword.lua index b8e37605..4b43efe5 100644 --- a/script/core/keyword.lua +++ b/script/core/keyword.lua @@ -275,8 +275,8 @@ until $1" if first == 'end' or first == 'else' or first == 'elseif' then - local startRow = guide.positionOf(lines, info.start) - local finishRow = guide.positionOf(lines, pos) + local startRow = guide.positionOf(info.start) + local finishRow = guide.positionOf(pos) local startSp = info.text:match('^%s*', lines[startRow].start + 1) local finishSp = info.text:match('^%s*', lines[finishRow].start + 1) if startSp == finishSp then diff --git a/script/core/reference.lua b/script/core/reference.lua index 5f5831c6..067d2e23 100644 --- a/script/core/reference.lua +++ b/script/core/reference.lua @@ -52,13 +52,13 @@ local accept = { ['doc.alias.name'] = true, } -return function (uri, offset) +return function (uri, position) local ast = files.getState(uri) if not ast then return nil end - local source = findSource(ast, offset, accept) + local source = findSource(ast, position, accept) if not source then return nil end diff --git a/script/core/type-formatting.lua b/script/core/type-formatting.lua index a225d9d7..12272f11 100644 --- a/script/core/type-formatting.lua +++ b/script/core/type-formatting.lua @@ -5,7 +5,7 @@ local guide = require "parser.guide" local function insertIndentation(uri, offset, edits) local lines = files.getLines(uri) local text = files.getOriginText(uri) - local row = guide.positionOf(lines, offset) + local row = guide.positionOf(offset) local line = lines[row] local indent = text:sub(line.start, line.finish):match '^%s*' for _, edit in ipairs(edits) do diff --git a/script/files.lua b/script/files.lua index ecaaa5a5..0e62a740 100644 --- a/script/files.lua +++ b/script/files.lua @@ -744,7 +744,7 @@ function m.position(uri, offset, leftOrRight) lines = m.getOriginLines(uri) text = m.getOriginText(uri) end - local row, col = guide.positionOf(lines, offset) + local row, col = guide.positionOf(offset) local start, finish = guide.lineRange(lines, row, true) start = start + 1 if col <= finish - start + 1 then diff --git a/script/parser/guide.lua b/script/parser/guide.lua index e5e9ead1..941fc7b1 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -548,24 +548,24 @@ function m.getRange(source) return start, finish end ---- 判断source是否包含offset -function m.isContain(source, offset) +--- 判断source是否包含position +function m.isContain(source, position) local start, finish = m.getStartFinish(source) if not start then return false end - return start <= offset and finish >= offset + return start <= position and finish >= position end ---- 判断offset在source的影响范围内 +--- 判断position在source的影响范围内 --- --- 主要针对赋值等语句时,key包含value -function m.isInRange(source, offset) +function m.isInRange(source, position) local start, finish = m.getRange(source) if not start then return false end - return start <= offset and finish >= offset + return start <= position and finish >= position end function m.isBetween(source, tStart, tFinish) @@ -597,8 +597,8 @@ local function addChilds(list, obj) f(obj, list) end ---- 遍历所有包含offset的source -function m.eachSourceContain(ast, offset, callback) +--- 遍历所有包含position的source +function m.eachSourceContain(ast, position, callback) local list = { ast } local mark = {} while true do @@ -610,8 +610,8 @@ function m.eachSourceContain(ast, offset, callback) list[len] = nil if not mark[obj] then mark[obj] = true - if m.isInRange(obj, offset) then - if m.isContain(obj, offset) then + if m.isInRange(obj, position) then + if m.isContain(obj, position) then local res = callback(obj) if res ~= nil then return res @@ -737,64 +737,24 @@ function m.eachSpecialOf(ast, name, callback) end end ---- 获取光标偏移对应的坐标。 ---- 如果在换行符的右侧,则认为在新的一行。 ---- 第一行的行号是1不是0。 ----@param lines table ----@return integer {name = 'row'} ----@return integer {name = 'col'} -function m.positionOf(lines, offset) - if offset <= 0 then - return 1, 0 - end - local lastLine = lines[#lines] - if offset >= lastLine.finish then - return #lines, lastLine.finish - lastLine.start - end - local min = 1 - local max = #lines - for _ = 1, 100 do - if max <= min then - local line = lines[min] - return min, offset - line.start - end - local row = (max - min) // 2 + min - local line = lines[row] - if offset < line.start then - max = row - 1 - elseif offset >= line.finish then - min = row + 1 - else - return row, offset - line.start - end - end - error('Stack overflow!') +--- 将 position 拆分成行号与列号 +--- +--- 第一行是0 +---@param position integer +---@return integer row +---@return integer col +function m.positionOf(position) + return position // 10000, position % 10000 end ---- 获取坐标对应的光标偏移。 ---- 一定会落在当前行的换行符左侧。 ---- 第一行的行号是1不是0。 ----@param lines table +--- 将行列合并为 position +--- +--- 第一行是0 ---@param row integer ---@param col integer ----@return integer {name = 'offset'} -function m.offsetOf(lines, row, col) - if row < 1 then - return 0 - end - if row > #lines then - local lastLine = lines[#lines] - return lastLine.finish - end - local line = lines[row] - local len = line.range - line.start - if col < 0 then - return line.start - elseif col > len then - return line.range - else - return line.start + col - end +---@return integer +function m.offsetOf(row, col) + return row * 10000 + col end function m.lineContent(lines, text, row, ignoreNL) diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 26341571..533aa9db 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -635,7 +635,7 @@ function parseType(parent) result.finish = getFinish() result.firstFinish = result.finish - local row = guide.positionOf(Lines, result.finish) + local row = guide.positionOf(result.finish) local function pushResume() local comments @@ -1178,8 +1178,8 @@ end local function isTailComment(lns, text, binded, doc) local lastDoc = binded[#binded] - local lastDocStartRow = guide.positionOf(lns, lastDoc.originalComment.start) - local lastDocStartLineData = guide.lineData(lns, lastDocStartRow) + local lastDocStartRow = guide.positionOf(lastDoc.originalComment.start) + local lastDocStartLineData = guide.lineData(lastDocStartRow) if haveCodeBeforeDocInCurLine(text, lastDocStartLineData, lastDoc.originalComment.start) then return true end @@ -1191,8 +1191,8 @@ local function isNextLine(lns, text, binded, doc) return false end local lastDoc = binded[#binded] - local lastRow = guide.positionOf(lns, lastDoc.finish) - local newRow = guide.positionOf(lns, doc.start) + local lastRow = guide.positionOf(lastDoc.finish) + local newRow = guide.positionOf(doc.start) return newRow - lastRow == 1 end @@ -1332,7 +1332,7 @@ local function bindDoc(sources, lns, binded) doc.bindSources = bindSources end bindGeneric(binded) - local row = guide.positionOf(lns, lastDoc.finish) + local row = guide.positionOf(lastDoc.finish) local cstart, cfinish = guide.lineRange(lns, row) local nstart, nfinish = guide.lineRange(lns, row + 1) bindDocsBetween(sources, binded, bindSources, cstart, cfinish) diff --git a/script/vm/getDocs.lua b/script/vm/getDocs.lua index c0205654..5fcf9478 100644 --- a/script/vm/getDocs.lua +++ b/script/vm/getDocs.lua @@ -186,7 +186,7 @@ local function makeDiagRange(uri, doc, results) names[name] = true end end - local row = guide.positionOf(lines, doc.start) + local row = guide.positionOf(doc.start) if doc.mode == 'disable-next-line' then if lines[row+1] then results[#results+1] = { -- cgit v1.2.3 From 6fddbbf0b34729327670ac1687d88b38739e12a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Tue, 14 Sep 2021 21:04:50 +0800 Subject: update --- script/parser/newparser.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'script') diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index e1d98d87..16bcd6a0 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -1589,7 +1589,7 @@ local function parseSimple(node, funcName) field = field } if field then - field.parent = node + field.parent = getfield field.type = 'field' else pushError { @@ -1619,7 +1619,7 @@ local function parseSimple(node, funcName) method = method } if method then - method.parent = node + method.parent = getmethod method.type = 'method' else pushError { @@ -3462,9 +3462,9 @@ local function parseLua() pushChunk(main) createLocal{ type = 'local', - start = 0, - finish = 0, - effect = 0, + start = -1, + finish = -1, + effect = -1, parent = main, tag = '_ENV', special= '_G', -- cgit v1.2.3 From 8880b7d63931469c0b7bfb69004f342236ce2811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 15 Sep 2021 16:11:30 +0800 Subject: cleanup --- script/core/code-action.lua | 2 +- script/core/completion.lua | 2 +- script/core/diagnostics/newfield-call.lua | 4 +-- script/core/diagnostics/newline-call.lua | 4 +-- script/core/keyword.lua | 4 +-- script/core/type-formatting.lua | 2 +- script/files.lua | 2 +- script/parser/guide.lua | 4 +-- script/parser/luadoc.lua | 42 ++++++++++++++----------------- script/parser/newparser.lua | 7 +++++- script/vm/getDocs.lua | 2 +- 11 files changed, 38 insertions(+), 37 deletions(-) (limited to 'script') diff --git a/script/core/code-action.lua b/script/core/code-action.lua index 1bac9359..922ebff3 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -57,7 +57,7 @@ end local function disableDiagnostic(uri, code, start, results) local lines = files.getLines(uri) - local row = guide.positionOf(start) + local row = guide.rowColOf(start) results[#results+1] = { title = lang.script('ACTION_DISABLE_DIAG', code), kind = 'quickfix', diff --git a/script/core/completion.lua b/script/core/completion.lua index 59dc19f3..1b64bef1 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -176,7 +176,7 @@ local function getSnip(source) if vm.isMetaFile(uri) then goto CONTINUE end - local row = guide.positionOf(def.start) + local row = guide.rowColOf(def.start) local firstRow = lines[row] local lastRow = lines[math.min(row + context - 1, #lines)] local snip = text:sub(firstRow.start, lastRow.finish) diff --git a/script/core/diagnostics/newfield-call.lua b/script/core/diagnostics/newfield-call.lua index 61d52dd2..83d205ca 100644 --- a/script/core/diagnostics/newfield-call.lua +++ b/script/core/diagnostics/newfield-call.lua @@ -27,8 +27,8 @@ return function (uri, callback) local func = call.node local args = call.args if args then - local funcLine = guide.positionOf(func.finish) - local argsLine = guide.positionOf(args.start) + local funcLine = guide.rowColOf(func.finish) + local argsLine = guide.rowColOf(args.start) if argsLine > funcLine then callback { start = call.start, diff --git a/script/core/diagnostics/newline-call.lua b/script/core/diagnostics/newline-call.lua index 69bf948f..1c31fa8d 100644 --- a/script/core/diagnostics/newline-call.lua +++ b/script/core/diagnostics/newline-call.lua @@ -26,8 +26,8 @@ return function (uri, callback) return end - local nodeRow = guide.positionOf(node.finish) - local argRow = guide.positionOf(args.start) + local nodeRow = guide.rowColOf(node.finish) + local argRow = guide.rowColOf(args.start) if nodeRow == argRow then return end diff --git a/script/core/keyword.lua b/script/core/keyword.lua index 4b43efe5..8e041f1c 100644 --- a/script/core/keyword.lua +++ b/script/core/keyword.lua @@ -275,8 +275,8 @@ until $1" if first == 'end' or first == 'else' or first == 'elseif' then - local startRow = guide.positionOf(info.start) - local finishRow = guide.positionOf(pos) + local startRow = guide.rowColOf(info.start) + local finishRow = guide.rowColOf(pos) local startSp = info.text:match('^%s*', lines[startRow].start + 1) local finishSp = info.text:match('^%s*', lines[finishRow].start + 1) if startSp == finishSp then diff --git a/script/core/type-formatting.lua b/script/core/type-formatting.lua index 12272f11..157a446d 100644 --- a/script/core/type-formatting.lua +++ b/script/core/type-formatting.lua @@ -5,7 +5,7 @@ local guide = require "parser.guide" local function insertIndentation(uri, offset, edits) local lines = files.getLines(uri) local text = files.getOriginText(uri) - local row = guide.positionOf(offset) + local row = guide.rowColOf(offset) local line = lines[row] local indent = text:sub(line.start, line.finish):match '^%s*' for _, edit in ipairs(edits) do diff --git a/script/files.lua b/script/files.lua index 0e62a740..98d9b83c 100644 --- a/script/files.lua +++ b/script/files.lua @@ -744,7 +744,7 @@ function m.position(uri, offset, leftOrRight) lines = m.getOriginLines(uri) text = m.getOriginText(uri) end - local row, col = guide.positionOf(offset) + local row, col = guide.rowColOf(offset) local start, finish = guide.lineRange(lines, row, true) start = start + 1 if col <= finish - start + 1 then diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 941fc7b1..14e19094 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -743,7 +743,7 @@ end ---@param position integer ---@return integer row ---@return integer col -function m.positionOf(position) +function m.rowColOf(position) return position // 10000, position % 10000 end @@ -753,7 +753,7 @@ end ---@param row integer ---@param col integer ---@return integer -function m.offsetOf(row, col) +function m.positionOf(row, col) return row * 10000 + col end diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 533aa9db..548539a9 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -1,11 +1,10 @@ local m = require 'lpeglabel' local re = require 'parser.relabel' -local lines = require 'parser.lines' local guide = require 'parser.guide' local grammar = require 'parser.grammar' local TokenTypes, TokenStarts, TokenFinishs, TokenContents -local Ci, Offset, pushError, Ct, NextComment, Lines +local Ci, Offset, pushError, NextComment local parseType local Parser = re.compile([[ Main <- (Token / Sp)* @@ -635,7 +634,7 @@ function parseType(parent) result.finish = getFinish() result.firstFinish = result.finish - local row = guide.positionOf(result.finish) + local row = guide.rowColOf(result.finish) local function pushResume() local comments @@ -644,8 +643,9 @@ function parseType(parent) if not nextComm then return false end - local line = Lines[row + i + 1] - if not line or line.finish < nextComm.start then + local nextCommRow = guide.rowColOf(nextComm.start) + local currentRow = row + i + 1 + if currentRow > nextCommRow then return false end if nextComm.text:sub(1, 2) == '-@' then @@ -1176,9 +1176,9 @@ local function haveCodeBeforeDocInCurLine(text, lineData, docStart) return text:sub(lineData.start + 1, docStart - 1):find '[%w_]' end -local function isTailComment(lns, text, binded, doc) +local function isTailComment(text, binded) local lastDoc = binded[#binded] - local lastDocStartRow = guide.positionOf(lastDoc.originalComment.start) + local lastDocStartRow = guide.rowColOf(lastDoc.originalComment.start) local lastDocStartLineData = guide.lineData(lastDocStartRow) if haveCodeBeforeDocInCurLine(text, lastDocStartLineData, lastDoc.originalComment.start) then return true @@ -1186,13 +1186,13 @@ local function isTailComment(lns, text, binded, doc) return false end -local function isNextLine(lns, text, binded, doc) +local function isNextLine(binded, doc) if not binded then return false end local lastDoc = binded[#binded] - local lastRow = guide.positionOf(lastDoc.finish) - local newRow = guide.positionOf(doc.start) + local lastRow = guide.rowColOf(lastDoc.finish) + local newRow = guide.rowColOf(doc.start) return newRow - lastRow == 1 end @@ -1318,7 +1318,7 @@ local function bindClassAndFields(binded) end end -local function bindDoc(sources, lns, binded) +local function bindDoc(sources, binded) if not binded then return end @@ -1332,12 +1332,10 @@ local function bindDoc(sources, lns, binded) doc.bindSources = bindSources end bindGeneric(binded) - local row = guide.positionOf(lastDoc.finish) - local cstart, cfinish = guide.lineRange(lns, row) - local nstart, nfinish = guide.lineRange(lns, row + 1) - bindDocsBetween(sources, binded, bindSources, cstart, cfinish) + local row = guide.rowColOf(lastDoc.finish) + bindDocsBetween(sources, binded, bindSources, guide.positionOf(row, 0), lastDoc.start) if #bindSources == 0 then - bindDocsBetween(sources, binded, bindSources, nstart, nfinish) + bindDocsBetween(sources, binded, bindSources, guide.positionOf(row + 1, 0), guide.positionOf(row + 2, 0)) end bindParamAndReturnIndex(binded) bindClassAndFields(binded) @@ -1361,18 +1359,18 @@ local function bindDocs(state) end) local binded for _, doc in ipairs(state.ast.docs) do - if not isNextLine(Lines, text, binded, doc) then - bindDoc(sources, Lines, binded) + if not isNextLine(binded, doc) then + bindDoc(sources, binded) binded = {} state.ast.docs.groups[#state.ast.docs.groups+1] = binded end binded[#binded+1] = doc - if isTailComment(Lines, text, binded, doc) then - bindDoc(sources, Lines, binded) + if isTailComment(text, binded) then + bindDoc(sources, binded) binded = nil end end - bindDoc(sources, Lines, binded) + bindDoc(sources, binded) end return function (state) @@ -1389,8 +1387,6 @@ return function (state) pushError = state.pushError - Lines = lines(state.lua) - local ci = 1 NextComment = function (offset, peek) local comment = comments[ci + (offset or 0)] diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 16bcd6a0..0137397d 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -361,6 +361,7 @@ local function skipNL() Line = Line + 1 LineOffset = Tokens[Index] + #token Index = Index + 2 + State.lines[Line] = LineOffset return true end return false @@ -392,8 +393,11 @@ local function resolveLongString(finishMark) local result, count = stringResult : gsub('\r\n', '\n') : gsub('[\r\n]', '\n') - Line = Line + count LineOffset = lastLN + start + for i = Line + 1, Line + count do + State.lines[i] = LineOffset + end + Line = Line + count stringResult = result end fastForwardToken(finishOffset + #finishMark) @@ -3503,6 +3507,7 @@ local function initState(lua, version, options) errs = {}, diags = {}, comms = {}, + lines = {}, options = options or {}, } if version == 'Lua 5.1' or version == 'LuaJIT' then diff --git a/script/vm/getDocs.lua b/script/vm/getDocs.lua index 5fcf9478..218dc048 100644 --- a/script/vm/getDocs.lua +++ b/script/vm/getDocs.lua @@ -186,7 +186,7 @@ local function makeDiagRange(uri, doc, results) names[name] = true end end - local row = guide.positionOf(doc.start) + local row = guide.rowColOf(doc.start) if doc.mode == 'disable-next-line' then if lines[row+1] then results[#results+1] = { -- cgit v1.2.3 From 33eff2cb98efe8380513b1cc2712baab2be3c940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 15 Sep 2021 16:35:06 +0800 Subject: update --- script/parser/guide.lua | 4 ---- script/parser/luadoc.lua | 21 ++++++++------------- script/parser/newparser.lua | 23 +++++++++++++++++++++-- 3 files changed, 29 insertions(+), 19 deletions(-) (limited to 'script') diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 14e19094..16ee3e30 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -781,10 +781,6 @@ function m.lineRange(lines, row, ignoreNL) end end -function m.lineData(lines, row) - return lines[row] -end - local isSetMap = { ['setglobal'] = true, ['local'] = true, diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 548539a9..10694918 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -4,7 +4,7 @@ local guide = require 'parser.guide' local grammar = require 'parser.grammar' local TokenTypes, TokenStarts, TokenFinishs, TokenContents -local Ci, Offset, pushError, NextComment +local Ci, Offset, pushError, NextComment, Lines local parseType local Parser = re.compile([[ Main <- (Token / Sp)* @@ -1171,19 +1171,13 @@ local function buildLuaDoc(comment) } end ----当前行在注释doc前是否有代码 -local function haveCodeBeforeDocInCurLine(text, lineData, docStart) - return text:sub(lineData.start + 1, docStart - 1):find '[%w_]' -end - local function isTailComment(text, binded) - local lastDoc = binded[#binded] - local lastDocStartRow = guide.rowColOf(lastDoc.originalComment.start) - local lastDocStartLineData = guide.lineData(lastDocStartRow) - if haveCodeBeforeDocInCurLine(text, lastDocStartLineData, lastDoc.originalComment.start) then - return true - end - return false + local lastDoc = binded[#binded] + local left = lastDoc.originalComment.start + local row, col = guide.rowColOf(left) + local lineStart = Lines[row] or 0 + local hasCodeBefore = text:sub(lineStart, lineStart + col):find '[%w_]' + return hasCodeBefore end local function isNextLine(binded, doc) @@ -1386,6 +1380,7 @@ return function (state) } pushError = state.pushError + Lines = state.lines local ci = 1 NextComment = function (offset, peek) diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 0137397d..201ca0aa 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -488,13 +488,19 @@ local function skipComment(isAction) local token = Tokens[Index + 1] if token == '--' or (token == '//' and isAction) then - local left = getPosition(Tokens[Index], 'left') + local start = Tokens[Index] + local left = getPosition(start, 'left') if token == '//' then pushCommentHeadError(left) end Index = Index + 2 local longComment = parseLongString() if longComment then + longComment.type = 'comment.long' + longComment.text = longComment[1] + longComment[1] = nil + longComment[2] = nil + State.comms[#State.comms+1] = longComment return true end while true do @@ -504,13 +510,26 @@ local function skipComment(isAction) end Index = Index + 2 end + State.comms[#State.comms+1] = { + type = 'comment.shot', + start = left, + finish = getPosition(Tokens[Index], 'right'), + text = ssub(start, Tokens[Index] or #Lua), + } return true end if token == '/*' then - local left = getPosition(Tokens[Index], 'left') + local start = Tokens[Index] + local left = getPosition(start, 'left') Index = Index + 2 local result, right = resolveLongString '*/' pushLongCommentError(left, right) + State.comms[#State.comms+1] = { + type = 'comment.long', + start = left, + finish = right, + text = result, + } return true end return false -- cgit v1.2.3 From c90f0680d1892eec6f02f8ea1970ead54ffa69f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 15 Sep 2021 16:59:24 +0800 Subject: update --- script/parser/luadoc.lua | 111 ++++++++++++++++++++++---------------------- script/parser/newparser.lua | 2 +- 2 files changed, 56 insertions(+), 57 deletions(-) (limited to 'script') diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 10694918..3a50f0b8 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -120,7 +120,6 @@ local function trim(str) end local function parseTokens(text, offset) - Ct = offset Ci = 0 Offset = offset TokenTypes = {} @@ -183,7 +182,7 @@ local function parseName(tp, parent) local class = { type = tp, start = getStart(), - finish = getFinish(), + finish = getFinish() + 1, parent = parent, [1] = nameText, } @@ -243,12 +242,12 @@ local function parseClass(parent) pushError { type = 'LUADOC_MISS_CLASS_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end result.start = getStart() - result.finish = getFinish() + result.finish = getFinish() + 1 if not peekToken() then return result end @@ -256,7 +255,7 @@ local function parseClass(parent) pushError { type = 'LUADOC_MISS_EXTENDS_SYMBOL', start = result.finish + 1, - finish = getStart() - 1, + finish = getStart(), } return result end @@ -270,12 +269,12 @@ local function parseClass(parent) pushError { type = 'LUADOC_MISS_CLASS_EXTENDS_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return result end result.extends[#result.extends+1] = extend - result.finish = getFinish() + result.finish = getFinish() + 1 if not checkToken('symbol', ',', 1) then break end @@ -292,7 +291,7 @@ local function parseTypeUnitArray(parent, node) local result = { type = 'doc.type.array', start = node.start, - finish = getFinish(), + finish = getFinish() + 1, node = node, parent = parent, } @@ -326,7 +325,7 @@ local function parseTypeUnitTable(parent, node) nextSymbolOrError('>') node.parent = result; - result.finish = getFinish() + result.finish = getFinish() + 1 result.tkey = key result.tvalue = value @@ -357,7 +356,7 @@ local function parseTypeUnitFunction() local vararg = { type = 'doc.type.name', start = getStart(), - finish = getFinish(), + finish = getFinish() + 1, parent = arg, [1] = '...', } @@ -365,14 +364,14 @@ local function parseTypeUnitFunction() if not arg.start then arg.start = arg.name.start end - arg.finish = getFinish() + arg.finish = getFinish() + 1 else arg.name = parseName('doc.type.name', arg) if not arg.name then pushError { type = 'LUADOC_MISS_ARG_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } break end @@ -383,7 +382,7 @@ local function parseTypeUnitFunction() nextToken() arg.optional = true end - arg.finish = getFinish() + arg.finish = getFinish() + 1 if not nextSymbolOrError(':') then break end @@ -391,7 +390,7 @@ local function parseTypeUnitFunction() if not arg.extends then break end - arg.finish = getFinish() + arg.finish = getFinish() + 1 end typeUnit.args[#typeUnit.args+1] = arg if checkToken('symbol', ',', 1) then @@ -420,7 +419,7 @@ local function parseTypeUnitFunction() end end end - typeUnit.finish = getFinish() + typeUnit.finish = getFinish() + 1 return typeUnit end @@ -448,7 +447,7 @@ local function parseTypeUnitLiteralTable() pushError { type = 'LUADOC_MISS_FIELD_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } break end @@ -459,7 +458,7 @@ local function parseTypeUnitLiteralTable() nextToken() field.optional = true end - field.finish = getFinish() + field.finish = getFinish() + 1 if not nextSymbolOrError(':') then break end @@ -467,7 +466,7 @@ local function parseTypeUnitLiteralTable() if not field.extends then break end - field.finish = getFinish() + field.finish = getFinish() + 1 end typeUnit.fields[#typeUnit.fields+1] = field @@ -478,7 +477,7 @@ local function parseTypeUnitLiteralTable() break end end - typeUnit.finish = getFinish() + typeUnit.finish = getFinish() + 1 return typeUnit end @@ -494,7 +493,7 @@ local function parseTypeUnit(parent, content) result = { type = 'doc.type.name', start = getStart(), - finish = getFinish(), + finish = getFinish() + 1, [1] = content, } end @@ -534,14 +533,14 @@ local function parseResume(parent) pushError { type = 'LUADOC_MISS_STRING', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end local _, str = nextToken() result[1] = str result.start = getStart() - result.finish = getFinish() + result.finish = getFinish() + 1 return result end @@ -594,7 +593,7 @@ function parseType(parent) local typeEnum = { type = 'doc.type.enum', start = getStart(), - finish = getFinish(), + finish = getFinish() + 1, parent = result, [1] = content, } @@ -617,7 +616,7 @@ function parseType(parent) local vararg = { type = 'doc.type.name', start = getStart(), - finish = getFinish(), + finish = getFinish() + 1, parent = result, [1] = content, } @@ -631,7 +630,7 @@ function parseType(parent) end nextToken() end - result.finish = getFinish() + result.finish = getFinish() + 1 result.firstFinish = result.finish local row = guide.rowColOf(result.finish) @@ -655,7 +654,7 @@ function parseType(parent) NextComment(i) row = row + i + 1 local finishPos = nextComm.text:find('#', 3) or #nextComm.text - parseTokens(nextComm.text:sub(3, finishPos), nextComm.start + 1) + parseTokens(nextComm.text:sub(3, finishPos), nextComm.start + 3) local resume = parseResume(result) if resume then if comments then @@ -699,7 +698,7 @@ function parseType(parent) pushError { type = 'LUADOC_MISS_TYPE_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end @@ -715,7 +714,7 @@ local function parseAlias() pushError { type = 'LUADOC_MISS_ALIAS_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end @@ -725,11 +724,11 @@ local function parseAlias() pushError { type = 'LUADOC_MISS_ALIAS_EXTENDS', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end - result.finish = getFinish() + result.finish = getFinish() + 1 return result end @@ -742,7 +741,7 @@ local function parseParam() pushError { type = 'LUADOC_MISS_PARAM_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end @@ -751,17 +750,17 @@ local function parseParam() result.optional = true end result.start = result.param.start - result.finish = getFinish() + result.finish = getFinish() + 1 result.extends = parseType(result) if not result.extends then pushError { type = 'LUADOC_MISS_PARAM_EXTENDS', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return result end - result.finish = getFinish() + result.finish = getFinish() + 1 result.firstFinish = result.extends.firstFinish return result end @@ -793,7 +792,7 @@ local function parseReturn() if #result.returns == 0 then return nil end - result.finish = getFinish() + result.finish = getFinish() + 1 return result end @@ -820,7 +819,7 @@ local function parseField() pushError { type = 'LUADOC_MISS_FIELD_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end @@ -836,11 +835,11 @@ local function parseField() pushError { type = 'LUADOC_MISS_FIELD_EXTENDS', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end - result.finish = getFinish() + result.finish = getFinish() + 1 return result end @@ -859,7 +858,7 @@ local function parseGeneric() pushError { type = 'LUADOC_MISS_GENERIC_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end @@ -871,14 +870,14 @@ local function parseGeneric() nextToken() object.extends = parseType(object) end - object.finish = getFinish() + object.finish = getFinish() + 1 result.generics[#result.generics+1] = object if not checkToken('symbol', ',', 1) then break end nextToken() end - result.finish = getFinish() + result.finish = getFinish() + 1 return result end @@ -891,7 +890,7 @@ local function parseVararg() pushError { type = 'LUADOC_MISS_VARARG_TYPE', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return end @@ -906,7 +905,7 @@ local function parseOverload() pushError { type = 'LUADOC_MISS_FUN_AFTER_OVERLOAD', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end @@ -928,7 +927,7 @@ local function parseDeprecated() return { type = 'doc.deprecated', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } end @@ -936,7 +935,7 @@ local function parseMeta() return { type = 'doc.meta', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } end @@ -951,7 +950,7 @@ local function parseVersion() pushError { type = 'LUADOC_MISS_VERSION', start = getStart(), - finish = getFinish(), + finish = getFinish() + 1, } break end @@ -974,12 +973,12 @@ local function parseVersion() pushError { type = 'LUADOC_MISS_VERSION', start = getStart(), - finish = getFinish(), + finish = getFinish() + 1, } break end version.version = tonumber(text) or text - version.finish = getFinish() + version.finish = getFinish() + 1 result.versions[#result.versions+1] = version if not checkToken('symbol', ',', 1) then break @@ -989,7 +988,7 @@ local function parseVersion() if #result.versions == 0 then return nil end - result.finish = getFinish() + result.finish = getFinish() + 1 return result end @@ -1006,7 +1005,7 @@ local function parseSee() if checkToken('symbol', '#', 1) then nextToken() result.field = parseName('doc.see.field', result) - result.finish = getFinish() + result.finish = getFinish() + 1 end return result end @@ -1020,13 +1019,13 @@ local function parseDiagnostic() pushError { type = 'LUADOC_MISS_DIAG_MODE', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end result.mode = mode result.start = getStart() - result.finish = getFinish() + result.finish = getFinish() + 1 if mode ~= 'disable-next-line' and mode ~= 'disable-line' and mode ~= 'disable' @@ -1047,7 +1046,7 @@ local function parseDiagnostic() pushError { type = 'LUADOC_MISS_DIAG_NAME', start = getFinish(), - finish = getFinish(), + finish = getFinish() + 1, } return result end @@ -1059,7 +1058,7 @@ local function parseDiagnostic() end end - result.finish = getFinish() + result.finish = getFinish() + 1 return result end @@ -1073,7 +1072,7 @@ local function convertTokens() pushError { type = 'LUADOC_MISS_CATE_NAME', start = getStart(), - finish = getFinish(), + finish = getFinish() + 1, } return nil end @@ -1143,7 +1142,7 @@ local function buildLuaDoc(comment) local doc = text:sub(startPos + 1) - parseTokens(doc, comment.start + startPos - 1) + parseTokens(doc, comment.start + startPos + 1) local result = convertTokens() if result then result.range = comment.finish diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 201ca0aa..9034480e 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -514,7 +514,7 @@ local function skipComment(isAction) type = 'comment.shot', start = left, finish = getPosition(Tokens[Index], 'right'), - text = ssub(start, Tokens[Index] or #Lua), + text = ssub(Lua, start + 2, Tokens[Index] and (Tokens[Index] - 1) or #Lua), } return true end -- cgit v1.2.3 From e70f82c0534c8973b3ad809a5ad72919412a832b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 15 Sep 2021 20:24:38 +0800 Subject: update --- script/parser/newparser.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'script') diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 9034480e..9e8e5b94 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -1405,7 +1405,10 @@ local function parseExpList(mini) end local nextToken = peekWord() if isKeyWord(nextToken) - and nextToken ~= 'function' then + and nextToken ~= 'function' + and nextToken ~= 'true' + and nextToken ~= 'false' + and nextToken ~= 'nil' then break end end -- cgit v1.2.3 From 03444fe030383163b35fcd8c557bccd31aeebe5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 15 Sep 2021 21:40:16 +0800 Subject: update --- script/parser/guide.lua | 2 +- script/parser/luadoc.lua | 2 +- script/parser/newparser.lua | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'script') diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 16ee3e30..be1305a3 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -92,7 +92,7 @@ local childMap = { ['main'] = {'#', 'docs'}, ['repeat'] = {'#', 'filter'}, ['while'] = {'filter', '#'}, - ['in'] = {'keys', '#'}, + ['in'] = {'keys', 'exps', '#'}, ['loop'] = {'loc', 'max', 'step', '#'}, ['if'] = {'#'}, ['ifblock'] = {'filter', '#'}, diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 3a50f0b8..314e8e51 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -1238,7 +1238,7 @@ local function bindDocsBetween(sources, binded, bindSources, start, finish) for i = index, max do local src = sources[i] if src and src.start >= start then - if src.start > finish then + if src.start >= finish then break end -- 遇到table后中断,处理以下情况: diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 9e8e5b94..0e12ab45 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -1905,6 +1905,9 @@ local function resolveName(node) loc.ref = {} end loc.ref[#loc.ref+1] = node + if loc.special then + addSpecial(loc.special, node) + end else node.type = 'getglobal' local env = getLocal(State.ENVMode, node.start) @@ -2517,6 +2520,9 @@ end local function bindValue(n, v, index, lastValue, isLocal, isSet) if isLocal then n.effect = lastRightPosition() + if v and v.special then + addSpecial(v.special, n) + end elseif isSet then n.type = GetToSetMap[n.type] or n.type if n.type == 'setlocal' then -- cgit v1.2.3 From c3093ad8a0b6cded8f0ec5eab75469df3231a59e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 16 Sep 2021 20:01:22 +0800 Subject: stash --- script/core/noder.lua | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) (limited to 'script') diff --git a/script/core/noder.lua b/script/core/noder.lua index 3fd316eb..80d1774c 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -379,7 +379,7 @@ local getKeyMap = util.switch() end) : case 'generic.closure' : call(function (source) - return 'gc:' .. source.call.start, nil + return 'gc:' .. source.call.finish, nil end) : case 'generic.value' : call(function (source) @@ -388,7 +388,7 @@ local getKeyMap = util.switch() tail = URI_CHAR .. guide.getUri(source.closure.call) end return sformat('gv:%s|%s%s' - , source.closure.call.start + , source.closure.call.finish , getKey(source.proto) , tail ) @@ -1231,6 +1231,58 @@ compileNodeMap = util.switch() end end end) + : case 'in' + : call(function (noders, id, source) + local keys = source.keys + local exps = source.exps + if not keys or not exps then + return + end + local node = exps[1] + local param1 = exps[2] + local param2 = exps[3] + local nodeID = getID(node) + local param1ID = getID(param1) + local param2ID = getID(param2) + if node.type == 'call' then + if not param1ID then + param1ID = sformat('%s%s%s' + , nodeID + , RETURN_INDEX + , 2 + ) + if not param2ID then + param2ID = sformat('%s%s%s' + , nodeID + , RETURN_INDEX + , 3 + ) + end + end + end + local call = { + type = 'dummy', + _id = 'c:' .. source.keyword[3], + finish = source.finish, + node = { + type = 'dummy', + _id = nodeID, + }, + args = { + [1] = { + type = 'dummy', + _id = param1ID, + }, + [2] = { + type = 'dummy', + _id = param2ID, + } + } + } + for i = 1, #keys do + compileCallReturn(noders, call, getID(keys[i]), i) + end + end) : case 'main' : call(function (noders, id, source) if source.returns then -- cgit v1.2.3 From 5256606b6f0a76beb5bc062eae3c0b93f7e11f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 16 Sep 2021 20:52:19 +0800 Subject: stash --- script/core/noder.lua | 60 ++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 34 deletions(-) (limited to 'script') diff --git a/script/core/noder.lua b/script/core/noder.lua index 80d1774c..749dcba6 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -379,7 +379,7 @@ local getKeyMap = util.switch() end) : case 'generic.closure' : call(function (source) - return 'gc:' .. source.call.finish, nil + return 'gc:' .. source.call.start, nil end) : case 'generic.value' : call(function (source) @@ -388,7 +388,7 @@ local getKeyMap = util.switch() tail = URI_CHAR .. guide.getUri(source.closure.call) end return sformat('gv:%s|%s%s' - , source.closure.call.finish + , source.closure.call.start , getKey(source.proto) , tail ) @@ -1241,43 +1241,35 @@ compileNodeMap = util.switch() local node = exps[1] local param1 = exps[2] local param2 = exps[3] - local nodeID = getID(node) - local param1ID = getID(param1) - local param2ID = getID(param2) if node.type == 'call' then - if not param1ID then - param1ID = sformat('%s%s%s' - , nodeID - , RETURN_INDEX - , 2 - ) - if not param2ID then - param2ID = sformat('%s%s%s' - , nodeID - , RETURN_INDEX - , 3 - ) + if not param1 then + param1 = { + type = 'select', + sindex = 2, + start = node.start, + finish = node.finish, + vararg = node, + } + compileCallReturn(noders, node, getID(param1), 2) + if not param2 then + param2 = { + type = 'select', + sindex = 2, + start = node.start, + finish = node.finish, + vararg = node, + } + compileCallReturn(noders, node, getID(param2), 3) end end end local call = { - type = 'dummy', - _id = 'c:' .. source.keyword[3], - finish = source.finish, - node = { - type = 'dummy', - _id = nodeID, - }, - args = { - [1] = { - type = 'dummy', - _id = param1ID, - }, - [2] = { - type = 'dummy', - _id = param2ID, - } - } + type = 'call', + dummy = true, + start = source.keyword[3], + finish = source.keyword[6], + node = node, + args = { param1, param2 } } for i = 1, #keys do compileCallReturn(noders, call, getID(keys[i]), i) -- cgit v1.2.3 From e1c72093b28cd08bc4a1b4a26dffd395651ca072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 16 Sep 2021 21:44:24 +0800 Subject: fix --- script/core/noder.lua | 2 ++ script/parser/luadoc.lua | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'script') diff --git a/script/core/noder.lua b/script/core/noder.lua index 749dcba6..3aad105e 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -1245,6 +1245,7 @@ compileNodeMap = util.switch() if not param1 then param1 = { type = 'select', + dummy = true, sindex = 2, start = node.start, finish = node.finish, @@ -1254,6 +1255,7 @@ compileNodeMap = util.switch() if not param2 then param2 = { type = 'select', + dummy = true, sindex = 2, start = node.start, finish = node.finish, diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 314e8e51..040bf4bb 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -552,7 +552,6 @@ function parseType(parent) enums = {}, resumes = {}, } - result.start = getStart() while true do local tp, content = peekToken() if not tp then @@ -630,6 +629,9 @@ function parseType(parent) end nextToken() end + if not result.start then + result.start = getFinish() + 1 + end result.finish = getFinish() + 1 result.firstFinish = result.finish @@ -697,7 +699,7 @@ function parseType(parent) if #result.types == 0 and #result.enums == 0 and #result.resumes == 0 then pushError { type = 'LUADOC_MISS_TYPE_NAME', - start = getFinish(), + start = getFinish() + 1, finish = getFinish() + 1, } return nil -- cgit v1.2.3 From cf9de80f4fa38e7a74ae115948cd7bb00ba984e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 16 Sep 2021 21:57:45 +0800 Subject: fix --- script/core/noder.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'script') diff --git a/script/core/noder.lua b/script/core/noder.lua index 3aad105e..52ab7731 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -1256,7 +1256,7 @@ compileNodeMap = util.switch() param2 = { type = 'select', dummy = true, - sindex = 2, + sindex = 3, start = node.start, finish = node.finish, vararg = node, -- cgit v1.2.3 From f2559d2f42f8357c49b13b5df3a72bf5d7418797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 16 Sep 2021 22:02:56 +0800 Subject: fix --- script/parser/luadoc.lua | 112 +++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 56 deletions(-) (limited to 'script') diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 040bf4bb..5cf32a54 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -160,7 +160,7 @@ local function getFinish() if Ci == 0 then return Offset end - return TokenFinishs[Ci] + Offset + return TokenFinishs[Ci] + Offset + 1 end local function try(callback) @@ -182,7 +182,7 @@ local function parseName(tp, parent) local class = { type = tp, start = getStart(), - finish = getFinish() + 1, + finish = getFinish(), parent = parent, [1] = nameText, } @@ -242,12 +242,12 @@ local function parseClass(parent) pushError { type = 'LUADOC_MISS_CLASS_NAME', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end result.start = getStart() - result.finish = getFinish() + 1 + result.finish = getFinish() if not peekToken() then return result end @@ -269,12 +269,12 @@ local function parseClass(parent) pushError { type = 'LUADOC_MISS_CLASS_EXTENDS_NAME', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return result end result.extends[#result.extends+1] = extend - result.finish = getFinish() + 1 + result.finish = getFinish() if not checkToken('symbol', ',', 1) then break end @@ -291,7 +291,7 @@ local function parseTypeUnitArray(parent, node) local result = { type = 'doc.type.array', start = node.start, - finish = getFinish() + 1, + finish = getFinish(), node = node, parent = parent, } @@ -325,7 +325,7 @@ local function parseTypeUnitTable(parent, node) nextSymbolOrError('>') node.parent = result; - result.finish = getFinish() + 1 + result.finish = getFinish() result.tkey = key result.tvalue = value @@ -356,7 +356,7 @@ local function parseTypeUnitFunction() local vararg = { type = 'doc.type.name', start = getStart(), - finish = getFinish() + 1, + finish = getFinish(), parent = arg, [1] = '...', } @@ -364,14 +364,14 @@ local function parseTypeUnitFunction() if not arg.start then arg.start = arg.name.start end - arg.finish = getFinish() + 1 + arg.finish = getFinish() else arg.name = parseName('doc.type.name', arg) if not arg.name then pushError { type = 'LUADOC_MISS_ARG_NAME', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } break end @@ -382,7 +382,7 @@ local function parseTypeUnitFunction() nextToken() arg.optional = true end - arg.finish = getFinish() + 1 + arg.finish = getFinish() if not nextSymbolOrError(':') then break end @@ -390,7 +390,7 @@ local function parseTypeUnitFunction() if not arg.extends then break end - arg.finish = getFinish() + 1 + arg.finish = getFinish() end typeUnit.args[#typeUnit.args+1] = arg if checkToken('symbol', ',', 1) then @@ -419,7 +419,7 @@ local function parseTypeUnitFunction() end end end - typeUnit.finish = getFinish() + 1 + typeUnit.finish = getFinish() return typeUnit end @@ -447,7 +447,7 @@ local function parseTypeUnitLiteralTable() pushError { type = 'LUADOC_MISS_FIELD_NAME', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } break end @@ -458,7 +458,7 @@ local function parseTypeUnitLiteralTable() nextToken() field.optional = true end - field.finish = getFinish() + 1 + field.finish = getFinish() if not nextSymbolOrError(':') then break end @@ -466,7 +466,7 @@ local function parseTypeUnitLiteralTable() if not field.extends then break end - field.finish = getFinish() + 1 + field.finish = getFinish() end typeUnit.fields[#typeUnit.fields+1] = field @@ -477,7 +477,7 @@ local function parseTypeUnitLiteralTable() break end end - typeUnit.finish = getFinish() + 1 + typeUnit.finish = getFinish() return typeUnit end @@ -493,7 +493,7 @@ local function parseTypeUnit(parent, content) result = { type = 'doc.type.name', start = getStart(), - finish = getFinish() + 1, + finish = getFinish(), [1] = content, } end @@ -533,14 +533,14 @@ local function parseResume(parent) pushError { type = 'LUADOC_MISS_STRING', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end local _, str = nextToken() result[1] = str result.start = getStart() - result.finish = getFinish() + 1 + result.finish = getFinish() return result end @@ -592,7 +592,7 @@ function parseType(parent) local typeEnum = { type = 'doc.type.enum', start = getStart(), - finish = getFinish() + 1, + finish = getFinish(), parent = result, [1] = content, } @@ -615,7 +615,7 @@ function parseType(parent) local vararg = { type = 'doc.type.name', start = getStart(), - finish = getFinish() + 1, + finish = getFinish(), parent = result, [1] = content, } @@ -630,9 +630,9 @@ function parseType(parent) nextToken() end if not result.start then - result.start = getFinish() + 1 + result.start = getFinish() end - result.finish = getFinish() + 1 + result.finish = getFinish() result.firstFinish = result.finish local row = guide.rowColOf(result.finish) @@ -699,8 +699,8 @@ function parseType(parent) if #result.types == 0 and #result.enums == 0 and #result.resumes == 0 then pushError { type = 'LUADOC_MISS_TYPE_NAME', - start = getFinish() + 1, - finish = getFinish() + 1, + start = getFinish(), + finish = getFinish(), } return nil end @@ -716,7 +716,7 @@ local function parseAlias() pushError { type = 'LUADOC_MISS_ALIAS_NAME', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end @@ -726,11 +726,11 @@ local function parseAlias() pushError { type = 'LUADOC_MISS_ALIAS_EXTENDS', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end - result.finish = getFinish() + 1 + result.finish = getFinish() return result end @@ -743,7 +743,7 @@ local function parseParam() pushError { type = 'LUADOC_MISS_PARAM_NAME', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end @@ -752,17 +752,17 @@ local function parseParam() result.optional = true end result.start = result.param.start - result.finish = getFinish() + 1 + result.finish = getFinish() result.extends = parseType(result) if not result.extends then pushError { type = 'LUADOC_MISS_PARAM_EXTENDS', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return result end - result.finish = getFinish() + 1 + result.finish = getFinish() result.firstFinish = result.extends.firstFinish return result end @@ -794,7 +794,7 @@ local function parseReturn() if #result.returns == 0 then return nil end - result.finish = getFinish() + 1 + result.finish = getFinish() return result end @@ -821,7 +821,7 @@ local function parseField() pushError { type = 'LUADOC_MISS_FIELD_NAME', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end @@ -837,11 +837,11 @@ local function parseField() pushError { type = 'LUADOC_MISS_FIELD_EXTENDS', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end - result.finish = getFinish() + 1 + result.finish = getFinish() return result end @@ -860,7 +860,7 @@ local function parseGeneric() pushError { type = 'LUADOC_MISS_GENERIC_NAME', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end @@ -872,14 +872,14 @@ local function parseGeneric() nextToken() object.extends = parseType(object) end - object.finish = getFinish() + 1 + object.finish = getFinish() result.generics[#result.generics+1] = object if not checkToken('symbol', ',', 1) then break end nextToken() end - result.finish = getFinish() + 1 + result.finish = getFinish() return result end @@ -892,7 +892,7 @@ local function parseVararg() pushError { type = 'LUADOC_MISS_VARARG_TYPE', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return end @@ -907,7 +907,7 @@ local function parseOverload() pushError { type = 'LUADOC_MISS_FUN_AFTER_OVERLOAD', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end @@ -929,7 +929,7 @@ local function parseDeprecated() return { type = 'doc.deprecated', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } end @@ -937,7 +937,7 @@ local function parseMeta() return { type = 'doc.meta', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } end @@ -951,8 +951,8 @@ local function parseVersion() if not tp then pushError { type = 'LUADOC_MISS_VERSION', - start = getStart(), - finish = getFinish() + 1, + start = getFinish(), + finish = getFinish(), } break end @@ -975,12 +975,12 @@ local function parseVersion() pushError { type = 'LUADOC_MISS_VERSION', start = getStart(), - finish = getFinish() + 1, + finish = getFinish(), } break end version.version = tonumber(text) or text - version.finish = getFinish() + 1 + version.finish = getFinish() result.versions[#result.versions+1] = version if not checkToken('symbol', ',', 1) then break @@ -990,7 +990,7 @@ local function parseVersion() if #result.versions == 0 then return nil end - result.finish = getFinish() + 1 + result.finish = getFinish() return result end @@ -1007,7 +1007,7 @@ local function parseSee() if checkToken('symbol', '#', 1) then nextToken() result.field = parseName('doc.see.field', result) - result.finish = getFinish() + 1 + result.finish = getFinish() end return result end @@ -1021,13 +1021,13 @@ local function parseDiagnostic() pushError { type = 'LUADOC_MISS_DIAG_MODE', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end result.mode = mode result.start = getStart() - result.finish = getFinish() + 1 + result.finish = getFinish() if mode ~= 'disable-next-line' and mode ~= 'disable-line' and mode ~= 'disable' @@ -1048,7 +1048,7 @@ local function parseDiagnostic() pushError { type = 'LUADOC_MISS_DIAG_NAME', start = getFinish(), - finish = getFinish() + 1, + finish = getFinish(), } return result end @@ -1060,7 +1060,7 @@ local function parseDiagnostic() end end - result.finish = getFinish() + 1 + result.finish = getFinish() return result end @@ -1074,7 +1074,7 @@ local function convertTokens() pushError { type = 'LUADOC_MISS_CATE_NAME', start = getStart(), - finish = getFinish() + 1, + finish = getFinish(), } return nil end -- cgit v1.2.3 From 31e9a5235cd17c8a61d2a0a732212cd68135bed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 17 Sep 2021 15:13:50 +0800 Subject: update --- script/parser/newparser.lua | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'script') diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 0e12ab45..9721526c 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -2340,17 +2340,26 @@ function parseExp(asAction, level) if uop then skipSpace() local child = parseExp(asAction, uopLevel) - exp = { - type = 'unary', - op = uop, - start = uop.start, - finish = child and child.finish or uop.finish, - [1] = child, - } - if child then - child.parent = exp + -- 预计算负数 + if uop.type == '-' + and child + and (child.type == 'number' or child.type == 'integer') then + child.start = uop.start + child[1] = - child[1] + exp = child else - missExp() + exp = { + type = 'unary', + op = uop, + start = uop.start, + finish = child and child.finish or uop.finish, + [1] = child, + } + if child then + child.parent = exp + else + missExp() + end end else exp = parseExpUnit() -- cgit v1.2.3 From bb5709481e7378901e8687beb7caac7521d48122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 17 Sep 2021 16:45:17 +0800 Subject: cleanup --- script/core/completion.lua | 380 +++++++++++++++++++++++---------------------- script/parser/guide.lua | 9 ++ 2 files changed, 200 insertions(+), 189 deletions(-) (limited to 'script') diff --git a/script/core/completion.lua b/script/core/completion.lua index 1b64bef1..83c26da5 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -53,17 +53,17 @@ local function trim(str) return str:match '^%s*(%S+)%s*$' end -local function findNearestSource(ast, offset) +local function findNearestSource(state, position) local source - guide.eachSourceContain(ast.ast, offset, function (src) + guide.eachSourceContain(state.ast, position, function (src) source = src end) return source end -local function findNearestTableField(ast, offset) +local function findNearestTableField(state, position) local source - guide.eachSourceContain(ast.ast, offset, function (src) + guide.eachSourceContain(state.ast, position, function (src) if src.type == 'table' or src.type == 'tablefield' or src.type == 'tableindex' @@ -74,8 +74,8 @@ local function findNearestTableField(ast, offset) return source end -local function findParent(ast, text, offset) - for i = offset, 1, -1 do +local function findParent(state, text, position) + for i = position, 1, -1 do local char = text:sub(i, i) if lookBackward.isSpace(char) then goto CONTINUE @@ -96,7 +96,7 @@ local function findParent(ast, text, offset) if not anyPos then return nil, nil end - local parent = guide.eachSourceContain(ast.ast, anyPos, function (source) + local parent = guide.eachSourceContain(state.ast, anyPos, function (source) if source.finish == anyPos then return source end @@ -109,9 +109,9 @@ local function findParent(ast, text, offset) return nil, nil end -local function findParentInStringIndex(ast, text, offset) +local function findParentInStringIndex(state, text, position) local near, nearStart - guide.eachSourceContain(ast.ast, offset, function (source) + guide.eachSourceContain(state.ast, position, function (source) local start = guide.getStartFinish(source) if not start then return @@ -222,8 +222,8 @@ local function buildFunction(results, source, value, oop, data) end end -local function buildInsertRequire(ast, targetUri, stemName) - local uri = guide.getUri(ast.ast) +local function buildInsertRequire(state, targetUri, stemName) + local uri = guide.getUri(state.ast) local lines = files.getLines(uri) local text = files.getText(uri) local start = 1 @@ -252,8 +252,8 @@ local function buildInsertRequire(ast, targetUri, stemName) } end -local function isSameSource(ast, source, pos) - if guide.getUri(source) ~= guide.getUri(ast.ast) then +local function isSameSource(state, source, pos) + if guide.getUri(source) ~= guide.getUri(state.ast) then return false end if source.type == 'field' @@ -283,10 +283,10 @@ local function getParams(func, oop) return '(' .. table.concat(args, ', ') .. ')' end -local function checkLocal(ast, word, offset, results) - local locals = guide.getVisibleLocals(ast.ast, offset) +local function checkLocal(state, word, position, results) + local locals = guide.getVisibleLocals(state.ast, position) for name, source in util.sortPairs(locals) do - if isSameSource(ast, source, offset) then + if isSameSource(state, source, position) then goto CONTINUE end if not matchKey(word, name) then @@ -330,13 +330,13 @@ local function checkLocal(ast, word, offset, results) end end -local function checkModule(ast, word, offset, results) +local function checkModule(state, word, position, results) if not config.get 'Lua.completion.autoRequire' then return end - local locals = guide.getVisibleLocals(ast.ast, offset) + local locals = guide.getVisibleLocals(state.ast, position) for uri in files.eachFile() do - if uri == guide.getUri(ast.ast) then + if uri == guide.getUri(state.ast) then goto CONTINUE end local path = furi.decode(uri) @@ -347,11 +347,11 @@ local function checkModule(ast, word, offset, results) and not config.get 'Lua.diagnostics.globals'[stemName] and stemName:match '^[%a_][%w_]*$' and matchKey(word, stemName) then - local targetAst = files.getState(uri) - if not targetAst then + local targetState = files.getState(uri) + if not targetState then goto CONTINUE end - local targetReturns = targetAst.ast.returns + local targetReturns = targetState.ast.returns if not targetReturns then goto CONTINUE end @@ -377,7 +377,7 @@ local function checkModule(ast, word, offset, results) command = 'lua.autoRequire:' .. sp:get_id(), arguments = { { - uri = guide.getUri(ast.ast), + uri = guide.getUri(state.ast), target = uri, name = stemName, }, @@ -393,7 +393,7 @@ local function checkModule(ast, word, offset, results) return { detail = buildDetail(targetSource), description = md, - --additionalTextEdits = buildInsertRequire(ast, originUri, stemName), + --additionalTextEdits = buildInsertRequire(state, originUri, stemName), } end) } @@ -402,7 +402,7 @@ local function checkModule(ast, word, offset, results) end end -local function checkFieldFromFieldToIndex(name, src, parent, word, start, offset) +local function checkFieldFromFieldToIndex(name, src, parent, word, start, position) if name:match '^[%a_][%w_]*$' then return nil end @@ -411,9 +411,9 @@ local function checkFieldFromFieldToIndex(name, src, parent, word, start, offset local text = files.getText(uri) local wordStart if word == '' then - wordStart = text:match('()%S', start + 1) or (offset + 1) + wordStart = text:match('()%S', start + 1) or (position + 1) else - wordStart = offset - #word + 1 + wordStart = position - #word + 1 end local newText if vm.getKeyType(src) == 'string' then @@ -423,7 +423,7 @@ local function checkFieldFromFieldToIndex(name, src, parent, word, start, offset end textEdit = { start = wordStart, - finish = offset, + finish = position, newText = newText, } local nxt = parent.next @@ -457,7 +457,7 @@ local function checkFieldFromFieldToIndex(name, src, parent, word, start, offset return textEdit, additionalTextEdits end -local function checkFieldThen(name, src, word, start, offset, parent, oop, results) +local function checkFieldThen(name, src, word, start, position, parent, oop, results) local value = searcher.getObjectValue(src) or src local kind = define.CompletionItemKind.Field if value.type == 'function' @@ -494,11 +494,11 @@ local function checkFieldThen(name, src, word, start, offset, parent, oop, resul local str = parent.next.index textEdit = { start = str.start + #str[2], - finish = offset, + finish = position, newText = name, } else - textEdit, additionalTextEdits = checkFieldFromFieldToIndex(name, src, parent, word, start, offset) + textEdit, additionalTextEdits = checkFieldFromFieldToIndex(name, src, parent, word, start, position) end results[#results+1] = { label = name, @@ -515,7 +515,7 @@ local function checkFieldThen(name, src, word, start, offset, parent, oop, resul } end -local function checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, results, locals, isGlobal) +local function checkFieldOfRefs(refs, state, word, start, position, parent, oop, results, locals, isGlobal) local fields = {} local funcs = {} local count = 0 @@ -524,7 +524,7 @@ local function checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, res if not name then goto CONTINUE end - if isSameSource(ast, src, start) then + if isSameSource(state, src, start) then goto CONTINUE end if isGlobal and locals and locals[name] then @@ -573,29 +573,29 @@ local function checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, res end for name, src in util.sortPairs(fields) do if src then - checkFieldThen(name, src, word, start, offset, parent, oop, results) + checkFieldThen(name, src, word, start, position, parent, oop, results) end end end -local function checkGlobal(ast, word, start, offset, parent, oop, results) - local locals = guide.getVisibleLocals(ast.ast, offset) +local function checkGlobal(state, word, start, position, parent, oop, results) + local locals = guide.getVisibleLocals(state.ast, position) local globals = vm.getGlobalSets '*' - checkFieldOfRefs(globals, ast, word, start, offset, parent, oop, results, locals, 'global') + checkFieldOfRefs(globals, state, word, start, position, parent, oop, results, locals, 'global') end -local function checkField(ast, word, start, offset, parent, oop, results) +local function checkField(state, word, start, position, parent, oop, results) if parent.tag == '_ENV' or parent.special == '_G' then local globals = vm.getGlobalSets '*' - checkFieldOfRefs(globals, ast, word, start, offset, parent, oop, results) + checkFieldOfRefs(globals, state, word, start, position, parent, oop, results) else local refs = vm.getRefs(parent, '*') - checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, results) + checkFieldOfRefs(refs, state, word, start, position, parent, oop, results) end end -local function checkTableField(ast, word, start, results) - local source = guide.eachSourceContain(ast.ast, start, function (source) +local function checkTableField(state, word, start, results) + local source = guide.eachSourceContain(state.ast, start, function (source) if source.start == start and source.parent and source.parent.type == 'table' then @@ -606,7 +606,7 @@ local function checkTableField(ast, word, start, results) return end local used = {} - guide.eachSourceType(ast.ast, 'tablefield', function (src) + guide.eachSourceType(state.ast, 'tablefield', function (src) if not src.field then return end @@ -623,7 +623,7 @@ local function checkTableField(ast, word, start, results) end) end -local function checkCommon(myUri, word, text, offset, results) +local function checkCommon(myUri, word, text, position, results) local showWord = config.get 'Lua.completion.showWord' if showWord == 'Disable' then return @@ -695,7 +695,7 @@ local function checkCommon(myUri, word, text, offset, results) if #results >= 100 then break end - if #str >= 3 and not used[str] and pos - 1 ~= offset then + if #str >= 3 and not used[str] and pos - 1 ~= position then used[str] = true if matchKey(word, str) then results[#results+1] = { @@ -710,26 +710,26 @@ local function checkCommon(myUri, word, text, offset, results) end end -local function isInString(ast, offset) - return guide.eachSourceContain(ast.ast, offset, function (source) +local function isInString(state, position) + return guide.eachSourceContain(state.ast, position, function (source) if source.type == 'string' then return true end end) end -local function checkKeyWord(ast, text, start, offset, word, hasSpace, afterLocal, results) +local function checkKeyWord(state, text, start, position, word, hasSpace, afterLocal, results) local snipType = config.get 'Lua.completion.keywordSnippet' - local symbol = lookBackward.findSymbol(text, start - 1) + local symbol = lookBackward.findSymbol(text, guide.offsetOf(state, start - 1)) local isExp = symbol == '(' or symbol == ',' or symbol == '=' local info = { hasSpace = hasSpace, isExp = isExp, text = text, start = start, - uri = guide.getUri(ast.ast), - offset = offset, - ast = ast, + uri = guide.getUri(state.ast), + position = position, + state = state, } for _, data in ipairs(keyWordMap) do local key = data[1] @@ -789,9 +789,9 @@ local function checkKeyWord(ast, text, start, offset, word, hasSpace, afterLocal end end -local function checkProvideLocal(ast, word, start, results) +local function checkProvideLocal(state, word, start, results) local block - guide.eachSourceContain(ast.ast, start, function (source) + guide.eachSourceContain(state.ast, start, function (source) if source.type == 'function' or source.type == 'main' then block = source @@ -825,8 +825,8 @@ local function checkProvideLocal(ast, word, start, results) end) end -local function checkFunctionArgByDocParam(ast, word, start, results) - local func = guide.eachSourceContain(ast.ast, start, function (source) +local function checkFunctionArgByDocParam(state, word, start, results) + local func = guide.eachSourceContain(state.ast, start, function (source) if source.type == 'function' then return source end @@ -876,10 +876,10 @@ local function isAfterLocal(text, start) return word == 'local' end -local function checkUri(ast, text, offset, results) +local function checkUri(state, text, position, results) local collect = {} - local myUri = guide.getUri(ast.ast) - guide.eachSourceContain(ast.ast, offset, function (source) + local myUri = guide.getUri(state.ast) + guide.eachSourceContain(state.ast, position, function (source) if source.type ~= 'string' then return end @@ -910,7 +910,7 @@ local function checkUri(ast, text, offset, results) collect[info.expect] = { textEdit = { start = source.start + #source[2], - finish = offset, + finish = position, newText = info.expect, } } @@ -996,8 +996,8 @@ local function checkUri(ast, text, offset, results) end end -local function checkLenPlusOne(ast, text, offset, results) - guide.eachSourceContain(ast.ast, offset, function (source) +local function checkLenPlusOne(state, text, position, results) + guide.eachSourceContain(state.ast, position, function (source) if source.type == 'getindex' or source.type == 'setindex' then local _, pos = text:find('%s*%[%s*%#', source.node.finish) @@ -1005,7 +1005,7 @@ local function checkLenPlusOne(ast, text, offset, results) return end local nodeText = text:sub(source.node.start, source.node.finish) - local writingText = trim(text:sub(pos + 1, offset - 1)) or '' + local writingText = trim(text:sub(pos + 1, position - 1)) or '' if not matchKey(writingText, nodeText) then return end @@ -1084,7 +1084,7 @@ local function mergeEnums(a, b, source) end end -local function checkTypingEnum(ast, text, offset, defs, str, results) +local function checkTypingEnum(state, text, position, defs, str, results) local enums = {} for _, def in ipairs(defs) do if def.type == 'doc.type.enum' @@ -1106,21 +1106,21 @@ local function checkTypingEnum(ast, text, offset, defs, str, results) end end -local function checkEqualEnumLeft(ast, text, offset, source, results) +local function checkEqualEnumLeft(state, text, position, source, results) if not source then return end - local str = guide.eachSourceContain(ast.ast, offset, function (src) + local str = guide.eachSourceContain(state.ast, position, function (src) if src.type == 'string' then return src end end) local defs = vm.getDefs(source) - checkTypingEnum(ast, text, offset, defs, str, results) + checkTypingEnum(state, text, position, defs, str, results) end -local function checkEqualEnum(ast, text, offset, results) - local start = lookBackward.findTargetSymbol(text, offset, '=') +local function checkEqualEnum(state, text, position, results) + local start = lookBackward.findTargetSymbol(text, guide.offsetOf(state, position), '=') if not start then return end @@ -1131,7 +1131,7 @@ local function checkEqualEnum(ast, text, offset, results) eqOrNeq = true end start = lookBackward.skipSpace(text, start - 1) - local source = findNearestSource(ast, start) + local source = findNearestSource(state, start) if not source then return end @@ -1141,11 +1141,11 @@ local function checkEqualEnum(ast, text, offset, results) if source.type == 'call' and not eqOrNeq then return end - checkEqualEnumLeft(ast, text, offset, source, results) + checkEqualEnumLeft(state, text, position, source, results) end -local function checkEqualEnumInString(ast, text, offset, results) - local source = findNearestSource(ast, offset) +local function checkEqualEnumInString(state, text, position, results) + local source = findNearestSource(state, position) local parent = source.parent if parent.type == 'binary' then if source ~= parent[2] then @@ -1157,118 +1157,118 @@ local function checkEqualEnumInString(ast, text, offset, results) if parent.op.type ~= '==' and parent.op.type ~= '~=' then return end - checkEqualEnumLeft(ast, text, offset, parent[1], results) + checkEqualEnumLeft(state, text, position, parent[1], results) end if parent.type == 'local' then - checkEqualEnumLeft(ast, text, offset, parent, results) + checkEqualEnumLeft(state, text, position, parent, results) end if parent.type == 'setlocal' or parent.type == 'setglobal' or parent.type == 'setfield' or parent.type == 'setindex' then - checkEqualEnumLeft(ast, text, offset, parent.node, results) + checkEqualEnumLeft(state, text, position, parent.node, results) end end -local function isFuncArg(ast, offset) - return guide.eachSourceContain(ast.ast, offset, function (source) +local function isFuncArg(state, position) + return guide.eachSourceContain(state.ast, position, function (source) if source.type == 'funcargs' then return true end end) end -local function trySpecial(ast, text, offset, results) - if isInString(ast, offset) then - checkUri(ast, text, offset, results) - checkEqualEnumInString(ast, text, offset, results) +local function trySpecial(state, text, position, results) + if isInString(state, position) then + checkUri(state, text, position, results) + checkEqualEnumInString(state, text, position, results) return end -- x[#x+1] - checkLenPlusOne(ast, text, offset, results) + checkLenPlusOne(state, text, position, results) -- type(o) == - checkEqualEnum(ast, text, offset, results) + checkEqualEnum(state, text, position, results) end -local function tryIndex(ast, text, offset, results) - local parent, oop = findParentInStringIndex(ast, text, offset) +local function tryIndex(state, text, position, results) + local parent, oop = findParentInStringIndex(state, text, position) if not parent then return end local word = parent.next.index[1] - checkField(ast, word, offset, offset, parent, oop, results) + checkField(state, word, position, position, parent, oop, results) end -local function tryWord(ast, text, offset, triggerCharacter, results) - local finish = lookBackward.skipSpace(text, offset) - local word, start = lookBackward.findWord(text, offset) +local function tryWord(state, text, position, triggerCharacter, results) + local finish = lookBackward.skipSpace(text, guide.offsetOf(state, position)) + local word, start = lookBackward.findWord(text, guide.offsetOf(state, position)) if not word then if triggerCharacter == nil then word = '' - start = offset + 1 + start = position + 1 else return nil end end - local hasSpace = triggerCharacter ~= nil and finish ~= offset - if isInString(ast, offset) then + local hasSpace = triggerCharacter ~= nil and finish ~= position + if isInString(state, position) then if not hasSpace then if #results == 0 then - checkCommon(ast.uri, word, text, offset, results) + checkCommon(state.uri, word, text, position, results) end end else - local parent, oop = findParent(ast, text, start - 1) + local parent, oop = findParent(state, text, start - 1) if parent then if not hasSpace then - checkField(ast, word, start, offset, parent, oop, results) + checkField(state, word, start, position, parent, oop, results) end - elseif isFuncArg(ast, offset) then - checkProvideLocal(ast, word, start, results) - checkFunctionArgByDocParam(ast, word, start, results) + elseif isFuncArg(state, position) then + checkProvideLocal(state, word, start, results) + checkFunctionArgByDocParam(state, word, start, results) else local afterLocal = isAfterLocal(text, start) - local stop = checkKeyWord(ast, text, start, offset, word, hasSpace, afterLocal, results) + local stop = checkKeyWord(state, text, start, position, word, hasSpace, afterLocal, results) if stop then return end if not hasSpace then if afterLocal then - checkProvideLocal(ast, word, start, results) + checkProvideLocal(state, word, start, results) else - checkLocal(ast, word, start, results) - checkTableField(ast, word, start, results) - local env = guide.getENV(ast.ast, start) - checkGlobal(ast, word, start, offset, env, false, results) - checkModule(ast, word, start, results) + checkLocal(state, word, start, results) + checkTableField(state, word, start, results) + local env = guide.getENV(state.ast, start) + checkGlobal(state, word, start, position, env, false, results) + checkModule(state, word, start, results) end end end if not hasSpace then - checkCommon(ast.uri, word, text, offset, results) + checkCommon(state.uri, word, text, position, results) end end end -local function trySymbol(ast, text, offset, results) - local symbol, start = lookBackward.findSymbol(text, offset) +local function trySymbol(state, text, position, results) + local symbol, start = lookBackward.findSymbol(text, guide.offsetOf(state, position)) if not symbol then return nil end - if isInString(ast, offset) then + if isInString(state, position) then return nil end if symbol == '.' or symbol == ':' then - local parent, oop = findParent(ast, text, start) + local parent, oop = findParent(state, text, start) if parent then tracy.ZoneBeginN 'completion.trySymbol' - checkField(ast, '', start, offset, parent, oop, results) + checkField(state, '', start, position, parent, oop, results) tracy.ZoneEnd() end end if symbol == '(' then - checkFunctionArgByDocParam(ast, '', start, results) + checkFunctionArgByDocParam(state, '', start, results) end end @@ -1354,9 +1354,9 @@ local function getCallEnumsAndFuncs(source, index, oop) end end -local function findCall(ast, text, offset) +local function findCall(state, text, position) local call - guide.eachSourceContain(ast.ast, offset, function (src) + guide.eachSourceContain(state.ast, position, function (src) if src.type == 'call' then if not call or call.start < src.start then call = src @@ -1366,13 +1366,13 @@ local function findCall(ast, text, offset) return call end -local function getCallArgInfo(call, text, offset) +local function getCallArgInfo(call, text, position) if not call.args then return 1, nil, nil end local oop = call.node.type == 'getmethod' for index, arg in ipairs(call.args) do - if arg.start <= offset and arg.finish >= offset then + if arg.start <= position and arg.finish >= position then return index, arg, oop end end @@ -1391,7 +1391,7 @@ local function getFuncParamByCallIndex(func, index) return func.args[index] end -local function checkTableLiteralField(ast, text, offset, tbl, fields, results) +local function checkTableLiteralField(state, text, position, tbl, fields, results) local mark = {} for _, field in ipairs(tbl) do if field.type == 'tablefield' @@ -1407,9 +1407,9 @@ local function checkTableLiteralField(ast, text, offset, tbl, fields, results) return guide.getKeyName(a) < guide.getKeyName(b) end) -- {$} - local left = lookBackward.findWord(text, offset) + local left = lookBackward.findWord(text, guide.offsetOf(state, position)) if not left then - local pos = lookBackward.findAnyPos(text, offset) + local pos = lookBackward.findAnyPos(text, guide.offsetOf(state, position)) local char = text:sub(pos, pos) if char == '{' or char == ',' or char == ';' then left = '' @@ -1435,8 +1435,8 @@ local function checkTableLiteralField(ast, text, offset, tbl, fields, results) end end -local function checkTableLiteralFieldByCall(ast, text, offset, call, defs, index, results) - local source = findNearestTableField(ast, offset) +local function checkTableLiteralFieldByCall(state, text, position, call, defs, index, results) + local source = findNearestTableField(state, position) if not source then return end @@ -1469,16 +1469,16 @@ local function checkTableLiteralFieldByCall(ast, text, offset, call, defs, index end ::CONTINUE:: end - checkTableLiteralField(ast, text, offset, tbl, fields, results) + checkTableLiteralField(state, text, position, tbl, fields, results) end -local function tryCallArg(ast, text, offset, results) - local call = findCall(ast, text, offset) +local function tryCallArg(state, text, position, results) + local call = findCall(state, text, position) if not call then return end local myResults = {} - local argIndex, arg, oop = getCallArgInfo(call, text, offset) + local argIndex, arg, oop = getCallArgInfo(call, text, position) if arg and arg.type == 'function' then return end @@ -1493,12 +1493,12 @@ local function tryCallArg(ast, text, offset, results) for _, enum in ipairs(myResults) do results[#results+1] = enum end - checkTableLiteralFieldByCall(ast, text, offset, call, defs, argIndex, results) + checkTableLiteralFieldByCall(state, text, position, call, defs, argIndex, results) end -local function tryTable(ast, text, offset, results) - offset = lookBackward.skipSpace(text, offset) - local source = findNearestTableField(ast, offset) +local function tryTable(state, text, position, results) + position = lookBackward.skipSpace(text, guide.offsetOf(state, position)) + local source = findNearestTableField(state, position) if not source then return end @@ -1521,21 +1521,21 @@ local function tryTable(ast, text, offset, results) fields[#fields+1] = field end end - checkTableLiteralField(ast, text, offset, tbl, fields, results) + checkTableLiteralField(state, text, position, tbl, fields, results) end -local function getComment(ast, offset) - for _, comm in ipairs(ast.comms) do - if offset >= comm.start - 2 and offset <= comm.finish then +local function getComment(state, position) + for _, comm in ipairs(state.comms) do + if position >= comm.start - 2 and position <= comm.finish then return comm end end return nil end -local function getLuaDoc(ast, offset) - for _, doc in ipairs(ast.ast.docs) do - if offset >= doc.start and offset <= doc.range then +local function getLuaDoc(state, position) + for _, doc in ipairs(state.ast.docs) do + if position >= doc.start and position <= doc.range then return doc end end @@ -1568,28 +1568,28 @@ local function tryLuaDocCate(word, results) end end -local function getLuaDocByContain(ast, offset) +local function getLuaDocByContain(state, position) local result local range = math.huge - guide.eachSourceContain(ast.ast.docs, offset, function (src) + guide.eachSourceContain(state.ast.docs, position, function (src) if not src.start then return end - if range >= offset - src.start - and offset <= src.finish then - range = offset - src.start + if range >= position - src.start + and position <= src.finish then + range = position - src.start result = src end end) return result end -local function getLuaDocByErr(ast, text, start, offset) +local function getLuaDocByErr(state, text, start, position) local targetError - for _, err in ipairs(ast.errs) do - if err.finish <= offset + for _, err in ipairs(state.errs) do + if err.finish <= position and err.start >= start then - if not text:sub(err.finish + 1, offset):find '%S' then + if not text:sub(err.finish + 1, position):find '%S' then targetError = err break end @@ -1599,8 +1599,8 @@ local function getLuaDocByErr(ast, text, start, offset) return nil end local targetDoc - for i = #ast.ast.docs, 1, -1 do - local doc = ast.ast.docs[i] + for i = #state.ast.docs, 1, -1 do + local doc = state.ast.docs[i] if doc.finish <= targetError.start then targetDoc = doc break @@ -1609,7 +1609,7 @@ local function getLuaDocByErr(ast, text, start, offset) return targetError, targetDoc end -local function tryLuaDocBySource(ast, offset, source, results) +local function tryLuaDocBySource(state, position, source, results) if source.type == 'doc.extends.name' then if source.parent.type == 'doc.class' then for _, doc in ipairs(vm.getDocDefines '*') do @@ -1621,7 +1621,7 @@ local function tryLuaDocBySource(ast, offset, source, results) kind = define.CompletionItemKind.Class, textEdit = doc[1]:find '[^%w_]' and { start = source.start, - finish = offset, + finish = position, newText = doc[1], }, } @@ -1639,7 +1639,7 @@ local function tryLuaDocBySource(ast, offset, source, results) kind = define.CompletionItemKind.Class, textEdit = doc[1]:find '[^%w_]' and { start = source.start, - finish = offset, + finish = position, newText = doc[1], }, } @@ -1648,8 +1648,8 @@ local function tryLuaDocBySource(ast, offset, source, results) return true elseif source.type == 'doc.param.name' then local funcs = {} - guide.eachSourceBetween(ast.ast, offset, math.huge, function (src) - if src.type == 'function' and src.start > offset then + guide.eachSourceBetween(state.ast, position, math.huge, function (src) + if src.type == 'function' and src.start > position then funcs[#funcs+1] = src end end) @@ -1702,7 +1702,7 @@ local function tryLuaDocBySource(ast, offset, source, results) return false end -local function tryLuaDocByErr(ast, offset, err, docState, results) +local function tryLuaDocByErr(state, position, err, docState, results) if err.type == 'LUADOC_MISS_CLASS_EXTENDS_NAME' then for _, doc in ipairs(vm.getDocDefines '*') do if doc.type == 'doc.class.name' @@ -1724,8 +1724,8 @@ local function tryLuaDocByErr(ast, offset, err, docState, results) end elseif err.type == 'LUADOC_MISS_PARAM_NAME' then local funcs = {} - guide.eachSourceBetween(ast.ast, offset, math.huge, function (src) - if src.type == 'function' and src.start > offset then + guide.eachSourceBetween(state.ast, position, math.huge, function (src) + if src.type == 'function' and src.start > position then funcs[#funcs+1] = src end end) @@ -1851,8 +1851,8 @@ local function tryLuaDocOfFunction(doc, results) } end -local function tryLuaDoc(ast, text, offset, results) - local doc = getLuaDoc(ast, offset) +local function tryLuaDoc(state, text, position, results) + local doc = getLuaDoc(state, position) if not doc then return end @@ -1871,29 +1871,29 @@ local function tryLuaDoc(ast, text, offset, results) end end -- 根据输入中的source来补全 - local source = getLuaDocByContain(ast, offset) + local source = getLuaDocByContain(state, position) if source then - local suc = tryLuaDocBySource(ast, offset, source, results) + local suc = tryLuaDocBySource(state, position, source, results) if suc then return end end -- 根据附近的错误消息来补全 - local err, expectDoc = getLuaDocByErr(ast, text, doc.start, offset) + local err, expectDoc = getLuaDocByErr(state, text, doc.start, position) if err then - tryLuaDocByErr(ast, offset, err, expectDoc, results) + tryLuaDocByErr(state, position, err, expectDoc, results) return end end -local function tryComment(ast, text, offset, results) +local function tryComment(state, text, position, results) if #results > 0 then return end - local word = lookBackward.findWord(text, offset) - local doc = getLuaDoc(ast, offset) + local word = lookBackward.findWord(text, guide.offsetOf(state, position)) + local doc = getLuaDoc(state, position) if not word then - local comment = getComment(ast, offset) + local comment = getComment(state, position) if comment.type == 'comment.short' or comment.type == 'comment.cshort' then if comment.text == '' then @@ -1912,23 +1912,24 @@ local function tryComment(ast, text, offset, results) if doc and doc.type ~= 'doc.comment' then return end - checkCommon(ast.uri, word, text, offset, results) + checkCommon(state.uri, word, text, position, results) end -local function makeCache(uri, offset, results) +local function makeCache(uri, position, results) local cache = workspace.getCache 'completion' if not uri then cache.results = nil return end local text = files.getText(uri) - local word = lookBackward.findWord(text, offset) + local state = files.getState(uri) + local word = lookBackward.findWord(text, guide.offsetOf(state, position)) if not word or #word < 2 then cache.results = nil return end cache.results = results - cache.offset = offset + cache.position= position cache.word = word:lower() cache.length = #word end @@ -1950,13 +1951,14 @@ local function isValidCache(word, result) return false end -local function getCache(uri, offset) +local function getCache(uri, position) local cache = workspace.getCache 'completion' if not cache.results then return nil end local text = files.getText(uri) - local word = lookBackward.findWord(text, offset) + local state = files.getState(uri) + local word = lookBackward.findWord(text, guide.offsetOf(state, position)) if not word then return nil end @@ -1980,7 +1982,7 @@ local function getCache(uri, offset) end if results.enableCommon then - checkCommon(uri, word, text, offset, results) + checkCommon(uri, word, text, position, results) end return cache.results @@ -1991,36 +1993,36 @@ local function clearCache() cache.results = nil end -local function completion(uri, offset, triggerCharacter) +local function completion(uri, position, triggerCharacter) tracy.ZoneBeginN 'completion cache' - local results = getCache(uri, offset) + local results = getCache(uri, position) tracy.ZoneEnd() if results then return results end tracy.ZoneBeginN 'completion #1' - local ast = files.getState(uri) + local state = files.getState(uri) local text = files.getText(uri) results = {} clearStack() tracy.ZoneEnd() tracy.ZoneBeginN 'completion #2' - if ast then - if getComment(ast, offset) then - tryLuaDoc(ast, text, offset, results) - tryComment(ast, text, offset, results) + if state then + if getComment(state, position) then + tryLuaDoc(state, text, position, results) + tryComment(state, text, position, results) else - trySpecial(ast, text, offset, results) - tryCallArg(ast, text, offset, results) - tryTable(ast, text, offset, results) - tryWord(ast, text, offset, triggerCharacter, results) - tryIndex(ast, text, offset, results) - trySymbol(ast, text, offset, results) + trySpecial(state, text, position, results) + tryCallArg(state, text, position, results) + tryTable(state, text, position, results) + tryWord(state, text, position, triggerCharacter, results) + tryIndex(state, text, position, results) + trySymbol(state, text, position, results) end else - local word = lookBackward.findWord(text, offset) + local word = lookBackward.findWord(text, guide.offsetOf(state, position)) if word then - checkCommon(nil, word, text, offset, results) + checkCommon(nil, word, text, position, results) end end tracy.ZoneEnd() @@ -2031,7 +2033,7 @@ local function completion(uri, offset, triggerCharacter) end tracy.ZoneBeginN 'completion #3' - makeCache(uri, offset, results) + makeCache(uri, position, results) tracy.ZoneEnd() return results end diff --git a/script/parser/guide.lua b/script/parser/guide.lua index be1305a3..4915f206 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -757,6 +757,15 @@ function m.positionOf(row, col) return row * 10000 + col end +--- 返回全文光标位置 +---@param state any +---@param position integer +function m.offsetOf(state, position) + local lines = state.lines + local row, col = m.rowColOf(position) + return (lines[row] or 1) + col - 1 +end + function m.lineContent(lines, text, row, ignoreNL) local line = lines[row] if not line then -- cgit v1.2.3 From db328eeed2ab7b67a179bb14edfdd0ad03c63bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 17 Sep 2021 17:54:55 +0800 Subject: update --- script/core/completion.lua | 63 +++++++++++++++++++++++++--------------------- script/parser/guide.lua | 28 ++++++++++++++++++++- 2 files changed, 62 insertions(+), 29 deletions(-) (limited to 'script') diff --git a/script/core/completion.lua b/script/core/completion.lua index 83c26da5..a3df659b 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -691,11 +691,14 @@ local function checkCommon(myUri, word, text, position, results) end end end - for str, pos in text:gmatch '([%a_][%w_]+)()' do + local state = files.getState(myUri) + for str, offset in text:gmatch '([%a_][%w_]+)()' do if #results >= 100 then break end - if #str >= 3 and not used[str] and pos - 1 ~= position then + if #str >= 3 + and not used[str] + and guide.offsetToPosition(state, offset) ~= position then used[str] = true if matchKey(word, str) then results[#results+1] = { @@ -720,7 +723,7 @@ end local function checkKeyWord(state, text, start, position, word, hasSpace, afterLocal, results) local snipType = config.get 'Lua.completion.keywordSnippet' - local symbol = lookBackward.findSymbol(text, guide.offsetOf(state, start - 1)) + local symbol = lookBackward.findSymbol(text, guide.positionToOffset(state, start - 1)) local isExp = symbol == '(' or symbol == ',' or symbol == '=' local info = { hasSpace = hasSpace, @@ -1120,7 +1123,7 @@ local function checkEqualEnumLeft(state, text, position, source, results) end local function checkEqualEnum(state, text, position, results) - local start = lookBackward.findTargetSymbol(text, guide.offsetOf(state, position), '=') + local start = lookBackward.findTargetSymbol(text, guide.positionToOffset(state, position), '=') if not start then return end @@ -1200,17 +1203,21 @@ local function tryIndex(state, text, position, results) end local function tryWord(state, text, position, triggerCharacter, results) - local finish = lookBackward.skipSpace(text, guide.offsetOf(state, position)) - local word, start = lookBackward.findWord(text, guide.offsetOf(state, position)) + local offset = guide.positionToOffset(state, position) + local finish = lookBackward.skipSpace(text, offset) + local word, start = lookBackward.findWord(text, offset) + local startPos if not word then if triggerCharacter == nil then word = '' - start = position + 1 + startPos = position + 1 else return nil end + else + startPos = guide.offsetToPosition(state, start) end - local hasSpace = triggerCharacter ~= nil and finish ~= position + local hasSpace = triggerCharacter ~= nil and finish ~= offset if isInString(state, position) then if not hasSpace then if #results == 0 then @@ -1218,29 +1225,29 @@ local function tryWord(state, text, position, triggerCharacter, results) end end else - local parent, oop = findParent(state, text, start - 1) + local parent, oop = findParent(state, text, startPos) if parent then if not hasSpace then - checkField(state, word, start, position, parent, oop, results) + checkField(state, word, startPos, position, parent, oop, results) end elseif isFuncArg(state, position) then - checkProvideLocal(state, word, start, results) - checkFunctionArgByDocParam(state, word, start, results) + checkProvideLocal(state, word, startPos, results) + checkFunctionArgByDocParam(state, word, startPos, results) else - local afterLocal = isAfterLocal(text, start) - local stop = checkKeyWord(state, text, start, position, word, hasSpace, afterLocal, results) + local afterLocal = isAfterLocal(text, startPos) + local stop = checkKeyWord(state, text, startPos, position, word, hasSpace, afterLocal, results) if stop then return end if not hasSpace then if afterLocal then - checkProvideLocal(state, word, start, results) + checkProvideLocal(state, word, startPos, results) else - checkLocal(state, word, start, results) - checkTableField(state, word, start, results) - local env = guide.getENV(state.ast, start) - checkGlobal(state, word, start, position, env, false, results) - checkModule(state, word, start, results) + checkLocal(state, word, startPos, results) + checkTableField(state, word, startPos, results) + local env = guide.getENV(state.ast, startPos) + checkGlobal(state, word, startPos, position, env, false, results) + checkModule(state, word, startPos, results) end end end @@ -1251,7 +1258,7 @@ local function tryWord(state, text, position, triggerCharacter, results) end local function trySymbol(state, text, position, results) - local symbol, start = lookBackward.findSymbol(text, guide.offsetOf(state, position)) + local symbol, start = lookBackward.findSymbol(text, guide.positionToOffset(state, position)) if not symbol then return nil end @@ -1407,9 +1414,9 @@ local function checkTableLiteralField(state, text, position, tbl, fields, result return guide.getKeyName(a) < guide.getKeyName(b) end) -- {$} - local left = lookBackward.findWord(text, guide.offsetOf(state, position)) + local left = lookBackward.findWord(text, guide.positionToOffset(state, position)) if not left then - local pos = lookBackward.findAnyPos(text, guide.offsetOf(state, position)) + local pos = lookBackward.findAnyPos(text, guide.positionToOffset(state, position)) local char = text:sub(pos, pos) if char == '{' or char == ',' or char == ';' then left = '' @@ -1497,7 +1504,7 @@ local function tryCallArg(state, text, position, results) end local function tryTable(state, text, position, results) - position = lookBackward.skipSpace(text, guide.offsetOf(state, position)) + position = lookBackward.skipSpace(text, guide.positionToOffset(state, position)) local source = findNearestTableField(state, position) if not source then return @@ -1890,7 +1897,7 @@ local function tryComment(state, text, position, results) if #results > 0 then return end - local word = lookBackward.findWord(text, guide.offsetOf(state, position)) + local word = lookBackward.findWord(text, guide.positionToOffset(state, position)) local doc = getLuaDoc(state, position) if not word then local comment = getComment(state, position) @@ -1923,7 +1930,7 @@ local function makeCache(uri, position, results) end local text = files.getText(uri) local state = files.getState(uri) - local word = lookBackward.findWord(text, guide.offsetOf(state, position)) + local word = lookBackward.findWord(text, guide.positionToOffset(state, position)) if not word or #word < 2 then cache.results = nil return @@ -1958,7 +1965,7 @@ local function getCache(uri, position) end local text = files.getText(uri) local state = files.getState(uri) - local word = lookBackward.findWord(text, guide.offsetOf(state, position)) + local word = lookBackward.findWord(text, guide.positionToOffset(state, position)) if not word then return nil end @@ -2020,7 +2027,7 @@ local function completion(uri, position, triggerCharacter) trySymbol(state, text, position, results) end else - local word = lookBackward.findWord(text, guide.offsetOf(state, position)) + local word = lookBackward.findWord(text, guide.positionToOffset(state, position)) if word then checkCommon(nil, word, text, position, results) end diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 4915f206..e2262cfd 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -760,12 +760,38 @@ end --- 返回全文光标位置 ---@param state any ---@param position integer -function m.offsetOf(state, position) +function m.positionToOffset(state, position) local lines = state.lines local row, col = m.rowColOf(position) return (lines[row] or 1) + col - 1 end +function m.offsetToPosition(state, offset) + local lines = state.lines + local left = 0 + local right = #lines + local row = 0 + while true do + row = (left + right) // 2 + if row == left then + if right ~= left then + if lines[right] <= offset then + row = right + end + end + break + end + local start = lines[row] + if start > offset then + right = row + else + left = row + end + end + local col = offset - (lines[row] or 1) + return m.positionOf(row, col) +end + function m.lineContent(lines, text, row, ignoreNL) local line = lines[row] if not line then -- cgit v1.2.3 From 84148fbedef3f3ae04552dcf3218e05027c17625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 17 Sep 2021 21:07:55 +0800 Subject: update --- script/core/completion.lua | 27 +++++++++++++++------------ script/core/keyword.lua | 8 +++----- script/core/look-backward.lua | 2 +- script/core/type-formatting.lua | 2 +- script/parser/guide.lua | 4 ++-- script/parser/newparser.lua | 4 +++- 6 files changed, 25 insertions(+), 22 deletions(-) (limited to 'script') diff --git a/script/core/completion.lua b/script/core/completion.lua index a3df659b..08d6f5f2 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -75,7 +75,8 @@ local function findNearestTableField(state, position) end local function findParent(state, text, position) - for i = position, 1, -1 do + local offset = guide.positionToOffset(state, position) + for i = offset, 1, -1 do local char = text:sub(i, i) if lookBackward.isSpace(char) then goto CONTINUE @@ -92,10 +93,11 @@ local function findParent(state, text, position) else return nil, nil end - local anyPos = lookBackward.findAnyPos(text, i-1) - if not anyPos then + local anyOffset = lookBackward.findAnyOffset(text, i-1) + if not anyOffset then return nil, nil end + local anyPos = guide.offsetToPosition(state, anyOffset) local parent = guide.eachSourceContain(state.ast, anyPos, function (source) if source.finish == anyPos then return source @@ -169,17 +171,18 @@ local function getSnip(source) if def ~= source and def.type == 'function' then local uri = guide.getUri(def) local text = files.getText(uri) - local lines = files.getLines(uri) + local state = files.getState(uri) + local lines = state.lines if not text then goto CONTINUE end if vm.isMetaFile(uri) then goto CONTINUE end - local row = guide.rowColOf(def.start) - local firstRow = lines[row] - local lastRow = lines[math.min(row + context - 1, #lines)] - local snip = text:sub(firstRow.start, lastRow.finish) + local firstRow = guide.rowColOf(def.start) + local lastRow = firstRow + context + local lastOffset = lines[lastRow] and (lines[lastRow] - 1) or #text + local snip = text:sub(lines[firstRow], lastOffset) return snip end ::CONTINUE:: @@ -698,7 +701,7 @@ local function checkCommon(myUri, word, text, position, results) end if #str >= 3 and not used[str] - and guide.offsetToPosition(state, offset) ~= position then + and guide.offsetToPosition(state, offset - 1) ~= position then used[str] = true if matchKey(word, str) then results[#results+1] = { @@ -723,7 +726,7 @@ end local function checkKeyWord(state, text, start, position, word, hasSpace, afterLocal, results) local snipType = config.get 'Lua.completion.keywordSnippet' - local symbol = lookBackward.findSymbol(text, guide.positionToOffset(state, start - 1)) + local symbol = lookBackward.findSymbol(text, guide.positionToOffset(state, start)) local isExp = symbol == '(' or symbol == ',' or symbol == '=' local info = { hasSpace = hasSpace, @@ -1215,7 +1218,7 @@ local function tryWord(state, text, position, triggerCharacter, results) return nil end else - startPos = guide.offsetToPosition(state, start) + startPos = guide.offsetToPosition(state, start - 1) end local hasSpace = triggerCharacter ~= nil and finish ~= offset if isInString(state, position) then @@ -1416,7 +1419,7 @@ local function checkTableLiteralField(state, text, position, tbl, fields, result -- {$} local left = lookBackward.findWord(text, guide.positionToOffset(state, position)) if not left then - local pos = lookBackward.findAnyPos(text, guide.positionToOffset(state, position)) + local pos = lookBackward.findAnyOffset(text, guide.positionToOffset(state, position)) local char = text:sub(pos, pos) if char == '{' or char == ',' or char == ';' then left = '' diff --git a/script/core/keyword.lua b/script/core/keyword.lua index 8e041f1c..0825f1bc 100644 --- a/script/core/keyword.lua +++ b/script/core/keyword.lua @@ -24,14 +24,12 @@ end", end return true end, function (info) - return guide.eachSourceContain(info.ast.ast, info.start, function (source) + return guide.eachSourceContain(info.state.ast, info.start, function (source) if source.type == 'while' or source.type == 'in' or source.type == 'loop' then - for i = 1, #source.keyword do - if info.start == source.keyword[i] then - return true - end + if source.finish - info.start <= 2 then + return true end end end) diff --git a/script/core/look-backward.lua b/script/core/look-backward.lua index ee89078f..2f90b768 100644 --- a/script/core/look-backward.lua +++ b/script/core/look-backward.lua @@ -77,7 +77,7 @@ function m.findTargetSymbol(text, offset, symbol) return nil end -function m.findAnyPos(text, offset) +function m.findAnyOffset(text, offset) for i = offset, 1, -1 do if not m.isSpace(text:sub(i, i)) then return i diff --git a/script/core/type-formatting.lua b/script/core/type-formatting.lua index 157a446d..d7bacbf8 100644 --- a/script/core/type-formatting.lua +++ b/script/core/type-formatting.lua @@ -27,7 +27,7 @@ local function findForward(text, offset, ...) end local function findBackward(text, offset, ...) - local pos = lookBackward.findAnyPos(text, offset) + local pos = lookBackward.findAnyOffset(text, offset) for _, symbol in ipairs { ... } do if text:sub(pos - #symbol + 1, pos) == symbol then return pos - #symbol + 1, symbol diff --git a/script/parser/guide.lua b/script/parser/guide.lua index e2262cfd..af623753 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -763,7 +763,7 @@ end function m.positionToOffset(state, position) local lines = state.lines local row, col = m.rowColOf(position) - return (lines[row] or 1) + col - 1 + return lines[row] + col - 1 end function m.offsetToPosition(state, offset) @@ -788,7 +788,7 @@ function m.offsetToPosition(state, offset) left = row end end - local col = offset - (lines[row] or 1) + local col = offset - lines[row] + 1 return m.positionOf(row, col) end diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 9721526c..e0144dcd 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -3544,7 +3544,9 @@ local function initState(lua, version, options) errs = {}, diags = {}, comms = {}, - lines = {}, + lines = { + [0] = 1, + }, options = options or {}, } if version == 'Lua 5.1' or version == 'LuaJIT' then -- cgit v1.2.3 From 1167244d45c4010912261d03b54aacc7115c69ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 17 Sep 2021 21:18:32 +0800 Subject: update --- script/core/completion.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'script') diff --git a/script/core/completion.lua b/script/core/completion.lua index 08d6f5f2..8d861aeb 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -1268,17 +1268,18 @@ local function trySymbol(state, text, position, results) if isInString(state, position) then return nil end + local startPos = guide.offsetToPosition(state, start) if symbol == '.' or symbol == ':' then - local parent, oop = findParent(state, text, start) + local parent, oop = findParent(state, text, startPos) if parent then tracy.ZoneBeginN 'completion.trySymbol' - checkField(state, '', start, position, parent, oop, results) + checkField(state, '', startPos, position, parent, oop, results) tracy.ZoneEnd() end end if symbol == '(' then - checkFunctionArgByDocParam(state, '', start, results) + checkFunctionArgByDocParam(state, '', startPos, results) end end -- cgit v1.2.3 From a7fcbe21fa6e06c46875fd8abb6d2eacb1db844e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Sat, 18 Sep 2021 16:04:24 +0800 Subject: update --- script/core/completion.lua | 76 ++++++++++++++++++++++++++++------------------ script/core/keyword.lua | 15 +++++---- 2 files changed, 55 insertions(+), 36 deletions(-) (limited to 'script') diff --git a/script/core/completion.lua b/script/core/completion.lua index 8d861aeb..e37dceed 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -405,19 +405,28 @@ local function checkModule(state, word, position, results) end end -local function checkFieldFromFieldToIndex(name, src, parent, word, start, position) +local function checkFieldFromFieldToIndex(name, src, parent, word, startPos, position) if name:match '^[%a_][%w_]*$' then return nil end local textEdit, additionalTextEdits - local uri = guide.getUri(parent) - local text = files.getText(uri) - local wordStart + local uri = guide.getUri(parent) + local text = files.getText(uri) + local state = files.getState(uri) + local startOffset = guide.positionToOffset(state, startPos) + local offset = guide.positionToOffset(state, position) + local wordStartOffset if word == '' then - wordStart = text:match('()%S', start + 1) or (position + 1) + wordStartOffset = text:match('()%S', startOffset + 1) + if wordStartOffset then + wordStartOffset = wordStartOffset - 1 + else + wordStartOffset = offset + end else - wordStart = position - #word + 1 + wordStartOffset = offset - #word end + local wordStartPos = guide.offsetToPosition(state, wordStartOffset) local newText if vm.getKeyType(src) == 'string' then newText = ('[%q]'):format(name) @@ -425,26 +434,28 @@ local function checkFieldFromFieldToIndex(name, src, parent, word, start, positi newText = ('[%s]'):format(name) end textEdit = { - start = wordStart, + start = wordStartPos, finish = position, newText = newText, } local nxt = parent.next if nxt then - local dotStart + local dotStart, dotFinish if nxt.type == 'setfield' or nxt.type == 'getfield' or nxt.type == 'tablefield' then dotStart = nxt.dot.start + dotFinish = nxt.dot.finish elseif nxt.type == 'setmethod' or nxt.type == 'getmethod' then dotStart = nxt.colon.start + dotFinish = nxt.colon.finish end if dotStart then additionalTextEdits = { { start = dotStart, - finish = dotStart, + finish = dotFinish, newText = '', } } @@ -460,7 +471,7 @@ local function checkFieldFromFieldToIndex(name, src, parent, word, start, positi return textEdit, additionalTextEdits end -local function checkFieldThen(name, src, word, start, position, parent, oop, results) +local function checkFieldThen(name, src, word, startPos, position, parent, oop, results) local value = searcher.getObjectValue(src) or src local kind = define.CompletionItemKind.Field if value.type == 'function' @@ -501,7 +512,7 @@ local function checkFieldThen(name, src, word, start, position, parent, oop, res newText = name, } else - textEdit, additionalTextEdits = checkFieldFromFieldToIndex(name, src, parent, word, start, position) + textEdit, additionalTextEdits = checkFieldFromFieldToIndex(name, src, parent, word, startPos, position) end results[#results+1] = { label = name, @@ -518,7 +529,7 @@ local function checkFieldThen(name, src, word, start, position, parent, oop, res } end -local function checkFieldOfRefs(refs, state, word, start, position, parent, oop, results, locals, isGlobal) +local function checkFieldOfRefs(refs, state, word, startPos, position, parent, oop, results, locals, isGlobal) local fields = {} local funcs = {} local count = 0 @@ -527,7 +538,7 @@ local function checkFieldOfRefs(refs, state, word, start, position, parent, oop, if not name then goto CONTINUE end - if isSameSource(state, src, start) then + if isSameSource(state, src, startPos) then goto CONTINUE end if isGlobal and locals and locals[name] then @@ -576,15 +587,15 @@ local function checkFieldOfRefs(refs, state, word, start, position, parent, oop, end for name, src in util.sortPairs(fields) do if src then - checkFieldThen(name, src, word, start, position, parent, oop, results) + checkFieldThen(name, src, word, startPos, position, parent, oop, results) end end end -local function checkGlobal(state, word, start, position, parent, oop, results) +local function checkGlobal(state, word, startPos, position, parent, oop, results) local locals = guide.getVisibleLocals(state.ast, position) local globals = vm.getGlobalSets '*' - checkFieldOfRefs(globals, state, word, start, position, parent, oop, results, locals, 'global') + checkFieldOfRefs(globals, state, word, startPos, position, parent, oop, results, locals, 'global') end local function checkField(state, word, start, position, parent, oop, results) @@ -876,9 +887,10 @@ local function checkFunctionArgByDocParam(state, word, start, results) end end -local function isAfterLocal(text, start) - local pos = lookBackward.skipSpace(text, start-1) - local word = lookBackward.findWord(text, pos) +local function isAfterLocal(state, text, startPos) + local offset = guide.positionToOffset(state, startPos) + local pos = lookBackward.skipSpace(text, offset) + local word = lookBackward.findWord(text, pos) return word == 'local' end @@ -1006,19 +1018,23 @@ local function checkLenPlusOne(state, text, position, results) guide.eachSourceContain(state.ast, position, function (source) if source.type == 'getindex' or source.type == 'setindex' then - local _, pos = text:find('%s*%[%s*%#', source.node.finish) - if not pos then + local finish = guide.positionToOffset(state, source.node.finish) + local _, offset = text:find('%s*%[%s*%#', finish) + if not offset then return end - local nodeText = text:sub(source.node.start, source.node.finish) - local writingText = trim(text:sub(pos + 1, position - 1)) or '' + local start = guide.positionToOffset(state, source.node.start) + 1 + local nodeText = text:sub(start, finish) + local writingText = trim(text:sub(offset + 1, guide.positionToOffset(state, position))) or '' if not matchKey(writingText, nodeText) then return end + local offsetPos = guide.offsetToPosition(state, offset) - 1 if source.parent == guide.getParentBlock(source) then + local sourceFinish = guide.positionToOffset(state, source.finish) -- state - local label = text:match('%#[ \t]*', pos) .. nodeText .. '+1' - local eq = text:find('^%s*%]?%s*%=', source.finish) + local label = text:match('%#[ \t]*', offset) .. nodeText .. '+1' + local eq = text:find('^%s*%]?%s*%=', sourceFinish) local newText = label .. ']' if not eq then newText = newText .. ' = ' @@ -1028,20 +1044,20 @@ local function checkLenPlusOne(state, text, position, results) match = nodeText, kind = define.CompletionItemKind.Snippet, textEdit = { - start = pos, + start = offsetPos, finish = source.finish, newText = newText, }, } else -- exp - local label = text:match('%#[ \t]*', pos) .. nodeText + local label = text:match('%#[ \t]*', offset) .. nodeText local newText = label .. ']' results[#results+1] = { label = label, kind = define.CompletionItemKind.Snippet, textEdit = { - start = pos, + start = offsetPos, finish = source.finish, newText = newText, }, @@ -1137,7 +1153,7 @@ local function checkEqualEnum(state, text, position, results) eqOrNeq = true end start = lookBackward.skipSpace(text, start - 1) - local source = findNearestSource(state, start) + local source = findNearestSource(state, guide.offsetToPosition(state, start)) if not source then return end @@ -1237,7 +1253,7 @@ local function tryWord(state, text, position, triggerCharacter, results) checkProvideLocal(state, word, startPos, results) checkFunctionArgByDocParam(state, word, startPos, results) else - local afterLocal = isAfterLocal(text, startPos) + local afterLocal = isAfterLocal(state, text, startPos) local stop = checkKeyWord(state, text, startPos, position, word, hasSpace, afterLocal, results) if stop then return diff --git a/script/core/keyword.lua b/script/core/keyword.lua index 0825f1bc..b0c75f7e 100644 --- a/script/core/keyword.lua +++ b/script/core/keyword.lua @@ -38,8 +38,9 @@ end", {'break'}, {'else'}, {'elseif', function (info, results) - if info.text:find('^%s*then', info.offset + 1) - or info.text:find('^%s*do', info.offset + 1) then + local offset = guide.positionToOffset(info.state, info.position) + if info.text:find('^%s*then', offset + 1) + or info.text:find('^%s*do', offset + 1) then return false end if info.hasSpace then @@ -153,8 +154,9 @@ end" end}, {'goto'}, {'if', function (info, results) - if info.text:find('^%s*then', info.offset + 1) - or info.text:find('^%s*do', info.offset + 1) then + local offset = guide.positionToOffset(info.state, info.position) + if info.text:find('^%s*then', offset + 1) + or info.text:find('^%s*do', offset + 1) then return false end if info.hasSpace then @@ -181,8 +183,9 @@ end" return true end}, {'in', function (info, results) - if info.text:find('^%s*then', info.offset + 1) - or info.text:find('^%s*do', info.offset + 1) then + local offset = guide.positionToOffset(info.state, info.position) + if info.text:find('^%s*then', offset + 1) + or info.text:find('^%s*do', offset + 1) then return false end if info.hasSpace then -- cgit v1.2.3 From b45a90132438bb2d84b7376066e5ff409833a13f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Sat, 18 Sep 2021 17:28:21 +0800 Subject: update --- script/core/completion.lua | 4 ++-- script/parser/guide.lua | 2 +- script/parser/newparser.lua | 41 +++++++++++++++++++++++------------------ 3 files changed, 26 insertions(+), 21 deletions(-) (limited to 'script') diff --git a/script/core/completion.lua b/script/core/completion.lua index e37dceed..51f1087e 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -1884,14 +1884,14 @@ local function tryLuaDoc(state, text, position, results) return end if doc.type == 'doc.comment' then - local line = text:sub(doc.start, doc.range) + local line = doc.originalComment.text -- 尝试 ---$ if line == '-' then tryLuaDocOfFunction(doc, results) return end -- 尝试 ---@$ - local cate = line:match('^-%s*@(%a*)$') + local cate = line:match('^-+%s*@(%a*)$') if cate then tryLuaDocCate(cate, results) return diff --git a/script/parser/guide.lua b/script/parser/guide.lua index af623753..4a0ca21f 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -781,7 +781,7 @@ function m.offsetToPosition(state, offset) end break end - local start = lines[row] + local start = lines[row] - 1 if start > offset then right = row else diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index e0144dcd..99518261 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -207,21 +207,7 @@ local LocalLimit = 200 local parseExp, parseAction -local function pushError(err) - local errs = State.errs - if err.finish < err.start then - err.finish = err.start - end - local last = errs[#errs] - if last then - if last.start <= err.start and last.finish >= err.finish then - return - end - end - err.level = err.level or 'error' - errs[#errs+1] = err - return err -end +local pushError local function addSpecial(name, obj) local root = State.ast @@ -3537,7 +3523,7 @@ local function initState(lua, version, options) Chunk = {} Tokens = tokens(lua) Index = 1 - State = { + local state = { version = version, lua = lua, ast = {}, @@ -3549,11 +3535,30 @@ local function initState(lua, version, options) }, options = options or {}, } + State = state if version == 'Lua 5.1' or version == 'LuaJIT' then - State.ENVMode = '@fenv' + state.ENVMode = '@fenv' else - State.ENVMode = '_ENV' + state.ENVMode = '_ENV' end + + pushError = function (err) + local errs = state.errs + if err.finish < err.start then + err.finish = err.start + end + local last = errs[#errs] + if last then + if last.start <= err.start and last.finish >= err.finish then + return + end + end + err.level = err.level or 'error' + errs[#errs+1] = err + return err + end + + state.pushError = pushError end return function (lua, mode, version, options) -- cgit v1.2.3 From bae4fa96a08158668d8b005f7885a774ad1c98fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Sat, 18 Sep 2021 17:51:43 +0800 Subject: update --- script/core/completion.lua | 6 +++--- script/parser/newparser.lua | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'script') diff --git a/script/core/completion.lua b/script/core/completion.lua index 51f1087e..46847540 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -842,8 +842,8 @@ local function checkProvideLocal(state, word, start, results) end) end -local function checkFunctionArgByDocParam(state, word, start, results) - local func = guide.eachSourceContain(state.ast, start, function (source) +local function checkFunctionArgByDocParam(state, word, startPos, results) + local func = guide.eachSourceContain(state.ast, startPos, function (source) if source.type == 'function' then return source end @@ -863,7 +863,7 @@ local function checkFunctionArgByDocParam(state, word, start, results) end local firstArg = func.args and func.args[1] if not firstArg - or firstArg.start <= start and firstArg.finish >= start then + or firstArg.start <= startPos and firstArg.finish >= startPos then local firstParam = params[1] if firstParam and matchKey(word, firstParam.param[1]) then local label = {} diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 99518261..7955a5c3 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -2131,7 +2131,6 @@ local function parseFunction(isLocal, isAction) params.finish = lastRightPosition() params.parent = func func.args = params - func.finish = params.finish end skipSpace() if Tokens[Index + 1] == ')' then @@ -2143,6 +2142,7 @@ local function parseFunction(isLocal, isAction) Index = Index + 2 skipSpace() else + func.finish = lastRightPosition() if params then params.finish = func.finish end -- cgit v1.2.3 From 621ee2b3e79dd452ddb3b96cf63a2bc2792b9254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 11:00:40 +0800 Subject: fix --- script/parser/luadoc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'script') diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 5cf32a54..0463d7d2 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -646,7 +646,7 @@ function parseType(parent) end local nextCommRow = guide.rowColOf(nextComm.start) local currentRow = row + i + 1 - if currentRow > nextCommRow then + if currentRow < nextCommRow then return false end if nextComm.text:sub(1, 2) == '-@' then -- cgit v1.2.3 From a847377582e5f22244aa587f9d79a07f9db03780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 11:30:39 +0800 Subject: update --- script/core/keyword.lua | 13 +++++++------ script/parser/newparser.lua | 5 ++++- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'script') diff --git a/script/core/keyword.lua b/script/core/keyword.lua index b0c75f7e..295026d7 100644 --- a/script/core/keyword.lua +++ b/script/core/keyword.lua @@ -271,15 +271,16 @@ until $1" return false end}, {'then', function (info, results) - local lines = files.getLines(info.uri) - local pos, first = info.text:match('%S+%s+()(%S+)', info.start) + local startOffset = guide.positionToOffset(info.state, info.start) + local pos, first = info.text:match('%S+%s+()(%S+)', startOffset + 1) if first == 'end' or first == 'else' or first == 'elseif' then - local startRow = guide.rowColOf(info.start) - local finishRow = guide.rowColOf(pos) - local startSp = info.text:match('^%s*', lines[startRow].start + 1) - local finishSp = info.text:match('^%s*', lines[finishRow].start + 1) + local startRow = guide.rowColOf(info.start) + local finishPosition = guide.offsetToPosition(info.state, pos) + local finishRow = guide.rowColOf(finishPosition) + local startSp = info.text:match('^%s*', info.state.lines[startRow]) + local finishSp = info.text:match('^%s*', info.state.lines[finishRow]) if startSp == finishSp then return false end diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 7955a5c3..de78fd6d 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -476,7 +476,9 @@ local function skipComment(isAction) or (token == '//' and isAction) then local start = Tokens[Index] local left = getPosition(start, 'left') + local chead = false if token == '//' then + chead = true pushCommentHeadError(left) end Index = Index + 2 @@ -497,7 +499,7 @@ local function skipComment(isAction) Index = Index + 2 end State.comms[#State.comms+1] = { - type = 'comment.shot', + type = chead and 'comment.cshort' or 'comment.short', start = left, finish = getPosition(Tokens[Index], 'right'), text = ssub(Lua, start + 2, Tokens[Index] and (Tokens[Index] - 1) or #Lua), @@ -1663,6 +1665,7 @@ local function parseSimple(node, funcName) call.finish = getPosition(Tokens[Index], 'right') Index = Index + 2 else + call.finish = lastRightPosition() missSymbol ')' end if args then -- cgit v1.2.3 From 1ab04aca1e0a3ad9d76aa11fa4e8eefe9781624b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 14:31:13 +0800 Subject: update --- script/core/completion.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'script') diff --git a/script/core/completion.lua b/script/core/completion.lua index 46847540..6f9605e2 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -1524,7 +1524,6 @@ local function tryCallArg(state, text, position, results) end local function tryTable(state, text, position, results) - position = lookBackward.skipSpace(text, guide.positionToOffset(state, position)) local source = findNearestTableField(state, position) if not source then return @@ -1553,7 +1552,7 @@ end local function getComment(state, position) for _, comm in ipairs(state.comms) do - if position >= comm.start - 2 and position <= comm.finish then + if position > comm.start and position <= comm.finish then return comm end end -- cgit v1.2.3 From b7f7789e46ab8c67d25704be696a1523762b1d80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 15:54:44 +0800 Subject: update --- script/parser/guide.lua | 5 +++-- script/parser/newparser.lua | 14 +++++++------- script/vm/getLinks.lua | 6 +++--- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'script') diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 4a0ca21f..fb5f3db4 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -725,10 +725,11 @@ end --- 获取指定的 special function m.eachSpecialOf(ast, name, callback) local root = m.getRoot(ast) - if not root.specials then + local state = root.state + if not state.specials then return end - local specials = root.specials[name] + local specials = state.specials[name] if not specials then return end diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index de78fd6d..9547a830 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -210,14 +210,13 @@ local parseExp, parseAction local pushError local function addSpecial(name, obj) - local root = State.ast - if not root.specials then - root.specials = {} + if not State.specials then + State.specials = {} end - if not root.specials[name] then - root.specials[name] = {} + if not State.specials[name] then + State.specials[name] = {} end - root.specials[name][#root.specials[name]+1] = obj + State.specials[name][#State.specials[name]+1] = obj obj.special = name end @@ -1739,7 +1738,7 @@ local function parseSimple(node, funcName) } call.args = args str.parent = args - node.parent = args + node.parent = call node = call elseif CharMapStrLH[token] then local str = parseLongString() @@ -3583,6 +3582,7 @@ return function (lua, mode, version, options) elseif mode == 'Action' then State.ast = parseAction() end + State.ast.state = State return State end diff --git a/script/vm/getLinks.lua b/script/vm/getLinks.lua index 161396f6..d2332504 100644 --- a/script/vm/getLinks.lua +++ b/script/vm/getLinks.lua @@ -6,12 +6,12 @@ local files = require 'files' local function getFileLinks(uri) local ws = require 'workspace' local links = {} - local ast = files.getState(uri) - if not ast then + local state = files.getState(uri) + if not state then return links end tracy.ZoneBeginN('getFileLinks') - guide.eachSpecialOf(ast.ast, 'require', function (source) + guide.eachSpecialOf(state.ast, 'require', function (source) local call = source.parent if not call or call.type ~= 'call' then return -- cgit v1.2.3 From b66a9c9340d63e1a22ba7d5ccad8d9df244240d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 16:37:54 +0800 Subject: update --- script/parser/luadoc.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'script') diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 0463d7d2..4a431e68 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -1,7 +1,7 @@ local m = require 'lpeglabel' local re = require 'parser.relabel' local guide = require 'parser.guide' -local grammar = require 'parser.grammar' +local parser = require 'parser.newparser' local TokenTypes, TokenStarts, TokenFinishs, TokenContents local Ci, Offset, pushError, NextComment, Lines @@ -1121,9 +1121,9 @@ local function trimTailComment(text) comment = text:sub(3) end if comment:find '^%s*[\'"[]' then - local result = grammar(nil, comment:gsub('^%s+', ''), 'string') - if result and result[1] then - comment = result[1][1] + local state = parser(comment:gsub('^%s+', ''), 'String') + if state and state.ast then + comment = state.ast[1] end end return comment @@ -1148,7 +1148,7 @@ local function buildLuaDoc(comment) local result = convertTokens() if result then result.range = comment.finish - local cstart = text:find('%S', (result.firstFinish or result.finish) - comment.start + 2) + local cstart = text:find('%S', (result.firstFinish or result.finish) - comment.start) if cstart and cstart < comment.finish then result.comment = { type = 'doc.tailcomment', -- cgit v1.2.3 From a45e980f0d51c47229d18d0f859e718d203b472f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 16:54:15 +0800 Subject: update --- script/core/noder.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'script') diff --git a/script/core/noder.lua b/script/core/noder.lua index 52ab7731..d6069833 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -1250,6 +1250,7 @@ compileNodeMap = util.switch() start = node.start, finish = node.finish, vararg = node, + parent = source, } compileCallReturn(noders, node, getID(param1), 2) if not param2 then @@ -1260,6 +1261,7 @@ compileNodeMap = util.switch() start = node.start, finish = node.finish, vararg = node, + parent = source, } compileCallReturn(noders, node, getID(param2), 3) end @@ -1271,7 +1273,8 @@ compileNodeMap = util.switch() start = source.keyword[3], finish = source.keyword[6], node = node, - args = { param1, param2 } + args = { param1, param2 }, + parent = source, } for i = 1, #keys do compileCallReturn(noders, call, getID(keys[i]), i) -- cgit v1.2.3 From 32aa2dac835a0c74b82b19d83d9fd06be7a947ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 17:24:44 +0800 Subject: cleanup --- script/core/code-action.lua | 3 --- script/core/command/autoRequire.lua | 1 - script/core/command/removeSpace.lua | 1 - script/core/completion.lua | 1 - script/core/diagnostics/different-requires.lua | 2 +- script/core/diagnostics/init.lua | 2 +- script/core/diagnostics/newfield-call.lua | 1 - script/core/diagnostics/newline-call.lua | 3 +-- script/core/diagnostics/trailing-space.lua | 36 ++++++++++++++------------ script/core/semantic-tokens.lua | 1 - script/core/type-formatting.lua | 1 - script/files.lua | 29 --------------------- script/parser/guide.lua | 12 --------- script/vm/getDocs.lua | 1 - 14 files changed, 23 insertions(+), 71 deletions(-) (limited to 'script') diff --git a/script/core/code-action.lua b/script/core/code-action.lua index 922ebff3..ce71f4af 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -5,7 +5,6 @@ local sp = require 'bee.subprocess' local guide = require "parser.guide" local function checkDisableByLuaDocExits(uri, row, mode, code) - local lines = files.getLines(uri) local ast = files.getState(uri) local text = files.getOriginText(uri) local line = lines[row] @@ -41,7 +40,6 @@ local function checkDisableByLuaDocExits(uri, row, mode, code) end local function checkDisableByLuaDocInsert(uri, row, mode, code) - local lines = files.getLines(uri) local ast = files.getState(uri) local text = files.getOriginText(uri) -- 先看看上一行是不是已经有了 @@ -56,7 +54,6 @@ local function checkDisableByLuaDocInsert(uri, row, mode, code) end local function disableDiagnostic(uri, code, start, results) - local lines = files.getLines(uri) local row = guide.rowColOf(start) results[#results+1] = { title = lang.script('ACTION_DISABLE_DIAG', code), diff --git a/script/core/command/autoRequire.lua b/script/core/command/autoRequire.lua index 2cb6a8f8..e784a827 100644 --- a/script/core/command/autoRequire.lua +++ b/script/core/command/autoRequire.lua @@ -6,7 +6,6 @@ local client = require 'client' local lang = require 'language' local function findInsertOffset(uri) - local lines = files.getLines(uri) local text = files.getText(uri) local fmt = { pair = false, diff --git a/script/core/command/removeSpace.lua b/script/core/command/removeSpace.lua index b94f9788..34c74ce0 100644 --- a/script/core/command/removeSpace.lua +++ b/script/core/command/removeSpace.lua @@ -13,7 +13,6 @@ end return function (data) local uri = data.uri - local lines = files.getLines(uri) local text = files.getText(uri) local ast = files.getState(uri) if not lines then diff --git a/script/core/completion.lua b/script/core/completion.lua index 6f9605e2..e56ed3f8 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -227,7 +227,6 @@ end local function buildInsertRequire(state, targetUri, stemName) local uri = guide.getUri(state.ast) - local lines = files.getLines(uri) local text = files.getText(uri) local start = 1 for i = 1, #lines do diff --git a/script/core/diagnostics/different-requires.lua b/script/core/diagnostics/different-requires.lua index 909342f4..fd7415b6 100644 --- a/script/core/diagnostics/different-requires.lua +++ b/script/core/diagnostics/different-requires.lua @@ -12,7 +12,7 @@ return function (uri, callback) end local cache = vm.getCache 'different-requires' guide.eachSpecialOf(state.ast, 'require', function (source) - local call = source.next + local call = source.parent if not call or call.type ~= 'call' then return end diff --git a/script/core/diagnostics/init.lua b/script/core/diagnostics/init.lua index 09688f6e..63a1bcf0 100644 --- a/script/core/diagnostics/init.lua +++ b/script/core/diagnostics/init.lua @@ -44,7 +44,7 @@ local function check(uri, name, results) if vm.isDiagDisabledAt(uri, result.start, name) then return end - if result.start == 0 then + if result.start < 0 then return end if mark[result.start] then diff --git a/script/core/diagnostics/newfield-call.lua b/script/core/diagnostics/newfield-call.lua index 83d205ca..669ed2bb 100644 --- a/script/core/diagnostics/newfield-call.lua +++ b/script/core/diagnostics/newfield-call.lua @@ -8,7 +8,6 @@ return function (uri, callback) return end - local lines = files.getLines(uri) local text = files.getText(uri) guide.eachSourceType(ast.ast, 'table', function (source) diff --git a/script/core/diagnostics/newline-call.lua b/script/core/diagnostics/newline-call.lua index 1c31fa8d..b28310e3 100644 --- a/script/core/diagnostics/newline-call.lua +++ b/script/core/diagnostics/newline-call.lua @@ -4,9 +4,8 @@ local lang = require 'language' return function (uri, callback) local ast = files.getState(uri) - local lines = files.getLines(uri) local text = files.getText(uri) - if not ast or not lines then + if not ast then return end diff --git a/script/core/diagnostics/trailing-space.lua b/script/core/diagnostics/trailing-space.lua index 824eb83f..5c66b118 100644 --- a/script/core/diagnostics/trailing-space.lua +++ b/script/core/diagnostics/trailing-space.lua @@ -13,40 +13,44 @@ local function isInString(ast, offset) end return function (uri, callback) - local ast = files.getState(uri) - if not ast then + local state = files.getState(uri) + if not state then return end local text = files.getText(uri) - local lines = files.getLines(uri) - for i = 1, #lines do - local start = lines[i].start - local range = lines[i].range - local lastChar = text:sub(range, range) + local lines = state.lines + for i = 0, #lines do + local startPos = lines[i] + local startOffset = guide.positionToOffset(state, startPos) + local finishOffset = text:find('[\r\n]', startOffset) or (#text + 1) + local lastOffset = finishOffset - 1 + local lastChar = text:sub(lastOffset, lastOffset) if lastChar ~= ' ' and lastChar ~= '\t' then goto NEXT_LINE end - if isInString(ast.ast, range) then + local lastPos = guide.offsetToPosition(state, lastOffset) + if isInString(state.ast, lastPos) then goto NEXT_LINE end - local first = start - for n = range - 1, start, -1 do + local firstOffset = startOffset + for n = lastOffset - 1, startOffset, -1 do local char = text:sub(n, n) if char ~= ' ' and char ~= '\t' then - first = n + 1 + firstOffset = n + 1 break end end - if first == start then + local firstPos = guide.offsetToPosition(state, firstOffset) - 1 + if firstOffset == startOffset then callback { - start = first, - finish = range, + start = firstPos, + finish = lastPos, message = lang.script.DIAG_LINE_ONLY_SPACE, } else callback { - start = first, - finish = range, + start = firstPos, + finish = lastPos, message = lang.script.DIAG_LINE_POST_SPACE, } end diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua index 96cbc5e1..238df862 100644 --- a/script/core/semantic-tokens.lua +++ b/script/core/semantic-tokens.lua @@ -214,7 +214,6 @@ end return function (uri, start, finish) local ast = files.getState(uri) - local lines = files.getLines(uri) local text = files.getText(uri) if not ast then return nil diff --git a/script/core/type-formatting.lua b/script/core/type-formatting.lua index d7bacbf8..cd2044bc 100644 --- a/script/core/type-formatting.lua +++ b/script/core/type-formatting.lua @@ -3,7 +3,6 @@ local lookBackward = require 'core.look-backward' local guide = require "parser.guide" local function insertIndentation(uri, offset, edits) - local lines = files.getLines(uri) local text = files.getOriginText(uri) local row = guide.rowColOf(offset) local line = lines[row] diff --git a/script/files.lua b/script/files.lua index 98d9b83c..a3595a4f 100644 --- a/script/files.lua +++ b/script/files.lua @@ -537,35 +537,6 @@ function m.getVisibles(uri) return visibles end ---- 获取文件行信息 ----@param uri uri ----@return table lines -function m.getLines(uri) - local file = m.fileMap[uri] - if not file then - return nil - end - local lines = m.linesMap[uri] - if not lines then - lines = parser.lines(file.text) - m.linesMap[uri] = lines - end - return lines -end - -function m.getOriginLines(uri) - local file = m.fileMap[uri] - if not file then - return nil - end - local lines = m.originLinesMap[uri] - if not lines then - lines = parser.lines(file.originText) - m.originLinesMap[uri] = lines - end - return lines -end - function m.getFile(uri) return m.fileMap[uri] or m.dllMap[uri] diff --git a/script/parser/guide.lua b/script/parser/guide.lua index fb5f3db4..cea56be8 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -805,18 +805,6 @@ function m.lineContent(lines, text, row, ignoreNL) end end -function m.lineRange(lines, row, ignoreNL) - local line = lines[row] - if not line then - return 0, 0 - end - if ignoreNL then - return line.start, line.range - else - return line.start, line.finish - end -end - local isSetMap = { ['setglobal'] = true, ['local'] = true, diff --git a/script/vm/getDocs.lua b/script/vm/getDocs.lua index 218dc048..7cac0935 100644 --- a/script/vm/getDocs.lua +++ b/script/vm/getDocs.lua @@ -177,7 +177,6 @@ function vm.isDeprecated(value, deep) end local function makeDiagRange(uri, doc, results) - local lines = files.getLines(uri) local names if doc.names then names = {} -- cgit v1.2.3 From c951f3472628bdccdbf13a6bd95bc36cc93523fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 17:41:25 +0800 Subject: update --- script/core/diagnostics/newline-call.lua | 12 ++++++----- script/core/diagnostics/redundant-value.lua | 32 ++++++++++++++--------------- script/files.lua | 6 ------ script/parser/newparser.lua | 16 +++++++++++---- 4 files changed, 35 insertions(+), 31 deletions(-) (limited to 'script') diff --git a/script/core/diagnostics/newline-call.lua b/script/core/diagnostics/newline-call.lua index b28310e3..dbb8c690 100644 --- a/script/core/diagnostics/newline-call.lua +++ b/script/core/diagnostics/newline-call.lua @@ -3,13 +3,13 @@ local guide = require 'parser.guide' local lang = require 'language' return function (uri, callback) - local ast = files.getState(uri) + local state = files.getState(uri) local text = files.getText(uri) - if not ast then + if not state then return end - guide.eachSourceType(ast.ast, 'call', function (source) + guide.eachSourceType(state.ast, 'call', function (source) local node = source.node local args = source.args if not args then @@ -20,8 +20,10 @@ return function (uri, callback) if not source.next then return end - if text:sub(args.start, args.start) ~= '(' - or text:sub(args.finish, args.finish) ~= ')' then + local startOffset = guide.positionToOffset(state, args.start) + 1 + local finishOffset = guide.positionToOffset(state, args.finish) + if text:sub(startOffset, startOffset) ~= '(' + or text:sub(finishOffset, finishOffset) ~= ')' then return end diff --git a/script/core/diagnostics/redundant-value.lua b/script/core/diagnostics/redundant-value.lua index d6cd97a7..4c913330 100644 --- a/script/core/diagnostics/redundant-value.lua +++ b/script/core/diagnostics/redundant-value.lua @@ -1,24 +1,24 @@ local files = require 'files' local define = require 'proto.define' local lang = require 'language' +local guide = require 'parser.guide' +local await = require 'await' -return function (uri, callback, code) - local ast = files.getState(uri) - if not ast then +return function (uri, callback) + local state = files.getState(uri) + if not state then return end - local diags = ast.diags[code] - if not diags then - return - end - - for _, info in ipairs(diags) do - callback { - start = info.start, - finish = info.finish, - tags = { define.DiagnosticTag.Unnecessary }, - message = lang.script('DIAG_OVER_MAX_VALUES', info.max, info.passed) - } - end + guide.eachSource(state.ast, function (src) + await.delay() + if src.redundant then + callback { + start = src.start, + finish = src.finish, + tags = { define.DiagnosticTag.Unnecessary }, + message = lang.script('DIAG_OVER_MAX_VALUES', src.redundant.max, src.redundant.passed) + } + end + end) end diff --git a/script/files.lua b/script/files.lua index a3595a4f..25f07ca2 100644 --- a/script/files.lua +++ b/script/files.lua @@ -35,8 +35,6 @@ m.assocMatcher = nil m.globalVersion = 0 m.fileCount = 0 m.astCount = 0 -m.linesMap = setmetatable({}, { __mode = 'v' }) -m.originLinesMap = setmetatable({}, { __mode = 'v' }) m.astMap = {} -- setmetatable({}, { __mode = 'v' }) --- 打开文件 @@ -160,8 +158,6 @@ function m.setText(uri, text, isTrust, instance) file.trusted = isTrust file.originText = text file.words = nil - m.linesMap[uri] = nil - m.originLinesMap[uri] = nil m.astMap[uri] = nil file.cache = {} file.cacheActiveTime = math.huge @@ -346,7 +342,6 @@ function m.removeAll() m.fileCount = m.fileCount - 1 m.fileMap[uri] = nil m.astMap[uri] = nil - m.linesMap[uri] = nil m.onWatch('remove', uri) end end @@ -366,7 +361,6 @@ function m.removeAllClosed() m.fileCount = m.fileCount - 1 m.fileMap[uri] = nil m.astMap[uri] = nil - m.linesMap[uri] = nil m.onWatch('remove', uri) end end diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 9547a830..ba91cd10 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -2573,6 +2573,7 @@ local function parseMultiVars(n1, parser, isLocal) skipSpace() local v1, v2, vrest local isSet + local max = 1 if expectAssign() then v1, v2, vrest = parseSetValues() isSet = true @@ -2583,6 +2584,7 @@ local function parseMultiVars(n1, parser, isLocal) bindValue(n1, v1, 1, nil, isLocal, isSet) local lastValue = v1 if n2 then + max = 2 bindValue(n2, v2, 2, lastValue, isLocal, isSet) lastValue = v2 or lastValue pushActionIntoCurrentChunk(n2) @@ -2591,21 +2593,28 @@ local function parseMultiVars(n1, parser, isLocal) for i = 1, #nrest do local n = nrest[i] local v = vrest and vrest[i] - bindValue(n, v, i + 2, lastValue, isLocal, isSet) + max = i + 2 + bindValue(n, v, max, lastValue, isLocal, isSet) lastValue = v or lastValue pushActionIntoCurrentChunk(n) end end if v2 and not n2 then - v2.redundant = true + v2.redundant = { + max = max, + passed = 2, + } pushActionIntoCurrentChunk(v2) end if vrest then for i = 1, #vrest do local v = vrest[i] if not nrest or not nrest[i] then - v.redundant = true + v.redundant = { + max = max, + passed = v + 2, + } pushActionIntoCurrentChunk(v) end end @@ -3530,7 +3539,6 @@ local function initState(lua, version, options) lua = lua, ast = {}, errs = {}, - diags = {}, comms = {}, lines = { [0] = 1, -- cgit v1.2.3 From f57367d3bcdc7229d1d9b3125f6fd4c60342ca50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 19:34:29 +0800 Subject: fix --- script/core/diagnostics/undefined-global.lua | 2 ++ script/core/noder.lua | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'script') diff --git a/script/core/diagnostics/undefined-global.lua b/script/core/diagnostics/undefined-global.lua index c7ddeac2..14754c16 100644 --- a/script/core/diagnostics/undefined-global.lua +++ b/script/core/diagnostics/undefined-global.lua @@ -5,6 +5,7 @@ local config = require 'config' local guide = require 'parser.guide' local noder = require 'core.noder' local collector = require 'core.collector' +local await = require 'await' local requireLike = { ['include'] = true, @@ -35,6 +36,7 @@ return function (uri, callback) if node.tag ~= '_ENV' then return end + await.delay() local id = 'def:' .. noder.getID(src) if not collector.has(id) then local message = lang.script('DIAG_UNDEF_GLOBAL', key) diff --git a/script/core/noder.lua b/script/core/noder.lua index d6069833..1107dcda 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -1583,11 +1583,6 @@ local partNodersMap = util.switch() m.compilePartNodes(noders, ref) end end - - local nxt = source.next - if nxt then - m.compilePartNodes(noders, nxt) - end end) : case 'setlocal' : case 'getlocal' @@ -1603,6 +1598,14 @@ local partNodersMap = util.switch() if parent.value == source then m.compilePartNodes(noders, parent) end + + if parent.type == 'call' then + local node = parent.node + if node.special == 'rawset' + or node.special == 'rawget' then + m.compilePartNodes(noders, parent) + end + end end) : case 'setfield' : case 'getfield' @@ -1634,6 +1637,14 @@ local partNodersMap = util.switch() if parent.value == source then m.compilePartNodes(noders, parent) end + + if parent.type == 'call' then + local node = parent.node + if node.special == 'rawset' + or node.special == 'rawget' then + m.compilePartNodes(noders, parent) + end + end end) : case 'label' : call(function (noders, source) -- cgit v1.2.3 From 9c79a00b41e1eff3a04a3daea6762ece89bb60eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 19:39:41 +0800 Subject: fix --- script/core/diagnostics/count-down-loop.lua | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'script') diff --git a/script/core/diagnostics/count-down-loop.lua b/script/core/diagnostics/count-down-loop.lua index 1a7dcf7d..49c48880 100644 --- a/script/core/diagnostics/count-down-loop.lua +++ b/script/core/diagnostics/count-down-loop.lua @@ -10,30 +10,39 @@ return function (uri, callback) end guide.eachSourceType(state.ast, 'loop', function (source) - if not source.loc or not source.loc.value then - return - end local maxNumer = source.max and tonumber(source.max[1]) if maxNumer ~= 1 then return end - local minNumber = source.loc and source.loc.value and tonumber(source.loc.value[1]) + local minNumber = source.init and tonumber(source.init[1]) if minNumber and minNumber <= 1 then return end if not source.step then callback { - start = source.loc.value.start, + start = source.init.start, finish = source.max.finish, - message = lang.script('DIAG_COUNT_DOWN_LOOP', ('%s, %s'):format(text:sub(source.loc.value.start, source.max.finish), '-1')) + message = lang.script('DIAG_COUNT_DOWN_LOOP' + , ('%s, %s'):format(text:sub( + guide.positionToOffset(state, source.init.start), + guide.positionToOffset(state, source.max.finish) + ) + , '-1') + ) } else local stepNumber = tonumber(source.step[1]) if stepNumber and stepNumber > 0 then callback { - start = source.loc.value.start, + start = source.init.start, finish = source.step.finish, - message = lang.script('DIAG_COUNT_DOWN_LOOP', ('%s, -%s'):format(text:sub(source.loc.value.start, source.max.finish), source.step[1])) + message = lang.script('DIAG_COUNT_DOWN_LOOP' + , ('%s, -%s'):format(text:sub( + guide.positionToOffset(state, source.init.start), + guide.positionToOffset(state, source.max.finish) + ) + , source.step[1]) + ) } end end -- cgit v1.2.3 From eda1918a82894137c58e19a7fdb1301e3c2bbf30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 20:03:07 +0800 Subject: update --- script/vm/getDocs.lua | 77 +++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 43 deletions(-) (limited to 'script') diff --git a/script/vm/getDocs.lua b/script/vm/getDocs.lua index 7cac0935..0c6b1695 100644 --- a/script/vm/getDocs.lua +++ b/script/vm/getDocs.lua @@ -187,55 +187,49 @@ local function makeDiagRange(uri, doc, results) end local row = guide.rowColOf(doc.start) if doc.mode == 'disable-next-line' then - if lines[row+1] then - results[#results+1] = { - mode = 'disable', - names = names, - offset = lines[row+1].start, - source = doc, - } - results[#results+1] = { - mode = 'enable', - names = names, - offset = lines[row+1].finish, - source = doc, - } - end + results[#results+1] = { + mode = 'disable', + names = names, + row = row + 1, + source = doc, + } + results[#results+1] = { + mode = 'enable', + names = names, + row = row + 2, + source = doc, + } elseif doc.mode == 'disable-line' then results[#results+1] = { mode = 'disable', names = names, - offset = lines[row].start, + row = row, source = doc, } results[#results+1] = { mode = 'enable', names = names, - offset = lines[row].finish, + row = row + 1, source = doc, } elseif doc.mode == 'disable' then - if lines[row+1] then - results[#results+1] = { - mode = 'disable', - names = names, - offset = lines[row+1].start, - source = doc, - } - end + results[#results+1] = { + mode = 'disable', + names = names, + row = row + 1, + source = doc, + } elseif doc.mode == 'enable' then - if lines[row+1] then - results[#results+1] = { - mode = 'enable', - names = names, - offset = lines[row+1].start, - source = doc, - } - end + results[#results+1] = { + mode = 'enable', + names = names, + row = row + 1, + source = doc, + } end end -function vm.isDiagDisabledAt(uri, offset, name) +function vm.isDiagDisabledAt(uri, position, name) local status = files.getState(uri) if not status then return false @@ -252,29 +246,26 @@ function vm.isDiagDisabledAt(uri, offset, name) end end table.sort(cache.diagnosticRanges, function (a, b) - return a.offset < b.offset + return a.row < b.row end) end if #cache.diagnosticRanges == 0 then return false end - local stack = {} + local myRow = guide.rowColOf(position) + local count = 0 for _, range in ipairs(cache.diagnosticRanges) do - if range.offset <= offset then + if range.row <= myRow then if not range.names or range.names[name] then if range.mode == 'disable' then - stack[#stack+1] = range + count = count + 1 elseif range.mode == 'enable' then - stack[#stack] = nil + count = count - 1 end end else break end end - local current = stack[#stack] - if not current then - return false - end - return true + return count > 0 end -- cgit v1.2.3 From 087a93d3df198aef7f0b7fb5a5af34b09fa630a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 20:51:51 +0800 Subject: update --- script/core/highlight.lua | 40 ++++++++++++++++++++-------------------- script/core/rename.lua | 25 +++++++++++++++---------- script/parser/guide.lua | 1 + script/parser/newparser.lua | 16 ++++++++-------- 4 files changed, 44 insertions(+), 38 deletions(-) (limited to 'script') diff --git a/script/core/highlight.lua b/script/core/highlight.lua index 47b482d5..02f3c07f 100644 --- a/script/core/highlight.lua +++ b/script/core/highlight.lua @@ -54,12 +54,12 @@ local function find(source, uri, callback) end end -local function checkInIf(source, text, offset) +local function checkInIf(state, source, text, position) -- 检查 end - local endA = source.finish - #'end' + 1 - local endB = source.finish - if offset >= endA - and offset <= endB + local endB = guide.positionToOffset(state, source.finish) + local endA = endB - #'end' + 1 + if position >= source.finish - #'end' + and position <= source.finish and text:sub(endA, endB) == 'end' then return true end @@ -68,7 +68,7 @@ local function checkInIf(source, text, offset) for i = 1, #block.keyword, 2 do local start = block.keyword[i] local finish = block.keyword[i+1] - if offset >= start and offset <= finish then + if position >= start and position <= finish then return true end end @@ -76,12 +76,12 @@ local function checkInIf(source, text, offset) return false end -local function makeIf(source, text, callback) +local function makeIf(state, source, text, callback) -- end - local endA = source.finish - #'end' + 1 - local endB = source.finish + local endB = guide.positionToOffset(state, source.finish) + local endA = endB - #'end' + 1 if text:sub(endA, endB) == 'end' then - callback(endA, endB) + callback(source.finish - #'end', source.finish) end -- 每个子模块 for _, block in ipairs(source) do @@ -94,8 +94,8 @@ local function makeIf(source, text, callback) return false end -local function findKeyWord(ast, text, offset, callback) - guide.eachSourceContain(ast.ast, offset, function (source) +local function findKeyWord(state, text, position, callback) + guide.eachSourceContain(state.ast, position, function (source) if source.type == 'do' or source.type == 'function' or source.type == 'loop' @@ -106,7 +106,7 @@ local function findKeyWord(ast, text, offset, callback) for i = 1, #source.keyword, 2 do local start = source.keyword[i] local finish = source.keyword[i+1] - if offset >= start and offset <= finish then + if position >= start and position <= finish then ok = true break end @@ -119,9 +119,9 @@ local function findKeyWord(ast, text, offset, callback) end end elseif source.type == 'if' then - local ok = checkInIf(source, text, offset) + local ok = checkInIf(state, source, text, position) if ok then - makeIf(source, text, callback) + makeIf(state, source, text, callback) end end end) @@ -238,15 +238,15 @@ local function isLiteralValue(source) end return function (uri, offset) - local ast = files.getState(uri) - if not ast then + local state = files.getState(uri) + if not state then return nil end local text = files.getText(uri) local results = {} local mark = {} - local source = findSource(ast, offset, accept) + local source = findSource(state, offset, accept) if source then local isGlobal = guide.isGlobal(source) local isLiteral = isLiteralValue(source) @@ -344,7 +344,7 @@ return function (uri, offset) end) end - findKeyWord(ast, text, offset, function (start, finish) + findKeyWord(state, text, offset, function (start, finish) results[#results+1] = { start = start, finish = finish, @@ -352,7 +352,7 @@ return function (uri, offset) } end) - checkRegion(ast, text, offset, function (start, finish) + checkRegion(state, text, offset, function (start, finish) results[#results+1] = { start = start, finish = finish, diff --git a/script/core/rename.lua b/script/core/rename.lua index 0ab7a055..0c48dbc4 100644 --- a/script/core/rename.lua +++ b/script/core/rename.lua @@ -36,12 +36,12 @@ local function isValidFunctionName(str) if isValidGlobal(str) then return true end - local pos = str:find(':', 1, true) - if not pos then + local offset = str:find(':', 1, true) + if not offset then return false end - return isValidGlobal(trim(str:sub(1, pos-1))) - and isValidName(trim(str:sub(pos+1))) + return isValidGlobal(trim(str:sub(1, offset-1))) + and isValidName(trim(str:sub(offset+1))) end local function isFunctionGlobalName(source) @@ -81,21 +81,26 @@ local function renameField(source, newname, callback) elseif parent.type == 'getmethod' then callback(source, source.start, source.finish, newname) elseif parent.type == 'setmethod' then - local uri = guide.getUri(source) - local text = files.getText(uri) + local uri = guide.getUri(source) + local text = files.getText(uri) + local state = files.getState(uri) local func = parent.value -- function mt:name () end --> mt['newname'] = function (self) end + local startOffset = guide.positionToOffset(state, parent.start) + 1 + local finishOffset = guide.positionToOffset(state, parent.node.finish) local newstr = string.format('%s[%s] = function ' - , text:sub(parent.start, parent.node.finish) + , text:sub(startOffset, finishOffset) , util.viewString(newname) ) callback(source, func.start, parent.finish, newstr) - local pl = text:find('(', parent.finish, true) + local finishOffset = guide.positionToOffset(state, parent.finish) + local pl = text:find('(', finishOffset, true) if pl then + local insertPos = guide.offsetToPosition(state, pl) if text:find('^%s*%)', pl + 1) then - callback(source, pl + 1, pl, 'self') + callback(source, insertPos, insertPos, 'self') else - callback(source, pl + 1, pl, 'self, ') + callback(source, insertPos, insertPos, 'self, ') end end end diff --git a/script/parser/guide.lua b/script/parser/guide.lua index cea56be8..28a275cf 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -54,6 +54,7 @@ local type = type ---@field ref parser.guide.object[] ---@field returnIndex integer ---@field docs parser.guide.object[] +---@field state table ---@field _root parser.guide.object ---@field _noders noders ---@field _mnode parser.guide.object diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index ba91cd10..957d98e8 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -416,11 +416,11 @@ local function parseLongString() fastForwardToken(finish + 1) local startPos = getPosition(start, 'left') local finishMark = sgsub(mark, '%[', ']') - local stringResult, finishOffset = resolveLongString(finishMark) + local stringResult, finishPos = resolveLongString(finishMark) return { type = 'string', start = startPos, - finish = getPosition(finishOffset, 'right'), + finish = finishPos, [1] = stringResult, [2] = mark, } @@ -1430,14 +1430,14 @@ local function parseExpList(mini) end local function parseIndex() - local bstart = getPosition(Tokens[Index], 'left') + local start = getPosition(Tokens[Index], 'left') Index = Index + 2 skipSpace() local exp = parseExp() local index = { type = 'index', - start = bstart, - finish = exp and exp.finish or (bstart + 1), + start = start, + finish = exp and exp.finish or (start + 1), index = exp } if exp then @@ -1764,9 +1764,9 @@ local function parseSimple(node, funcName) node.parent = call node = call else - local index = parseIndex() + local index = parseIndex() + local bstart = index.start index.type = 'getindex' - index.bstart = index.start index.start = node.start index.node = node node.next = index @@ -1775,7 +1775,7 @@ local function parseSimple(node, funcName) if funcName then pushError { type = 'INDEX_IN_FUNC_NAME', - start = index.bstart, + start = bstart, finish = index.finish, } end -- cgit v1.2.3 From c608e84003aed61a16484296edad3fe4ff363322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 21:50:50 +0800 Subject: update --- script/core/signature.lua | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'script') diff --git a/script/core/signature.lua b/script/core/signature.lua index 26d9867c..007a3787 100644 --- a/script/core/signature.lua +++ b/script/core/signature.lua @@ -7,20 +7,22 @@ local guide = require 'parser.guide' local lookback = require 'core.look-backward' local function findNearCall(uri, ast, pos) - local text = files.getText(uri) + local text = files.getText(uri) + local state = files.getState(uri) local nearCall guide.eachSourceContain(ast.ast, pos, function (src) if src.type == 'call' or src.type == 'table' or src.type == 'function' then + local finishOffset = guide.positionToOffset(state, src.finish) -- call(),$ if src.finish <= pos - and text:sub(src.finish, src.finish) == ')' then + and text:sub(finishOffset, finishOffset) == ')' then return end -- {},$ if src.finish <= pos - and text:sub(src.finish, src.finish) == '}' then + and text:sub(finishOffset, finishOffset) == '}' then return end if not nearCall or nearCall.start <= src.start then @@ -56,13 +58,13 @@ local function makeOneSignature(source, oop, index) for start, finish in converted:gmatch '%s*()[^,]+()' do i = i + 1 params[i] = { - label = {start + argStart, finish - 1 + argStart}, + label = {start + argStart - 1, finish - 1 + argStart}, } end -- 不定参数 if index > i and i > 0 then local lastLabel = params[i].label - local text = label:sub(lastLabel[1], lastLabel[2]) + local text = label:sub(lastLabel[1] + 1, lastLabel[2]) if text == '...' then index = i end @@ -88,11 +90,15 @@ local function makeSignatures(text, call, pos) args[#args+1] = arg end end + local uri = guide.getUri(call) + local state = files.getState(uri) for i, arg in ipairs(args) do - local start = lookback.findTargetSymbol(text, arg.start - 1, '(') - or lookback.findTargetSymbol(text, arg.start - 1, ',') - or arg.start - if start > pos then + local startOffset = guide.positionToOffset(state, arg.start) + startOffset = lookback.findTargetSymbol(text, startOffset, '(') + or lookback.findTargetSymbol(text, startOffset, ',') + or startOffset + local startPos = guide.offsetToPosition(state, startOffset) + if startPos > pos then index = i - 1 break end @@ -102,7 +108,8 @@ local function makeSignatures(text, call, pos) end end if not index then - local backSymbol = lookback.findSymbol(text, pos) + local offset = guide.positionToOffset(state, pos) + local backSymbol = lookback.findSymbol(text, offset) if backSymbol == ',' or backSymbol == '(' then index = #args + 1 @@ -130,13 +137,14 @@ local function makeSignatures(text, call, pos) end return function (uri, pos) - local ast = files.getState(uri) - if not ast then + local state = files.getState(uri) + if not state then return nil end local text = files.getText(uri) - pos = lookback.skipSpace(text, pos) - local call = findNearCall(uri, ast, pos) + local offset = guide.positionToOffset(state, pos) + pos = guide.offsetToPosition(state, lookback.skipSpace(text, offset)) + local call = findNearCall(uri, state, pos) if not call then return nil end -- cgit v1.2.3 From 687313e295f299c1e0e410d4d72d96b1f87b681c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 22:07:48 +0800 Subject: update --- script/core/command/autoRequire.lua | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'script') diff --git a/script/core/command/autoRequire.lua b/script/core/command/autoRequire.lua index e784a827..d711fb16 100644 --- a/script/core/command/autoRequire.lua +++ b/script/core/command/autoRequire.lua @@ -4,19 +4,22 @@ local config = require 'config' local rpath = require 'workspace.require-path' local client = require 'client' local lang = require 'language' +local guide = require 'parser.guide' -local function findInsertOffset(uri) +local function findInsertRow(uri) local text = files.getText(uri) + local state = files.getState(uri) + local lines = state.lines local fmt = { pair = false, quot = '"', col = nil, } - for i = 1, #lines do + for i = 0, #lines do local ln = lines[i] - local lnText = text:sub(ln.start, ln.finish) + local lnText = text:match('[^\r\n]*', ln) if not lnText:find('require', 1, true) then - return ln.start, fmt + return i, fmt else local lpPos = lnText:find '%(' if lpPos then @@ -32,7 +35,7 @@ local function findInsertOffset(uri) end end end - return 1, fmt + return 0, fmt end local function askAutoRequire(visiblePaths) @@ -69,7 +72,7 @@ local function askAutoRequire(visiblePaths) return nameMap[result] end -local function applyAutoRequire(uri, offset, name, result, fmt) +local function applyAutoRequire(uri, row, name, result, fmt) local quotedResult = ('%q'):format(result) if fmt.quot == "'" then quotedResult = ([['%s']]):format(quotedResult:sub(2, -2) @@ -87,11 +90,11 @@ local function applyAutoRequire(uri, offset, name, result, fmt) if fmt.col and fmt.col > #text then sp = (' '):rep(fmt.col - #text - 1) end - text = ('\nlocal %s%s= require%s\n'):format(name, sp, quotedResult) + text = ('local %s%s= require%s\n'):format(name, sp, quotedResult) client.editText(uri, { { - start = offset, - finish = offset - 1, + start = guide.positionOf(row, 0), + finish = guide.positionOf(row, 0), text = text, } }) @@ -120,6 +123,6 @@ return function (data) return end - local offset, fmt = findInsertOffset(uri) + local offset, fmt = findInsertRow(uri) applyAutoRequire(uri, offset, name, result, fmt) end -- cgit v1.2.3 From b6f99a71289f37e3c473a43d0a5290866a0822eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 23:26:28 +0800 Subject: update --- script/core/document-symbol.lua | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'script') diff --git a/script/core/document-symbol.lua b/script/core/document-symbol.lua index 9f950d25..cfabedab 100644 --- a/script/core/document-symbol.lua +++ b/script/core/document-symbol.lua @@ -5,20 +5,26 @@ local define = require 'proto.define' local util = require 'utility' local function buildName(source, text) + local uri = guide.getUri(source) + local state = files.getState(uri) + local startOffset = guide.positionToOffset(state, source.start) if source.type == 'setmethod' or source.type == 'getmethod' then if source.method then - return text:sub(source.start, source.method.finish) + local finishOffset = guide.positionToOffset(state, source.method.finish) + return text:sub(startOffset + 1, finishOffset) end end if source.type == 'setfield' or source.type == 'tablefield' or source.type == 'getfield' then if source.field then - return text:sub(source.start, source.field.finish) + local finishOffset = guide.positionToOffset(state, source.field.finish) + return text:sub(startOffset + 1, finishOffset) end end - return text:sub(source.start, source.finish) + local finishOffset = guide.positionToOffset(state, source.finish) + return text:sub(startOffset + 1, finishOffset) end local function buildFunctionParams(func) @@ -208,7 +214,7 @@ local function buildAnonymousFunction(source, text, used, symbols) detail = ('%sfunction (%s)'):format(head, buildFunctionParams(source)), kind = define.SymbolKind.Function, range = { source.start, source.finish }, - selectionRange = { source.start, source.start }, + selectionRange = { source.keyword[1], source.keyword[2] }, valueRange = { source.start, source.finish }, } end -- cgit v1.2.3 From c2a8838012780eb57fa7de36ae0cfa6fd4388b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Wed, 22 Sep 2021 23:44:21 +0800 Subject: update --- script/core/code-action.lua | 52 +++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 16 deletions(-) (limited to 'script') diff --git a/script/core/code-action.lua b/script/core/code-action.lua index ce71f4af..5c8f1634 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -194,8 +194,13 @@ local function solveSyntaxByAddDoEnd(uri, err, results) [uri] = { { start = err.start, + finish = err.start, + newText = 'do ', + }, + { + start = err.finish, finish = err.finish, - newText = ('do %s end'):format(text:sub(err.start, err.finish)), + newText = ' end', }, } } @@ -262,7 +267,7 @@ local function solveSyntax(uri, diag, results) end local function solveNewlineCall(uri, diag, results) - local start = files.unrange(uri, diag.range) + local start = files.unrange(uri, diag.range) results[#results+1] = { title = lang.script.ACTION_ADD_SEMICOLON, kind = 'quickfix', @@ -346,18 +351,18 @@ local function checkQuickFix(results, uri, start, diagnostics) end local function checkSwapParams(results, uri, start, finish) - local ast = files.getState(uri) - local text = files.getText(uri) - if not ast then + local state = files.getState(uri) + local text = files.getText(uri) + if not state then return end local args = {} - guide.eachSourceBetween(ast.ast, start, finish, function (source) + guide.eachSourceBetween(state.ast, start, finish, function (source) if source.type == 'callargs' or source.type == 'funcargs' then local targetIndex for index, arg in ipairs(source) do - if arg.start - 1 <= finish and arg.finish >= start then + if arg.start <= finish and arg.finish >= start then -- should select only one param if targetIndex then return @@ -370,11 +375,17 @@ local function checkSwapParams(results, uri, start, finish) end local node if source.type == 'callargs' then - node = text:sub(source.parent.node.start, source.parent.node.finish) + node = text:sub( + guide.positionToOffset(state, source.parent.node.start) + 1, + guide.positionToOffset(state, source.parent.node.finish) + ) elseif source.type == 'funcargs' then local var = source.parent.parent if guide.isSet(var) then - node = text:sub(var.start, var.finish) + node = text:sub( + guide.positionToOffset(state, var.start) + 1, + guide.positionToOffset(state, var.finish) + ) else node = lang.script.SYMBOL_ANONYMOUS end @@ -408,12 +419,18 @@ local function checkSwapParams(results, uri, start, finish) { start = myArg.start, finish = myArg.finish, - newText = text:sub(targetArg.start, targetArg.finish), + newText = text:sub( + guide.positionToOffset(state, targetArg.start) + 1, + guide.positionToOffset(state, targetArg.finish) + ), }, { start = targetArg.start, finish = targetArg.finish, - newText = text:sub(myArg.start, myArg.finish), + newText = text:sub( + guide.positionToOffset(state, myArg.start) + 1, + guide.positionToOffset(state, myArg.finish) + ), }, } } @@ -496,13 +513,16 @@ end --end local function checkJsonToLua(results, uri, start, finish) - local text = files.getText(uri) - local jsonStart = text:match ('()[%{%[]', start) + local text = files.getText(uri) + local state = files.getState(uri) + local startOffset = guide.positionToOffset(state, start) + local finishOffset = guide.positionToOffset(state, finish) + local jsonStart = text:match ('()[%{%[]', startOffset + 1) if not jsonStart then return end local jsonFinish - for i = math.min(finish, #text), jsonStart + 1, -1 do + for i = math.min(finishOffset, #text), jsonStart + 1, -1 do local char = text:sub(i, i) if char == ']' or char == '}' then @@ -525,8 +545,8 @@ local function checkJsonToLua(results, uri, start, finish) arguments = { { uri = uri, - start = jsonStart, - finish = jsonFinish, + start = guide.offsetToPosition(state, jsonStart) - 1, + finish = guide.offsetToPosition(state, jsonFinish), } } }, -- cgit v1.2.3 From 0a60aa17c240d4fb080b091891f659a9d74aeffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 00:00:30 +0800 Subject: update --- script/files.lua | 107 ------------------------------------------------------- 1 file changed, 107 deletions(-) (limited to 'script') diff --git a/script/files.lua b/script/files.lua index 25f07ca2..e0c0dccb 100644 --- a/script/files.lua +++ b/script/files.lua @@ -202,8 +202,6 @@ function m.setRawText(uri, text) local file = m.fileMap[uri] file.text = text file.originText = text - m.linesMap[uri] = nil - m.originLinesMap[uri] = nil m.astMap[uri] = nil end @@ -317,8 +315,6 @@ function m.remove(uri) end m.fileMap[uri] = nil m.astMap[uri] = nil - m.linesMap[uri] = nil - m.originLinesMap[uri] = nil m._pairsCache = nil m.flushFileCache(uri) @@ -549,109 +545,6 @@ end ---@alias position table ---- 获取 position 对应的光标位置 ----@param uri uri ----@param position position ----@param isFinish? boolean ----@return integer -function m.offset(uri, position, isFinish) - local file = m.getFile(uri) - local lines = m.getLines(uri) - local text = m.getText(uri) - if not file then - return 0 - end - if file._diffInfo then - lines = m.getOriginLines(uri) - text = m.getOriginText(uri) - end - local row = position.line + 1 - local start, finish, char - if row > #lines then - start, finish = guide.lineRange(lines, #lines) - start = start + 1 - char = util.utf8Len(text, start, finish) - else - start, finish = guide.lineRange(lines, row) - start = start + 1 - char = position.character - end - local utf8Len = util.utf8Len(text, start, finish) - local offset - if char <= 0 then - offset = start - else - if char >= utf8Len then - char = utf8Len - end - local left = utf8.offset(text, char, start) - local right = utf8.offset(text, char + 1, start) - if isFinish then - offset = left - else - offset = right - end - end - if file._diffInfo then - local start, finish = smerger.getOffset(file._diffInfo, offset) - if isFinish then - offset = finish - else - offset = start - end - end - return offset -end - ---- 获取 position 对应的光标位置(根据附近的单词) ----@param uri uri ----@param position position ----@return integer -function m.offsetOfWord(uri, position) - local file = m.getFile(uri) - local lines = m.getLines(uri) - local text = m.getText(uri) - if not file then - return 0 - end - if file._diffInfo then - lines = m.getOriginLines(uri) - text = m.getOriginText(uri) - end - local row = position.line + 1 - local start, finish, char - if row > #lines then - start, finish = guide.lineRange(lines, #lines) - start = start + 1 - char = util.utf8Len(text, start, finish) - else - start, finish = guide.lineRange(lines, row) - start = start + 1 - char = position.character - end - local utf8Len = util.utf8Len(text, start, finish) - local offset - if char <= 0 then - offset = start - else - if char >= utf8Len then - char = utf8Len - end - local left = utf8.offset(text, char, start) - local right = utf8.offset(text, char + 1, start) - if isNameChar(text:sub(left, right - 1)) - and not isNameChar(text:sub(right, right)) then - offset = left - else - offset = right - end - end - if file._diffInfo then - offset = smerger.getOffset(file._diffInfo, offset) - end - return offset -end - --- 将应用差异前的offset转换为应用差异后的offset ---@param uri uri ---@param offset integer -- cgit v1.2.3 From 5c9b1b467af1636ea21a9bd3d398e220790eea54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 15:00:50 +0800 Subject: cleanup --- script/core/code-action.lua | 21 ++++++++-------- script/core/command/solve.lua | 12 ++++----- script/core/semantic-tokens.lua | 5 ++-- script/files.lua | 5 ++-- script/proto/converter.lua | 50 ++++++++++++++++++++++++++++++++++++ script/provider/provider.lua | 56 ++++++++++++++++++++--------------------- 6 files changed, 100 insertions(+), 49 deletions(-) create mode 100644 script/proto/converter.lua (limited to 'script') diff --git a/script/core/code-action.lua b/script/core/code-action.lua index 5c8f1634..2bc6ae50 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -1,8 +1,9 @@ -local files = require 'files' -local lang = require 'language' -local util = require 'utility' -local sp = require 'bee.subprocess' -local guide = require "parser.guide" +local files = require 'files' +local lang = require 'language' +local util = require 'utility' +local sp = require 'bee.subprocess' +local guide = require "parser.guide" +local converter = require 'proto.converter' local function checkDisableByLuaDocExits(uri, row, mode, code) local ast = files.getState(uri) @@ -131,8 +132,8 @@ end local function solveUndefinedGlobal(uri, diag, results) local ast = files.getState(uri) - local offset = files.offsetOfWord(uri, diag.range.start) - guide.eachSourceContain(ast.ast, offset, function (source) + local start = converter.unpackRange(uri, diag.range) + guide.eachSourceContain(ast.ast, start, function (source) if source.type ~= 'getglobal' then return end @@ -150,8 +151,8 @@ end local function solveLowercaseGlobal(uri, diag, results) local ast = files.getState(uri) - local offset = files.offsetOfWord(uri, diag.range.start) - guide.eachSourceContain(ast.ast, offset, function (source) + local start = converter.unpackRange(uri, diag.range) + guide.eachSourceContain(ast.ast, start, function (source) if source.type ~= 'setglobal' then return end @@ -267,7 +268,7 @@ local function solveSyntax(uri, diag, results) end local function solveNewlineCall(uri, diag, results) - local start = files.unrange(uri, diag.range) + local start = converter.unpackRange(uri, diag.range) results[#results+1] = { title = lang.script.ACTION_ADD_SEMICOLON, kind = 'quickfix', diff --git a/script/core/command/solve.lua b/script/core/command/solve.lua index a493de24..790adbee 100644 --- a/script/core/command/solve.lua +++ b/script/core/command/solve.lua @@ -1,7 +1,8 @@ -local files = require 'files' -local guide = require 'parser.guide' -local proto = require 'proto' -local lang = require 'language' +local files = require 'files' +local guide = require 'parser.guide' +local proto = require 'proto' +local lang = require 'language' +local converter = require 'proto.converter' local opMap = { ['+'] = true, @@ -34,8 +35,7 @@ return function (data) return end - local start = files.offsetOfWord(uri, data.range.start) - local finish = files.offsetOfWord(uri, data.range['end']) + local start, finish = converter.unpackRange(uri, data.range) local result = guide.eachSourceContain(ast.ast, start, function (source) if source.start ~= start diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua index 238df862..405f2735 100644 --- a/script/core/semantic-tokens.lua +++ b/script/core/semantic-tokens.lua @@ -5,6 +5,7 @@ local define = require 'proto.define' local vm = require 'vm' local util = require 'utility' local guide = require 'parser.guide' +local converter = require 'proto.converter' local Care = {} Care['setglobal'] = function (source, results) @@ -188,8 +189,8 @@ local function buildTokens(uri, results) local lastLine = 0 local lastStartChar = 0 for i, source in ipairs(results) do - local startPos = files.position(uri, source.start, 'left') - local finishPos = files.position(uri, source.finish, 'right') + local startPos = converter.packPosition(uri, source.start) + local finishPos = converter.packPosition(uri, source.finish) local line = startPos.line local startChar = startPos.character local deltaLine = line - lastLine diff --git a/script/files.lua b/script/files.lua index e0c0dccb..d6ea057f 100644 --- a/script/files.lua +++ b/script/files.lua @@ -518,6 +518,7 @@ function m.getVisibles(uri) end local visibles = {} for i, range in ipairs(ranges) do + -- TODO 改成行号 local start, finish = m.unrange(uri, range) visibles[i] = { start = start, @@ -543,8 +544,6 @@ local function isNameChar(text) return false end ----@alias position table - --- 将应用差异前的offset转换为应用差异后的offset ---@param uri uri ---@param offset integer @@ -626,7 +625,7 @@ function m.position(uri, offset, leftOrRight) end --- 将起点与终点位置转化为 range ----@alias range table + ---@param uri uri ---@param offset1 integer ---@param offset2 integer diff --git a/script/proto/converter.lua b/script/proto/converter.lua new file mode 100644 index 00000000..4b4b9f5d --- /dev/null +++ b/script/proto/converter.lua @@ -0,0 +1,50 @@ +local guide = require 'parser.guide' + +local m = {} + + +---@alias position {line: integer, character: integer} + +---@param uri uri +---@param pos integer +---@return position +function m.packPosition(uri, pos) + local row, col = guide.rowColOf(pos) + return { + line = row, + character = col, + } +end + +---@param uri uri +---@param position position +function m.unpackPosition(uri, position) + local pos = guide.positionOf(position.line, position.character) + return pos +end + +---@alias range {start: position, end: position} + +---@param uri uri +---@param start integer +---@param finish integer +---@return range +function m.packRange(uri, start, finish) + local range = { + start = m.packPosition(uri, start), + ['end'] = m.packPosition(uri, finish), + } + return range +end + +---@param uri uri +---@param range range +---@return integer start +---@return integer finish +function m.unpackRange(uri, range) + local start = m.unpackPosition(uri, range.start) + local finish = m.unpackPosition(uri, range['end']) + return start, finish +end + +return m diff --git a/script/provider/provider.lua b/script/provider/provider.lua index e1bd0f4f..d4bf0bee 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -13,6 +13,7 @@ local lang = require 'language' local progress = require 'progress' local tm = require 'text-merger' local cfgLoader = require 'config.loader' +local converter = require 'proto.converter' local function updateConfig() local new @@ -183,8 +184,8 @@ proto.on('textDocument/hover', function (params) if not files.exists(uri) then return nil end - local offset = files.offsetOfWord(uri, params.position) - local hover, source = core.byUri(uri, offset) + local pos = converter.unpackPosition(uri, params.position) + local hover, source = core.byUri(uri, pos) if not hover then return nil end @@ -205,8 +206,8 @@ proto.on('textDocument/definition', function (params) if not files.exists(uri) then return nil end - local offset = files.offsetOfWord(uri, params.position) - local result = core(uri, offset) + local pos = converter.unpackPosition(uri, params.position) + local result = core(uri, pos) if not result then return nil end @@ -240,8 +241,8 @@ proto.on('textDocument/typeDefinition', function (params) if not files.exists(uri) then return nil end - local offset = files.offsetOfWord(uri, params.position) - local result = core(uri, offset) + local pos = converter.unpackPosition(uri, params.position) + local result = core(uri, pos) if not result then return nil end @@ -275,8 +276,8 @@ proto.on('textDocument/references', function (params) if not files.exists(uri) then return nil end - local offset = files.offsetOfWord(uri, params.position) - local result = core(uri, offset) + local pos = converter.unpackPosition(uri, params.position) + local result = core(uri, pos) if not result then return nil end @@ -296,8 +297,8 @@ proto.on('textDocument/documentHighlight', function (params) if not files.exists(uri) then return nil end - local offset = files.offsetOfWord(uri, params.position) - local result = core(uri, offset) + local pos = converter.unpackPosition(uri, params.position) + local result = core(uri, pos) if not result then return nil end @@ -319,8 +320,8 @@ proto.on('textDocument/rename', function (params) if not files.exists(uri) then return nil end - local offset = files.offsetOfWord(uri, params.position) - local result = core.rename(uri, offset, params.newName) + local pos = converter.unpackPosition(uri, params.position) + local result = core.rename(uri, pos, params.newName) if not result then return nil end @@ -344,8 +345,8 @@ proto.on('textDocument/prepareRename', function (params) if not files.exists(uri) then return nil end - local offset = files.offsetOfWord(uri, params.position) - local result = core.prepareRename(uri, offset) + local pos = converter.unpackPosition(uri, params.position) + local result = core.prepareRename(uri, pos) if not result then return nil end @@ -391,8 +392,8 @@ proto.on('textDocument/completion', function (params) end await.setPriority(1000) local clock = os.clock() - local offset = files.offset(uri, params.position) - local result = core.completion(uri, offset - 1, triggerCharacter) + local pos = converter.unpackPosition(uri, params.position) + local result = core.completion(uri, pos, triggerCharacter) local passed = os.clock() - clock if passed > 0.1 then log.warn(('Completion takes %.3f sec.'):format(passed)) @@ -517,9 +518,9 @@ proto.on('textDocument/signatureHelp', function (params) end await.close('signatureHelp') await.setID('signatureHelp') - local offset = files.offset(uri, params.position) + local pos = converter.unpackPosition(uri, params.position) local core = require 'core.signature' - local results = core(uri, offset - 1) + local results = core(uri, pos) if not results then return nil end @@ -599,7 +600,7 @@ proto.on('textDocument/codeAction', function (params) return nil end - local start, finish = files.unrange(uri, range) + local start, finish = converter.unpackRange(uri, range) local results = core(uri, start, finish, diagnostics) if not results or #results == 0 then @@ -705,8 +706,7 @@ proto.on('textDocument/semanticTokens/range', function (params) start = 0 finish = #files.getText(uri) else - start = files.offsetOfWord(uri, params.range.start) - finish = files.offsetOfWord(uri, params.range['end']) + start, finish = converter.unpackRange(uri, params.range) end local results = core(uri, start, finish) return { @@ -729,8 +729,8 @@ proto.on('textDocument/foldingRange', function (params) local results = {} for _, region in ipairs(regions) do - local startLine = files.position(uri, region.start, 'left').line - local endLine = files.position(uri, region.finish, 'right').line + local startLine = converter.packPosition(uri, region.start).line + local endLine = converter.packPosition(uri, region.finish).line if not region.hideLastLine then endLine = endLine - 1 end @@ -778,8 +778,8 @@ proto.on('textDocument/onTypeFormatting', function (params) return nil end local core = require 'core.type-formatting' - local offset = files.offset(uri, params.position) - local edits = core(uri, offset - 1, ch) + local pos = converter.unpackPosition(uri, params.position) + local edits = core(uri, pos, ch) if not edits or #edits == 0 then return nil end @@ -804,13 +804,13 @@ proto.on('$/requestHint', function (params) end workspace.awaitReady() local uri = params.textDocument.uri - local start, finish = files.unrange(uri, params.range) + local start, finish = converter.unpackRange(uri, params.range) local results = core(uri, start, finish) local hintResults = {} for i, res in ipairs(results) do hintResults[i] = { text = res.text, - pos = files.position(uri, res.offset, res.where), + pos = converter.packPosition(uri, res.offset), kind = res.kind, } end @@ -840,7 +840,7 @@ do for _, edit in ipairs(piece) do edits[#edits+1] = { text = edit.text, - pos = files.position(uri, edit.offset, edit.where), + pos = converter.packPosition(uri, edit.offset), } end end -- cgit v1.2.3 From 466874e8a8e360634833a07508fb48131530b704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 16:02:08 +0800 Subject: cleanup --- script/brave/work.lua | 2 +- script/client.lua | 3 ++- script/core/code-action.lua | 2 +- script/core/command/jsonToLua.lua | 15 ++++++------- script/core/command/removeSpace.lua | 11 +++++----- script/core/command/solve.lua | 2 +- script/core/noder.lua | 2 +- script/provider/diagnostic.lua | 31 ++++++++++++++------------- script/provider/provider.lua | 42 ++++++++++++++++++------------------- 9 files changed, 57 insertions(+), 53 deletions(-) (limited to 'script') diff --git a/script/brave/work.lua b/script/brave/work.lua index ee7b4acd..7af36fda 100644 --- a/script/brave/work.lua +++ b/script/brave/work.lua @@ -26,7 +26,7 @@ brave.on('timer', function (time) end) brave.on('compile', function (text) - local state, err = parser.compile(text, 'lua', 'Lua 5.4') + local state, err = parser.compile(text, 'Lua', 'Lua 5.4') if not state then log.error(err) return diff --git a/script/client.lua b/script/client.lua index c22b59ab..c539a0f7 100644 --- a/script/client.lua +++ b/script/client.lua @@ -4,6 +4,7 @@ local lang = require 'language' local proto = require 'proto' local define = require 'proto.define' local config = require 'config' +local converter = require 'proto.converter' local m = {} @@ -223,7 +224,7 @@ function m.editText(uri, edits) local files = require 'files' local textEdits = {} for i, edit in ipairs(edits) do - textEdits[i] = define.textEdit(files.range(uri, edit.start, edit.finish), edit.text) + textEdits[i] = define.textEdit(converter.packRange(uri, edit.start, edit.finish), edit.text) end proto.request('workspace/applyEdit', { edit = { diff --git a/script/core/code-action.lua b/script/core/code-action.lua index 2bc6ae50..40aef8fc 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -166,7 +166,7 @@ local function findSyntax(uri, diag) local ast = files.getState(uri) for _, err in ipairs(ast.errs) do if err.type:lower():gsub('_', '-') == diag.code then - local range = files.range(uri, err.start, err.finish) + local range = converter.packRange(uri, err.start, err.finish) if util.equal(range, diag.range) then return err end diff --git a/script/core/command/jsonToLua.lua b/script/core/command/jsonToLua.lua index c4f001ff..8a493b5e 100644 --- a/script/core/command/jsonToLua.lua +++ b/script/core/command/jsonToLua.lua @@ -1,9 +1,10 @@ -local files = require 'files' -local json = require 'json' -local util = require 'utility' -local proto = require 'proto' -local define = require 'proto.define' -local lang = require 'language' +local files = require 'files' +local json = require 'json' +local util = require 'utility' +local proto = require 'proto' +local define = require 'proto.define' +local lang = require 'language' +local converter = require 'proto.converter' return function (data) local text = files.getText(data.uri) @@ -26,7 +27,7 @@ return function (data) changes = { [data.uri] = { { - range = files.range(data.uri, data.start, data.finish), + range = converter.packRange(data.uri, data.start, data.finish), newText = luaStr, } } diff --git a/script/core/command/removeSpace.lua b/script/core/command/removeSpace.lua index 34c74ce0..3d7795a1 100644 --- a/script/core/command/removeSpace.lua +++ b/script/core/command/removeSpace.lua @@ -1,7 +1,8 @@ -local files = require 'files' -local guide = require 'parser.guide' -local proto = require 'proto' -local lang = require 'language' +local files = require 'files' +local guide = require 'parser.guide' +local proto = require 'proto' +local lang = require 'language' +local converter = require 'proto.converter' local function isInString(ast, offset) return guide.eachSourceContain(ast.ast, offset, function (source) @@ -30,7 +31,7 @@ return function (data) goto NEXT_LINE end textEdit[#textEdit+1] = { - range = files.range(uri, start, finish), + range = converter.packRange(uri, start, finish), newText = '', } goto NEXT_LINE diff --git a/script/core/command/solve.lua b/script/core/command/solve.lua index 790adbee..9428d065 100644 --- a/script/core/command/solve.lua +++ b/script/core/command/solve.lua @@ -85,7 +85,7 @@ return function (data) changes = { [uri] = { { - range = files.range(uri, result.start, result.finish), + range = converter.packRange(uri, result.start, result.finish), newText = ('(%s)'):format(text:sub(result.start, result.finish)), } }, diff --git a/script/core/noder.lua b/script/core/noder.lua index 1107dcda..177a151c 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -1337,7 +1337,7 @@ function m.compileNode(noders, source) local id = getID(source) bindValue(noders, source, id) - if specialMap[source.special] then + if id and specialMap[source.special] then noders.skip[id] = true end diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua index db377ea0..ec579428 100644 --- a/script/provider/diagnostic.lua +++ b/script/provider/diagnostic.lua @@ -1,14 +1,15 @@ -local await = require 'await' -local proto = require 'proto.proto' -local define = require 'proto.define' -local lang = require 'language' -local files = require 'files' -local config = require 'config' -local core = require 'core.diagnostics' -local util = require 'utility' -local ws = require 'workspace' -local progress = require "progress" -local client = require 'client' +local await = require 'await' +local proto = require 'proto.proto' +local define = require 'proto.define' +local lang = require 'language' +local files = require 'files' +local config = require 'config' +local core = require 'core.diagnostics' +local util = require 'utility' +local ws = require 'workspace' +local progress = require "progress" +local client = require 'client' +local converter = require 'proto.converter' local m = {} m._start = false @@ -48,14 +49,14 @@ local function buildSyntaxError(uri, err) local relUri = rel.uri relatedInformation[#relatedInformation+1] = { message = rmessage, - location = define.location(relUri, files.range(relUri, rel.start, rel.finish)), + location = define.location(relUri, converter.packRange(relUri, rel.start, rel.finish)), } end end return { code = err.type:lower():gsub('_', '-'), - range = files.range(uri, err.start, err.finish), + range = converter.packRange(uri, err.start, err.finish), severity = define.DiagnosticSeverity.Error, source = lang.script.DIAG_SYNTAX_CHECK, message = message, @@ -75,13 +76,13 @@ local function buildDiagnostic(uri, diag) local rtext = files.getText(rel.uri) relatedInformation[#relatedInformation+1] = { message = rel.message or rtext:sub(rel.start, rel.finish), - location = define.location(rel.uri, files.range(rel.uri, rel.start, rel.finish)) + location = define.location(rel.uri, converter.packRange(rel.uri, rel.start, rel.finish)) } end end return { - range = files.range(uri, diag.start, diag.finish), + range = converter.packRange(uri, diag.start, diag.finish), source = lang.script.DIAG_DIAGNOSTICS, severity = diag.level, message = diag.message, diff --git a/script/provider/provider.lua b/script/provider/provider.lua index d4bf0bee..af62372b 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -194,7 +194,7 @@ proto.on('textDocument/hover', function (params) value = tostring(hover), kind = 'markdown', }, - range = files.range(uri, source.start, source.finish), + range = converter.packRange(uri, source.start, source.finish), } end) @@ -218,13 +218,13 @@ proto.on('textDocument/definition', function (params) if files.exists(targetUri) then if client.getAbility 'textDocument.definition.linkSupport' then response[i] = define.locationLink(targetUri - , files.range(targetUri, info.target.start, info.target.finish) - , files.range(targetUri, info.target.start, info.target.finish) - , files.range(uri, info.source.start, info.source.finish) + , converter.packRange(targetUri, info.target.start, info.target.finish) + , converter.packRange(targetUri, info.target.start, info.target.finish) + , converter.packRange(uri, info.source.start, info.source.finish) ) else response[i] = define.location(targetUri - , files.range(targetUri, info.target.start, info.target.finish) + , converter.packRange(targetUri, info.target.start, info.target.finish) ) end end @@ -253,13 +253,13 @@ proto.on('textDocument/typeDefinition', function (params) if files.exists(targetUri) then if client.getAbility 'textDocument.typeDefinition.linkSupport' then response[i] = define.locationLink(targetUri - , files.range(targetUri, info.target.start, info.target.finish) - , files.range(targetUri, info.target.start, info.target.finish) - , files.range(uri, info.source.start, info.source.finish) + , converter.packRange(targetUri, info.target.start, info.target.finish) + , converter.packRange(targetUri, info.target.start, info.target.finish) + , converter.packRange(uri, info.source.start, info.source.finish) ) else response[i] = define.location(targetUri - , files.range(targetUri, info.target.start, info.target.finish) + , converter.packRange(targetUri, info.target.start, info.target.finish) ) end end @@ -285,7 +285,7 @@ proto.on('textDocument/references', function (params) for i, info in ipairs(result) do local targetUri = info.uri response[i] = define.location(targetUri - , files.range(targetUri, info.target.start, info.target.finish) + , converter.packRange(targetUri, info.target.start, info.target.finish) ) end return response @@ -305,7 +305,7 @@ proto.on('textDocument/documentHighlight', function (params) local response = {} for _, info in ipairs(result) do response[#response+1] = { - range = files.range(uri, info.start, info.finish), + range = converter.packRange(uri, info.start, info.finish), kind = info.kind, } end @@ -333,7 +333,7 @@ proto.on('textDocument/rename', function (params) if not workspaceEdit.changes[ruri] then workspaceEdit.changes[ruri] = {} end - local textEdit = define.textEdit(files.range(ruri, info.start, info.finish), info.text) + local textEdit = define.textEdit(converter.packRange(ruri, info.start, info.finish), info.text) workspaceEdit.changes[ruri][#workspaceEdit.changes[ruri]+1] = textEdit end return workspaceEdit @@ -351,7 +351,7 @@ proto.on('textDocument/prepareRename', function (params) return nil end return { - range = files.range(uri, result.start, result.finish), + range = converter.packRange(uri, result.start, result.finish), placeholder = result.text, } end) @@ -418,7 +418,7 @@ proto.on('textDocument/completion', function (params) commitCharacters = res.commitCharacters, command = res.command, textEdit = res.textEdit and { - range = files.range( + range = converter.packRange( uri, res.textEdit.start, res.textEdit.finish @@ -429,7 +429,7 @@ proto.on('textDocument/completion', function (params) local t = {} for j, edit in ipairs(res.additionalTextEdits) do t[j] = { - range = files.range( + range = converter.packRange( uri, edit.start, edit.finish @@ -493,7 +493,7 @@ proto.on('completionItem/resolve', function (item) local t = {} for j, edit in ipairs(resolved.additionalTextEdits) do t[j] = { - range = files.range( + range = converter.packRange( uri, edit.start, edit.finish @@ -563,12 +563,12 @@ proto.on('textDocument/documentSymbol', function (params) local function convert(symbol) await.delay() - symbol.range = files.range( + symbol.range = converter.packRange( uri, symbol.range[1], symbol.range[2] ) - symbol.selectionRange = files.range( + symbol.selectionRange = converter.packRange( uri, symbol.selectionRange[1], symbol.selectionRange[2] @@ -611,7 +611,7 @@ proto.on('textDocument/codeAction', function (params) if res.edit then for turi, changes in pairs(res.edit.changes) do for _, change in ipairs(changes) do - change.range = files.range(turi, change.start, change.finish) + change.range = converter.packRange(turi, change.start, change.finish) change.start = nil change.finish = nil end @@ -658,7 +658,7 @@ proto.on('workspace/symbol', function (params) local function convert(symbol) symbol.location = define.location( symbol.uri, - files.range( + converter.packRange( symbol.uri, symbol.range[1], symbol.range[2] @@ -790,7 +790,7 @@ proto.on('textDocument/onTypeFormatting', function (params) local results = {} for i, edit in ipairs(edits) do results[i] = { - range = files.range(uri, edit.start, edit.finish), + range = converter.packRange(uri, edit.start, edit.finish), newText = edit.text:gsub('\t', tab), } end -- cgit v1.2.3 From 5fd5881a00a9a3c99ee0b8c9e17d1bd40f1f5309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 16:03:37 +0800 Subject: cleanup --- script/core/completion.lua | 29 ------------------ script/files.lua | 76 ---------------------------------------------- 2 files changed, 105 deletions(-) (limited to 'script') diff --git a/script/core/completion.lua b/script/core/completion.lua index e56ed3f8..bb55506a 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -225,35 +225,6 @@ local function buildFunction(results, source, value, oop, data) end end -local function buildInsertRequire(state, targetUri, stemName) - local uri = guide.getUri(state.ast) - local text = files.getText(uri) - local start = 1 - for i = 1, #lines do - local ln = lines[i] - local lnText = text:sub(ln.start, ln.finish) - if not lnText:find('require', 1, true) then - start = ln.start - break - end - end - local path = furi.decode(targetUri) - local visiblePaths = rpath.getVisiblePath(path, config.get 'Lua.runtime.path', true) - if not visiblePaths or #visiblePaths == 0 then - return nil - end - table.sort(visiblePaths, function (a, b) - return #a.expect < #b.expect - end) - return { - { - start = start, - finish = start - 1, - newText = ('local %s = require %q\n'):format(stemName, visiblePaths[1].expect) - } - } -end - local function isSameSource(state, source, pos) if guide.getUri(source) ~= guide.getUri(state.ast) then return false diff --git a/script/files.lua b/script/files.lua index d6ea057f..e7999533 100644 --- a/script/files.lua +++ b/script/files.lua @@ -576,78 +576,6 @@ function m.diffedOffsetBack(uri, offset) return smerger.getOffsetBack(file._diffInfo, offset) end ---- 将光标位置转化为 position ----@param uri uri ----@param offset integer ----@param leftOrRight? '"left"'|'"right"' ----@return position -function m.position(uri, offset, leftOrRight) - local file = m.getFile(uri) - local lines = m.getLines(uri) - local text = m.getText(uri) - if not file then - return { - line = 0, - character = 0, - } - end - if file._diffInfo then - local start, finish = smerger.getOffsetBack(file._diffInfo, offset) - if leftOrRight == 'right' then - offset = finish - else - offset = start - end - lines = m.getOriginLines(uri) - text = m.getOriginText(uri) - end - local row, col = guide.rowColOf(offset) - local start, finish = guide.lineRange(lines, row, true) - start = start + 1 - if col <= finish - start + 1 then - local ucol = util.utf8Len(text, start, start + col - 1) - if row < 1 then - row = 1 - end - if leftOrRight == 'left' and ucol > 0 then - ucol = ucol - 1 - end - return { - line = row - 1, - character = ucol, - } - else - return { - line = row - 1, - character = util.utf8Len(text, start, finish), - } - end -end - ---- 将起点与终点位置转化为 range - ----@param uri uri ----@param offset1 integer ----@param offset2 integer -function m.range(uri, offset1, offset2) - local range = { - start = m.position(uri, offset1, 'left'), - ['end'] = m.position(uri, offset2, 'right'), - } - return range -end - ---- convert `range` to `offsetStart` and `offsetFinish` ----@param uri table ----@param range table ----@return integer start ----@return integer finish -function m.unrange(uri, range) - local start = m.offset(uri, range.start, true) - local finish = m.offset(uri, range['end'], false) - return start, finish -end - --- 获取文件的自定义缓存信息(在文件内容更新后自动失效) function m.getCache(uri) local file = m.fileMap[uri] @@ -778,8 +706,6 @@ end function m.flushCache() for uri, file in pairs(m.fileMap) do file.cacheActiveTime = math.huge - m.linesMap[uri] = nil - m.originLinesMap[uri] = nil m.astMap[uri] = nil file.cache = {} end @@ -791,8 +717,6 @@ function m.flushFileCache(uri) return end file.cacheActiveTime = math.huge - m.linesMap[uri] = nil - m.originLinesMap[uri] = nil m.astMap[uri] = nil file.cache = {} end -- cgit v1.2.3 From 1b2ca30ec04f69d0fbc8127bb72eff488218e086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 16:10:03 +0800 Subject: cleanup --- script/client.lua | 6 +++--- script/proto/converter.lua | 41 +++++++++++++++++++++++++++++++++++++++++ script/proto/define.lua | 32 -------------------------------- script/provider/diagnostic.lua | 4 ++-- script/provider/provider.lua | 14 +++++++------- 5 files changed, 53 insertions(+), 44 deletions(-) (limited to 'script') diff --git a/script/client.lua b/script/client.lua index c539a0f7..e77eaaae 100644 --- a/script/client.lua +++ b/script/client.lua @@ -216,15 +216,15 @@ function m.setConfig(changes, onlyMemory) end end ----@alias textEdit {start: integer, finish: integer, text: string} +---@alias textEditor {start: integer, finish: integer, text: string} ---@param uri uri ----@param edits textEdit[] +---@param edits textEditor[] function m.editText(uri, edits) local files = require 'files' local textEdits = {} for i, edit in ipairs(edits) do - textEdits[i] = define.textEdit(converter.packRange(uri, edit.start, edit.finish), edit.text) + textEdits[i] = converter.textEdit(converter.packRange(uri, edit.start, edit.finish), edit.text) end proto.request('workspace/applyEdit', { edit = { diff --git a/script/proto/converter.lua b/script/proto/converter.lua index 4b4b9f5d..b8744181 100644 --- a/script/proto/converter.lua +++ b/script/proto/converter.lua @@ -18,6 +18,7 @@ end ---@param uri uri ---@param position position +---@return integer function m.unpackPosition(uri, position) local pos = guide.positionOf(position.line, position.character) return pos @@ -47,4 +48,44 @@ function m.unpackRange(uri, range) return start, finish end +---@alias location {uri: uri, range: range} + +---@param uri string +---@param range range +---@return location +function m.location(uri, range) + return { + uri = uri, + range = range, + } +end + +---@alias locationLink {targetUri:uri, targetRange: range, targetSelectionRange: range, originSelectionRange: range} + +---@param uri string +---@param range range +---@param selection range +---@param origin range +---@return locationLink +function m.locationLink(uri, range, selection, origin) + return { + targetUri = uri, + targetRange = range, + targetSelectionRange = selection, + originSelectionRange = origin, + } +end + +---@alias textEdit {range: range, newText: string} + +---@param range range +---@param newtext string +---@return textEdit +function m.textEdit(range, newtext) + return { + range = range, + newText = newtext, + } +end + return m diff --git a/script/proto/define.lua b/script/proto/define.lua index 2e61bc3e..0cdc6406 100644 --- a/script/proto/define.lua +++ b/script/proto/define.lua @@ -1,37 +1,5 @@ local m = {} ----@alias location table ----@param uri string ----@param range range ----@return location -function m.location(uri, range) - return { - uri = uri, - range = range, - } -end - ----@alias locationLink table ----@param uri string ----@param range range ----@param selection range ----@param origin range -function m.locationLink(uri, range, selection, origin) - return { - targetUri = uri, - targetRange = range, - targetSelectionRange = selection, - originSelectionRange = origin, - } -end - -function m.textEdit(range, newtext) - return { - range = range, - newText = newtext, - } -end - --- 诊断等级 m.DiagnosticSeverity = { Error = 1, diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua index ec579428..37c25cf9 100644 --- a/script/provider/diagnostic.lua +++ b/script/provider/diagnostic.lua @@ -49,7 +49,7 @@ local function buildSyntaxError(uri, err) local relUri = rel.uri relatedInformation[#relatedInformation+1] = { message = rmessage, - location = define.location(relUri, converter.packRange(relUri, rel.start, rel.finish)), + location = converter.location(relUri, converter.packRange(relUri, rel.start, rel.finish)), } end end @@ -76,7 +76,7 @@ local function buildDiagnostic(uri, diag) local rtext = files.getText(rel.uri) relatedInformation[#relatedInformation+1] = { message = rel.message or rtext:sub(rel.start, rel.finish), - location = define.location(rel.uri, converter.packRange(rel.uri, rel.start, rel.finish)) + location = converter.location(rel.uri, converter.packRange(rel.uri, rel.start, rel.finish)) } end end diff --git a/script/provider/provider.lua b/script/provider/provider.lua index af62372b..938b3102 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -217,13 +217,13 @@ proto.on('textDocument/definition', function (params) if targetUri then if files.exists(targetUri) then if client.getAbility 'textDocument.definition.linkSupport' then - response[i] = define.locationLink(targetUri + response[i] = converter.locationLink(targetUri , converter.packRange(targetUri, info.target.start, info.target.finish) , converter.packRange(targetUri, info.target.start, info.target.finish) , converter.packRange(uri, info.source.start, info.source.finish) ) else - response[i] = define.location(targetUri + response[i] = converter.location(targetUri , converter.packRange(targetUri, info.target.start, info.target.finish) ) end @@ -252,13 +252,13 @@ proto.on('textDocument/typeDefinition', function (params) if targetUri then if files.exists(targetUri) then if client.getAbility 'textDocument.typeDefinition.linkSupport' then - response[i] = define.locationLink(targetUri + response[i] = converter.locationLink(targetUri , converter.packRange(targetUri, info.target.start, info.target.finish) , converter.packRange(targetUri, info.target.start, info.target.finish) , converter.packRange(uri, info.source.start, info.source.finish) ) else - response[i] = define.location(targetUri + response[i] = converter.location(targetUri , converter.packRange(targetUri, info.target.start, info.target.finish) ) end @@ -284,7 +284,7 @@ proto.on('textDocument/references', function (params) local response = {} for i, info in ipairs(result) do local targetUri = info.uri - response[i] = define.location(targetUri + response[i] = converter.location(targetUri , converter.packRange(targetUri, info.target.start, info.target.finish) ) end @@ -333,7 +333,7 @@ proto.on('textDocument/rename', function (params) if not workspaceEdit.changes[ruri] then workspaceEdit.changes[ruri] = {} end - local textEdit = define.textEdit(converter.packRange(ruri, info.start, info.finish), info.text) + local textEdit = converter.textEdit(converter.packRange(ruri, info.start, info.finish), info.text) workspaceEdit.changes[ruri][#workspaceEdit.changes[ruri]+1] = textEdit end return workspaceEdit @@ -656,7 +656,7 @@ proto.on('workspace/symbol', function (params) end local function convert(symbol) - symbol.location = define.location( + symbol.location = converter.location( symbol.uri, converter.packRange( symbol.uri, -- cgit v1.2.3 From 7253c49258c847601fe27d7e623d7d416556ba06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 16:39:54 +0800 Subject: update --- script/proto/converter.lua | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'script') diff --git a/script/proto/converter.lua b/script/proto/converter.lua index b8744181..d2be23d2 100644 --- a/script/proto/converter.lua +++ b/script/proto/converter.lua @@ -1,4 +1,5 @@ local guide = require 'parser.guide' +local files = require 'files' local m = {} @@ -10,6 +11,12 @@ local m = {} ---@return position function m.packPosition(uri, pos) local row, col = guide.rowColOf(pos) + local state = files.getState(uri) + local text = files.getText(uri) + if text then + local lineOffset = state.lines[row] + col = utf8.len(text, lineOffset, lineOffset + col - 1, true) + end return { line = row, character = col, @@ -20,7 +27,14 @@ end ---@param position position ---@return integer function m.unpackPosition(uri, position) - local pos = guide.positionOf(position.line, position.character) + local row, col = position.line, position.character + local state = files.getState(uri) + local text = files.getText(uri) + if text then + local lineOffset = state.lines[row] + col = utf8.offset(text, lineOffset + col, lineOffset) - 1 + end + local pos = guide.positionOf(row, col) return pos end -- cgit v1.2.3 From c73a5ccba1b39784b8b5ce8ce3f8694aee3e19da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 17:02:59 +0800 Subject: update --- script/core/code-action.lua | 58 ++++++++++++++----------------------- script/core/command/removeSpace.lua | 42 +++++++++++++++++---------- script/files.lua | 8 ++--- 3 files changed, 53 insertions(+), 55 deletions(-) (limited to 'script') diff --git a/script/core/code-action.lua b/script/core/code-action.lua index 40aef8fc..c9f2ddd2 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -6,51 +6,37 @@ local guide = require "parser.guide" local converter = require 'proto.converter' local function checkDisableByLuaDocExits(uri, row, mode, code) - local ast = files.getState(uri) + local state = files.getState(uri) local text = files.getOriginText(uri) - local line = lines[row] - if ast.ast.docs and line then - for _, doc in ipairs(ast.ast.docs) do - if doc.start >= line.start - and doc.finish <= line.finish then - if doc.type == 'doc.diagnostic' then - if doc.mode == mode then - if doc.names then - return { - start = doc.finish, - finish = doc.finish, - newText = text:sub(doc.finish, doc.finish) - .. ', ' - .. code - } - else - return { - start = doc.finish, - finish = doc.finish, - newText = text:sub(doc.finish, doc.finish) - .. ': ' - .. code - } - end - end + local lines = state.lines + if state.ast.docs and lines then + guide.eachSourceBetween(state.ast.docs, guide.positionOf(row, 0), guide.positionOf(row + 1, 0), function (doc) + if doc.type == 'doc.diagnostic' + and doc.mode == mode then + if doc.names then + return { + start = doc.finish, + finish = doc.finish, + newText = ', ' .. code, + } + else + return { + start = doc.finish, + finish = doc.finish, + newText = ': ' .. code, + } end end - end + end) end return nil end local function checkDisableByLuaDocInsert(uri, row, mode, code) - local ast = files.getState(uri) - local text = files.getOriginText(uri) - -- 先看看上一行是不是已经有了 - -- 没有的话就插入一行 - local line = lines[row] return { - start = line.start, - finish = line.start, - newText = '---@diagnostic ' .. mode .. ': ' .. code .. '\n' - .. text:sub(line.start, line.start) + start = guide.positionOf(row, 0), + finish = guide.positionOf(row, 0), + newText = '---@diagnostic ' .. mode .. ': ' .. code .. '\n', } end diff --git a/script/core/command/removeSpace.lua b/script/core/command/removeSpace.lua index 3d7795a1..d92fee79 100644 --- a/script/core/command/removeSpace.lua +++ b/script/core/command/removeSpace.lua @@ -15,27 +15,39 @@ end return function (data) local uri = data.uri local text = files.getText(uri) - local ast = files.getState(uri) - if not lines then + local state = files.getState(uri) + if not state then return end + local lines = {} local textEdit = {} - for i = 1, #lines do - local line = guide.lineContent(lines, text, i, true) - local pos = line:find '[ \t]+$' - if pos then - local start, finish = guide.lineRange(lines, i, true) - start = start + pos - if isInString(ast, start) then - goto NEXT_LINE - end - textEdit[#textEdit+1] = { - range = converter.packRange(uri, start, finish), - newText = '', - } + for i = 0, #lines do + local startPos = lines[i] + local startOffset = guide.positionToOffset(state, startPos) + local finishOffset = text:find('[\r\n]', startOffset) or (#text + 1) + local lastOffset = finishOffset - 1 + local lastChar = text:sub(lastOffset, lastOffset) + if lastChar ~= ' ' and lastChar ~= '\t' then + goto NEXT_LINE + end + local lastPos = guide.offsetToPosition(state, lastOffset) + if isInString(state.ast, lastPos) then goto NEXT_LINE end + local firstOffset = startOffset + for n = lastOffset - 1, startOffset, -1 do + local char = text:sub(n, n) + if char ~= ' ' and char ~= '\t' then + firstOffset = n + 1 + break + end + end + local firstPos = guide.offsetToPosition(state, firstOffset) - 1 + textEdit[#textEdit+1] = { + range = converter.packRange(uri, firstPos, lastPos), + newText = '', + } ::NEXT_LINE:: end diff --git a/script/files.lua b/script/files.lua index e7999533..0c2c2874 100644 --- a/script/files.lua +++ b/script/files.lua @@ -518,11 +518,11 @@ function m.getVisibles(uri) end local visibles = {} for i, range in ipairs(ranges) do - -- TODO 改成行号 - local start, finish = m.unrange(uri, range) + local startRow = guide.rowColOf(range.start) + local finishRow = guide.rowColOf(range['end']) visibles[i] = { - start = start, - finish = finish, + start = guide.positionOf(startRow, 0), + finish = guide.positionOf(finishRow, 0), } end return visibles -- cgit v1.2.3 From cf8bf5e0dff95fb19dc8fc15e7f3cfd5e44edb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 17:03:54 +0800 Subject: disable fornow --- script/core/type-formatting.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'script') diff --git a/script/core/type-formatting.lua b/script/core/type-formatting.lua index cd2044bc..e3494220 100644 --- a/script/core/type-formatting.lua +++ b/script/core/type-formatting.lua @@ -36,6 +36,7 @@ local function findBackward(text, offset, ...) end local function checkSplitOneLine(results, uri, offset, ch) + do return end if ch ~= '\n' then return end -- cgit v1.2.3 From e98031d6afff3e8a1b383ad0548d5857c3f06ace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 17:25:48 +0800 Subject: fix --- script/files.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'script') diff --git a/script/files.lua b/script/files.lua index 0c2c2874..dc39a446 100644 --- a/script/files.lua +++ b/script/files.lua @@ -7,12 +7,10 @@ local proto = require 'proto' local lang = require 'language' local await = require 'await' local timer = require 'timer' -local plugin = require 'plugin' local util = require 'utility' local guide = require 'parser.guide' local smerger = require 'string-merger' local progress = require "progress" -local client = require 'client' local unicode @@ -98,6 +96,7 @@ function m.exists(uri) end local function pluginOnSetText(file, text) + local plugin = require 'plugin' file._diffInfo = nil local suc, result = plugin.dispatch('OnSetText', file.uri, text) if not suc then @@ -409,7 +408,8 @@ function m.eachDll() end function m.compileState(uri, text) - local ws = require 'workspace' + local ws = require 'workspace' + local client = require 'client' if not m.isOpen(uri) and not m.isLibrary(uri) and #text >= config.get 'Lua.workspace.preloadFileSize' * 1000 then -- cgit v1.2.3 From 48fe9fdd2071da918d3c7f0011f0e8c56b865b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 17:34:51 +0800 Subject: fix --- script/files.lua | 4 ++-- script/proto/converter.lua | 24 ++++++++++++++---------- script/provider/diagnostic.lua | 2 +- 3 files changed, 17 insertions(+), 13 deletions(-) (limited to 'script') diff --git a/script/files.lua b/script/files.lua index dc39a446..19f4da89 100644 --- a/script/files.lua +++ b/script/files.lua @@ -518,8 +518,8 @@ function m.getVisibles(uri) end local visibles = {} for i, range in ipairs(ranges) do - local startRow = guide.rowColOf(range.start) - local finishRow = guide.rowColOf(range['end']) + local startRow = range.start.line + local finishRow = range['end'].line visibles[i] = { start = guide.positionOf(startRow, 0), finish = guide.positionOf(finishRow, 0), diff --git a/script/proto/converter.lua b/script/proto/converter.lua index d2be23d2..9ff7e4dd 100644 --- a/script/proto/converter.lua +++ b/script/proto/converter.lua @@ -11,11 +11,13 @@ local m = {} ---@return position function m.packPosition(uri, pos) local row, col = guide.rowColOf(pos) - local state = files.getState(uri) - local text = files.getText(uri) - if text then - local lineOffset = state.lines[row] - col = utf8.len(text, lineOffset, lineOffset + col - 1, true) + if col > 0 then + local state = files.getState(uri) + local text = files.getText(uri) + if text then + local lineOffset = state.lines[row] + col = utf8.len(text, lineOffset, lineOffset + col - 1, true) + end end return { line = row, @@ -28,11 +30,13 @@ end ---@return integer function m.unpackPosition(uri, position) local row, col = position.line, position.character - local state = files.getState(uri) - local text = files.getText(uri) - if text then - local lineOffset = state.lines[row] - col = utf8.offset(text, lineOffset + col, lineOffset) - 1 + if col > 0 then + local state = files.getState(uri) + local text = files.getText(uri) + if text then + local lineOffset = state.lines[row] + col = utf8.offset(text, col + 1, lineOffset) - 1 + end end local pos = guide.positionOf(row, col) return pos diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua index 37c25cf9..382b73d9 100644 --- a/script/provider/diagnostic.lua +++ b/script/provider/diagnostic.lua @@ -46,7 +46,7 @@ local function buildSyntaxError(uri, err) else rmessage = text:sub(rel.start, rel.finish) end - local relUri = rel.uri + local relUri = rel.uri or uri relatedInformation[#relatedInformation+1] = { message = rmessage, location = converter.location(relUri, converter.packRange(relUri, rel.start, rel.finish)), -- cgit v1.2.3 From 127f0c549bb46d218e4b81db6c4ffd40394927ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 19:17:13 +0800 Subject: update parser --- script/parser/newparser.lua | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'script') diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 957d98e8..e4210d0f 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -192,7 +192,6 @@ local ChunkFinishMap = { ['else'] = true, ['elseif'] = true, ['in'] = true, - ['do'] = true, ['then'] = true, ['until'] = true, [';'] = true, @@ -201,6 +200,22 @@ local ChunkFinishMap = { ['}'] = true, } +local ListFinishMap = { + ['end'] = true, + ['else'] = true, + ['elseif'] = true, + ['in'] = true, + ['then'] = true, + ['do'] = true, + ['until'] = true, + ['for'] = true, + ['if'] = true, + ['local'] = true, + ['repeat'] = true, + ['return'] = true, + ['while'] = true, +} + local State, Lua, Line, LineOffset, Chunk, Tokens, Index, LastTokenFinish, Mode, LocalCount local LocalLimit = 200 @@ -1367,7 +1382,7 @@ local function parseExpList(mini) if not token then break end - if ChunkFinishMap[token] then + if ListFinishMap[token] then break end if token == ',' then @@ -1395,7 +1410,8 @@ local function parseExpList(mini) and nextToken ~= 'function' and nextToken ~= 'true' and nextToken ~= 'false' - and nextToken ~= 'nil' then + and nextToken ~= 'nil' + and nextToken ~= 'not' then break end end @@ -1820,7 +1836,9 @@ local function parseVarargs() break end end - if not varargs.node and Mode == 'Lua' then + if not varargs.node + and Mode == 'Lua' + and Chunk[#Chunk].type ~= 'main' then pushError { type = 'UNEXPECT_DOTS', start = varargs.start, @@ -1931,8 +1949,7 @@ local function isChunkFinishToken(token) if tp == 'for' or tp == 'in' or tp == 'loop' then - return token == 'do' - or token == 'end' + return token == 'end' end if tp == 'if' or tp == 'ifblock' @@ -1943,7 +1960,7 @@ local function isChunkFinishToken(token) or token == 'else' or token == 'elseif' end - return token ~= 'do' + return true end local function parseActions() @@ -2226,16 +2243,13 @@ local function parseExpUnit() return nil end -local function parseUnaryOP(level) +local function parseUnaryOP() local token = Tokens[Index + 1] local symbol = UnarySymbol[token] and token or UnaryAlias[token] if not symbol then return nil end local myLevel = UnarySymbol[symbol] - if level and myLevel < level then - return nil - end local op = { type = symbol, start = getPosition(Tokens[Index], 'left'), @@ -2324,7 +2338,7 @@ end function parseExp(asAction, level) local exp - local uop, uopLevel = parseUnaryOP(level) + local uop, uopLevel = parseUnaryOP() if uop then skipSpace() local child = parseExp(asAction, uopLevel) @@ -3249,7 +3263,10 @@ local function parseWhile() Index = Index + 2 skipSpace() - local filter = parseExp() + local nextToken = Tokens[Index + 1] + local filter = nextToken ~= 'do' + and nextToken ~= 'then' + and parseExp() if filter then action.filter = filter action.finish = filter.finish -- cgit v1.2.3 From 5e6897bc1a25b936724af6eeb5fc463a8d395d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 19:28:34 +0800 Subject: fix --- script/core/command/removeSpace.lua | 5 ++--- script/core/diagnostics/trailing-space.lua | 3 +-- script/proto/converter.lua | 2 +- script/provider/provider.lua | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) (limited to 'script') diff --git a/script/core/command/removeSpace.lua b/script/core/command/removeSpace.lua index d92fee79..3021d4a4 100644 --- a/script/core/command/removeSpace.lua +++ b/script/core/command/removeSpace.lua @@ -20,11 +20,10 @@ return function (data) return end - local lines = {} + local lines = state.lines local textEdit = {} for i = 0, #lines do - local startPos = lines[i] - local startOffset = guide.positionToOffset(state, startPos) + local startOffset = lines[i] local finishOffset = text:find('[\r\n]', startOffset) or (#text + 1) local lastOffset = finishOffset - 1 local lastChar = text:sub(lastOffset, lastOffset) diff --git a/script/core/diagnostics/trailing-space.lua b/script/core/diagnostics/trailing-space.lua index 5c66b118..cc51cf77 100644 --- a/script/core/diagnostics/trailing-space.lua +++ b/script/core/diagnostics/trailing-space.lua @@ -20,8 +20,7 @@ return function (uri, callback) local text = files.getText(uri) local lines = state.lines for i = 0, #lines do - local startPos = lines[i] - local startOffset = guide.positionToOffset(state, startPos) + local startOffset = lines[i] local finishOffset = text:find('[\r\n]', startOffset) or (#text + 1) local lastOffset = finishOffset - 1 local lastChar = text:sub(lastOffset, lastOffset) diff --git a/script/proto/converter.lua b/script/proto/converter.lua index 9ff7e4dd..53b65b12 100644 --- a/script/proto/converter.lua +++ b/script/proto/converter.lua @@ -35,7 +35,7 @@ function m.unpackPosition(uri, position) local text = files.getText(uri) if text then local lineOffset = state.lines[row] - col = utf8.offset(text, col + 1, lineOffset) - 1 + col = utf8.offset(text, col + 1, lineOffset) - lineOffset end end local pos = guide.positionOf(row, col) diff --git a/script/provider/provider.lua b/script/provider/provider.lua index 938b3102..39683b2b 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -530,7 +530,7 @@ proto.on('textDocument/signatureHelp', function (params) for j, param in ipairs(result.params) do parameters[j] = { label = { - param.label[1] - 1, + param.label[1], param.label[2], } } -- cgit v1.2.3 From 7ddc57e0f0a8b32d7d8bfa9228e856d897fc8de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 20:38:07 +0800 Subject: update --- script/core/code-action.lua | 1 - script/core/type-formatting.lua | 72 ++++++++++++++++++++++------------------- script/parser/newparser.lua | 2 +- 3 files changed, 39 insertions(+), 36 deletions(-) (limited to 'script') diff --git a/script/core/code-action.lua b/script/core/code-action.lua index c9f2ddd2..ff141bbf 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -7,7 +7,6 @@ local converter = require 'proto.converter' local function checkDisableByLuaDocExits(uri, row, mode, code) local state = files.getState(uri) - local text = files.getOriginText(uri) local lines = state.lines if state.ast.docs and lines then guide.eachSourceBetween(state.ast.docs, guide.positionOf(row, 0), guide.positionOf(row + 1, 0), function (doc) diff --git a/script/core/type-formatting.lua b/script/core/type-formatting.lua index e3494220..b946184b 100644 --- a/script/core/type-formatting.lua +++ b/script/core/type-formatting.lua @@ -2,85 +2,89 @@ local files = require 'files' local lookBackward = require 'core.look-backward' local guide = require "parser.guide" -local function insertIndentation(uri, offset, edits) - local text = files.getOriginText(uri) - local row = guide.rowColOf(offset) - local line = lines[row] - local indent = text:sub(line.start, line.finish):match '^%s*' +local function insertIndentation(uri, position, edits) + local text = files.getText(uri) + local state = files.getState(uri) + local row = guide.rowColOf(position) + local offset = state.lines[row] + local indent = text:match('^%s*', offset) for _, edit in ipairs(edits) do edit.text = edit.text:gsub('\n', '\n' .. indent) end end -local function findForward(text, offset, ...) - local pos = text:match('^[ \t]*()', offset) - if not pos then +local function findForward(uri, position, ...) + local text = files.getText(uri) + local state = files.getState(uri) + local offset = guide.positionToOffset(state, position) + local firstOffset = text:match('^[ \t]*()', offset + 1) + if not firstOffset then return nil end for _, symbol in ipairs { ... } do - if text:sub(pos, pos + #symbol - 1) == symbol then - return pos, symbol + if text:sub(firstOffset, firstOffset + #symbol - 1) == symbol then + return guide.offsetToPosition(state, firstOffset - 1), symbol end end return nil end -local function findBackward(text, offset, ...) - local pos = lookBackward.findAnyOffset(text, offset) +local function findBackward(uri, position, ...) + local text = files.getText(uri) + local state = files.getState(uri) + local offset = guide.positionToOffset(state, position) + local lastOffset = lookBackward.findAnyOffset(text, offset) for _, symbol in ipairs { ... } do - if text:sub(pos - #symbol + 1, pos) == symbol then - return pos - #symbol + 1, symbol + if text:sub(lastOffset - #symbol + 1, lastOffset) == symbol then + return guide.offsetToPosition(state, lastOffset) end end return nil end -local function checkSplitOneLine(results, uri, offset, ch) - do return end +local function checkSplitOneLine(results, uri, position, ch) if ch ~= '\n' then return end - local text = files.getOriginText(uri) - local fOffset, fSymbol = findForward(text, offset + 1, 'end', '}') - if not fOffset then + local fPosition, fSymbol = findForward(uri, position, 'end', '}') + if not fPosition then return end - local bOffset, bSymbol = findBackward(text, offset, 'then', 'do', ')', '{') - if not bOffset then + local bPosition = findBackward(uri, position, 'then', 'do', ')', '{') + if not bPosition then return end local edits = {} edits[#edits+1] = { - start = bOffset + #bSymbol, - finish = offset, + start = bPosition, + finish = position, text = '\n\t', } edits[#edits+1] = { - start = offset + 1, - finish = fOffset + #fSymbol - 1, - text = '' + start = position, + finish = fPosition + 1, + text = '', } edits[#edits+1] = { - start = fOffset + #fSymbol, - finish = fOffset + #fSymbol - 1, - text = '\n' .. fSymbol + start = fPosition + 1, + finish = fPosition + 1, + text = '\n' .. fSymbol:sub(1, 1) } - insertIndentation(uri, bOffset, edits) + insertIndentation(uri, bPosition, edits) for _, edit in ipairs(edits) do results[#results+1] = edit end end -return function (uri, offset, ch) +return function (uri, position, ch) local ast = files.getState(uri) - local text = files.getOriginText(uri) - if not ast or not text then + if not ast then return nil end local results = {} -- split `function () $ end` - checkSplitOneLine(results, uri, offset, ch) + checkSplitOneLine(results, uri, position, ch) return results end diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index e4210d0f..96b1fb64 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -2627,7 +2627,7 @@ local function parseMultiVars(n1, parser, isLocal) if not nrest or not nrest[i] then v.redundant = { max = max, - passed = v + 2, + passed = i + 2, } pushActionIntoCurrentChunk(v) end -- cgit v1.2.3 From 291a7b3a7fcaee5bc761722ca46265f3cd7f70f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 20:51:25 +0800 Subject: fix --- script/core/code-action.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'script') diff --git a/script/core/code-action.lua b/script/core/code-action.lua index ff141bbf..8256107e 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -6,10 +6,13 @@ local guide = require "parser.guide" local converter = require 'proto.converter' local function checkDisableByLuaDocExits(uri, row, mode, code) + if row < 0 then + return nil + end local state = files.getState(uri) local lines = state.lines if state.ast.docs and lines then - guide.eachSourceBetween(state.ast.docs, guide.positionOf(row, 0), guide.positionOf(row + 1, 0), function (doc) + return guide.eachSourceBetween(state.ast.docs, guide.positionOf(row, 0), guide.positionOf(row + 1, 0), function (doc) if doc.type == 'doc.diagnostic' and doc.mode == mode then if doc.names then @@ -73,8 +76,8 @@ local function disableDiagnostic(uri, code, start, results) checkDisableByLuaDocExits (uri, row - 1, 'disable-next-line', code) or checkDisableByLuaDocInsert(uri, row, 'disable-next-line', code)) pushEdit(lang.script('ACTION_DISABLE_DIAG_FILE', code), - checkDisableByLuaDocExits (uri, 1, 'disable', code) - or checkDisableByLuaDocInsert(uri, 1, 'disable', code)) + checkDisableByLuaDocExits (uri, 0, 'disable', code) + or checkDisableByLuaDocInsert(uri, 0, 'disable', code)) end local function markGlobal(uri, name, results) -- cgit v1.2.3 From c95e9c91236bccb4593a0d9d218dca78bcb06ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Thu, 23 Sep 2021 22:15:47 +0800 Subject: update --- script/files.lua | 20 +++++++++++++ script/parser/guide.lua | 24 ++++++---------- script/parser/lines.lua | 20 ++++--------- script/proto/converter.lua | 72 ++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 97 insertions(+), 39 deletions(-) (limited to 'script') diff --git a/script/files.lua b/script/files.lua index 19f4da89..659a1aa0 100644 --- a/script/files.lua +++ b/script/files.lua @@ -112,6 +112,7 @@ local function pluginOnSetText(file, text) suc, result, diffs = xpcall(smerger.mergeDiff, log.error, text, result) if suc then file._diffInfo = diffs + file.originLines = parser.lines(text) return result else if DEVELOP and result then @@ -291,6 +292,17 @@ function m.getOriginText(uri) return file.originText end +--- 获取文件原始行表 +---@param uri uri +---@return integer[] +function m.getOriginLines(uri) + local file = m.fileMap[uri] + if not file then + return nil + end + return file.originLines +end + function m.getChildFiles(uri) local results = {} local uris = m.getAllUris() @@ -576,6 +588,14 @@ function m.diffedOffsetBack(uri, offset) return smerger.getOffsetBack(file._diffInfo, offset) end +function m.hasDiffed(uri) + local file = m.getFile(uri) + if not file then + return false + end + return file._diffInfo ~= nil +end + --- 获取文件的自定义缓存信息(在文件内容更新后自动失效) function m.getCache(uri) local file = m.fileMap[uri] diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 28a275cf..b65d9680 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -759,17 +759,19 @@ function m.positionOf(row, col) return row * 10000 + col end +function m.positionToOffsetByLines(lines, position) + local row, col = m.rowColOf(position) + return lines[row] + col - 1 +end + --- 返回全文光标位置 ---@param state any ---@param position integer function m.positionToOffset(state, position) - local lines = state.lines - local row, col = m.rowColOf(position) - return lines[row] + col - 1 + return m.positionToOffsetByLines(state.lines, position) end -function m.offsetToPosition(state, offset) - local lines = state.lines +function m.offsetToPositionByLines(lines, offset) local left = 0 local right = #lines local row = 0 @@ -794,16 +796,8 @@ function m.offsetToPosition(state, offset) return m.positionOf(row, col) end -function m.lineContent(lines, text, row, ignoreNL) - local line = lines[row] - if not line then - return '' - end - if ignoreNL then - return text:sub(line.start, line.range) - else - return text:sub(line.start, line.finish) - end +function m.offsetToPosition(state, offset) + return m.offsetToPositionByLines(state.lines, offset) end local isSetMap = { diff --git a/script/parser/lines.lua b/script/parser/lines.lua index 06023df1..964aabf4 100644 --- a/script/parser/lines.lua +++ b/script/parser/lines.lua @@ -5,30 +5,20 @@ local ssub = string.sub return function (text) local current = 1 local lines = {} - local i = 1 + lines[0] = 1 + local i = 0 while true do local pos = sfind(text,'[\r\n]', current) if not pos then break end - local line = { - start = current - 1, - range = pos - 1, - } - lines[i] = line i = i + 1 if ssub(text, pos, pos + 1) == '\r\n' then - current = pos + 2 - line.finish = pos + 1 + current = pos + 2 else - current = pos + 1 - line.finish = pos + current = pos + 1 end + lines[i] = current end - lines[i] = { - start = current - 1, - finish = #text, - range = #text, - } return lines end diff --git a/script/proto/converter.lua b/script/proto/converter.lua index 53b65b12..5fb73c14 100644 --- a/script/proto/converter.lua +++ b/script/proto/converter.lua @@ -3,13 +3,9 @@ local files = require 'files' local m = {} - ---@alias position {line: integer, character: integer} ----@param uri uri ----@param pos integer ----@return position -function m.packPosition(uri, pos) +local function rawPackPosition(uri, pos) local row, col = guide.rowColOf(pos) if col > 0 then local state = files.getState(uri) @@ -25,10 +21,39 @@ function m.packPosition(uri, pos) } end ----@param uri uri ----@param position position ----@return integer -function m.unpackPosition(uri, position) + +local function diffedPackPosition(uri, originPos) + local state = files.getState(uri) + local originLines = files.getOriginLines(uri) + local originOffset = guide.positionToOffsetByLines(originLines, originPos) + local offset = files.diffedOffsetBack(uri, originOffset) + local pos = guide.offsetToPosition(state, offset) + local row, col = guide.rowColOf(pos) + if col > 0 then + local text = files.getOriginText(uri) + if text then + local lineOffset = originLines[row] + col = utf8.len(text, lineOffset, lineOffset + col - 1, true) + end + end + return { + line = row, + character = col, + } +end + +---@param uri uri +---@param pos integer +---@return position +function m.packPosition(uri, pos) + if files.hasDiffed(uri) then + return diffedPackPosition(uri, pos) + else + return rawPackPosition(uri, pos) + end +end + +local function rawUnpackPosition(uri, position) local row, col = position.line, position.character if col > 0 then local state = files.getState(uri) @@ -42,6 +67,35 @@ function m.unpackPosition(uri, position) return pos end +local function diffedUnpackPosition(uri, position) + local row, col = position.line, position.character + local originLines = files.getOriginLines(uri) + if col > 0 then + local text = files.getOriginText(uri) + if text then + local lineOffset = originLines[row] + col = utf8.offset(text, col + 1, lineOffset) - lineOffset + end + end + local state = files.getState(uri) + local originPos = guide.positionOf(row, col) + local originOffset = guide.positionToOffsetByLines(originLines, originPos) + local offset = files.diffedOffset(originOffset) + local pos = guide.offsetToPosition(state, offset) + return pos +end + +---@param uri uri +---@param position position +---@return integer +function m.unpackPosition(uri, position) + if files.hasDiffed(uri) then + return diffedUnpackPosition(uri, position) + else + return rawUnpackPosition(uri, position) + end +end + ---@alias range {start: position, end: position} ---@param uri uri -- cgit v1.2.3 From 9f73d326ccea763762cefd2866e477796221b10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 24 Sep 2021 10:16:04 +0800 Subject: fix --- script/core/noder.lua | 2 +- script/parser/newparser.lua | 62 +++++++++++++++++++++++---------------------- 2 files changed, 33 insertions(+), 31 deletions(-) (limited to 'script') diff --git a/script/core/noder.lua b/script/core/noder.lua index 177a151c..927f3c6d 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -1271,7 +1271,7 @@ compileNodeMap = util.switch() type = 'call', dummy = true, start = source.keyword[3], - finish = source.keyword[6], + finish = exps[#exps].finish, node = node, args = { param1, param2 }, parent = source, diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index 96b1fb64..ee2c5e62 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -1496,36 +1496,6 @@ local function parseTable() goto CONTINUE end local lastRight = lastRightPosition() - if token == '[' then - if wantSep then - pushError { - type = 'MISS_SEP_IN_TABLE', - start = lastRight, - finish = getPosition(Tokens[Index], 'left'), - } - end - wantSep = true - index = index + 1 - local tindex = parseIndex() - skipSpace() - if expectAssign() then - skipSpace() - local ivalue = parseExp() - tindex.type = 'tableindex' - tindex.parent = tbl - if ivalue then - ivalue.parent = tindex - tindex.finish = ivalue.finish - tindex.value = ivalue - else - missExp() - end - tbl[index] = tindex - else - missSymbol '=' - end - goto CONTINUE - end local exp = parseExp(true) if exp then @@ -1581,6 +1551,38 @@ local function parseTable() tbl[index] = texp goto CONTINUE end + + if token == '[' then + if wantSep then + pushError { + type = 'MISS_SEP_IN_TABLE', + start = lastRight, + finish = getPosition(Tokens[Index], 'left'), + } + end + wantSep = true + index = index + 1 + local tindex = parseIndex() + skipSpace() + if expectAssign() then + skipSpace() + local ivalue = parseExp() + tindex.type = 'tableindex' + tindex.parent = tbl + if ivalue then + ivalue.parent = tindex + tindex.finish = ivalue.finish + tindex.value = ivalue + else + missExp() + end + tbl[index] = tindex + else + missSymbol '=' + end + goto CONTINUE + end + missSymbol '}' break ::CONTINUE:: -- cgit v1.2.3 From 05e9b84c2f9c0effbe5ae86c19fd390ba8067e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 24 Sep 2021 11:54:59 +0800 Subject: fix --- script/proto/converter.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'script') diff --git a/script/proto/converter.lua b/script/proto/converter.lua index 5fb73c14..0ff07290 100644 --- a/script/proto/converter.lua +++ b/script/proto/converter.lua @@ -21,14 +21,13 @@ local function rawPackPosition(uri, pos) } end - -local function diffedPackPosition(uri, originPos) +local function diffedPackPosition(uri, pos) local state = files.getState(uri) + local offset = guide.positionToOffset(state, pos) + local originOffset = files.diffedOffsetBack(uri, offset) local originLines = files.getOriginLines(uri) - local originOffset = guide.positionToOffsetByLines(originLines, originPos) - local offset = files.diffedOffsetBack(uri, originOffset) - local pos = guide.offsetToPosition(state, offset) - local row, col = guide.rowColOf(pos) + local originPos = guide.offsetToPositionByLines(originLines, originOffset) + local row, col = guide.rowColOf(originPos) if col > 0 then local text = files.getOriginText(uri) if text then @@ -80,7 +79,7 @@ local function diffedUnpackPosition(uri, position) local state = files.getState(uri) local originPos = guide.positionOf(row, col) local originOffset = guide.positionToOffsetByLines(originLines, originPos) - local offset = files.diffedOffset(originOffset) + local offset = files.diffedOffset(uri, originOffset) local pos = guide.offsetToPosition(state, offset) return pos end -- cgit v1.2.3 From 8870b6a8f8827c7eaa70f9663f754586aa2408fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 24 Sep 2021 15:02:50 +0800 Subject: resolve #639 --- script/core/hover/label.lua | 3 +-- script/core/infer.lua | 5 +++-- script/core/noder.lua | 3 +++ script/parser/luadoc.lua | 2 +- script/parser/newparser.lua | 16 ++++++++-------- 5 files changed, 16 insertions(+), 13 deletions(-) (limited to 'script') diff --git a/script/core/hover/label.lua b/script/core/hover/label.lua index a29cf672..3322e0d3 100644 --- a/script/core/hover/label.lua +++ b/script/core/hover/label.lua @@ -50,8 +50,7 @@ local function asValue(source, title) local literal = infer.searchAndViewLiterals(source) local cont if not infer.hasType(source, 'string') - and not type:find('%[%]$') - and not type:find('%w%<') then + and not type:find('%[%]$') then if #vm.getRefs(source, '*') > 0 or infer.hasType(source, 'table') then cont = buildTable(source) diff --git a/script/core/infer.lua b/script/core/infer.lua index d6784c67..2915f7f5 100644 --- a/script/core/infer.lua +++ b/script/core/infer.lua @@ -371,9 +371,10 @@ function m.getDocName(doc) return nodeName .. '[]' end if doc.type == 'doc.type.table' then - local key = m.viewDocName(doc.tkey) or '?' + local node = m.viewDocName(doc.node) or '?' + local key = m.viewDocName(doc.tkey) or '?' local value = m.viewDocName(doc.tvalue) or '?' - return ('table<%s, %s>'):format(key, value) + return ('%s<%s, %s>'):format(node, key, value) end if doc.type == 'doc.type.function' then return m.viewDocFunction(doc) diff --git a/script/core/noder.lua b/script/core/noder.lua index 927f3c6d..f364f458 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -905,6 +905,9 @@ compileNodeMap = util.switch() end) : case 'doc.type.table' : call(function (noders, id, source) + if source.node then + pushForward(noders, id, getID(source.node), INFO_CLASS_TO_EXNTENDS) + end if source.tkey then local keyID = id .. TABLE_KEY pushForward(noders, keyID, getID(source.tkey)) diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 4a431e68..56da32f2 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -324,7 +324,7 @@ local function parseTypeUnitTable(parent, node) end nextSymbolOrError('>') - node.parent = result; + node.parent = result result.finish = getFinish() result.tkey = key result.tvalue = value diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index ee2c5e62..8469b68d 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -374,6 +374,12 @@ local function fastForwardToken(offset) or myOffset >= offset then break end + local token = Tokens[Index + 1] + if NLMap[token] then + Line = Line + 1 + LineOffset = Tokens[Index] + #token + State.lines[Line] = LineOffset + end Index = Index + 2 end end @@ -390,14 +396,8 @@ local function resolveLongString(finishMark) local stringResult = ssub(Lua, start, finishOffset - 1) local lastLN = stringResult:find '[\r\n][^\r\n]*$' if lastLN then - local result, count = stringResult - : gsub('\r\n', '\n') - : gsub('[\r\n]', '\n') - LineOffset = lastLN + start - for i = Line + 1, Line + count do - State.lines[i] = LineOffset - end - Line = Line + count + local result = stringResult + : gsub('\r\n?', '\n') stringResult = result end fastForwardToken(finishOffset + #finishMark) -- cgit v1.2.3 From ba29b31eccde71832b97a2d01af6339e5e52a94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Fri, 24 Sep 2021 15:03:57 +0800 Subject: `completion.displayContext` default to `0` --- script/config/config.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'script') diff --git a/script/config/config.lua b/script/config/config.lua index b44b48dc..52848a44 100644 --- a/script/config/config.lua +++ b/script/config/config.lua @@ -180,7 +180,7 @@ local Template = { ['Lua.completion.enable'] = Type.Boolean >> true, ['Lua.completion.callSnippet'] = Type.String >> 'Disable', ['Lua.completion.keywordSnippet'] = Type.String >> 'Replace', - ['Lua.completion.displayContext'] = Type.Integer >> 6, + ['Lua.completion.displayContext'] = Type.Integer >> 0, ['Lua.completion.workspaceWord'] = Type.Boolean >> true, ['Lua.completion.showWord'] = Type.String >> 'Fallback', ['Lua.completion.autoRequire'] = Type.Boolean >> true, -- cgit v1.2.3