diff options
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/core/completion.lua | 83 | ||||
-rw-r--r-- | server/src/core/definition.lua | 17 | ||||
-rw-r--r-- | server/src/core/diagnostics.lua | 27 | ||||
-rw-r--r-- | server/src/core/implementation.lua | 21 | ||||
-rw-r--r-- | server/src/emmy/manager.lua | 24 | ||||
-rw-r--r-- | server/src/emmy/type.lua | 33 | ||||
-rw-r--r-- | server/src/method/textDocument/completion.lua | 54 | ||||
-rw-r--r-- | server/src/method/textDocument/publishDiagnostics.lua | 5 | ||||
-rw-r--r-- | server/src/parser/ast.lua | 47 | ||||
-rw-r--r-- | server/src/parser/grammar.lua | 17 | ||||
-rw-r--r-- | server/src/vm/emmy.lua | 53 | ||||
-rw-r--r-- | server/src/vm/local.lua | 7 | ||||
-rw-r--r-- | server/src/vm/vm.lua | 43 |
13 files changed, 311 insertions, 120 deletions
diff --git a/server/src/core/completion.lua b/server/src/core/completion.lua index 4a487441..d0da95cd 100644 --- a/server/src/core/completion.lua +++ b/server/src/core/completion.lua @@ -397,6 +397,14 @@ local function searchEmmyKeyword(vm, source, word, callback) end end +local function searchEmmyClass(vm, source, word, callback) + vm.emmyMgr:eachClass(function (class) + if matchKey(word, class:getName()) then + callback(class:getName(), class:getSource(), CompletionItemKind.Class) + end + end) +end + local function searchSource(vm, source, word, callback) if source.type == 'keyword' then searchAsKeyowrd(vm, source, word, callback) @@ -430,6 +438,9 @@ local function searchSource(vm, source, word, callback) searchEmmyKeyword(vm, source, word, callback) return end + if source:get 'target class' then + searchEmmyClass(vm, source, word, callback) + end end local function searchInRequire(vm, select, source, callback) @@ -650,11 +661,9 @@ local function makeList(source, pos, word) end, list end -local function searchToclose(text, word, callback, pos) - if #word > 0 then - pos = pos - 1 - end - if text:sub(pos, pos) ~= '*' then +local function searchToclose(text, source, word, callback) + local pos = source.start + if text:sub(pos-1, pos-1) ~= '*' then return false end if not matchKey(word, 'toclose') then @@ -685,7 +694,62 @@ local function keywordSource(vm, word, pos) } end -return function (vm, text, pos, word, oldText) +local function findStartPos(pos, buf) + local res = nil + for i = pos, 1, -1 do + local c = buf:sub(i, i) + if c:find '[%w_]' then + res = i + else + break + end + end + if not res then + for i = pos, 1, -1 do + local c = buf:sub(i, i) + if c == '.' or c == ':' or c == '|' then + res = i + break + elseif c == '#' or c == '@' then + res = i + 1 + break + elseif c:find '[%s%c]' then + else + break + end + end + end + if not res then + return pos + end + return res +end + +local function findWord(position, text) + local word = text + for i = position, 1, -1 do + local c = text:sub(i, i) + if not c:find '[%w_]' then + word = text:sub(i+1, position) + break + end + end + return word:match('^([%w_]*)') +end + +local function getSource(vm, pos, text, filter) + local word = findWord(pos, text) + local source = findSource(vm, pos, filter) + if source then + return source, pos, word + end + pos = findStartPos(pos, text) + source = findSource(vm, pos, filter) + or keywordSource(vm, word, pos) + return source, pos, word +end + +return function (vm, text, pos, oldText) local filter = { ['name'] = true, ['string'] = true, @@ -695,10 +759,7 @@ return function (vm, text, pos, word, oldText) ['emmyIncomplete'] = true, ['call'] = true, } - local source = findSource(vm, pos, filter) - or findSource(vm, pos-1, filter) - or findSource(vm, pos+1, filter) - or keywordSource(vm, word, pos) + local source, pos, word = getSource(vm, pos, text, filter) if not source then return nil end @@ -709,7 +770,7 @@ return function (vm, text, pos, word, oldText) end end local callback, list = makeList(source, pos, word) - if searchToclose(text, word, callback, pos) then + if searchToclose(text, source, word, callback) then return list end searchSpecial(vm, source, word, callback, pos) diff --git a/server/src/core/definition.lua b/server/src/core/definition.lua index a7296bfb..1c030452 100644 --- a/server/src/core/definition.lua +++ b/server/src/core/definition.lua @@ -196,6 +196,20 @@ local function jumpUri(vm, source, lsp) return positions end +local function parseClass(vm, source) + local className = source:get 'target class' + local positions = {} + vm.emmyMgr:eachClass(className, function (class) + local src = class:getSource() + positions[#positions+1] = { + src.start, + src.finish, + src.uri, + } + end) + return positions +end + return function (vm, source, lsp) if not source then return nil @@ -217,4 +231,7 @@ return function (vm, source, lsp) return parseValue(vm, source, lsp) or parseValueSimily(vm, source, lsp) end + if source:get 'target class' then + return parseClass(vm, source) + end end diff --git a/server/src/core/diagnostics.lua b/server/src/core/diagnostics.lua index d49f8da2..0732b7e3 100644 --- a/server/src/core/diagnostics.lua +++ b/server/src/core/diagnostics.lua @@ -439,10 +439,6 @@ function mt:checkEmmyClass(source, callback) local related = {} local current = class for _ = 1, 10 do - if parent:getName() == class:getName() then - callback(source.start, source.finish, lang.script.DIAG_CYCLIC_EXTENDS, related) - break - end local extends = current.extends if not extends then break @@ -452,20 +448,37 @@ function mt:checkEmmyClass(source, callback) finish = current:getSource().finish, uri = current:getSource().uri, } - current = parent - parent = self.vm.emmyMgr:eachClass(extends, function (parent) + current = self.vm.emmyMgr:eachClass(extends, function (parent) return parent end) - if not parent then + if not current then + break + end + if current:getName() == class:getName() then + callback(source.start, source.finish, lang.script.DIAG_CYCLIC_EXTENDS, related) break end end end +function mt:checkEmmyType(source, callback) + for _, tpsource in ipairs(source) do + local name = tpsource[1] + local class = self.vm.emmyMgr:eachClass(name, function (class) + return class + end) + if not class then + callback(tpsource.start, tpsource.finish, lang.script.DIAG_UNDEFINED_CLASS) + end + end +end + function mt:searchEmmyLua(callback) self.vm:eachSource(function (source) if source.type == 'emmyClass' then self:checkEmmyClass(source, callback) + elseif source.type == 'emmyType' then + self:checkEmmyType(source, callback) end end) end diff --git a/server/src/core/implementation.lua b/server/src/core/implementation.lua index 1b8006b1..450b9a0c 100644 --- a/server/src/core/implementation.lua +++ b/server/src/core/implementation.lua @@ -166,6 +166,20 @@ local function jumpUri(vm, source, lsp) return positions end +local function parseClass(vm, source) + local className = source:get 'target class' + local positions = {} + vm.emmyMgr:eachClass(className, function (class) + local src = class:getSource() + positions[#positions+1] = { + src.start, + src.finish, + src.uri, + } + end) + return positions +end + return function (vm, source, lsp) if not source then return nil @@ -180,4 +194,11 @@ return function (vm, source, lsp) if source:get 'target uri' then return jumpUri(vm, source, lsp) end + if source:get 'in index' then + return parseValue(vm, source, lsp) + or parseValueSimily(vm, source, lsp) + end + if source:get 'target class' then + return parseClass(vm, source) + end end diff --git a/server/src/emmy/manager.lua b/server/src/emmy/manager.lua index 99b46420..cd5c97f7 100644 --- a/server/src/emmy/manager.lua +++ b/server/src/emmy/manager.lua @@ -1,5 +1,6 @@ local listMgr = require 'vm.list' local newClass = require 'emmy.class' +local newType = require 'emmy.type' local mt = {} mt.__index = mt @@ -26,7 +27,7 @@ function mt:flushClass(name) list.version = version end -function mt:eachClass(name, callback) +function mt:eachClassByName(name, callback) self:flushClass(name) local list = self._class[name] if not list then @@ -42,6 +43,22 @@ function mt:eachClass(name, callback) end end +function mt:eachClass(...) + local n = select('#', ...) + if n == 1 then + local callback = ... + for name in pairs(self._class) do + local res = self:eachClassByName(name, callback) + if res ~= nil then + return res + end + end + else + local name, callback = ... + return self:eachClassByName(name, callback) + end +end + function mt:addClass(source) local className = source[1][1] self:flushClass(className) @@ -57,10 +74,15 @@ function mt:addClass(source) return list[source.id] end +function mt:createType(source) + return newType(source) +end + function mt:remove() end return function () + ---@class emmyMgr local self = setmetatable({ _class = {}, }, mt) diff --git a/server/src/emmy/type.lua b/server/src/emmy/type.lua new file mode 100644 index 00000000..84b43144 --- /dev/null +++ b/server/src/emmy/type.lua @@ -0,0 +1,33 @@ +local listMgr = require 'vm.list' + +local function buildName(source) + local names = {} + for i, type in ipairs(source) do + names[i] = type[1] + end + return table.concat(names, '|') +end + +local mt = {} +mt.__index = mt +mt.type = 'emmy.type' + +function mt:getType() + return self.name +end + +function mt:getName() + return self.name +end + +function mt:getSource() + return listMgr.get(self.source) +end + +return function (source) + local self = setmetatable({ + name = buildName(source), + source = source.id, + }, mt) + return self +end diff --git a/server/src/method/textDocument/completion.lua b/server/src/method/textDocument/completion.lua index 7f60708b..1b9aa73f 100644 --- a/server/src/method/textDocument/completion.lua +++ b/server/src/method/textDocument/completion.lua @@ -16,70 +16,27 @@ local function posToRange(lines, start, finish) } end -local function findStartPos(pos, buf) - local res = nil - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c:find '[%w_]' then - res = i - else - break - end - end - if not res then - for i = pos, 1, -1 do - local c = buf:sub(i, i) - if c == '.' or c == ':' then - res = i - elseif c:find '[%s%c]' then - else - break - end - end - end - if not res then - return pos - end - return res -end - -local function findWord(position, text) - local word = text - for i = position, 1, -1 do - local c = text:sub(i, i) - if not c:find '[%w_]' then - word = text:sub(i+1, position) - break - end - end - return word:match('^([%w_]*)') -end - local function fastCompletion(lsp, params, lines) local uri = params.textDocument.uri local text, oldText = lsp:getText(uri) -- lua是从1开始的,因此都要+1 local position = lines:positionAsChar(params.position.line + 1, params.position.character) - local word = findWord(position, text) - local startPos = findStartPos(position, text) local vm = lsp:getVM(uri) - if not vm or not startPos then + if not vm then vm = lsp:loadVM(uri) if not vm then return nil end end - startPos = startPos or position - local items = core.completion(vm, text, startPos, word, oldText) + local items = core.completion(vm, text, position, oldText) if not items or #items == 0 then vm = lsp:loadVM(uri) if not vm then return nil end - startPos = startPos or position - items = core.completion(vm, text, startPos, word) + items = core.completion(vm, text, position) if not items or #items == 0 then return nil end @@ -93,16 +50,13 @@ local function finishCompletion(lsp, params, lines) local text = lsp:getText(uri) -- lua是从1开始的,因此都要+1 local position = lines:positionAsChar(params.position.line + 1, params.position.character) - local word = findWord(position, text) - local startPos = findStartPos(position, text) local vm = lsp:loadVM(uri) if not vm then return nil end - startPos = startPos or position - local items = core.completion(vm, text, startPos, word) + local items = core.completion(vm, text, position) if not items or #items == 0 then return nil end diff --git a/server/src/method/textDocument/publishDiagnostics.lua b/server/src/method/textDocument/publishDiagnostics.lua index fbe65bb3..3a4e4658 100644 --- a/server/src/method/textDocument/publishDiagnostics.lua +++ b/server/src/method/textDocument/publishDiagnostics.lua @@ -43,7 +43,7 @@ local function getRange(start, finish, lines) } end -local function createInfo(data, lines) +local function createInfo(lsp, data, lines) local diagnostic = { source = lang.script.DIAG_DIAGNOSTICS, range = getRange(data.start, data.finish, lines), @@ -54,6 +54,7 @@ local function createInfo(data, lines) if data.related then local related = {} for i, info in ipairs(data.related) do + local _, lines = lsp:getVM(info.uri) local message = info.message if not message then local start_line = lines:rowcol(info.start) @@ -144,7 +145,7 @@ return function (lsp, params) if vm then local datas = core.diagnostics(vm, lines, uri) for _, data in ipairs(datas) do - diagnostics[#diagnostics+1] = createInfo(data, lines) + diagnostics[#diagnostics+1] = createInfo(lsp, data, lines) end end if errs then diff --git a/server/src/parser/ast.lua b/server/src/parser/ast.lua index 3b397c0d..ff0a4306 100644 --- a/server/src/parser/ast.lua +++ b/server/src/parser/ast.lua @@ -629,8 +629,10 @@ local Defs = { end if isField then table[#table+1] = arg - wantField = false - start = arg.finish + 1 + if arg.finish then + wantField = false + start = arg.finish + 1 + end else wantField = true start = arg @@ -1113,7 +1115,10 @@ local Defs = { [1] = '' } end, - EmmyClass = function (class, extends) + EmmyClass = function (class, startPos, extends) + if extends and extends[1] == '' then + extends.start = startPos + end return { type = 'emmyClass', start = class.start, @@ -1122,17 +1127,26 @@ local Defs = { [2] = extends, } end, - EmmyType = function (typeDef, ...) - if ... then - typeDef.enum = {...} - end + EmmyType = function (typeDef) return typeDef end, EmmyCommonType = function (...) - return { + local result = { type = 'emmyType', ... } + for i = 1, #result // 2 do + local startPos = result[i * 2] + local emmyName = result[i * 2 + 1] + if emmyName[1] == '' then + emmyName.start = startPos + end + result[i + 1] = emmyName + end + for i = #result // 2 + 2, #result do + result[i] = nil + end + return result end, EmmyArrayType = function (typeName) typeName.type = 'emmyArrayType' @@ -1145,23 +1159,26 @@ local Defs = { return typeName end, EmmyFunctionType = function (...) - return { + local result = { type = 'emmyFunctionType', ... } + return result end, - EmmyAlias = function (name, emmyName) + EmmyAlias = function (name, emmyName, ...) return { type = 'emmyAlias', - [1] = name, - [2] = emmyName, + name, + emmyName, + ... } end, - EmmyParam = function (argName, emmyName) + EmmyParam = function (argName, emmyName, ...) return { type = 'emmyParam', - [1] = argName, - [2] = emmyName, + argName, + emmyName, + ... } end, EmmyReturn = function (...) diff --git a/server/src/parser/grammar.lua b/server/src/parser/grammar.lua index 6743ed89..599aada2 100644 --- a/server/src/parser/grammar.lua +++ b/server/src/parser/grammar.lua @@ -338,7 +338,7 @@ ArgList <- (DOTS / Name / Sp {} COMMA)* Table <- Sp ({} TL TableFields? DirtyTR) -> Table -TableFields <- (TableSep {} / TableField)+ +TableFields <- (Emmy / TableSep {} / TableField)+ TableSep <- COMMA / SEMICOLON TableField <- NewIndex / NewField / Exp NewIndex <- Sp ({} BL DirtyExp DirtyBR NeedAssign DirtyExp) @@ -362,6 +362,7 @@ LabelEnd <- {} -> LabelEnd -- 纯占位,修改了 `relabel.lua` 使重复定义不抛错 Action <- !END . Set <- END +Emmy <- '---@' ]] grammar 'Action' [[ @@ -533,26 +534,24 @@ EmmyIncomplete <- MustEmmyName -> EmmyIncomplete EmmyClass <- (MustEmmyName EmmyParentClass?) -EmmyParentClass <- %s* ':' %s* MustEmmyName +EmmyParentClass <- %s* {} ':' %s* MustEmmyName -EmmyType <- (EmmyTypeDef EmmyTypeEnums*) - -> EmmyType -EmmyTypeDef <- EmmyFunctionType +EmmyType <- EmmyFunctionType / EmmyArrayType / EmmyTableType / EmmyCommonType EmmyCommonType <- EmmyTypeNames -> EmmyCommonType -EmmyTypeNames <- EmmyTypeName ('|' EmmyTypeName)* +EmmyTypeNames <- EmmyTypeName (%s* {} '|' %s* !String EmmyTypeName)* EmmyTypeName <- EmmyFunctionType / EmmyArrayType / EmmyTableType / MustEmmyName -EmmyTypeEnums <- %s+ '|' %s+ String +EmmyTypeEnums <- %s* '|' %s* String -EmmyAlias <- MustEmmyName %s+ EmmyType +EmmyAlias <- MustEmmyName %s+ EmmyType EmmyTypeEnums* -EmmyParam <- MustEmmyName %s+ EmmyType +EmmyParam <- MustEmmyName %s+ EmmyType EmmyTypeEnums* EmmyReturn <- EmmyType diff --git a/server/src/vm/emmy.lua b/server/src/vm/emmy.lua index 6e5c2b13..22f72ae6 100644 --- a/server/src/vm/emmy.lua +++ b/server/src/vm/emmy.lua @@ -1,15 +1,66 @@ local mt = require 'vm.manager' +function mt:clearEmmy() + self._emmy = nil +end + +function mt:doEmmy(action) + local tp = action.type + if tp == 'emmyClass' then + self:doEmmyClass(action) + elseif tp == 'emmyType' then + self:doEmmyType(action) + elseif tp == 'emmyAlias' then + elseif tp == 'emmyParam' then + elseif tp == 'emmyReturn' then + elseif tp == 'emmyField' then + elseif tp == 'emmyGeneric' then + elseif tp == 'emmyVararg' then + elseif tp == 'emmyLanguage' then + elseif tp == 'emmyArrayType' then + elseif tp == 'emmyTableType' then + elseif tp == 'emmyFunctionType' then + elseif tp == 'emmySee' then + elseif tp == 'emmyIncomplete' then + self:doEmmyIncomplete(action) + end +end + +function mt:getEmmy() + local emmy = self._emmy + self._emmy = nil + return emmy +end + function mt:doEmmyClass(action) local emmyMgr = self.emmyMgr self:instantSource(action) local class = emmyMgr:addClass(action) - self.emmy = class + local extends = action[2] + if extends then + self:instantSource(extends) + extends:set('target class', extends[1]) + end + self._emmy = class action:set('emmy.class', class) + if self.lsp then + self.lsp.global:markSet(self:getUri()) + end end function mt:doEmmyType(action) local emmyMgr = self.emmyMgr + self:instantSource(action) + local type = emmyMgr:createType(action) + self._emmy = type + action:set('emmy.type', type) + for _, obj in ipairs(action) do + self:instantSource(obj) + obj:set('target class', obj[1]) + end + if self.lsp then + self.lsp.global:markGet(self:getUri()) + end end function mt:doEmmyIncomplete(action) diff --git a/server/src/vm/local.lua b/server/src/vm/local.lua index e75ed149..d047b106 100644 --- a/server/src/vm/local.lua +++ b/server/src/vm/local.lua @@ -111,6 +111,13 @@ function mt:shadow(old) end group[#group+1] = self self._shadow = group + + if not self:getSource() then + log.debug('not self:getSource()', table.dump(self)) + end + if not old.close then + log.debug('not old.close', table.dump(old)) + end old:close(self:getSource().start - 1) end diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua index 0e84468b..f10e07a4 100644 --- a/server/src/vm/vm.lua +++ b/server/src/vm/vm.lua @@ -41,12 +41,14 @@ function mt:buildTable(source) end local n = 0 for index, obj in ipairs(source) do + local emmy = self:getEmmy() if obj.type == 'pair' then local value = self:getFirstInMulti(self:getExp(obj[2])) local key = obj[1] self:instantSource(obj) self:instantSource(key) key:bindValue(value, 'set') + value:setEmmy(emmy) if key.index then local index = self:getIndex(obj) key:set('parent', tbl) @@ -58,6 +60,8 @@ function mt:buildTable(source) tbl:setChild(key[1], value, key) end end + elseif obj.type:sub(1, 4) == 'emmy' then + self:doEmmy(obj) else local value = self:getExp(obj) if value.type == 'multi' then @@ -776,10 +780,11 @@ function mt:doGoTo(source) end end -function mt:setOne(var, value) +function mt:setOne(var, value, emmy) if not value then value = valueMgr.create('nil', self:getDefaultSource()) end + value:setEmmy(emmy) self:instantSource(var) if var.type == 'name' then self:setName(var[1], var, value) @@ -803,6 +808,7 @@ function mt:setOne(var, value) end function mt:doSet(action) + local emmy = self:getEmmy() if not action[2] then return end @@ -822,11 +828,12 @@ function mt:doSet(action) local i = 0 self:forList(vars, function (var) i = i + 1 - self:setOne(var, values[i]) + self:setOne(var, values[i], emmy) end) end function mt:doLocal(action) + local emmy = self:getEmmy() self:instantSource(action) local vars = action[1] local exps = action[2] @@ -849,9 +856,8 @@ function mt:doLocal(action) if values then value = values[i] end - self:createLocal(key[1], key, value) + self:createLocal(key[1], key, value, emmy) end) - self.emmy = nil end function mt:doIf(action) @@ -1008,6 +1014,10 @@ function mt:doAction(action) end end local tp = action.type + if tp:sub(1, 4) == 'emmy' then + self:doEmmy(action) + return + end if tp == 'do' then self:doDo(action) elseif tp == 'break' then @@ -1039,27 +1049,11 @@ function mt:doAction(action) self:doFunction(action) elseif tp == 'localfunction' then self:doLocalFunction(action) - elseif tp == 'emmyClass' then - --self:doEmmyClass(action) - elseif tp == 'emmyType' then - --self:doEmmyType(action) - elseif tp == 'emmyAlias' then - elseif tp == 'emmyParam' then - elseif tp == 'emmyReturn' then - elseif tp == 'emmyField' then - elseif tp == 'emmyGeneric' then - elseif tp == 'emmyVararg' then - elseif tp == 'emmyLanguage' then - elseif tp == 'emmyArrayType' then - elseif tp == 'emmyTableType' then - elseif tp == 'emmyFunctionType' then - elseif tp == 'emmySee' then - elseif tp == 'emmyIncomplete' then - self:doEmmyIncomplete(action) else self:getExp(action) action:set('as action', true) end + self:clearEmmy() end function mt:doActions(actions) @@ -1161,20 +1155,20 @@ function mt:bindLabel(source, label, action) end end -function mt:createLocal(key, source, value) +function mt:createLocal(key, source, value, emmy) local loc = self:bindLocal(source) if not value then value = self:createValue('nil', source) end if loc then loc:setValue(value) - loc:setEmmy(self.emmy) + loc:setEmmy(emmy) self:saveLocal(key, loc) return loc end loc = localMgr.create(key, source, value) - loc:setEmmy(self.emmy) + loc:setEmmy(emmy) self:saveLocal(key, loc) self:bindLocal(source, loc, 'local') value:addInfo('local', source) @@ -1281,6 +1275,7 @@ return function (ast, lsp, uri) main = nil, env = nil, emmy = nil, + ---@type emmyMgr emmyMgr = lsp and lsp.emmy or emmyMgr(), lsp = lsp, uri = uri or '', |