summaryrefslogtreecommitdiff
path: root/server-beta/src
diff options
context:
space:
mode:
Diffstat (limited to 'server-beta/src')
-rw-r--r--server-beta/src/await.lua100
-rw-r--r--server-beta/src/brave/brave.lua70
-rw-r--r--server-beta/src/brave/init.lua4
-rw-r--r--server-beta/src/brave/log.lua52
-rw-r--r--server-beta/src/brave/work.lua55
-rw-r--r--server-beta/src/config.lua193
-rw-r--r--server-beta/src/core/definition.lua105
-rw-r--r--server-beta/src/core/diagnostics/ambiguity-1.lua69
-rw-r--r--server-beta/src/core/diagnostics/duplicate-index.lua62
-rw-r--r--server-beta/src/core/diagnostics/emmy-lua.lua3
-rw-r--r--server-beta/src/core/diagnostics/empty-block.lua49
-rw-r--r--server-beta/src/core/diagnostics/global-in-nil-env.lua66
-rw-r--r--server-beta/src/core/diagnostics/init.lua41
-rw-r--r--server-beta/src/core/diagnostics/lowercase-global.lua39
-rw-r--r--server-beta/src/core/diagnostics/newfield-call.lua37
-rw-r--r--server-beta/src/core/diagnostics/newline-call.lua38
-rw-r--r--server-beta/src/core/diagnostics/redefined-local.lua32
-rw-r--r--server-beta/src/core/diagnostics/redundant-parameter.lua102
-rw-r--r--server-beta/src/core/diagnostics/redundant-value.lua24
-rw-r--r--server-beta/src/core/diagnostics/trailing-space.lua55
-rw-r--r--server-beta/src/core/diagnostics/undefined-env-child.lua32
-rw-r--r--server-beta/src/core/diagnostics/undefined-global.lua63
-rw-r--r--server-beta/src/core/diagnostics/unused-function.lua45
-rw-r--r--server-beta/src/core/diagnostics/unused-label.lua22
-rw-r--r--server-beta/src/core/diagnostics/unused-local.lua46
-rw-r--r--server-beta/src/core/diagnostics/unused-vararg.lua31
-rw-r--r--server-beta/src/core/highlight.lua230
-rw-r--r--server-beta/src/core/hover/arg.lua20
-rw-r--r--server-beta/src/core/hover/init.lua56
-rw-r--r--server-beta/src/core/hover/label.lua103
-rw-r--r--server-beta/src/core/hover/name.lua64
-rw-r--r--server-beta/src/core/hover/return.lua34
-rw-r--r--server-beta/src/core/hover/table.lua35
-rw-r--r--server-beta/src/core/reference.lua84
-rw-r--r--server-beta/src/core/rename.lua374
-rw-r--r--server-beta/src/define/DiagnosticDefaultSeverity.lua21
-rw-r--r--server-beta/src/define/DiagnosticSeverity.lua6
-rw-r--r--server-beta/src/define/ErrorCodes.lua16
-rw-r--r--server-beta/src/doctor.lua380
-rw-r--r--server-beta/src/file-uri.lua108
-rw-r--r--server-beta/src/files.lua290
-rw-r--r--server-beta/src/fs-utility.lua314
-rw-r--r--server-beta/src/glob/gitignore.lua221
-rw-r--r--server-beta/src/glob/glob.lua122
-rw-r--r--server-beta/src/glob/init.lua4
-rw-r--r--server-beta/src/glob/matcher.lua151
-rw-r--r--server-beta/src/json/decode.lua153
-rw-r--r--server-beta/src/json/encode.lua135
-rw-r--r--server-beta/src/json/init.lua6
-rw-r--r--server-beta/src/jsonrpc.lua41
-rw-r--r--server-beta/src/language.lua137
-rw-r--r--server-beta/src/library.lua296
-rw-r--r--server-beta/src/log.lua140
-rw-r--r--server-beta/src/parser/ast.lua1738
-rw-r--r--server-beta/src/parser/calcline.lua93
-rw-r--r--server-beta/src/parser/compile.lua549
-rw-r--r--server-beta/src/parser/emmy.lua321
-rw-r--r--server-beta/src/parser/grammar.lua537
-rw-r--r--server-beta/src/parser/guide.lua621
-rw-r--r--server-beta/src/parser/init.lua11
-rw-r--r--server-beta/src/parser/lines.lua46
-rw-r--r--server-beta/src/parser/parse.lua45
-rw-r--r--server-beta/src/parser/relabel.lua361
-rw-r--r--server-beta/src/parser/split.lua9
-rw-r--r--server-beta/src/proto/define.lua140
-rw-r--r--server-beta/src/proto/init.lua3
-rw-r--r--server-beta/src/proto/proto.lua133
-rw-r--r--server-beta/src/provider/capability.lua42
-rw-r--r--server-beta/src/provider/completion.lua53
-rw-r--r--server-beta/src/provider/diagnostic.lua209
-rw-r--r--server-beta/src/provider/init.lua298
-rw-r--r--server-beta/src/provider/markdown.lua22
-rw-r--r--server-beta/src/pub/init.lua4
-rw-r--r--server-beta/src/pub/pub.lua236
-rw-r--r--server-beta/src/pub/report.lua21
-rw-r--r--server-beta/src/service/init.lua3
-rw-r--r--server-beta/src/service/service.lua137
-rw-r--r--server-beta/src/timer.lua218
-rw-r--r--server-beta/src/utility.lua452
-rw-r--r--server-beta/src/vm/dummySource.lua13
-rw-r--r--server-beta/src/vm/eachDef.lua65
-rw-r--r--server-beta/src/vm/eachField.lua169
-rw-r--r--server-beta/src/vm/eachRef.lua500
-rw-r--r--server-beta/src/vm/getGlobal.lua6
-rw-r--r--server-beta/src/vm/getGlobals.lua45
-rw-r--r--server-beta/src/vm/getLibrary.lua89
-rw-r--r--server-beta/src/vm/getLinks.lua48
-rw-r--r--server-beta/src/vm/getValue.lua895
-rw-r--r--server-beta/src/vm/init.lua11
-rw-r--r--server-beta/src/vm/special.lua0
-rw-r--r--server-beta/src/vm/vm.lua81
-rw-r--r--server-beta/src/workspace/init.lua3
-rw-r--r--server-beta/src/workspace/workspace.lua194
93 files changed, 0 insertions, 13397 deletions
diff --git a/server-beta/src/await.lua b/server-beta/src/await.lua
deleted file mode 100644
index 5a960e96..00000000
--- a/server-beta/src/await.lua
+++ /dev/null
@@ -1,100 +0,0 @@
-local timer = require 'timer'
-
----@class await
-local m = {}
-m.type = 'await'
-
-m.coTracker = setmetatable({}, { __mode = 'k' })
-m.delayQueue = {}
-m.delayQueueIndex = 1
-
---- 设置错误处理器
----@param errHandle function {comment = '当有错误发生时,会以错误堆栈为参数调用该函数'}
-function m.setErrorHandle(errHandle)
- m.errorHandle = errHandle
-end
-
-function m.checkResult(co, ...)
- local suc, err = ...
- if not suc and m.errorHandle then
- m.errorHandle(debug.traceback(co, err))
- end
- return ...
-end
-
---- 创建一个任务
-function m.create(callback, ...)
- local co = coroutine.create(callback)
- m.coTracker[co] = true
- return m.checkResult(co, coroutine.resume(co, ...))
-end
-
---- 休眠一段时间
----@param time number
-function m.sleep(time, getVersion)
- if not coroutine.isyieldable() then
- if m.errorHandle then
- m.errorHandle(debug.traceback('Cannot yield'))
- end
- return
- end
- local version = getVersion and getVersion()
- local co = coroutine.running()
- timer.wait(time, function ()
- if version == (getVersion and getVersion()) then
- return m.checkResult(co, coroutine.resume(co))
- else
- coroutine.close(co)
- end
- end)
- return coroutine.yield(getVersion)
-end
-
---- 等待直到唤醒
----@param callback function
-function m.wait(callback, ...)
- if not coroutine.isyieldable() then
- return
- end
- local co = coroutine.running()
- callback(function (...)
- return m.checkResult(co, coroutine.resume(co, ...))
- end)
- return coroutine.yield(...)
-end
-
---- 延迟
-function m.delay(getVersion)
- if not coroutine.isyieldable() then
- return
- end
- local co = coroutine.running()
- local version = getVersion and getVersion()
- m.delayQueue[#m.delayQueue+1] = function ()
- if version == (getVersion and getVersion()) then
- return m.checkResult(co, coroutine.resume(co))
- else
- coroutine.close(co)
- end
- end
- return coroutine.yield()
-end
-
---- 步进
-function m.step()
- local waker = m.delayQueue[m.delayQueueIndex]
- if waker then
- m.delayQueue[m.delayQueueIndex] = false
- m.delayQueueIndex = m.delayQueueIndex + 1
- waker()
- return true
- else
- for i = 1, #m.delayQueue do
- m.delayQueue[i] = nil
- end
- m.delayQueueIndex = 1
- return false
- end
-end
-
-return m
diff --git a/server-beta/src/brave/brave.lua b/server-beta/src/brave/brave.lua
deleted file mode 100644
index 08909074..00000000
--- a/server-beta/src/brave/brave.lua
+++ /dev/null
@@ -1,70 +0,0 @@
-local thread = require 'bee.thread'
-
----@class pub_brave
-local m = {}
-m.type = 'brave'
-m.ability = {}
-m.queue = {}
-
---- 注册成为勇者
-function m.register(id)
- m.taskpad = thread.channel('taskpad' .. id)
- m.waiter = thread.channel('waiter' .. id)
- m.id = id
-
- if #m.queue > 0 then
- for _, info in ipairs(m.queue) do
- m.waiter:push(info.name, info.params)
- end
- end
- m.queue = nil
-
- m.start()
-end
-
---- 注册能力
-function m.on(name, callback)
- m.ability[name] = callback
-end
-
---- 报告
-function m.push(name, params)
- if m.waiter then
- m.waiter:push(name, params)
- else
- m.queue[#m.queue+1] = {
- name = name,
- params = params,
- }
- end
-end
-
---- 开始找工作
-function m.start()
- m.push('mem', collectgarbage 'count')
- while true do
- local suc, name, id, params = m.taskpad:pop()
- if not suc then
- -- 找不到工作的勇者,只好睡觉
- thread.sleep(0.001)
- goto CONTINUE
- end
- local ability = m.ability[name]
- -- TODO
- if not ability then
- m.waiter:push(id)
- log.error('Brave can not handle this work: ' .. name)
- goto CONTINUE
- end
- local ok, res = xpcall(ability, log.error, params)
- if ok then
- m.waiter:push(id, res)
- else
- m.waiter:push(id)
- end
- m.push('mem', collectgarbage 'count')
- ::CONTINUE::
- end
-end
-
-return m
diff --git a/server-beta/src/brave/init.lua b/server-beta/src/brave/init.lua
deleted file mode 100644
index 24c2e412..00000000
--- a/server-beta/src/brave/init.lua
+++ /dev/null
@@ -1,4 +0,0 @@
-local brave = require 'brave.brave'
-require 'brave.work'
-
-return brave
diff --git a/server-beta/src/brave/log.lua b/server-beta/src/brave/log.lua
deleted file mode 100644
index cd27cd55..00000000
--- a/server-beta/src/brave/log.lua
+++ /dev/null
@@ -1,52 +0,0 @@
-local brave = require 'brave'
-
-local tablePack = table.pack
-local tostring = tostring
-local tableConcat = table.concat
-local debugTraceBack = debug.traceback
-local debugGetInfo = debug.getinfo
-
-_ENV = nil
-
-local function pushLog(level, ...)
- local t = tablePack(...)
- for i = 1, t.n do
- t[i] = tostring(t[i])
- end
- local str = tableConcat(t, '\t', 1, t.n)
- if level == 'error' then
- str = str .. '\n' .. debugTraceBack(nil, 3)
- end
- local info = debugGetInfo(3, 'Sl')
- brave.push('log', {
- level = level,
- msg = str,
- src = info.source,
- line = info.currentline,
- })
- return str
-end
-
-local m = {}
-
-function m.info(...)
- pushLog('info', ...)
-end
-
-function m.debug(...)
- pushLog('debug', ...)
-end
-
-function m.trace(...)
- pushLog('trace', ...)
-end
-
-function m.warn(...)
- pushLog('warn', ...)
-end
-
-function m.error(...)
- pushLog('error', ...)
-end
-
-return m
diff --git a/server-beta/src/brave/work.lua b/server-beta/src/brave/work.lua
deleted file mode 100644
index dba27808..00000000
--- a/server-beta/src/brave/work.lua
+++ /dev/null
@@ -1,55 +0,0 @@
-local brave = require 'brave.brave'
-local jsonrpc = require 'jsonrpc'
-local parser = require 'parser'
-local fs = require 'bee.filesystem'
-local furi = require 'file-uri'
-local util = require 'utility'
-
-brave.on('loadProto', function ()
- while true do
- local proto = jsonrpc.decode(io.read, log.error)
- if proto then
- brave.push('proto', proto)
- end
- end
-end)
-
-brave.on('compile', function (text)
- local state, err = parser:compile(text, 'lua', 'Lua 5.4')
- if not state then
- log.error(err)
- return
- end
- local lines = parser:lines(text)
- return {
- root = state.root,
- value = state.value,
- errs = state.errs,
- lines = lines,
- }
-end)
-
-brave.on('listDirectory', function (uri)
- local path = fs.path(furi.decode(uri))
- local uris = {}
- for child in path:list_directory() do
- local childUri = furi.encode(child:string())
- uris[#uris+1] = childUri
- end
- return uris
-end)
-
-brave.on('isDirectory', function (uri)
- local path = fs.path(furi.decode(uri))
- return fs.is_directory(path)
-end)
-
-brave.on('loadFile', function (uri)
- local filename = furi.decode(uri)
- return util.loadFile(filename)
-end)
-
-brave.on('saveFile', function (params)
- local filename = furi.decode(params.uri)
- return util.saveFile(filename, params.text)
-end)
diff --git a/server-beta/src/config.lua b/server-beta/src/config.lua
deleted file mode 100644
index 758402b0..00000000
--- a/server-beta/src/config.lua
+++ /dev/null
@@ -1,193 +0,0 @@
-local util = require 'utility'
-local DiagnosticDefaultSeverity = require 'define.DiagnosticDefaultSeverity'
-
-local m = {}
-m.version = 0
-
-local function Boolean(v)
- if type(v) == 'boolean' then
- return true, v
- end
- return false
-end
-
-local function Integer(v)
- if type(v) == 'number' then
- return true, math.floor(v)
- end
- return false
-end
-
-local function String(v)
- return true, tostring(v)
-end
-
-local function Str2Hash(sep)
- return function (v)
- if type(v) == 'string' then
- local t = {}
- for s in v:gmatch('[^'..sep..']+') do
- t[s] = true
- end
- return true, t
- end
- if type(v) == 'table' then
- local t = {}
- for _, s in ipairs(v) do
- if type(s) == 'string' then
- t[s] = true
- end
- end
- return true, t
- end
- return false
- end
-end
-
-local function Array(checker)
- return function (tbl)
- if type(tbl) ~= 'table' then
- return false
- end
- local t = {}
- for _, v in ipairs(tbl) do
- local ok, result = checker(v)
- if ok then
- t[#t+1] = result
- end
- end
- return true, t
- end
-end
-
-local function Hash(keyChecker, valueChecker)
- return function (tbl)
- if type(tbl) ~= 'table' then
- return false
- end
- local t = {}
- for k, v in pairs(tbl) do
- local ok1, key = keyChecker(k)
- local ok2, value = valueChecker(v)
- if ok1 and ok2 then
- t[key] = value
- end
- end
- if not next(t) then
- return false
- end
- return true, t
- end
-end
-
-local function Or(...)
- local checkers = {...}
- return function (obj)
- for _, checker in ipairs(checkers) do
- local suc, res = checker(obj)
- if suc then
- return true, res
- end
- end
- return false
- end
-end
-
-local ConfigTemplate = {
- runtime = {
- version = {'Lua 5.3', String},
- library = {{}, Str2Hash ';'},
- path = {{
- "?.lua",
- "?/init.lua",
- "?/?.lua"
- }, Array(String)},
- },
- diagnostics = {
- enable = {true, Boolean},
- globals = {{}, Str2Hash ';'},
- disable = {{}, Str2Hash ';'},
- severity = {
- util.deepCopy(DiagnosticDefaultSeverity),
- Hash(String, String),
- },
- },
- workspace = {
- ignoreDir = {{}, Str2Hash ';'},
- ignoreSubmodules= {true, Boolean},
- useGitIgnore = {true, Boolean},
- maxPreload = {300, Integer},
- preloadFileSize = {100, Integer},
- library = {{}, Hash(
- String,
- Or(Boolean, Array(String))
- )}
- },
- completion = {
- enable = {true, Boolean},
- callSnippet = {'Both', String},
- keywordSnippet = {'Both', String},
- },
- plugin = {
- enable = {false, Boolean},
- path = {'.vscode/lua-plugin/*.lua', String},
- },
-}
-
-local OtherTemplate = {
- associations = {{}, Hash(String, String)},
- exclude = {{}, Hash(String, Boolean)},
-}
-
-local function init()
- if m.config then
- return
- end
-
- m.config = {}
- for c, t in pairs(ConfigTemplate) do
- m.config[c] = {}
- for k, info in pairs(t) do
- m.config[c][k] = info[1]
- end
- end
-
- m.other = {}
- for k, info in pairs(OtherTemplate) do
- m.other[k] = info[1]
- end
-end
-
-function m.setConfig(config, other)
- m.version = m.version + 1
- xpcall(function ()
- for c, t in pairs(config) do
- for k, v in pairs(t) do
- local region = ConfigTemplate[c]
- if region then
- local info = region[k]
- local suc, v = info[2](v)
- if suc then
- m.config[c][k] = v
- else
- m.config[c][k] = info[1]
- end
- end
- end
- end
- for k, v in pairs(other) do
- local info = OtherTemplate[k]
- local suc, v = info[2](v)
- if suc then
- m.other[k] = v
- else
- m.other[k] = info[1]
- end
- end
- log.debug('Config update: ', util.dump(m.config), util.dump(m.other))
- end, log.error)
-end
-
-init()
-
-return m
diff --git a/server-beta/src/core/definition.lua b/server-beta/src/core/definition.lua
deleted file mode 100644
index 865fc7cb..00000000
--- a/server-beta/src/core/definition.lua
+++ /dev/null
@@ -1,105 +0,0 @@
-local guide = require 'parser.guide'
-local workspace = require 'workspace'
-local files = require 'files'
-local vm = require 'vm'
-
-local function findDef(source, callback)
- if source.type ~= 'local'
- and source.type ~= 'getlocal'
- and source.type ~= 'setlocal'
- and source.type ~= 'setglobal'
- and source.type ~= 'getglobal'
- and source.type ~= 'field'
- and source.type ~= 'method'
- and source.type ~= 'string'
- and source.type ~= 'number'
- and source.type ~= 'boolean'
- and source.type ~= 'goto' then
- return
- end
- vm.eachDef(source, function (info)
- if info.mode == 'declare'
- or info.mode == 'set'
- or info.mode == 'return' then
- local src = info.source
- local root = guide.getRoot(src)
- local uri = root.uri
- if src.type == 'setfield'
- or src.type == 'getfield'
- or src.type == 'tablefield' then
- callback(src.field, uri)
- elseif src.type == 'setindex'
- or src.type == 'getindex'
- or src.type == 'tableindex' then
- callback(src.index, uri)
- elseif src.type == 'getmethod'
- or src.type == 'setmethod' then
- callback(src.method, uri)
- else
- callback(src, uri)
- end
- end
- end)
-end
-
-local function checkRequire(source, offset, callback)
- if source.type ~= 'call' then
- return
- end
- local func = source.node
- local pathSource = source.args and source.args[1]
- if not pathSource then
- return
- end
- if not guide.isContain(pathSource, offset) then
- return
- end
- local literal = guide.getLiteral(pathSource)
- if type(literal) ~= 'string' then
- return
- end
- local name = func.special
- if name == 'require' then
- local result = workspace.findUrisByRequirePath(literal, true)
- for _, uri in ipairs(result) do
- callback(uri)
- end
- elseif name == 'dofile'
- or name == 'loadfile' then
- local result = workspace.findUrisByFilePath(literal, true)
- for _, uri in ipairs(result) do
- callback(uri)
- end
- end
-end
-
-return function (uri, offset)
- local ast = files.getAst(uri)
- if not ast then
- return nil
- end
- local results = {}
- guide.eachSourceContain(ast.ast, offset, function (source)
- checkRequire(source, offset, function (uri)
- results[#results+1] = {
- uri = files.getOriginUri(uri),
- source = source,
- target = {
- start = 0,
- finish = 0,
- }
- }
- end)
- findDef(source, function (target, uri)
- results[#results+1] = {
- target = target,
- uri = files.getOriginUri(uri),
- source = source,
- }
- end)
- end)
- if #results == 0 then
- return nil
- end
- return results
-end
diff --git a/server-beta/src/core/diagnostics/ambiguity-1.lua b/server-beta/src/core/diagnostics/ambiguity-1.lua
deleted file mode 100644
index 37815fb5..00000000
--- a/server-beta/src/core/diagnostics/ambiguity-1.lua
+++ /dev/null
@@ -1,69 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local lang = require 'language'
-
-local opMap = {
- ['+'] = true,
- ['-'] = true,
- ['*'] = true,
- ['/'] = true,
- ['//'] = true,
- ['^'] = true,
- ['<<'] = true,
- ['>>'] = true,
- ['&'] = true,
- ['|'] = true,
- ['~'] = true,
- ['..'] = true,
-}
-
-local literalMap = {
- ['number'] = true,
- ['boolean'] = true,
- ['string'] = true,
- ['table'] = true,
-}
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
- local text = files.getText(uri)
- guide.eachSourceType(ast.ast, 'binary', function (source)
- if source.op.type ~= 'or' then
- return
- end
- local first = source[1]
- local second = source[2]
- -- a + (b or 0) --> (a + b) or 0
- do
- if opMap[first.op and first.op.type]
- and first.type ~= 'unary'
- and not second.op
- and literalMap[second.type]
- and not literalMap[first[2].type]
- then
- callback {
- start = source.start,
- finish = source.finish,
- message = lang.script('DIAG_AMBIGUITY_1', text:sub(first.start, first.finish))
- }
- end
- end
- -- (a or 0) + c --> a or (0 + c)
- do
- if opMap[second.op and second.op.type]
- and second.type ~= 'unary'
- and not first.op
- and literalMap[second[1].type]
- then
- callback {
- start = source.start,
- finish = source.finish,
- message = lang.script('DIAG_AMBIGUITY_1', text:sub(second.start, second.finish))
- }
- end
- end
- end)
-end
diff --git a/server-beta/src/core/diagnostics/duplicate-index.lua b/server-beta/src/core/diagnostics/duplicate-index.lua
deleted file mode 100644
index 76b1c958..00000000
--- a/server-beta/src/core/diagnostics/duplicate-index.lua
+++ /dev/null
@@ -1,62 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local lang = require 'language'
-local define = require 'proto.define'
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
-
- guide.eachSourceType(ast.ast, 'table', function (source)
- local mark = {}
- for _, obj in ipairs(source) do
- if obj.type == 'tablefield'
- or obj.type == 'tableindex' then
- local name = guide.getKeyName(obj)
- if name then
- if not mark[name] then
- mark[name] = {}
- end
- mark[name][#mark[name]+1] = obj.field or obj.index
- end
- end
- end
-
- for name, defs in pairs(mark) do
- local sname = name:match '^.|(.+)$'
- if #defs > 1 and sname then
- local related = {}
- for i = 1, #defs do
- local def = defs[i]
- related[i] = {
- start = def.start,
- finish = def.finish,
- uri = uri,
- }
- end
- for i = 1, #defs - 1 do
- local def = defs[i]
- callback {
- start = def.start,
- finish = def.finish,
- related = related,
- message = lang.script('DIAG_DUPLICATE_INDEX', sname),
- level = define.DiagnosticSeverity.Hint,
- tags = { define.DiagnosticTag.Unnecessary },
- }
- end
- for i = #defs, #defs do
- local def = defs[i]
- callback {
- start = def.start,
- finish = def.finish,
- related = related,
- message = lang.script('DIAG_DUPLICATE_INDEX', sname),
- }
- end
- end
- end
- end)
-end
diff --git a/server-beta/src/core/diagnostics/emmy-lua.lua b/server-beta/src/core/diagnostics/emmy-lua.lua
deleted file mode 100644
index b3d19c21..00000000
--- a/server-beta/src/core/diagnostics/emmy-lua.lua
+++ /dev/null
@@ -1,3 +0,0 @@
-return function ()
-
-end
diff --git a/server-beta/src/core/diagnostics/empty-block.lua b/server-beta/src/core/diagnostics/empty-block.lua
deleted file mode 100644
index 2024f4e3..00000000
--- a/server-beta/src/core/diagnostics/empty-block.lua
+++ /dev/null
@@ -1,49 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local lang = require 'language'
-local define = require 'proto.define'
-
--- 检查空代码块
--- 但是排除忙等待(repeat/while)
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
-
- guide.eachSourceType(ast.ast, 'if', function (source)
- for _, block in ipairs(source) do
- if #block > 0 then
- return
- end
- end
- callback {
- start = source.start,
- finish = source.finish,
- tags = { define.DiagnosticTag.Unnecessary },
- message = lang.script.DIAG_EMPTY_BLOCK,
- }
- end)
- guide.eachSourceType(ast.ast, 'loop', function (source)
- if #source > 0 then
- return
- end
- callback {
- start = source.start,
- finish = source.finish,
- tags = { define.DiagnosticTag.Unnecessary },
- message = lang.script.DIAG_EMPTY_BLOCK,
- }
- end)
- guide.eachSourceType(ast.ast, 'in', function (source)
- if #source > 0 then
- return
- end
- callback {
- start = source.start,
- finish = source.finish,
- tags = { define.DiagnosticTag.Unnecessary },
- message = lang.script.DIAG_EMPTY_BLOCK,
- }
- end)
-end
diff --git a/server-beta/src/core/diagnostics/global-in-nil-env.lua b/server-beta/src/core/diagnostics/global-in-nil-env.lua
deleted file mode 100644
index 9a0d4f35..00000000
--- a/server-beta/src/core/diagnostics/global-in-nil-env.lua
+++ /dev/null
@@ -1,66 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local lang = require 'language'
-
--- TODO: 检查路径是否可达
-local function mayRun(path)
- return true
-end
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
- local root = guide.getRoot(ast.ast)
- local env = guide.getENV(root)
-
- local nilDefs = {}
- if not env.ref then
- return
- end
- for _, ref in ipairs(env.ref) do
- if ref.type == 'setlocal' then
- if ref.value and ref.value.type == 'nil' then
- nilDefs[#nilDefs+1] = ref
- end
- end
- end
-
- if #nilDefs == 0 then
- return
- end
-
- local function check(source)
- local node = source.node
- if node.tag == '_ENV' then
- local ok
- for _, nilDef in ipairs(nilDefs) do
- local mode, pathA = guide.getPath(nilDef, source)
- if mode == 'before'
- and mayRun(pathA) then
- ok = nilDef
- break
- end
- end
- if ok then
- callback {
- start = source.start,
- finish = source.finish,
- uri = uri,
- message = lang.script.DIAG_GLOBAL_IN_NIL_ENV,
- related = {
- {
- start = ok.start,
- finish = ok.finish,
- uri = uri,
- }
- }
- }
- end
- end
- end
-
- guide.eachSourceType(ast.ast, 'getglobal', check)
- guide.eachSourceType(ast.ast, 'setglobal', check)
-end
diff --git a/server-beta/src/core/diagnostics/init.lua b/server-beta/src/core/diagnostics/init.lua
deleted file mode 100644
index 0d523f26..00000000
--- a/server-beta/src/core/diagnostics/init.lua
+++ /dev/null
@@ -1,41 +0,0 @@
-local files = require 'files'
-local define = require 'proto.define'
-local config = require 'config'
-local await = require 'await'
-
-local function check(uri, name, level, results)
- if config.config.diagnostics.disable[name] then
- return
- end
- level = config.config.diagnostics.severity[name] or level
- local severity = define.DiagnosticSeverity[level]
- local clock = os.clock()
- require('core.diagnostics.' .. name)(uri, function (result)
- result.level = severity or result.level
- result.code = name
- results[#results+1] = result
- end, name)
- local passed = os.clock() - clock
- if passed >= 0.5 then
- log.warn(('Diagnostics [%s] @ [%s] takes [%.3f] sec!'):format(name, uri, passed))
- await.delay()
- end
-end
-
-return function (uri)
- local ast = files.getAst(uri)
- if not ast then
- return nil
- end
- local results = {}
-
- for name, level in pairs(define.DiagnosticDefaultSeverity) do
- check(uri, name, level, results)
- end
-
- if #results == 0 then
- return nil
- end
-
- return results
-end
diff --git a/server-beta/src/core/diagnostics/lowercase-global.lua b/server-beta/src/core/diagnostics/lowercase-global.lua
deleted file mode 100644
index bc48e1e6..00000000
--- a/server-beta/src/core/diagnostics/lowercase-global.lua
+++ /dev/null
@@ -1,39 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local lang = require 'language'
-local config = require 'config'
-local library = require 'library'
-
--- 不允许定义首字母小写的全局变量(很可能是拼错或者漏删)
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
-
- local definedGlobal = {}
- for name in pairs(config.config.diagnostics.globals) do
- definedGlobal[name] = true
- end
- for name in pairs(library.global) do
- definedGlobal[name] = true
- end
-
- guide.eachSourceType(ast.ast, 'setglobal', function (source)
- local name = guide.getName(source)
- if definedGlobal[name] then
- return
- end
- local first = name:match '%w'
- if not first then
- return
- end
- if first:match '%l' then
- callback {
- start = source.start,
- finish = source.finish,
- message = lang.script.DIAG_LOWERCASE_GLOBAL,
- }
- end
- end)
-end
diff --git a/server-beta/src/core/diagnostics/newfield-call.lua b/server-beta/src/core/diagnostics/newfield-call.lua
deleted file mode 100644
index 75681cbc..00000000
--- a/server-beta/src/core/diagnostics/newfield-call.lua
+++ /dev/null
@@ -1,37 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local lang = require 'language'
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
-
- local lines = files.getLines(uri)
- local text = files.getText(uri)
-
- guide.eachSourceType(ast.ast, 'table', function (source)
- for i = 1, #source do
- local field = source[i]
- if field.type == 'call' then
- local func = field.node
- local args = field.args
- if args then
- local funcLine = guide.positionOf(lines, func.finish)
- local argsLine = guide.positionOf(lines, args.start)
- if argsLine > funcLine then
- callback {
- start = field.start,
- finish = field.finish,
- message = lang.script('DIAG_PREFIELD_CALL'
- , text:sub(func.start, func.finish)
- , text:sub(args.start, args.finish)
- )
- }
- end
- end
- end
- end
- end)
-end
diff --git a/server-beta/src/core/diagnostics/newline-call.lua b/server-beta/src/core/diagnostics/newline-call.lua
deleted file mode 100644
index cb318380..00000000
--- a/server-beta/src/core/diagnostics/newline-call.lua
+++ /dev/null
@@ -1,38 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local lang = require 'language'
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
- local lines = files.getLines(uri)
-
- guide.eachSourceType(ast.ast, 'call', function (source)
- local node = source.node
- local args = source.args
- if not args then
- return
- end
-
- -- 必须有其他人在继续使用当前对象
- if not source.next then
- return
- end
-
- local nodeRow = guide.positionOf(lines, node.finish)
- local argRow = guide.positionOf(lines, args.start)
- if nodeRow == argRow then
- return
- end
-
- if #args == 1 then
- callback {
- start = args.start,
- finish = args.finish,
- message = lang.script.DIAG_PREVIOUS_CALL,
- }
- end
- end)
-end
diff --git a/server-beta/src/core/diagnostics/redefined-local.lua b/server-beta/src/core/diagnostics/redefined-local.lua
deleted file mode 100644
index f6176794..00000000
--- a/server-beta/src/core/diagnostics/redefined-local.lua
+++ /dev/null
@@ -1,32 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local lang = require 'language'
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
- guide.eachSourceType(ast.ast, 'local', function (source)
- local name = source[1]
- if name == '_'
- or name == '_ENV' then
- return
- end
- local exist = guide.getLocal(source, name, source.start-1)
- if exist then
- callback {
- start = source.start,
- finish = source.finish,
- message = lang.script('DIAG_REDEFINED_LOCAL', name),
- related = {
- {
- start = exist.start,
- finish = exist.finish,
- uri = uri,
- }
- },
- }
- end
- end)
-end
diff --git a/server-beta/src/core/diagnostics/redundant-parameter.lua b/server-beta/src/core/diagnostics/redundant-parameter.lua
deleted file mode 100644
index ec14188e..00000000
--- a/server-beta/src/core/diagnostics/redundant-parameter.lua
+++ /dev/null
@@ -1,102 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local vm = require 'vm'
-local lang = require 'language'
-local define = require 'proto.define'
-local await = require 'await'
-
-local function countLibraryArgs(source)
- local func = vm.getLibrary(source)
- if not func then
- return nil
- end
- local result = 0
- if not func.args then
- return result
- end
- if func.args[#func.args].type == '...' then
- return math.maxinteger
- end
- result = result + #func.args
- return result
-end
-
-local function countCallArgs(source)
- local result = 0
- if not source.args then
- return 0
- end
- if source.node and source.node.type == 'getmethod' then
- result = result + 1
- end
- result = result + #source.args
- return result
-end
-
-local function countFuncArgs(source)
- local result = 0
- if not source.args then
- return result
- end
- if source.args[#source.args].type == '...' then
- return math.maxinteger
- end
- if source.parent and source.parent.type == 'setmethod' then
- result = result + 1
- end
- result = result + #source.args
- return result
-end
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
-
- guide.eachSourceType(ast.ast, 'call', function (source)
- local callArgs = countCallArgs(source)
- if callArgs == 0 then
- return
- end
-
- await.delay(function ()
- return files.globalVersion
- end)
-
- local func = source.node
- local funcArgs
- vm.eachDef(func, function (info)
- if info.mode == 'value' then
- local src = info.source
- if src.type == 'function' then
- local args = countFuncArgs(src)
- if not funcArgs or args > funcArgs then
- funcArgs = args
- end
- end
- end
- end)
-
- funcArgs = funcArgs or countLibraryArgs(func)
- if not funcArgs then
- return
- end
-
- local delta = callArgs - funcArgs
- if delta <= 0 then
- return
- end
- for i = #source.args - delta + 1, #source.args do
- local arg = source.args[i]
- if arg then
- callback {
- start = arg.start,
- finish = arg.finish,
- tags = { define.DiagnosticTag.Unnecessary },
- message = lang.script('DIAG_OVER_MAX_ARGS', funcArgs, callArgs)
- }
- end
- end
- end)
-end
diff --git a/server-beta/src/core/diagnostics/redundant-value.lua b/server-beta/src/core/diagnostics/redundant-value.lua
deleted file mode 100644
index be483448..00000000
--- a/server-beta/src/core/diagnostics/redundant-value.lua
+++ /dev/null
@@ -1,24 +0,0 @@
-local files = require 'files'
-local define = require 'proto.define'
-local lang = require 'language'
-
-return function (uri, callback, code)
- local ast = files.getAst(uri)
- if not ast 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
-end
diff --git a/server-beta/src/core/diagnostics/trailing-space.lua b/server-beta/src/core/diagnostics/trailing-space.lua
deleted file mode 100644
index e54a6e60..00000000
--- a/server-beta/src/core/diagnostics/trailing-space.lua
+++ /dev/null
@@ -1,55 +0,0 @@
-local files = require 'files'
-local lang = require 'language'
-local guide = require 'parser.guide'
-
-local function isInString(ast, offset)
- local result = false
- guide.eachSourceType(ast, 'string', function (source)
- if offset >= source.start and offset <= source.finish then
- result = true
- end
- end)
- return result
-end
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast 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)
- if lastChar ~= ' ' and lastChar ~= '\t' then
- goto NEXT_LINE
- end
- if isInString(ast.ast, range) then
- goto NEXT_LINE
- end
- local first = start
- for n = range - 1, start, -1 do
- local char = text:sub(n, n)
- if char ~= ' ' and char ~= '\t' then
- first = n + 1
- break
- end
- end
- if first == start then
- callback {
- start = first,
- finish = range,
- message = lang.script.DIAG_LINE_ONLY_SPACE,
- }
- else
- callback {
- start = first,
- finish = range,
- message = lang.script.DIAG_LINE_POST_SPACE,
- }
- end
- ::NEXT_LINE::
- end
-end
diff --git a/server-beta/src/core/diagnostics/undefined-env-child.lua b/server-beta/src/core/diagnostics/undefined-env-child.lua
deleted file mode 100644
index df096cb8..00000000
--- a/server-beta/src/core/diagnostics/undefined-env-child.lua
+++ /dev/null
@@ -1,32 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local vm = require 'vm'
-local lang = require 'language'
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
- -- 再遍历一次 getglobal ,找出 _ENV 被重载的情况
- guide.eachSourceType(ast.ast, 'getglobal', function (source)
- -- 单独验证自己是否在重载过的 _ENV 中有定义
- if source.node.tag == '_ENV' then
- return
- end
- local setInENV = vm.eachRef(source, function (info)
- if info.mode == 'set' then
- return true
- end
- end)
- if setInENV then
- return
- end
- local key = source[1]
- callback {
- start = source.start,
- finish = source.finish,
- message = lang.script('DIAG_UNDEF_ENV_CHILD', key),
- }
- end)
-end
diff --git a/server-beta/src/core/diagnostics/undefined-global.lua b/server-beta/src/core/diagnostics/undefined-global.lua
deleted file mode 100644
index ed81ced3..00000000
--- a/server-beta/src/core/diagnostics/undefined-global.lua
+++ /dev/null
@@ -1,63 +0,0 @@
-local files = require 'files'
-local vm = require 'vm'
-local lang = require 'language'
-local library = require 'library'
-local config = require 'config'
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
-
- local globalCache = {}
-
- -- 遍历全局变量,检查所有没有 mode['set'] 的全局变量
- local globals = vm.getGlobals(ast.ast)
- for key, infos in pairs(globals) do
- if infos.mode['set'] == true then
- goto CONTINUE
- end
- if globalCache[key] then
- goto CONTINUE
- end
- local skey = key and key:match '^s|(.+)$'
- if not skey then
- goto CONTINUE
- end
- if library.global[skey] then
- goto CONTINUE
- end
- if config.config.diagnostics.globals[skey] then
- goto CONTINUE
- end
- if globalCache[key] == nil then
- local uris = files.findGlobals(key)
- for i = 1, #uris do
- local destAst = files.getAst(uris[i])
- local destGlobals = vm.getGlobals(destAst.ast)
- if destGlobals[key] and destGlobals[key].mode['set'] then
- globalCache[key] = true
- goto CONTINUE
- end
- end
- end
- globalCache[key] = false
- local message = lang.script('DIAG_UNDEF_GLOBAL', skey)
- local otherVersion = library.other[skey]
- local customVersion = library.custom[skey]
- if otherVersion then
- message = ('%s(%s)'):format(message, lang.script('DIAG_DEFINED_VERSION', table.concat(otherVersion, '/'), config.config.runtime.version))
- elseif customVersion then
- message = ('%s(%s)'):format(message, lang.script('DIAG_DEFINED_CUSTOM', table.concat(customVersion, '/')))
- end
- for _, info in ipairs(infos) do
- callback {
- start = info.source.start,
- finish = info.source.finish,
- message = message,
- }
- end
- ::CONTINUE::
- end
-end
diff --git a/server-beta/src/core/diagnostics/unused-function.lua b/server-beta/src/core/diagnostics/unused-function.lua
deleted file mode 100644
index 6c53cdf7..00000000
--- a/server-beta/src/core/diagnostics/unused-function.lua
+++ /dev/null
@@ -1,45 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local vm = require 'vm'
-local define = require 'proto.define'
-local lang = require 'language'
-local await = require 'await'
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
- -- 只检查局部函数与全局函数
- guide.eachSourceType(ast.ast, 'function', function (source)
- local parent = source.parent
- if not parent then
- return
- end
- if parent.type ~= 'local'
- and parent.type ~= 'setlocal'
- and parent.type ~= 'setglobal' then
- return
- end
- local hasSet
- local hasGet = vm.eachRef(source, function (info)
- if info.mode == 'get' then
- return true
- elseif info.mode == 'set'
- or info.mode == 'declare' then
- hasSet = true
- end
- end)
- if not hasGet and hasSet then
- callback {
- start = source.start,
- finish = source.finish,
- tags = { define.DiagnosticTag.Unnecessary },
- message = lang.script.DIAG_UNUSED_FUNCTION,
- }
- end
- await.delay(function ()
- return files.globalVersion
- end)
- end)
-end
diff --git a/server-beta/src/core/diagnostics/unused-label.lua b/server-beta/src/core/diagnostics/unused-label.lua
deleted file mode 100644
index e6d998ba..00000000
--- a/server-beta/src/core/diagnostics/unused-label.lua
+++ /dev/null
@@ -1,22 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local define = require 'proto.define'
-local lang = require 'language'
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
-
- guide.eachSourceType(ast.ast, 'label', function (source)
- if not source.ref then
- callback {
- start = source.start,
- finish = source.finish,
- tags = { define.DiagnosticTag.Unnecessary },
- message = lang.script('DIAG_UNUSED_LABEL', source[1]),
- }
- end
- end)
-end
diff --git a/server-beta/src/core/diagnostics/unused-local.lua b/server-beta/src/core/diagnostics/unused-local.lua
deleted file mode 100644
index 22b2e16b..00000000
--- a/server-beta/src/core/diagnostics/unused-local.lua
+++ /dev/null
@@ -1,46 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local define = require 'proto.define'
-local lang = require 'language'
-
-local function hasGet(loc)
- if not loc.ref then
- return false
- end
- for _, ref in ipairs(loc.ref) do
- if ref.type == 'getlocal' then
- if not ref.next then
- return true
- end
- local nextType = ref.next.type
- if nextType ~= 'setmethod'
- and nextType ~= 'setfield'
- and nextType ~= 'setindex' then
- return true
- end
- end
- end
- return false
-end
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
- guide.eachSourceType(ast.ast, 'local', function (source)
- local name = source[1]
- if name == '_'
- or name == '_ENV' then
- return
- end
- if not hasGet(source) then
- callback {
- start = source.start,
- finish = source.finish,
- tags = { define.DiagnosticTag.Unnecessary },
- message = lang.script('DIAG_UNUSED_LOCAL', name),
- }
- end
- end)
-end
diff --git a/server-beta/src/core/diagnostics/unused-vararg.lua b/server-beta/src/core/diagnostics/unused-vararg.lua
deleted file mode 100644
index 74cc08e7..00000000
--- a/server-beta/src/core/diagnostics/unused-vararg.lua
+++ /dev/null
@@ -1,31 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local define = require 'proto.define'
-local lang = require 'language'
-
-return function (uri, callback)
- local ast = files.getAst(uri)
- if not ast then
- return
- end
-
- guide.eachSourceType(ast.ast, 'function', function (source)
- local args = source.args
- if not args then
- return
- end
-
- for _, arg in ipairs(args) do
- if arg.type == '...' then
- if not arg.ref then
- callback {
- start = arg.start,
- finish = arg.finish,
- tags = { define.DiagnosticTag.Unnecessary },
- message = lang.script.DIAG_UNUSED_VARARG,
- }
- end
- end
- end
- end)
-end
diff --git a/server-beta/src/core/highlight.lua b/server-beta/src/core/highlight.lua
deleted file mode 100644
index 61e3f91a..00000000
--- a/server-beta/src/core/highlight.lua
+++ /dev/null
@@ -1,230 +0,0 @@
-local guide = require 'parser.guide'
-local files = require 'files'
-local vm = require 'vm'
-local define = require 'proto.define'
-
-local function ofLocal(source, callback)
- callback(source)
- if source.ref then
- for _, ref in ipairs(source.ref) do
- callback(ref)
- end
- end
-end
-
-local function ofField(source, uri, callback)
- local parent = source.parent
- if not parent then
- return
- end
- local myKey = guide.getKeyName(source)
- if parent.type == 'tableindex'
- or parent.type == 'tablefield' then
- local tbl = parent.parent
- vm.eachField(tbl, function (info)
- if info.key ~= myKey then
- return
- end
- local destUri = guide.getRoot(info.source).uri
- if destUri ~= uri then
- return
- end
- callback(info.source)
- end)
- else
- vm.eachField(parent.node, function (info)
- if info.key ~= myKey then
- return
- end
- local destUri = guide.getRoot(info.source).uri
- if destUri ~= uri then
- return
- end
- callback(info.source)
- end)
- end
-end
-
-local function ofIndex(source, uri, callback)
- local parent = source.parent
- if not parent then
- return
- end
- if parent.type == 'setindex'
- or parent.type == 'getindex'
- or parent.type == 'tableindex' then
- ofField(source, uri, callback)
- end
-end
-
-local function ofLabel(source, callback)
- vm.eachRef(source, function (info)
- callback(info.source)
- end)
-end
-
-local function find(source, uri, callback)
- if source.type == 'local' then
- ofLocal(source, callback)
- elseif source.type == 'getlocal'
- or source.type == 'setlocal' then
- ofLocal(source.node, callback)
- elseif source.type == 'field'
- or source.type == 'method' then
- ofField(source, uri, callback)
- elseif source.type == 'string'
- or source.type == 'boolean'
- or source.type == 'number' then
- ofIndex(source, uri, callback)
- callback(source)
- elseif source.type == 'nil' then
- callback(source)
- elseif source.type == 'goto'
- or source.type == 'label' then
- ofLabel(source, callback)
- end
-end
-
-local function checkInIf(source, text, offset)
- -- 检查 end
- local endA = source.finish - #'end' + 1
- local endB = source.finish
- if offset >= endA
- and offset <= endB
- and text:sub(endA, endB) == 'end' then
- return true
- end
- -- 检查每个子模块
- for _, block in ipairs(source) do
- 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
- return true
- end
- end
- end
- return false
-end
-
-local function makeIf(source, text, callback)
- -- end
- local endA = source.finish - #'end' + 1
- local endB = source.finish
- if text:sub(endA, endB) == 'end' then
- callback(endA, endB)
- end
- -- 每个子模块
- for _, block in ipairs(source) do
- for i = 1, #block.keyword, 2 do
- local start = block.keyword[i]
- local finish = block.keyword[i+1]
- callback(start, finish)
- end
- end
- return false
-end
-
-local function findKeyword(source, text, offset, callback)
- if source.type == 'do'
- or source.type == 'function'
- or source.type == 'loop'
- or source.type == 'in'
- or source.type == 'while'
- or source.type == 'repeat' then
- local ok
- 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
- ok = true
- break
- end
- end
- if ok then
- for i = 1, #source.keyword, 2 do
- local start = source.keyword[i]
- local finish = source.keyword[i+1]
- callback(start, finish)
- end
- end
- elseif source.type == 'if' then
- local ok = checkInIf(source, text, offset)
- if ok then
- makeIf(source, text, callback)
- end
- end
-end
-
-return function (uri, offset)
- local ast = files.getAst(uri)
- if not ast then
- return nil
- end
- local text = files.getText(uri)
- local results = {}
- local mark = {}
- guide.eachSourceContain(ast.ast, offset, function (source)
- find(source, uri, function (target)
- local kind
- if target.type == 'getfield' then
- target = target.field
- kind = define.DocumentHighlightKind.Read
- elseif target.type == 'setfield'
- or target.type == 'tablefield' then
- target = target.field
- kind = define.DocumentHighlightKind.Write
- elseif target.type == 'getmethod' then
- target = target.method
- kind = define.DocumentHighlightKind.Read
- elseif target.type == 'setmethod' then
- target = target.method
- kind = define.DocumentHighlightKind.Write
- elseif target.type == 'getindex' then
- target = target.index
- kind = define.DocumentHighlightKind.Read
- elseif target.type == 'setindex'
- or target.type == 'tableindex' then
- target = target.index
- kind = define.DocumentHighlightKind.Write
- elseif target.type == 'getlocal'
- or target.type == 'getglobal'
- or target.type == 'goto' then
- kind = define.DocumentHighlightKind.Read
- elseif target.type == 'setlocal'
- or target.type == 'local'
- or target.type == 'setglobal'
- or target.type == 'label' then
- kind = define.DocumentHighlightKind.Write
- elseif target.type == 'string'
- or target.type == 'boolean'
- or target.type == 'number'
- or target.type == 'nil' then
- kind = define.DocumentHighlightKind.Text
- else
- log.warn('Unknow target.type:', target.type)
- return
- end
- if mark[target] then
- return
- end
- mark[target] = true
- results[#results+1] = {
- start = target.start,
- finish = target.finish,
- kind = kind,
- }
- end)
- findKeyword(source, text, offset, function (start, finish)
- results[#results+1] = {
- start = start,
- finish = finish,
- kind = define.DocumentHighlightKind.Write
- }
- end)
- end)
- if #results == 0 then
- return nil
- end
- return results
-end
diff --git a/server-beta/src/core/hover/arg.lua b/server-beta/src/core/hover/arg.lua
deleted file mode 100644
index be344488..00000000
--- a/server-beta/src/core/hover/arg.lua
+++ /dev/null
@@ -1,20 +0,0 @@
-local guide = require 'parser.guide'
-local vm = require 'vm'
-
-local function asFunction(source)
- if not source.args then
- return ''
- end
- local args = {}
- for i = 1, #source.args do
- local arg = source.args[i]
- args[i] = ('%s: %s'):format(guide.getName(arg), vm.getType(arg))
- end
- return table.concat(args, ', ')
-end
-
-return function (source)
- if source.type == 'function' then
- return asFunction(source)
- end
-end
diff --git a/server-beta/src/core/hover/init.lua b/server-beta/src/core/hover/init.lua
deleted file mode 100644
index b99c14b2..00000000
--- a/server-beta/src/core/hover/init.lua
+++ /dev/null
@@ -1,56 +0,0 @@
-local files = require 'files'
-local guide = require 'parser.guide'
-local vm = require 'vm'
-local getLabel = require 'core.hover.label'
-
-local function getHoverAsFunction(source)
- local values = vm.getValue(source)
- local labels = {}
- for _, value in ipairs(values) do
- if value.type == 'function' then
- labels[#labels+1] = getLabel(value.source)
- end
- end
-
- local label = table.concat(labels, '\n')
- return {
- label = label,
- source = source,
- }
-end
-
-local function getHoverAsValue(source)
- local label = getLabel(source)
- return {
- label = label,
- source = source,
- }
-end
-
-local function getHover(source)
- local isFunction = vm.hasType(source, 'function')
- if isFunction then
- return getHoverAsFunction(source)
- else
- return getHoverAsValue(source)
- end
-end
-
-return function (uri, offset)
- local ast = files.getAst(uri)
- if not ast then
- return nil
- end
- local hover = guide.eachSourceContain(ast.ast, offset, function (source)
- if source.type == 'local'
- or source.type == 'setlocal'
- or source.type == 'getlocal'
- or source.type == 'setglobal'
- or source.type == 'getglobal'
- or source.type == 'field'
- or source.type == 'method' then
- return getHover(source)
- end
- end)
- return hover
-end
diff --git a/server-beta/src/core/hover/label.lua b/server-beta/src/core/hover/label.lua
deleted file mode 100644
index 72ce60f4..00000000
--- a/server-beta/src/core/hover/label.lua
+++ /dev/null
@@ -1,103 +0,0 @@
-local buildName = require 'core.hover.name'
-local buildArg = require 'core.hover.arg'
-local buildReturn = require 'core.hover.return'
-local buildTable = require 'core.hover.table'
-local vm = require 'vm'
-local util = require 'utility'
-
-local function asFunction(source)
- local name = buildName(source)
- local arg = buildArg(source)
- local rtn = buildReturn(source)
- local lines = {}
- lines[1] = ('function %s(%s)'):format(name, arg)
- lines[2] = rtn
- return table.concat(lines, '\n')
-end
-
-local function asLocal(source)
- local name = buildName(source)
- local type = vm.getType(source)
- local literal = vm.getLiteral(source)
- if type == 'table' then
- type = buildTable(source)
- end
- if literal == nil then
- return ('local %s: %s'):format(name, type)
- else
- return ('local %s: %s = %s'):format(name, type, util.viewLiteral(literal))
- end
-end
-
-local function asGlobal(source)
- local name = buildName(source)
- local type = vm.getType(source)
- local literal = vm.getLiteral(source)
- if type == 'table' then
- type = buildTable(source)
- end
- if literal == nil then
- return ('global %s: %s'):format(name, type)
- else
- return ('global %s: %s = %s'):format(name, type, util.viewLiteral(literal))
- end
-end
-
-local function isGlobalField(source)
- if source.type == 'field'
- or source.type == 'method' then
- source = source.parent
- end
- if source.type == 'setfield'
- or source.type == 'getfield'
- or source.type == 'setmethod'
- or source.type == 'getmethod'
- or source.type == 'tablefield' then
- local node = source.node
- if node.type == 'setglobal'
- or node.type == 'getglobal' then
- return true
- end
- return isGlobalField(node)
- else
- return false
- end
-end
-
-local function asField(source)
- if isGlobalField(source) then
- return asGlobal(source)
- end
- local name = buildName(source)
- local type = vm.getType(source)
- local literal = vm.getLiteral(source)
- if type == 'table' then
- type = buildTable(source)
- end
- if literal == nil then
- return ('field %s: %s'):format(name, type)
- else
- return ('field %s: %s = %s'):format(name, type, util.viewLiteral(literal))
- end
-end
-
-return function (source)
- if source.type == 'function' then
- return asFunction(source)
- elseif source.type == 'local'
- or source.type == 'getlocal'
- or source.type == 'setlocal' then
- return asLocal(source)
- elseif source.type == 'setglobal'
- or source.type == 'getglobal' then
- return asGlobal(source)
- elseif source.type == 'getfield'
- or source.type == 'setfield'
- or source.type == 'getmethod'
- or source.type == 'setmethod'
- or source.type == 'tablefield'
- or source.type == 'field'
- or source.type == 'method' then
- return asField(source)
- end
-end
diff --git a/server-beta/src/core/hover/name.lua b/server-beta/src/core/hover/name.lua
deleted file mode 100644
index a22a8b5a..00000000
--- a/server-beta/src/core/hover/name.lua
+++ /dev/null
@@ -1,64 +0,0 @@
-local guide = require 'parser.guide'
-local vm = require 'vm'
-
-local function asLocal(source)
- return guide.getName(source)
-end
-
-local function asMethod(source)
- local class = vm.eachField(source.node, function (info)
- if info.key == 's|type' or info.key == 's|__name' or info.key == 's|name' then
- if info.value and info.value.type == 'string' then
- return info.value[1]
- end
- end
- end)
- local node = class or guide.getName(source.node) or '?'
- local method = guide.getName(source)
- return ('%s:%s'):format(node, method)
-end
-
-local function asField(source)
- local class = vm.eachField(source.node, function (info)
- if info.key == 's|type' or info.key == 's|__name' or info.key == 's|name' then
- if info.value and info.value.type == 'string' then
- return info.value[1]
- end
- end
- end)
- local node = class or guide.getName(source.node) or '?'
- local method = guide.getName(source)
- return ('%s.%s'):format(node, method)
-end
-
-local function asGlobal(source)
- return guide.getName(source)
-end
-
-local function buildName(source)
- if source.type == 'local'
- or source.type == 'getlocal'
- or source.type == 'setlocal' then
- return asLocal(source) or ''
- end
- if source.type == 'setglobal'
- or source.type == 'getglobal' then
- return asGlobal(source) or ''
- end
- if source.type == 'setmethod'
- or source.type == 'getmethod' then
- return asMethod(source) or ''
- end
- if source.type == 'setfield'
- or source.tyoe == 'getfield'
- or source.type == 'tablefield' then
- return asField(source) or ''
- end
- local parent = source.parent
- if parent then
- return buildName(parent)
- end
- return ''
-end
-
-return buildName
diff --git a/server-beta/src/core/hover/return.lua b/server-beta/src/core/hover/return.lua
deleted file mode 100644
index c22626a6..00000000
--- a/server-beta/src/core/hover/return.lua
+++ /dev/null
@@ -1,34 +0,0 @@
-local guide = require 'parser.guide'
-local vm = require 'vm'
-
-local function asFunction(source)
- if not source.returns then
- return nil
- end
- local returns = {}
- for _, rtn in ipairs(source.returns) do
- for i = 1, #rtn do
- local values = vm.getValue(rtn[i])
- returns[#returns+1] = values
- end
- break
- end
- if #returns == 0 then
- return nil
- end
- local lines = {}
- for i = 1, #returns do
- if i == 1 then
- lines[i] = (' -> %s'):format(vm.viewType(returns[i]))
- else
- lines[i] = ('% 3d. %s'):format(i, returns[i])
- end
- end
- return table.concat(lines, '\n')
-end
-
-return function (source)
- if source.type == 'function' then
- return asFunction(source)
- end
-end
diff --git a/server-beta/src/core/hover/table.lua b/server-beta/src/core/hover/table.lua
deleted file mode 100644
index 9ed86692..00000000
--- a/server-beta/src/core/hover/table.lua
+++ /dev/null
@@ -1,35 +0,0 @@
-local vm = require 'vm'
-
-local function checkClass(source)
-end
-
-return function (source)
- local fields = {}
- local class
- vm.eachField(source, function (info)
- if info.key == 's|type' or info.key == 's|__name' or info.key == 's|name' then
- if info.value and info.value.type == 'string' then
- class = info.value[1]
- end
- end
- local type = vm.getType(info.source)
- fields[#fields+1] = ('%s'):format(type)
- end)
- local fieldsBuf
- if #fields == 0 then
- fieldsBuf = '{}'
- else
- local lines = {}
- lines[#lines+1] = '{'
- for _, field in ipairs(fields) do
- lines[#lines+1] = ' ' .. field
- end
- lines[#lines+1] = '}'
- fieldsBuf = table.concat(lines, '\n')
- end
- if class then
- return ('%s %s'):format(class, fieldsBuf)
- else
- return fieldsBuf
- end
-end
diff --git a/server-beta/src/core/reference.lua b/server-beta/src/core/reference.lua
deleted file mode 100644
index 7e265e97..00000000
--- a/server-beta/src/core/reference.lua
+++ /dev/null
@@ -1,84 +0,0 @@
-local guide = require 'parser.guide'
-local files = require 'files'
-local vm = require 'vm'
-
-local function isFunction(source, offset)
- if source.type ~= 'function' then
- return false
- end
- -- 必须点在 `function` 这个单词上才能查找函数引用
- return offset >= source.start and offset < source.start + #'function'
-end
-
-local function findRef(source, offset, callback)
- if source.type ~= 'local'
- and source.type ~= 'getlocal'
- and source.type ~= 'setlocal'
- and source.type ~= 'setglobal'
- and source.type ~= 'getglobal'
- and source.type ~= 'field'
- and source.type ~= 'tablefield'
- and source.type ~= 'method'
- and source.type ~= 'string'
- and source.type ~= 'number'
- and source.type ~= 'boolean'
- and source.type ~= 'goto'
- and source.type ~= 'label'
- and not isFunction(source, offset) then
- return
- end
- vm.eachRef(source, function (info)
- if info.mode == 'declare'
- or info.mode == 'set'
- or info.mode == 'get'
- or info.mode == 'return' then
- local src = info.source
- local root = guide.getRoot(src)
- local uri = root.uri
- if src.type == 'setfield'
- or src.type == 'getfield'
- or src.type == 'tablefield' then
- callback(src.field, uri)
- elseif src.type == 'setindex'
- or src.type == 'getindex'
- or src.type == 'tableindex' then
- callback(src.index, uri)
- elseif src.type == 'getmethod'
- or src.type == 'setmethod' then
- callback(src.method, uri)
- else
- callback(src, uri)
- end
- end
- if info.mode == 'value' then
- local src = info.source
- local root = guide.getRoot(src)
- local uri = root.uri
- if src.type == 'function' then
- if src.parent.type == 'return' then
- callback(src, uri)
- end
- end
- end
- end)
-end
-
-return function (uri, offset)
- local ast = files.getAst(uri)
- if not ast then
- return nil
- end
- local results = {}
- guide.eachSourceContain(ast.ast, offset, function (source)
- findRef(source, offset, function (target, uri)
- results[#results+1] = {
- target = target,
- uri = files.getOriginUri(uri),
- }
- end)
- end)
- if #results == 0 then
- return nil
- end
- return results
-end
diff --git a/server-beta/src/core/rename.lua b/server-beta/src/core/rename.lua
deleted file mode 100644
index 3e4512da..00000000
--- a/server-beta/src/core/rename.lua
+++ /dev/null
@@ -1,374 +0,0 @@
-local files = require 'files'
-local vm = require 'vm'
-local guide = require 'parser.guide'
-local proto = require 'proto'
-local define = require 'proto.define'
-local util = require 'utility'
-
-local Forcing
-
-local function askForcing(str)
- if TEST then
- return true
- end
- if Forcing == false then
- return false
- end
- local version = files.globalVersion
- -- TODO
- local item = proto.awaitRequest('window/showMessageRequest', {
- type = define.MessageType.Warning,
- message = ('[%s]不是有效的标识符,是否强制替换?'):format(str),
- actions = {
- {
- title = '强制替换',
- },
- {
- title = '取消',
- },
- }
- })
- if version ~= files.globalVersion then
- Forcing = false
- proto.notify('window/showMessage', {
- type = define.MessageType.Warning,
- message = '文件发生了变化,替换取消。'
- })
- return false
- end
- if not item then
- Forcing = false
- return false
- end
- if item.title == '强制替换' then
- Forcing = true
- return true
- else
- Forcing = false
- return false
- end
-end
-
-local function askForMultiChange(results, newname)
- if TEST then
- return true
- end
- local uris = {}
- for _, result in ipairs(results) do
- local uri = result.uri
- if not uris[uri] then
- uris[uri] = 0
- uris[#uris+1] = uri
- end
- uris[uri] = uris[uri] + 1
- end
- if #uris <= 1 then
- return true
- end
-
- local version = files.globalVersion
- -- TODO
- local item = proto.awaitRequest('window/showMessageRequest', {
- type = define.MessageType.Warning,
- message = ('将修改 %d 个文件,共 %d 处。'):format(
- #uris,
- #results
- ),
- actions = {
- {
- title = '继续',
- },
- {
- title = '放弃',
- },
- }
- })
- if version ~= files.globalVersion then
- proto.notify('window/showMessage', {
- type = define.MessageType.Warning,
- message = '文件发生了变化,替换取消。'
- })
- return false
- end
- if item and item.title == '继续' then
- local fileList = {}
- for _, uri in ipairs(uris) do
- fileList[#fileList+1] = ('%s (%d)'):format(uri, uris[uri])
- end
-
- log.debug(('Renamed [%s]\r\n%s'):format(newname, table.concat(fileList, '\r\n')))
- return true
- end
- return false
-end
-
-local function trim(str)
- return str:match '^%s*(%S+)%s*$'
-end
-
-local function isValidName(str)
- return str:match '^[%a_][%w_]*$'
-end
-
-local function isValidGlobal(str)
- for s in str:gmatch '[^%.]*' do
- if not isValidName(trim(s)) then
- return false
- end
- end
- return true
-end
-
-local function isValidFunctionName(str)
- if isValidGlobal(str) then
- return true
- end
- local pos = str:find(':', 1, true)
- if not pos then
- return false
- end
- return isValidGlobal(trim(str:sub(1, pos-1)))
- and isValidName(trim(str:sub(pos+1)))
-end
-
-local function isFunctionGlobalName(source)
- local parent = source.parent
- if parent.type ~= 'setglobal' then
- return false
- end
- local value = parent.value
- if not value.type ~= 'function' then
- return false
- end
- return value.start <= parent.start
-end
-
-local function renameLocal(source, newname, callback)
- if isValidName(newname) then
- callback(source, source.start, source.finish, newname)
- return
- end
- if askForcing(newname) then
- callback(source, source.start, source.finish, newname)
- end
-end
-
-local function renameField(source, newname, callback)
- if isValidName(newname) then
- callback(source, source.start, source.finish, newname)
- return true
- end
- local parent = source.parent
- if parent.type == 'setfield'
- or parent.type == 'getfield' then
- local dot = parent.dot
- local newstr = '[' .. util.viewString(newname) .. ']'
- callback(source, dot.start, source.finish, newstr)
- elseif parent.type == 'tablefield' then
- local newstr = '[' .. util.viewString(newname) .. ']'
- callback(source, source.start, source.finish, newstr)
- elseif parent.type == 'getmethod' then
- if not askForcing(newname) then
- return false
- end
- callback(source, source.start, source.finish, newname)
- elseif parent.type == 'setmethod' then
- local uri = guide.getRoot(source).uri
- local text = files.getText(uri)
- local func = parent.value
- -- function mt:name () end --> mt['newname'] = function (self) end
- local newstr = string.format('%s[%s] = function '
- , text:sub(parent.start, parent.node.finish)
- , util.viewString(newname)
- )
- callback(source, func.start, parent.finish, newstr)
- local pl = text:find('(', parent.finish, true)
- if pl then
- if func.args then
- callback(source, pl + 1, pl, 'self, ')
- else
- callback(source, pl + 1, pl, 'self')
- end
- end
- end
- return true
-end
-
-local function renameGlobal(source, newname, callback)
- if isValidGlobal(newname) then
- callback(source, source.start, source.finish, newname)
- return true
- end
- if isValidFunctionName(newname) then
- if not isFunctionGlobalName(source) then
- askForcing(newname)
- end
- callback(source, source.start, source.finish, newname)
- return true
- end
- local newstr = '_ENV[' .. util.viewString(newname) .. ']'
- -- function name () end --> _ENV['newname'] = function () end
- if source.value and source.value.type == 'function'
- and source.value.start < source.start then
- callback(source, source.value.start, source.finish, newstr .. ' = function ')
- return true
- end
- callback(source, source.start, source.finish, newstr)
- return true
-end
-
-local function ofLocal(source, newname, callback)
- renameLocal(source, newname, callback)
- if source.ref then
- for _, ref in ipairs(source.ref) do
- renameLocal(ref, newname, callback)
- end
- end
-end
-
-local function ofField(source, newname, callback)
- return vm.eachRef(source, function (info)
- local src = info.source
- if src.type == 'tablefield'
- or src.type == 'getfield'
- or src.type == 'setfield' then
- src = src.field
- elseif src.type == 'tableindex'
- or src.type == 'getindex'
- or src.type == 'setindex' then
- src = src.index
- elseif src.type == 'getmethod'
- or src.type == 'setmethod' then
- src = src.method
- end
- if src.type == 'string' then
- local quo = src[2]
- local text = util.viewString(newname, quo)
- callback(src, src.start, src.finish, text)
- return
- elseif src.type == 'field'
- or src.type == 'method' then
- local suc = renameField(src, newname, callback)
- if not suc then
- return false
- end
- elseif src.type == 'setglobal'
- or src.type == 'getglobal' then
- local suc = renameGlobal(src, newname, callback)
- if not suc then
- return false
- end
- end
- end)
-end
-
-local function rename(source, newname, callback)
- if source.type == 'label'
- or source.type == 'goto' then
- if not isValidName(newname) and not askForcing(newname)then
- return false
- end
- vm.eachRef(source, function (info)
- callback(info.source, info.source.start, info.source.finish, newname)
- end)
- elseif source.type == 'local' then
- return ofLocal(source, newname, callback)
- elseif source.type == 'setlocal'
- or source.type == 'getlocal' then
- return ofLocal(source.node, newname, callback)
- elseif source.type == 'field'
- or source.type == 'method'
- or source.type == 'tablefield'
- or source.type == 'string'
- or source.type == 'setglobal'
- or source.type == 'getglobal' then
- return ofField(source, newname, callback)
- end
- return true
-end
-
-local function prepareRename(source)
- if source.type == 'label'
- or source.type == 'goto'
- or source.type == 'local'
- or source.type == 'setlocal'
- or source.type == 'getlocal'
- or source.type == 'field'
- or source.type == 'method'
- or source.type == 'tablefield'
- or source.type == 'setglobal'
- or source.type == 'getglobal' then
- return source, source[1]
- elseif source.type == 'string' then
- local parent = source.parent
- if not parent then
- return nil
- end
- if parent.type == 'setindex'
- or parent.type == 'getindex'
- or parent.type == 'tableindex' then
- return source, source[1]
- end
- return nil
- end
- return nil
-end
-
-local m = {}
-
-function m.rename(uri, pos, newname)
- local ast = files.getAst(uri)
- if not ast then
- return nil
- end
- local results = {}
-
- guide.eachSourceContain(ast.ast, pos, function(source)
- rename(source, newname, function (target, start, finish, text)
- results[#results+1] = {
- start = start,
- finish = finish,
- text = text,
- uri = guide.getRoot(target).uri,
- }
- end)
- end)
-
- if Forcing == false then
- Forcing = nil
- return nil
- end
-
- if #results == 0 then
- return nil
- end
-
- if not askForMultiChange(results, newname) then
- return nil
- end
-
- return results
-end
-
-function m.prepareRename(uri, pos)
- local ast = files.getAst(uri)
- if not ast then
- return nil
- end
-
- local result
- guide.eachSourceContain(ast.ast, pos, function(source)
- local res, text = prepareRename(source)
- if res then
- result = {
- start = source.start,
- finish = source.finish,
- text = text,
- }
- end
- end)
-
- return result
-end
-
-return m
diff --git a/server-beta/src/define/DiagnosticDefaultSeverity.lua b/server-beta/src/define/DiagnosticDefaultSeverity.lua
deleted file mode 100644
index cc26cab2..00000000
--- a/server-beta/src/define/DiagnosticDefaultSeverity.lua
+++ /dev/null
@@ -1,21 +0,0 @@
-return {
- ['unused-local'] = 'Hint',
- ['unused-function'] = 'Hint',
- ['undefined-global'] = 'Warning',
- ['global-in-nil-env'] = 'Warning',
- ['unused-label'] = 'Hint',
- ['unused-vararg'] = 'Hint',
- ['trailing-space'] = 'Hint',
- ['redefined-local'] = 'Hint',
- ['newline-call'] = 'Information',
- ['redundant-parameter'] = 'Hint',
- ['ambiguity-1'] = 'Warning',
- ['lowercase-global'] = 'Information',
- ['undefined-env-child'] = 'Information',
- ['duplicate-index'] = 'Warning',
- ['duplicate-method'] = 'Warning',
- ['empty-block'] = 'Hint',
- ['redundant-value'] = 'Hint',
- ['emmy-lua'] = 'Warning',
- ['set-const'] = 'Error',
-}
diff --git a/server-beta/src/define/DiagnosticSeverity.lua b/server-beta/src/define/DiagnosticSeverity.lua
deleted file mode 100644
index 05bd3659..00000000
--- a/server-beta/src/define/DiagnosticSeverity.lua
+++ /dev/null
@@ -1,6 +0,0 @@
-return {
- Error = 1,
- Warning = 2,
- Information = 3,
- Hint = 4,
-}
diff --git a/server-beta/src/define/ErrorCodes.lua b/server-beta/src/define/ErrorCodes.lua
deleted file mode 100644
index befb5630..00000000
--- a/server-beta/src/define/ErrorCodes.lua
+++ /dev/null
@@ -1,16 +0,0 @@
-
-return {
- -- Defined by JSON RPC
- ParseError = -32700,
- InvalidRequest = -32600,
- MethodNotFound = -32601,
- InvalidParams = -32602,
- InternalError = -32603,
- serverErrorStart = -32099,
- serverErrorEnd = -32000,
- ServerNotInitialized = -32002,
- UnknownErrorCode = -32001,
-
- -- Defined by the protocol.
- RequestCancelled = -32800,
-}
diff --git a/server-beta/src/doctor.lua b/server-beta/src/doctor.lua
deleted file mode 100644
index 08ec69cf..00000000
--- a/server-beta/src/doctor.lua
+++ /dev/null
@@ -1,380 +0,0 @@
-local type = type
-local next = next
-local ipairs = ipairs
-local rawget = rawget
-local pcall = pcall
-local getregistry = debug.getregistry
-local getmetatable = debug.getmetatable
-local getupvalue = debug.getupvalue
-local getuservalue = debug.getuservalue
-local getlocal = debug.getlocal
-local getinfo = debug.getinfo
-local maxinterger = math.maxinteger
-local mathType = math.type
-local tableConcat = table.concat
-local _G = _G
-local registry = getregistry()
-local tableSort = table.sort
-
-_ENV = nil
-
-local m = {}
-
-local function getTostring(obj)
- local mt = getmetatable(obj)
- if not mt then
- return nil
- end
- local toString = rawget(mt, '__tostring')
- if not toString then
- return nil
- end
- local suc, str = pcall(toString, obj)
- if not suc then
- return nil
- end
- if type(str) ~= 'string' then
- return nil
- end
- return str
-end
-
-local function formatName(obj)
- local tp = type(obj)
- if tp == 'nil' then
- return 'nil:nil'
- elseif tp == 'boolean' then
- if obj == true then
- return 'boolean:true'
- else
- return 'boolean:false'
- end
- elseif tp == 'number' then
- if mathType(obj) == 'integer' then
- return ('number:%d'):format(obj)
- else
- -- 如果浮点数可以完全表示为整数,那么就转换为整数
- local str = ('%.10f'):format(obj):gsub('%.?[0]+$', '')
- if str:find('.', 1, true) then
- -- 如果浮点数不能表示为整数,那么再加上它的精确表示法
- str = ('%s(%q)'):format(str, obj)
- end
- return 'number:' .. str
- end
- elseif tp == 'string' then
- local str = ('%q'):format(obj)
- if #str > 100 then
- local new = ('%s...(len=%d)'):format(str:sub(1, 100), #str)
- if #new < #str then
- str = new
- end
- end
- return 'string:' .. str
- elseif tp == 'function' then
- local info = getinfo(obj, 'S')
- if info.what == 'c' then
- return ('function:%p(C)'):format(obj)
- elseif info.what == 'main' then
- return ('function:%p(main)'):format(obj)
- else
- return ('function:%p(%s:%d-%d)'):format(obj, info.source, info.linedefined, info.lastlinedefined)
- end
- elseif tp == 'table' then
- local id = getTostring(obj)
- if not id then
- if obj == _G then
- id = '_G'
- elseif obj == registry then
- id = 'registry'
- end
- end
- if id then
- return ('table:%p(%s)'):format(obj, id)
- else
- return ('table:%p'):format(obj)
- end
- elseif tp == 'userdata' then
- local id = getTostring(obj)
- if id then
- return ('userdata:%p(%s)'):format(obj, id)
- else
- return ('userdata:%p'):format(obj)
- end
- else
- return ('%s:%p'):format(tp, obj)
- end
-end
-
---- 内存快照
----@return table
-function m.snapshot()
- local mark = {}
- local find
-
- local function findTable(t, result)
- result = result or {}
- local mt = getmetatable(t)
- local wk, wv
- if mt then
- local mode = rawget(mt, '__mode')
- if type(mode) == 'string' then
- if mode:find('k', 1, true) then
- wk = true
- end
- if mode:find('v', 1, true) then
- wv = true
- end
- end
- end
- for k, v in next, t do
- if not wk then
- local keyInfo = find(k)
- if keyInfo then
- result[#result+1] = {
- type = 'key',
- name = formatName(k),
- info = keyInfo,
- }
- end
- end
- if not wv then
- local valueInfo = find(v)
- if valueInfo then
- result[#result+1] = {
- type = 'field',
- name = formatName(k) .. '|' .. formatName(v),
- info = valueInfo,
- }
- end
- end
- end
- local MTInfo = find(getmetatable(t))
- if MTInfo then
- result[#result+1] = {
- type = 'metatable',
- name = '',
- info = MTInfo,
- }
- end
- if #result == 0 then
- return nil
- end
- return result
- end
-
- local function findFunction(f, result, trd, stack)
- result = result or {}
- for i = 1, maxinterger do
- local n, v = getupvalue(f, i)
- if not n then
- break
- end
- local valueInfo = find(v)
- if valueInfo then
- result[#result+1] = {
- type = 'upvalue',
- name = n,
- info = valueInfo,
- }
- end
- end
- if trd then
- for i = 1, maxinterger do
- local n, l = getlocal(trd, stack, i)
- if not n then
- break
- end
- local valueInfo = find(l)
- if valueInfo then
- result[#result+1] = {
- type = 'local',
- name = n,
- info = valueInfo,
- }
- end
- end
- end
- if #result == 0 then
- return nil
- end
- return result
- end
-
- local function findUserData(u, result)
- result = result or {}
- for i = 1, maxinterger do
- local v, b = getuservalue(u, i)
- if not b then
- break
- end
- local valueInfo = find(v)
- if valueInfo then
- result[#result+1] = {
- type = 'uservalue',
- name = formatName(i),
- info = valueInfo,
- }
- end
- end
- local MTInfo = find(getmetatable(u))
- if MTInfo then
- result[#result+1] = {
- type = 'metatable',
- name = '',
- info = MTInfo,
- }
- end
- if #result == 0 then
- return nil
- end
- return result
- end
-
- local function findThread(trd, result)
- -- 不查找主线程,主线程一定是临时的(视为弱引用)
- if trd == registry[1] then
- return nil
- end
- result = result or {}
-
- for i = 1, maxinterger do
- local info = getinfo(trd, i, 'Sf')
- if not info then
- break
- end
- local funcInfo = find(info.func, trd, i)
- if funcInfo then
- result[#result+1] = {
- type = 'stack',
- name = i .. '@' .. formatName(info.func),
- info = funcInfo,
- }
- end
- end
-
- if #result == 0 then
- return nil
- end
- return result
- end
-
- function find(obj, trd, stack)
- if mark[obj] then
- return mark[obj]
- end
- local tp = type(obj)
- if tp == 'table' then
- mark[obj] = {}
- mark[obj] = findTable(obj, mark[obj])
- elseif tp == 'function' then
- mark[obj] = {}
- mark[obj] = findFunction(obj, mark[obj], trd, stack)
- elseif tp == 'userdata' then
- mark[obj] = {}
- mark[obj] = findUserData(obj, mark[obj])
- elseif tp == 'thread' then
- mark[obj] = {}
- mark[obj] = findThread(obj, mark[obj])
- else
- return nil
- end
- if mark[obj] then
- mark[obj].object = obj
- end
- return mark[obj]
- end
-
- return {
- name = formatName(registry),
- type = 'root',
- info = find(registry),
- }
-end
-
---- 寻找对象的引用
----@return string
-function m.catch(...)
- local targets = {}
- for _, target in ipairs {...} do
- targets[target] = true
- end
- local report = m.snapshot()
- local path = {}
- local result = {}
- local mark = {}
-
- local function push()
- result[#result+1] = tableConcat(path, ' => ')
- end
-
- local function search(t)
- path[#path+1] = ('(%s)%s'):format(t.type, t.name)
- local addTarget
- if targets[t.info.object] then
- targets[t.info.object] = nil
- addTarget = t.info.object
- push(t)
- end
- if not mark[t.info] then
- mark[t.info] = true
- for _, obj in ipairs(t.info) do
- search(obj)
- end
- end
- path[#path] = nil
- if addTarget then
- targets[addTarget] = true
- end
- end
-
- search(report)
-
- return result
-end
-
---- 生成一个报告
----@return string
-function m.report()
- local snapshot = m.snapshot()
- local cache = {}
- local mark = {}
-
- local function scan(t)
- local obj = t.info.object
- local tp = type(obj)
- if tp == 'table'
- or tp == 'userdata'
- or tp == 'function'
- or tp == 'string'
- or tp == 'thread' then
- local point = ('%p'):format(obj)
- if not cache[point] then
- cache[point] = {
- point = point,
- count = 0,
- name = formatName(obj),
- }
- end
- cache[point].count = cache[point].count + 1
- end
- if not mark[t.info] then
- mark[t.info] = true
- for _, child in ipairs(t.info) do
- scan(child)
- end
- end
- end
-
- scan(snapshot)
-
- local list = {}
- for _, info in next, cache do
- list[#list+1] = info
- end
- tableSort(list, function (a, b)
- return a.name < b.name
- end)
- return list
-end
-
-return m
diff --git a/server-beta/src/file-uri.lua b/server-beta/src/file-uri.lua
deleted file mode 100644
index 8acd4f64..00000000
--- a/server-beta/src/file-uri.lua
+++ /dev/null
@@ -1,108 +0,0 @@
-local platform = require 'bee.platform'
-
-local esc = {
- [':'] = '%3A',
- ['/'] = '%2F',
- ['?'] = '%3F',
- ['#'] = '%23',
- ['['] = '%5B',
- [']'] = '%5D',
- ['@'] = '%40',
-
- ['!'] = '%21', -- sub-delims
- ['$'] = '%24',
- ['&'] = '%26',
- ["'"] = '%27',
- ['('] = '%28',
- [')'] = '%29',
- ['*'] = '%2A',
- ['+'] = '%2B',
- [','] = '%2C',
- [';'] = '%3B',
- ['='] = '%3D',
-
- [' '] = '%20',
-}
-
-local escPatt = '[^%w%-%.%_%~%/]'
-
-local function normalize(str)
- return str:gsub('%%(%x%x)', function (n)
- return string.char(tonumber(n, 16))
- end)
-end
-
-local m = {}
-
--- c:\my\files --> file:///c%3A/my/files
--- /usr/home --> file:///usr/home
--- \\server\share\some\path --> file://server/share/some/path
-
---- path -> uri
----@param path string
----@return string uri
-function m.encode(path)
- local authority = ''
- if platform.OS == 'Windows' then
- path = path:gsub('\\', '/')
- end
-
- if path:sub(1, 2) == '//' then
- local idx = path:find('/', 3)
- if idx then
- authority = path:sub(3, idx)
- path = path:sub(idx + 1)
- if path == '' then
- path = '/'
- end
- else
- authority = path:sub(3)
- path = '/'
- end
- end
-
- if path:sub(1, 1) ~= '/' then
- path = '/' .. path
- end
-
- -- lower-case windows drive letters in /C:/fff or C:/fff
- if path:match '/%u:' then
- path = path:lower()
- end
-
- local uri = 'file://'
- .. authority:gsub(escPatt, esc)
- .. path:gsub(escPatt, esc)
- return uri
-end
-
--- file:///c%3A/my/files --> c:\my\files
--- file:///usr/home --> /usr/home
--- file://server/share/some/path --> \\server\share\some\path
-
---- uri -> path
----@param uri string
----@return string path
-function m.decode(uri)
- local scheme, authority, path = uri:match('([^:]*):?/?/?([^/]*)(.*)')
- if not scheme then
- return ''
- end
- scheme = normalize(scheme)
- authority = normalize(authority)
- path = normalize(path)
- local value
- if scheme == 'file' and #authority > 0 and #path > 1 then
- value = '//' .. authority .. path
- elseif path:match '/%a:' then
- value = path:sub(2, 2):lower() .. path:sub(3)
- else
- value = path
- end
- if platform.OS == 'Windows' then
- value = value:gsub('/', '\\')
- end
- return value
-end
-
-return m
diff --git a/server-beta/src/files.lua b/server-beta/src/files.lua
deleted file mode 100644
index ac27117c..00000000
--- a/server-beta/src/files.lua
+++ /dev/null
@@ -1,290 +0,0 @@
-local platform = require 'bee.platform'
-local config = require 'config'
-local glob = require 'glob'
-local furi = require 'file-uri'
-local parser = require 'parser'
-local vm = require 'vm.vm'
-local guide = require 'parser.guide'
-
-local m = {}
-
-m.openMap = {}
-m.fileMap = {}
-m.assocVersion = -1
-m.assocMatcher = nil
-m.globalVersion = 0
-
---- 打开文件
----@param uri string
-function m.open(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- m.openMap[uri] = true
-end
-
---- 关闭文件
----@param uri string
-function m.close(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- m.openMap[uri] = nil
-end
-
---- 是否打开
----@param uri string
----@return boolean
-function m.isOpen(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- return m.openMap[uri] == true
-end
-
---- 是否存在
----@return boolean
-function m.exists(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- return m.fileMap[uri] ~= nil
-end
-
---- 设置文件文本
----@param uri string
----@param text string
-function m.setText(uri, text)
- local originUri = uri
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- if not m.fileMap[uri] then
- m.fileMap[uri] = {
- uri = originUri,
- }
- end
- local file = m.fileMap[uri]
- if file.text == text then
- return
- end
- file.text = text
- file.vm = nil
- file.lines = nil
- file.ast = nil
- file.globals = nil
- file.links = nil
- m.globalVersion = m.globalVersion + 1
- vm.refreshCache()
-
- local diagnostic = require 'provider.diagnostic'
- diagnostic.refresh(originUri)
-end
-
---- 监听编译完成
-function m.onCompiled(uri, callback)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- local file = m.fileMap[uri]
- if not file then
- return
- end
- if not file.onCompiledList then
- file.onCompiledList = {}
- end
- file.onCompiledList[#file.onCompiledList+1] = callback
-end
-
---- 获取文件文本
----@param uri string
----@return string text
-function m.getText(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- local file = m.fileMap[uri]
- if not file then
- return nil
- end
- return file.text
-end
-
---- 移除文件
----@param uri string
-function m.remove(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- local file = m.fileMap[uri]
- if not file then
- return
- end
- m.fileMap[uri] = nil
-
- m.globalVersion = m.globalVersion + 1
- vm.refreshCache()
-
- local diagnostic = require 'service.diagnostic'
- diagnostic.refresh(file.uri)
- diagnostic.clear(file.uri)
-end
-
---- 移除所有文件
-function m.removeAll()
- for uri in pairs(m.fileMap) do
- m.fileMap[uri] = nil
- end
- m.globalVersion = m.globalVersion + 1
- vm.refreshCache()
-end
-
---- 遍历文件
-function m.eachFile()
- return pairs(m.fileMap)
-end
-
---- 获取文件语法树
----@param uri string
----@return table ast
-function m.getAst(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- local file = m.fileMap[uri]
- if file.ast == nil then
- local state, err = parser:compile(file.text, 'lua', config.config.runtime.version)
- if state then
- state.uri = file.uri
- state.ast.uri = file.uri
- file.ast = state
- else
- log.error(err)
- file.ast = false
- return nil
- end
- end
- return file.ast
-end
-
---- 获取文件行信息
----@param uri string
----@return table lines
-function m.getLines(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- local file = m.fileMap[uri]
- if not file then
- return nil
- end
- if not file.lines then
- file.lines = parser:lines(file.text)
- end
- return file.lines
-end
-
---- 获取原始uri
-function m.getOriginUri(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- local file = m.fileMap[uri]
- if not file then
- return nil
- end
- return file.uri
-end
-
---- 寻找全局变量
-function m.findGlobals(name)
- local uris = {}
- for uri, file in pairs(m.fileMap) do
- if not file.globals then
- file.globals = {}
- local ast = m.getAst(uri)
- if ast then
- local globals = vm.getGlobals(ast.ast)
- for name in pairs(globals) do
- file.globals[name] = true
- end
- end
- end
- if file.globals[name] then
- uris[#uris+1] = file.uri
- end
- end
- return uris
-end
-
---- 寻找link自己的其他文件
-function m.findLinkTo(uri)
- if platform.OS == 'Windows' then
- uri = uri:lower()
- end
- local result = {}
- for _, file in pairs(m.fileMap) do
- if file.links == nil then
- local ast = m.getAst(file.uri)
- if ast then
- file.links = vm.getLinks(ast.ast)
- else
- file.links = false
- end
- end
- if file.links then
- for linkUri in pairs(file.links) do
- if m.eq(uri, linkUri) then
- result[#result+1] = file.uri
- end
- end
- end
- end
- return result
-end
-
---- 判断文件名相等
-function m.eq(a, b)
- if platform.OS == 'Windows' then
- return a:lower() == b:lower()
- else
- return a == b
- end
-end
-
---- 获取文件关联
-function m.getAssoc()
- if m.assocVersion == config.version then
- return m.assocMatcher
- end
- m.assocVersion = config.version
- local patt = {}
- for k, v in pairs(config.other.associations) do
- if m.eq(v, 'lua') then
- patt[#patt+1] = k
- end
- end
- m.assocMatcher = glob.glob(patt)
- if platform.OS == 'Windows' then
- m.assocMatcher:setOption 'ignoreCase'
- end
- return m.assocMatcher
-end
-
---- 判断是否是Lua文件
----@param uri string
----@return boolean
-function m.isLua(uri)
- local ext = uri:match '%.([^%.%/%\\]-)$'
- if not ext then
- return false
- end
- if m.eq(ext, 'lua') then
- return true
- end
- local matcher = m.getAssoc()
- local path = furi.decode(uri)
- return matcher(path)
-end
-
-return m
diff --git a/server-beta/src/fs-utility.lua b/server-beta/src/fs-utility.lua
deleted file mode 100644
index 14dcb08f..00000000
--- a/server-beta/src/fs-utility.lua
+++ /dev/null
@@ -1,314 +0,0 @@
-local fs = require 'bee.filesystem'
-local platform = require 'bee.platform'
-
-local type = type
-local ioOpen = io.open
-local pcall = pcall
-local pairs = pairs
-local setmetatable = setmetatable
-local next = next
-
-_ENV = nil
-
-local m = {}
---- 读取文件
----@param path string
-function m.loadFile(path)
- if type(path) ~= 'string' then
- path = path:string()
- end
- local f, e = ioOpen(path, 'rb')
- if not f then
- return nil, e
- end
- if f:read(3) ~= '\xEF\xBB\xBF' then
- f:seek("set")
- end
- local buf = f:read 'a'
- f:close()
- return buf
-end
-
---- 写入文件
----@param path string
----@param content string
-function m.saveFile(path, content)
- if type(path) ~= 'string' then
- path = path:string()
- end
- local f, e = ioOpen(path, "wb")
-
- if f then
- f:write(content)
- f:close()
- return true
- else
- return false, e
- end
-end
-
-local function buildOptional(optional)
- optional = optional or {}
- optional.add = optional.add or {}
- optional.del = optional.del or {}
- optional.mod = optional.mod or {}
- optional.err = optional.err or {}
- return optional
-end
-
-local function fsAbsolute(path, optional)
- if type(path) == 'string' then
- local suc, res = pcall(fs.path, path)
- if not suc then
- optional.err[#optional.err+1] = res
- return nil
- end
- path = res
- end
- local suc, res = pcall(fs.absolute, path)
- if not suc then
- optional.err[#optional.err+1] = res
- return nil
- end
- return res
-end
-
-local function fsIsDirectory(path, optional)
- local suc, res = pcall(fs.is_directory, path)
- if not suc then
- optional.err[#optional.err+1] = res
- return false
- end
- return res
-end
-
-local function fsRemove(path, optional)
- local suc, res = pcall(fs.remove, path)
- if not suc then
- optional.err[#optional.err+1] = res
- end
- optional.del[#optional.del+1] = path:string()
-end
-
-local function fsExists(path, optional)
- local suc, res = pcall(fs.exists, path)
- if not suc then
- optional.err[#optional.err+1] = res
- return false
- end
- return res
-end
-
-local function fsCopy(source, target, optional)
- local suc, res = pcall(fs.copy_file, source, target, true)
- if not suc then
- optional.err[#optional.err+1] = res
- return false
- end
- return true
-end
-
-local function fsCreateDirectories(path, optional)
- local suc, res = pcall(fs.create_directories, path)
- if not suc then
- optional.err[#optional.err+1] = res
- return false
- end
- return true
-end
-
-local function fileRemove(path, optional)
- if optional.onRemove and optional.onRemove(path) == false then
- return
- end
- if fsIsDirectory(path, optional) then
- for child in path:list_directory() do
- fileRemove(child, optional)
- end
- end
- if fsRemove(path, optional) then
- optional.del[#optional.del+1] = path:string()
- end
-end
-
-local function fileCopy(source, target, optional)
- local isDir1 = fsIsDirectory(source, optional)
- local isDir2 = fsIsDirectory(target, optional)
- local isExists = fsExists(target, optional)
- if isDir1 then
- if isDir2 or fsCreateDirectories(target) then
- for filePath in source:list_directory() do
- local name = filePath:filename()
- fileCopy(filePath, target / name, optional)
- end
- end
- else
- if isExists and not isDir2 then
- local buf1, err1 = m.loadFile(source)
- local buf2, err2 = m.loadFile(target)
- if buf1 and buf2 then
- if buf1 ~= buf2 then
- if fsCopy(source, target, optional) then
- optional.mod[#optional.mod+1] = target:string()
- end
- end
- else
- if not buf1 then
- optional.err[#optional.err+1] = err1
- end
- if not buf2 then
- optional.err[#optional.err+1] = err2
- end
- end
- else
- if fsCopy(source, target, optional) then
- optional.add[#optional.add+1] = target:string()
- end
- end
- end
-end
-
-local function fileSync(source, target, optional)
- local isDir1 = fsIsDirectory(source, optional)
- local isDir2 = fsIsDirectory(target, optional)
- local isExists = fsExists(target, optional)
- if isDir1 then
- if isDir2 then
- local fileList = m.fileList()
- for filePath in target:list_directory() do
- fileList[filePath] = true
- end
- for filePath in source:list_directory() do
- local name = filePath:filename()
- local targetPath = target / name
- fileSync(filePath, targetPath, optional)
- fileList[targetPath] = nil
- end
- for path in pairs(fileList) do
- fileRemove(path, optional)
- end
- else
- if isExists then
- fileRemove(target, optional)
- end
- if fsCreateDirectories(target) then
- for filePath in source:list_directory() do
- local name = filePath:filename()
- fileCopy(filePath, target / name, optional)
- end
- end
- end
- else
- if isDir2 then
- fileRemove(target, optional)
- end
- if isExists then
- local buf1, err1 = m.loadFile(source)
- local buf2, err2 = m.loadFile(target)
- if buf1 and buf2 then
- if buf1 ~= buf2 then
- if fsCopy(source, target, optional) then
- optional.mod[#optional.mod+1] = target:string()
- end
- end
- else
- if not buf1 then
- optional.err[#optional.err+1] = err1
- end
- if not buf2 then
- optional.err[#optional.err+1] = err2
- end
- end
- else
- if fsCopy(source, target, optional) then
- optional.add[#optional.add+1] = target:string()
- end
- end
- end
-end
-
---- 文件列表
-function m.fileList(optional)
- optional = optional or buildOptional(optional)
- local os = platform.OS
- local keyMap = {}
- local fileList = {}
- local function computeKey(path)
- path = fsAbsolute(path, optional)
- if not path then
- return nil
- end
- local key
- if os == 'Windows' then
- key = path:string():lower()
- else
- key = path:string()
- end
- return key
- end
- return setmetatable({}, {
- __index = function (_, path)
- local key = computeKey(path)
- return fileList[key]
- end,
- __newindex = function (_, path, value)
- local key = computeKey(path)
- if not key then
- return
- end
- if value == nil then
- keyMap[key] = nil
- else
- keyMap[key] = path
- fileList[key] = value
- end
- end,
- __pairs = function ()
- local key, path
- return function ()
- key, path = next(keyMap, key)
- return path, fileList[key]
- end
- end,
- })
-end
-
---- 删除文件(夹)
-function m.fileRemove(path, optional)
- optional = buildOptional(optional)
- path = fsAbsolute(path, optional)
-
- fileRemove(path, optional)
-
- return optional
-end
-
---- 复制文件(夹)
----@param source string
----@param target string
----@return table
-function m.fileCopy(source, target, optional)
- optional = buildOptional(optional)
- source = fsAbsolute(source, optional)
- target = fsAbsolute(target, optional)
-
- fileCopy(source, target, optional)
-
- return optional
-end
-
---- 同步文件(夹)
----@param source string
----@param target string
----@return table
-function m.fileSync(source, target, optional)
- optional = buildOptional(optional)
- source = fsAbsolute(source, optional)
- target = fsAbsolute(target, optional)
-
- fileSync(source, target, optional)
-
- return optional
-end
-
-return m
diff --git a/server-beta/src/glob/gitignore.lua b/server-beta/src/glob/gitignore.lua
deleted file mode 100644
index f98a2f31..00000000
--- a/server-beta/src/glob/gitignore.lua
+++ /dev/null
@@ -1,221 +0,0 @@
-local m = require 'lpeglabel'
-local matcher = require 'glob.matcher'
-
-local function prop(name, pat)
- return m.Cg(m.Cc(true), name) * pat
-end
-
-local function object(type, pat)
- return m.Ct(
- m.Cg(m.Cc(type), 'type') *
- m.Cg(pat, 'value')
- )
-end
-
-local function expect(p, err)
- return p + m.T(err)
-end
-
-local parser = m.P {
- 'Main',
- ['Sp'] = m.S(' \t')^0,
- ['Slash'] = m.S('/\\')^1,
- ['Main'] = m.Ct(m.V'Sp' * m.P'{' * m.V'Pattern' * (',' * expect(m.V'Pattern', 'Miss exp after ","'))^0 * m.P'}')
- + m.Ct(m.V'Pattern')
- + m.T'Main Failed'
- ,
- ['Pattern'] = m.Ct(m.V'Sp' * prop('neg', m.P'!') * expect(m.V'Unit', 'Miss exp after "!"'))
- + m.Ct(m.V'Unit')
- ,
- ['NeedRoot'] = prop('root', (m.P'.' * m.V'Slash' + m.V'Slash')),
- ['Unit'] = m.V'Sp' * m.V'NeedRoot'^-1 * expect(m.V'Exp', 'Miss exp') * m.V'Sp',
- ['Exp'] = m.V'Sp' * (m.V'FSymbol' + object('/', m.V'Slash') + m.V'Word')^0 * m.V'Sp',
- ['Word'] = object('word', m.Ct((m.V'CSymbol' + m.V'Char' - m.V'FSymbol')^1)),
- ['CSymbol'] = object('*', m.P'*')
- + object('?', m.P'?')
- + object('[]', m.V'Range')
- ,
- ['Char'] = object('char', (1 - m.S',{}[]*?/\\')^1),
- ['FSymbol'] = object('**', m.P'**'),
- ['Range'] = m.P'[' * m.Ct(m.V'RangeUnit'^0) * m.P']'^-1,
- ['RangeUnit'] = m.Ct(- m.P']' * m.C(m.P(1)) * (m.P'-' * - m.P']' * m.C(m.P(1)))^-1),
-}
-
-local mt = {}
-mt.__index = mt
-mt.__name = 'gitignore'
-
-function mt:addPattern(pat)
- if type(pat) ~= 'string' then
- return
- end
- self.pattern[#self.pattern+1] = pat
- if self.options.ignoreCase then
- pat = pat:lower()
- end
- local states, err = parser:match(pat)
- if not states then
- self.errors[#self.errors+1] = {
- pattern = pat,
- message = err
- }
- return
- end
- for _, state in ipairs(states) do
- self.matcher[#self.matcher+1] = matcher(state)
- end
-end
-
-function mt:setOption(op, val)
- if val == nil then
- val = true
- end
- self.options[op] = val
-end
-
----@param key string | "'type'" | "'list'"
----@param func function | "function (path) end"
-function mt:setInterface(key, func)
- if type(func) ~= 'function' then
- return
- end
- self.interface[key] = func
-end
-
-function mt:callInterface(name, ...)
- local func = self.interface[name]
- return func(...)
-end
-
-function mt:hasInterface(name)
- return self.interface[name] ~= nil
-end
-
-function mt:checkDirectory(catch, path, matcher)
- if not self:hasInterface 'type' then
- return true
- end
- if not matcher:isNeedDirectory() then
- return true
- end
- if #catch < #path then
- -- if path is 'a/b/c' and catch is 'a/b'
- -- then the catch must be a directory
- return true
- else
- return self:callInterface('type', path) == 'directory'
- end
-end
-
-function mt:simpleMatch(path)
- for i = #self.matcher, 1, -1 do
- local matcher = self.matcher[i]
- local catch = matcher(path)
- if catch and self:checkDirectory(catch, path, matcher) then
- if matcher:isNegative() then
- return false
- else
- return true
- end
- end
- end
- return nil
-end
-
-function mt:finishMatch(path)
- local paths = {}
- for filename in path:gmatch '[^/\\]+' do
- paths[#paths+1] = filename
- end
- for i = 1, #paths do
- local newPath = table.concat(paths, '/', 1, i)
- local passed = self:simpleMatch(newPath)
- if passed == true then
- return true
- elseif passed == false then
- return false
- end
- end
- return false
-end
-
-function mt:scan(callback)
- local files = {}
- if type(callback) ~= 'function' then
- callback = nil
- end
- local list = {}
- local result = self:callInterface('list', '')
- if type(result) ~= 'table' then
- return files
- end
- for _, path in ipairs(result) do
- list[#list+1] = path:match '([^/\\]+)[/\\]*$'
- end
- while #list > 0 do
- local current = list[#list]
- if not current then
- break
- end
- list[#list] = nil
- if not self:simpleMatch(current) then
- local fileType = self:callInterface('type', current)
- if fileType == 'file' then
- if callback then
- callback(current)
- end
- files[#files+1] = current
- elseif fileType == 'directory' then
- local result = self:callInterface('list', current)
- if type(result) == 'table' then
- for _, path in ipairs(result) do
- local filename = path:match '([^/\\]+)[/\\]*$'
- if filename then
- list[#list+1] = current .. '/' .. filename
- end
- end
- end
- end
- end
- end
- return files
-end
-
-function mt:__call(path)
- if self.options.ignoreCase then
- path = path:lower()
- end
- return self:finishMatch(path)
-end
-
-return function (pattern, options, interface)
- local self = setmetatable({
- pattern = {},
- options = {},
- matcher = {},
- errors = {},
- interface = {},
- }, mt)
-
- if type(pattern) == 'table' then
- for _, pat in ipairs(pattern) do
- self:addPattern(pat)
- end
- else
- self:addPattern(pattern)
- end
-
- if type(options) == 'table' then
- for op, val in pairs(options) do
- self:setOption(op, val)
- end
- end
-
- if type(interface) == 'table' then
- for key, func in pairs(interface) do
- self:setInterface(key, func)
- end
- end
-
- return self
-end
diff --git a/server-beta/src/glob/glob.lua b/server-beta/src/glob/glob.lua
deleted file mode 100644
index aa8923f3..00000000
--- a/server-beta/src/glob/glob.lua
+++ /dev/null
@@ -1,122 +0,0 @@
-local m = require 'lpeglabel'
-local matcher = require 'glob.matcher'
-
-local function prop(name, pat)
- return m.Cg(m.Cc(true), name) * pat
-end
-
-local function object(type, pat)
- return m.Ct(
- m.Cg(m.Cc(type), 'type') *
- m.Cg(pat, 'value')
- )
-end
-
-local function expect(p, err)
- return p + m.T(err)
-end
-
-local parser = m.P {
- 'Main',
- ['Sp'] = m.S(' \t')^0,
- ['Slash'] = m.S('/\\')^1,
- ['Main'] = m.Ct(m.V'Sp' * m.P'{' * m.V'Pattern' * (',' * expect(m.V'Pattern', 'Miss exp after ","'))^0 * m.P'}')
- + m.Ct(m.V'Pattern')
- + m.T'Main Failed'
- ,
- ['Pattern'] = m.Ct(m.V'Sp' * prop('neg', m.P'!') * expect(m.V'Unit', 'Miss exp after "!"'))
- + m.Ct(m.V'Unit')
- ,
- ['NeedRoot'] = prop('root', (m.P'.' * m.V'Slash' + m.V'Slash')),
- ['Unit'] = m.V'Sp' * m.V'NeedRoot'^-1 * expect(m.V'Exp', 'Miss exp') * m.V'Sp',
- ['Exp'] = m.V'Sp' * (m.V'FSymbol' + object('/', m.V'Slash') + m.V'Word')^0 * m.V'Sp',
- ['Word'] = object('word', m.Ct((m.V'CSymbol' + m.V'Char' - m.V'FSymbol')^1)),
- ['CSymbol'] = object('*', m.P'*')
- + object('?', m.P'?')
- + object('[]', m.V'Range')
- ,
- ['Char'] = object('char', (1 - m.S',{}[]*?/\\')^1),
- ['FSymbol'] = object('**', m.P'**'),
- ['RangeWord'] = 1 - m.P']',
- ['Range'] = m.P'[' * m.Ct(m.V'RangeUnit'^0) * m.P']'^-1,
- ['RangeUnit'] = m.Ct(m.C(m.V'RangeWord') * m.P'-' * m.C(m.V'RangeWord'))
- + m.V'RangeWord',
-}
-
-local mt = {}
-mt.__index = mt
-mt.__name = 'glob'
-
-function mt:addPattern(pat)
- if type(pat) ~= 'string' then
- return
- end
- self.pattern[#self.pattern+1] = pat
- if self.options.ignoreCase then
- pat = pat:lower()
- end
- local states, err = parser:match(pat)
- if not states then
- self.errors[#self.errors+1] = {
- pattern = pat,
- message = err
- }
- return
- end
- for _, state in ipairs(states) do
- if state.neg then
- self.refused[#self.refused+1] = matcher(state)
- else
- self.passed[#self.passed+1] = matcher(state)
- end
- end
-end
-
-function mt:setOption(op, val)
- if val == nil then
- val = true
- end
- self.options[op] = val
-end
-
-function mt:__call(path)
- if self.options.ignoreCase then
- path = path:lower()
- end
- for _, refused in ipairs(self.refused) do
- if refused(path) then
- return false
- end
- end
- for _, passed in ipairs(self.passed) do
- if passed(path) then
- return true
- end
- end
- return false
-end
-
-return function (pattern, options)
- local self = setmetatable({
- pattern = {},
- options = {},
- passed = {},
- refused = {},
- errors = {},
- }, mt)
-
- if type(pattern) == 'table' then
- for _, pat in ipairs(pattern) do
- self:addPattern(pat)
- end
- else
- self:addPattern(pattern)
- end
-
- if type(options) == 'table' then
- for op, val in pairs(options) do
- self:setOption(op, val)
- end
- end
- return self
-end
diff --git a/server-beta/src/glob/init.lua b/server-beta/src/glob/init.lua
deleted file mode 100644
index 6578a0d4..00000000
--- a/server-beta/src/glob/init.lua
+++ /dev/null
@@ -1,4 +0,0 @@
-return {
- glob = require 'glob.glob',
- gitignore = require 'glob.gitignore',
-}
diff --git a/server-beta/src/glob/matcher.lua b/server-beta/src/glob/matcher.lua
deleted file mode 100644
index f4c2b12c..00000000
--- a/server-beta/src/glob/matcher.lua
+++ /dev/null
@@ -1,151 +0,0 @@
-local m = require 'lpeglabel'
-
-local Slash = m.S('/\\')^1
-local Symbol = m.S',{}[]*?/\\'
-local Char = 1 - Symbol
-local Path = Char^1 * Slash
-local NoWord = #(m.P(-1) + Symbol)
-local function whatHappened()
- return m.Cmt(m.P(1)^1, function (...)
- print(...)
- end)
-end
-
-local mt = {}
-mt.__index = mt
-mt.__name = 'matcher'
-
-function mt:exp(state, index)
- local exp = state[index]
- if not exp then
- return
- end
- if exp.type == 'word' then
- return self:word(exp, state, index + 1)
- elseif exp.type == 'char' then
- return self:char(exp, state, index + 1)
- elseif exp.type == '**' then
- return self:anyPath(exp, state, index + 1)
- elseif exp.type == '*' then
- return self:anyChar(exp, state, index + 1)
- elseif exp.type == '?' then
- return self:oneChar(exp, state, index + 1)
- elseif exp.type == '[]' then
- return self:range(exp, state, index + 1)
- elseif exp.type == '/' then
- return self:slash(exp, state, index + 1)
- end
-end
-
-function mt:word(exp, state, index)
- local current = self:exp(exp.value, 1)
- local after = self:exp(state, index)
- if after then
- return current * Slash * after
- else
- return current
- end
-end
-
-function mt:char(exp, state, index)
- local current = m.P(exp.value)
- local after = self:exp(state, index)
- if after then
- return current * after * NoWord
- else
- return current * NoWord
- end
-end
-
-function mt:anyPath(_, state, index)
- local after = self:exp(state, index)
- if after then
- return m.P {
- 'Main',
- Main = after
- + Path * m.V'Main'
- }
- else
- return Path^0
- end
-end
-
-function mt:anyChar(_, state, index)
- local after = self:exp(state, index)
- if after then
- return m.P {
- 'Main',
- Main = after
- + Char * m.V'Main'
- }
- else
- return Char^0
- end
-end
-
-function mt:oneChar(_, state, index)
- local after = self:exp(state, index)
- if after then
- return Char * after
- else
- return Char
- end
-end
-
-function mt:range(exp, state, index)
- local after = self:exp(state, index)
- local ranges = {}
- local selects = {}
- for _, range in ipairs(exp.value) do
- if #range == 1 then
- selects[#selects+1] = range[1]
- elseif #range == 2 then
- ranges[#ranges+1] = range[1] .. range[2]
- end
- end
- local current = m.S(table.concat(selects)) + m.R(table.unpack(ranges))
- if after then
- return current * after
- else
- return current
- end
-end
-
-function mt:slash(_, state, index)
- local after = self:exp(state, index)
- if after then
- return after
- else
- self.needDirectory = true
- return nil
- end
-end
-
-function mt:pattern(state)
- if state.root then
- return m.C(self:exp(state, 1))
- else
- return m.C(self:anyPath(nil, state, 1))
- end
-end
-
-function mt:isNeedDirectory()
- return self.needDirectory == true
-end
-
-function mt:isNegative()
- return self.state.neg == true
-end
-
-function mt:__call(path)
- return self.matcher:match(path)
-end
-
-return function (state, options)
- local self = setmetatable({
- options = options,
- state = state,
- }, mt)
- self.matcher = self:pattern(state)
- return self
-end
diff --git a/server-beta/src/json/decode.lua b/server-beta/src/json/decode.lua
deleted file mode 100644
index 36f8aa54..00000000
--- a/server-beta/src/json/decode.lua
+++ /dev/null
@@ -1,153 +0,0 @@
-local lpeg = require 'lpeglabel'
-local tablePack = table.pack
-local rawset = rawset
-local tointeger = math.tointeger
-local tonumber = tonumber
-local setmetatable = setmetatable
-local stringChar = string.char
-local error = error
-
-_ENV = nil
-
-local SaveSort
-local P = lpeg.P
-local S = lpeg.S
-local R = lpeg.R
-local V = lpeg.V
-local C = lpeg.C
-local Ct = lpeg.Ct
-local Cc = lpeg.Cc
-local Cp = lpeg.Cp
-local Cs = lpeg.Cs
-
-local EscMap = {
- ['t'] = '\t',
- ['r'] = '\r',
- ['n'] = '\n',
- ['"'] = '"',
- ['\\'] = '\\',
-}
-local BoolMap = {
- ['true'] = true,
- ['false'] = false,
-}
-
-local hashmt = {
- __pairs = function (self)
- local i = 1
- local function next()
- i = i + 1
- local k = self[i]
- if k == nil then
- return
- end
- local v = self[k]
- if v == nil then
- return next()
- end
- return k, v
- end
- return next
- end,
- __newindex = function (self, k, v)
- local i = 2
- while self[i] do
- i = i + 1
- end
- rawset(self, i, k)
- rawset(self, k, v)
- end,
-}
-
------------------------------------------------------------------------------
--- JSON4Lua: JSON encoding / decoding support for the Lua language.
--- json Module.
--- Author: Craig Mason-Jones
--- Homepage: http://github.com/craigmj/json4lua/
--- Version: 1.0.0
--- This module is released under the MIT License (MIT).
--- Please see LICENCE.txt for details.
---
-local function Utf8(str)
- local n = tonumber(str, 16)
- -- math.floor(x/2^y) == lazy right shift
- -- a % 2^b == bitwise_and(a, (2^b)-1)
- -- 64 = 2^6
- -- 4096 = 2^12 (or 2^6 * 2^6)
- local x
- if n < 0x80 then
- x = stringChar(n % 0x80)
- elseif n < 0x800 then
- -- [110x xxxx] [10xx xxxx]
- x = stringChar(0xC0 + ((n // 64) % 0x20), 0x80 + (n % 0x40))
- else
- -- [1110 xxxx] [10xx xxxx] [10xx xxxx]
- x = stringChar(0xE0 + ((n // 4096) % 0x10), 0x80 + ((n // 64) % 0x40), 0x80 + (n % 0x40))
- end
- return x
-end
-
-local function HashTable(patt)
- return C(patt) / function (_, ...)
- local hash = tablePack(...)
- local n = hash.n
- hash.n = nil
- if SaveSort then
- local max = n // 2
- for i = 1, max do
- local key, value = hash[2*i-1], hash[2*i]
- hash[key] = value
- hash[i+1] = key
- end
- hash[1] = nil
- for i = max+2, max*2 do
- hash[i] = nil
- end
- return setmetatable(hash, hashmt)
- else
- local max = n // 2
- for i = 1, max do
- local a = 2*i-1
- local b = 2*i
- local key, value = hash[a], hash[b]
- hash[key] = value
- hash[a] = nil
- hash[b] = nil
- end
- return hash
- end
- end
-end
-
-local Token = P
-{
- V'Value' * Cp(),
- Nl = P'\r\n' + S'\r\n',
- Sp = S' \t' + '//' * (1-V'Nl')^0,
- Spnl = (V'Sp' + V'Nl')^0,
- Bool = C(P'true' + P'false') / BoolMap,
- Int = C('0' + (P'-'^-1 * R'19' * R'09'^0)) / tointeger,
- Float = C(P'-'^-1 * ('0' + R'19' * R'09'^0) * '.' * R'09'^0) / tonumber,
- Null = P'null' * Cc(nil),
- String = '"' * Cs(V'Char'^0) * '"',
- Char = V'Esc' + V'Utf8' + (1 - P'"' - P'\t' - V'Nl'),
- Esc = P'\\' * C(S'tnr"\\') / EscMap,
- Utf8 = P'\\u' * C(P(4)) / Utf8,
- Hash = V'Spnl' * '{' * V'Spnl' * HashTable((V'Object' + P',' * V'Spnl')^0) * V'Spnl' * P'}' * V'Spnl',
- Array = V'Spnl' * '[' * V'Spnl' * Ct((V'Value' * V'Spnl' + P',' * V'Spnl')^0) * V'Spnl' * P']' * V'Spnl',
- Object = V'Spnl' * V'Key' * V'Spnl' * V'Value' * V'Spnl',
- Key = V'String' * V'Spnl' * ':',
- Value = V'Hash' + V'Array' + V'Bool' + V'Null' + V'String' + V'Float' + V'Int',
-}
-
-return function (str, save_sort_)
- SaveSort = save_sort_
- local table, res, pos = Token:match(str)
- if not table then
- if not pos or pos <= #str then
- pos = pos or 1
- error(('没匹配完[%s][%s]\n%s'):format(pos, res, str:sub(pos, pos+100)))
- end
- end
- return table
-end
diff --git a/server-beta/src/json/encode.lua b/server-beta/src/json/encode.lua
deleted file mode 100644
index 492c5a58..00000000
--- a/server-beta/src/json/encode.lua
+++ /dev/null
@@ -1,135 +0,0 @@
-local rep = string.rep
-local gsub = string.gsub
-local sort = table.sort
-local find = string.find
-local tostring = tostring
-local getmetatable = debug.getmetatable
-local type = type
-local next = next
-local pairs = pairs
-local tableConcat = table.concat
-
-_ENV = nil
-
-local index
-local lines
-local n = -1
-local tabs = {}
-
-local esc_map = {
- ['\\'] = '\\\\',
- ['\r'] = '\\r',
- ['\n'] = '\\n',
- ['\t'] = '\\t',
- ['"'] = '\\"',
-}
-
-local function encode(data, key)
- n = n + 1
- if not tabs[n] then
- tabs[n] = rep(' ', n)
- end
- local tp = type(data)
- if tp == 'table' then
- if not data[1] and next(data) then
- -- 认为这个是哈希表
- if key then
- index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": {\r\n'
- else
- index=index+1;lines[index] = tabs[n] .. '{\r\n'
- end
- local meta = getmetatable(data)
- local sep
- if meta and meta.__pairs then
- for k, v in meta.__pairs(data), data do
- if encode(v, k) then
- index=index+1;lines[index] = ',\r\n'
- sep = true
- end
- end
- else
- local list = {}
- local i = 0
- for k in next, data do
- i=i+1;list[i] = k
- end
- sort(list)
- for j = 1, i do
- local k = list[j]
- if encode(data[k], k) then
- index=index+1;lines[index] = ',\r\n'
- sep = true
- end
- end
- end
- if sep then
- lines[index] = '\r\n'
- end
- index=index+1;lines[index] = tabs[n] .. '}'
- else
- -- 认为这个是数组
- if key then
- index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": [\r\n'
- else
- index=index+1;lines[index] = tabs[n] .. '[\r\n'
- end
- local sep
- for k, v in pairs(data) do
- if encode(v) then
- index=index+1;lines[index] = ',\r\n'
- sep = true
- end
- end
- if sep then
- lines[index] = '\r\n'
- end
- index=index+1;lines[index] = tabs[n] .. ']'
- end
- elseif tp == 'number' then
- data = tostring(data)
- -- 判断 inf -inf -nan(ind) 1.#INF -1.#INF -1.#IND
- if find(data, '%a') then
- data = '0'
- end
- if key then
- index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": ' .. data
- else
- index=index+1;lines[index] = tabs[n] .. data
- end
- elseif tp == 'boolean' then
- if key then
- index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": ' .. tostring(data)
- else
- index=index+1;lines[index] = tabs[n] .. tostring(data)
- end
- elseif tp == 'nil' then
- if key then
- index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": null'
- else
- index=index+1;lines[index] = tabs[n] .. 'null'
- end
- elseif tp == 'string' then
- local str = gsub(data, '[\\\r\n\t"]', esc_map)
- if key then
- index=index+1;lines[index] = tabs[n] .. '"' .. gsub(key, '[\\\r\n\t"]', esc_map) .. '": "' .. str .. '"'
- else
- index=index+1;lines[index] = tabs[n] .. '"' .. str .. '"'
- end
- else
- n = n - 1
- return false
- end
- n = n - 1
- return true
-end
-
-local function json(t)
- lines = {}
- index = 0
-
- encode(t)
-
- return tableConcat(lines)
-end
-
-return json
diff --git a/server-beta/src/json/init.lua b/server-beta/src/json/init.lua
deleted file mode 100644
index c28e7aed..00000000
--- a/server-beta/src/json/init.lua
+++ /dev/null
@@ -1,6 +0,0 @@
-local api = {
- decode = require 'json.decode',
- encode = require 'json.encode',
-}
-
-return api
diff --git a/server-beta/src/jsonrpc.lua b/server-beta/src/jsonrpc.lua
deleted file mode 100644
index 5c73f54d..00000000
--- a/server-beta/src/jsonrpc.lua
+++ /dev/null
@@ -1,41 +0,0 @@
-local json = require 'json'
-local pcall = pcall
-
-_ENV = nil
-
----@class jsonrpc
-local m = {}
-m.type = 'jsonrpc'
-
-function m.encode(pack)
- pack.jsonrpc = '2.0'
- local content = json.encode(pack)
- local buf = ('Content-Length: %d\r\n\r\n%s'):format(#content, content)
- return buf
-end
-
-function m.decode(reader, errHandle)
- -- 读取协议头
- local line = reader 'l'
- -- 不支持修改文本编码
- if line:find('Content-Type', 1, true) then
- return nil
- end
- local len = line:match('Content%-Length%: (%d+)')
- if not len then
- errHandle('Error header: ' .. line)
- return nil
- end
- local content = reader(len + 2)
- if not content then
- return nil
- end
- local suc, res = pcall(json.decode, content)
- if not suc then
- errHandle('Proto parse error: ' .. res)
- return nil
- end
- return res
-end
-
-return m
diff --git a/server-beta/src/language.lua b/server-beta/src/language.lua
deleted file mode 100644
index d1a4b4cf..00000000
--- a/server-beta/src/language.lua
+++ /dev/null
@@ -1,137 +0,0 @@
-local fs = require 'bee.filesystem'
-local lni = require 'lni'
-local util = require 'utility'
-
-local function supportLanguage()
- local list = {}
- for path in (ROOT / 'locale'):list_directory() do
- if fs.is_directory(path) then
- list[#list+1] = path:filename():string():lower()
- end
- end
- return list
-end
-
-local function osLanguage()
- return LANG:lower()
-end
-
-local function getLanguage(id)
- local support = supportLanguage()
- -- 检查是否支持语言
- if support[id] then
- return id
- end
- -- 根据语言的前2个字母来找近似语言
- for _, lang in ipairs(support) do
- if lang:sub(1, 2) == id:sub(1, 2) then
- return lang
- end
- end
- -- 使用英文
- return 'enUS'
-end
-
-local function loadFileByLanguage(name, language)
- local path = ROOT / 'locale' / language / (name .. '.lni')
- local buf = util.loadFile(path:string())
- if not buf then
- return {}
- end
- local suc, tbl = xpcall(lni, log.error, buf, path:string())
- if not suc then
- return {}
- end
- return tbl
-end
-
-local function formatAsArray(str, ...)
- local index = 0
- local args = {...}
- return str:gsub('%{(.-)%}', function (pat)
- local id, fmt
- local pos = pat:find(':', 1, true)
- if pos then
- id = pat:sub(1, pos-1)
- fmt = pat:sub(pos+1)
- else
- id = pat
- fmt = 's'
- end
- id = tonumber(id)
- if not id then
- index = index + 1
- id = index
- end
- return ('%'..fmt):format(args[id])
- end)
-end
-
-local function formatAsTable(str, ...)
- local args = ...
- return str:gsub('%{(.-)%}', function (pat)
- local id, fmt
- local pos = pat:find(':', 1, true)
- if pos then
- id = pat:sub(1, pos-1)
- fmt = pat:sub(pos+1)
- else
- id = pat
- fmt = 's'
- end
- if not id then
- return
- end
- return ('%'..fmt):format(args[id])
- end)
-end
-
-local function loadLang(name, language)
- local tbl = loadFileByLanguage(name, 'en-US')
- if language ~= 'en-US' then
- local other = loadFileByLanguage(name, language)
- for k, v in pairs(other) do
- tbl[k] = v
- end
- end
- return setmetatable(tbl, {
- __index = function (self, key)
- self[key] = key
- return key
- end,
- __call = function (self, key, ...)
- local str = self[key]
- local suc, res
- if type(...) == 'table' then
- suc, res = pcall(formatAsTable, str, ...)
- else
- suc, res = pcall(formatAsArray, str, ...)
- end
- if suc then
- return res
- else
- -- 这里不能使用翻译,以免死循环
- log.warn(('[%s][%s-%s] formated error: %s'):format(
- language, name, key, str
- ))
- return str
- end
- end,
- })
-end
-
-local function init()
- local id = osLanguage()
- local language = getLanguage(id)
- log.info(('VSC language: %s'):format(id))
- log.info(('LS language: %s'):format(language))
- return setmetatable({ id = language }, {
- __index = function (self, name)
- local tbl = loadLang(name, language)
- self[name] = tbl
- return tbl
- end,
- })
-end
-
-return init()
diff --git a/server-beta/src/library.lua b/server-beta/src/library.lua
deleted file mode 100644
index d4dba7c9..00000000
--- a/server-beta/src/library.lua
+++ /dev/null
@@ -1,296 +0,0 @@
-local lni = require 'lni'
-local fs = require 'bee.filesystem'
-local config = require 'config'
-local util = require 'utility'
-
-local m = {}
-
-local function mergeEnum(lib, locale)
- if not lib or not locale then
- return
- end
- local pack = {}
- for _, enum in ipairs(lib) do
- if enum.enum then
- pack[enum.enum] = enum
- end
- if enum.code then
- pack[enum.code] = enum
- end
- end
- for _, enum in ipairs(locale) do
- if pack[enum.enum] then
- if enum.description then
- pack[enum.enum].description = enum.description
- end
- end
- if pack[enum.code] then
- if enum.description then
- pack[enum.code].description = enum.description
- end
- end
- end
-end
-
-local function mergeField(lib, locale)
- if not lib or not locale then
- return
- end
- local pack = {}
- for _, field in ipairs(lib) do
- if field.field then
- pack[field.field] = field
- end
- end
- for _, field in ipairs(locale) do
- if pack[field.field] then
- if field.description then
- pack[field.field].description = field.description
- end
- end
- end
-end
-
-local function mergeLocale(libs, locale)
- if not libs or not locale then
- return
- end
- for name in pairs(locale) do
- if libs[name] then
- if locale[name].description then
- libs[name].description = locale[name].description
- end
- mergeEnum(libs[name].enums, locale[name].enums)
- mergeField(libs[name].fields, locale[name].fields)
- end
- end
-end
-
-local function isMatchVersion(version)
- if not version then
- return true
- end
- local runtimeVersion = config.config.runtime.version
- if type(version) == 'table' then
- for i = 1, #version do
- if version[i] == runtimeVersion then
- return true
- end
- end
- else
- if version == runtimeVersion then
- return true
- end
- end
- return false
-end
-
-local function insertGlobal(tbl, key, value)
- if not isMatchVersion(value.version) then
- return false
- end
- if not value.doc then
- value.doc = key
- end
- tbl[key] = value
- return true
-end
-
-local function insertOther(tbl, key, value)
- if not value.version then
- return
- end
- if not tbl[key] then
- tbl[key] = {}
- end
- if type(value.version) == 'string' then
- tbl[key][#tbl[key]+1] = value.version
- elseif type(value.version) == 'table' then
- for _, version in ipairs(value.version) do
- if type(version) == 'string' then
- tbl[key][#tbl[key]+1] = version
- end
- end
- end
- table.sort(tbl[key])
-end
-
-local function insertCustom(tbl, key, value, libName)
- if not tbl[key] then
- tbl[key] = {}
- end
- tbl[key][#tbl[key]+1] = libName
- table.sort(tbl[key])
-end
-
-local function isEnableGlobal(libName)
- if config.config.runtime.library[libName] then
- return true
- end
- if libName:sub(1, 1) == '@' then
- return true
- end
- return false
-end
-
-local function mergeSource(alllibs, name, lib, libName)
- if not lib.source then
- if isEnableGlobal(libName) then
- local suc = insertGlobal(alllibs.global, name, lib)
- if not suc then
- insertOther(alllibs.other, name, lib)
- end
- else
- insertCustom(alllibs.custom, name, lib, libName)
- end
- return
- end
- for _, source in ipairs(lib.source) do
- local sourceName = source.name or name
- if source.type == 'global' then
- if isEnableGlobal(libName) then
- local suc = insertGlobal(alllibs.global, sourceName, lib)
- if not suc then
- insertOther(alllibs.other, sourceName, lib)
- end
- else
- insertCustom(alllibs.custom, sourceName, lib, libName)
- end
- elseif source.type == 'library' then
- insertGlobal(alllibs.library, sourceName, lib)
- elseif source.type == 'object' then
- insertGlobal(alllibs.object, sourceName, lib)
- end
- end
-end
-
-local function copy(t)
- local new = {}
- for k, v in pairs(t) do
- new[k] = v
- end
- return new
-end
-
-local function insertChild(tbl, name, key, value)
- if not name or not key then
- return
- end
- if not isMatchVersion(value.version) then
- return
- end
- if not value.doc then
- value.doc = ('%s.%s'):format(name, key)
- end
- if not tbl[name] then
- tbl[name] = {
- type = name,
- name = name,
- child = {},
- }
- end
- tbl[name].child[key] = copy(value)
-end
-
-local function mergeParent(alllibs, name, lib, libName)
- for _, parent in ipairs(lib.parent) do
- if parent.type == 'global' then
- if isEnableGlobal(libName) then
- insertChild(alllibs.global, parent.name, name, lib)
- end
- elseif parent.type == 'library' then
- insertChild(alllibs.library, parent.name, name, lib)
- elseif parent.type == 'object' then
- insertChild(alllibs.object, parent.name, name, lib)
- end
- end
-end
-
-local function mergeLibs(alllibs, libs, libName)
- if not libs then
- return
- end
- for _, lib in pairs(libs) do
- if lib.parent then
- mergeParent(alllibs, lib.name, lib, libName)
- else
- mergeSource(alllibs, lib.name, lib, libName)
- end
- end
-end
-
-local function loadLocale(language, relative)
- local localePath = ROOT / 'locale' / language / relative
- local localeBuf = util.loadFile(localePath:string())
- if localeBuf then
- local locale = util.container()
- xpcall(lni, log.error, localeBuf, localePath:string(), {locale})
- return locale
- end
- return nil
-end
-
-local function fix(libs)
- for name, lib in pairs(libs) do
- lib.name = lib.name or name
- lib.child = {}
- end
-end
-
-local function scan(path)
- local result = {path}
- local i = 0
- return function ()
- i = i + 1
- local current = result[i]
- if not current then
- return nil
- end
- if fs.is_directory(current) then
- for path in current:list_directory() do
- result[#result+1] = path
- end
- end
- return current
- end
-end
-
-local function init()
- local lang = require 'language'
- local id = lang.id
- m.global = util.container()
- m.library = util.container()
- m.object = util.container()
- m.other = util.container()
- m.custom = util.container()
-
- for libPath in (ROOT / 'libs'):list_directory() do
- local libName = libPath:filename():string()
- for path in scan(libPath) do
- local libs
- local buf = util.loadFile(path:string())
- if buf then
- libs = util.container()
- xpcall(lni, log.error, buf, path:string(), {libs})
- fix(libs)
- end
- local relative = fs.relative(path, ROOT)
-
- local locale = loadLocale('en-US', relative)
- mergeLocale(libs, locale)
- if id ~= 'en-US' then
- locale = loadLocale(id, relative)
- mergeLocale(libs, locale)
- end
- mergeLibs(m, libs, libName)
- end
- end
-end
-
-function m.reload()
- init()
-end
-
-init()
-
-return m
diff --git a/server-beta/src/log.lua b/server-beta/src/log.lua
deleted file mode 100644
index 1a66685a..00000000
--- a/server-beta/src/log.lua
+++ /dev/null
@@ -1,140 +0,0 @@
-local fs = require 'bee.filesystem'
-
-local osTime = os.time
-local osClock = os.clock
-local osDate = os.date
-local ioOpen = io.open
-local tablePack = table.pack
-local tableConcat = table.concat
-local tostring = tostring
-local debugTraceBack = debug.traceback
-local mathModf = math.modf
-local debugGetInfo = debug.getinfo
-local ioStdErr = io.stderr
-
-_ENV = nil
-
-local m = {}
-
-m.file = nil
-m.startTime = osTime() - osClock()
-m.size = 0
-m.maxSize = 100 * 1024 * 1024
-
-local function trimSrc(src)
- src = src:sub(m.prefixLen + 3, -5)
- src = src:gsub('^[/\\]+', '')
- src = src:gsub('[\\/]+', '.')
- return src
-end
-
-local function init_log_file()
- if not m.file then
- m.file = ioOpen(m.path, 'w')
- if not m.file then
- return
- end
- m.file:write('')
- m.file:close()
- m.file = ioOpen(m.path, 'ab')
- if not m.file then
- return
- end
- m.file:setvbuf 'no'
- end
-end
-
-local function pushLog(level, ...)
- if not m.path then
- return
- end
- if m.size > m.maxSize then
- return
- end
- local t = tablePack(...)
- for i = 1, t.n do
- t[i] = tostring(t[i])
- end
- local str = tableConcat(t, '\t', 1, t.n)
- if level == 'error' then
- str = str .. '\n' .. debugTraceBack(nil, 3)
- end
- local info = debugGetInfo(3, 'Sl')
- return m.raw(0, level, str, info.source, info.currentline)
-end
-
-function m.info(...)
- pushLog('info', ...)
-end
-
-function m.debug(...)
- pushLog('debug', ...)
-end
-
-function m.trace(...)
- pushLog('trace', ...)
-end
-
-function m.warn(...)
- pushLog('warn', ...)
-end
-
-function m.error(...)
- pushLog('error', ...)
-end
-
-function m.raw(thd, level, msg, source, currentline)
- if level == 'error' then
- ioStdErr:write(msg .. '\n')
- end
- init_log_file()
- if not m.file then
- return
- end
- local sec, ms = mathModf(m.startTime + osClock())
- local timestr = osDate('%H:%M:%S', sec)
- local agl = ''
- if #level < 5 then
- agl = (' '):rep(5 - #level)
- end
- local buf
- if currentline == -1 then
- buf = ('[%s.%03.f][%s]: %s[#%d]%s\n'):format(timestr, ms * 1000, level, agl, thd, msg)
- else
- buf = ('[%s.%03.f][%s]: %s[#%d:%s:%s]%s\n'):format(timestr, ms * 1000, level, agl, thd, trimSrc(source), currentline, msg)
- end
- m.file:write(buf)
- m.size = m.size + #buf
- if m.size > m.maxSize then
- m.file:write('[REACH MAX SIZE]')
- end
- return
-end
-
-function m.init(root, path)
- local lastBuf
- if m.file then
- m.file:close()
- m.file = nil
- local file = ioOpen(m.path, 'rb')
- if file then
- lastBuf = file:read 'a'
- file:close()
- end
- end
- m.path = path:string()
- m.prefixLen = #root:string()
- m.size = 0
- if not fs.exists(path:parent_path()) then
- fs.create_directories(path:parent_path())
- end
- if lastBuf then
- init_log_file()
- if m.file then
- m.file:write(lastBuf)
- m.size = m.size + #lastBuf
- end
- end
-end
-
-return m
diff --git a/server-beta/src/parser/ast.lua b/server-beta/src/parser/ast.lua
deleted file mode 100644
index dfd7656d..00000000
--- a/server-beta/src/parser/ast.lua
+++ /dev/null
@@ -1,1738 +0,0 @@
-local emmy = require 'parser.emmy'
-
-local tonumber = tonumber
-local stringChar = string.char
-local utf8Char = utf8.char
-local tableUnpack = table.unpack
-local mathType = math.type
-local tableRemove = table.remove
-local pairs = pairs
-local tableSort = table.sort
-
-_ENV = nil
-
-local State
-local PushError
-local PushDiag
-
--- goto 单独处理
-local RESERVED = {
- ['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 VersionOp = {
- ['&'] = {'Lua 5.3', 'Lua 5.4'},
- ['~'] = {'Lua 5.3', 'Lua 5.4'},
- ['|'] = {'Lua 5.3', 'Lua 5.4'},
- ['<<'] = {'Lua 5.3', 'Lua 5.4'},
- ['>>'] = {'Lua 5.3', 'Lua 5.4'},
- ['//'] = {'Lua 5.3', 'Lua 5.4'},
-}
-
-local function checkOpVersion(op)
- local versions = VersionOp[op.type]
- if not versions then
- return
- end
- for i = 1, #versions do
- if versions[i] == State.version then
- return
- end
- end
- PushError {
- type = 'UNSUPPORT_SYMBOL',
- start = op.start,
- finish = op.finish,
- version = versions,
- info = {
- version = State.version,
- }
- }
-end
-
-local function checkMissEnd(start)
- if not State.MissEndErr then
- return
- end
- local err = State.MissEndErr
- State.MissEndErr = nil
- local _, finish = State.lua:find('[%w_]+', start)
- if not finish then
- return
- end
- err.info.related = {
- {
- start = start,
- finish = finish,
- }
- }
- PushError {
- type = 'MISS_END',
- start = start,
- finish = finish,
- }
-end
-
-local function getSelect(vararg, index)
- return {
- type = 'select',
- start = vararg.start,
- finish = vararg.finish,
- vararg = vararg,
- index = index,
- }
-end
-
-local function getValue(values, i)
- if not values then
- return nil, nil
- end
- local value = values[i]
- if not value then
- local last = values[#values]
- if not last then
- return nil, nil
- end
- if last.type == 'call' or last.type == 'varargs' then
- return getSelect(last, i - #values + 1)
- end
- return nil, nil
- end
- if value.type == 'call' or value.type == 'varargs' then
- value = getSelect(value, 1)
- end
- return value
-end
-
-local function createLocal(key, effect, value, attrs)
- if not key then
- return nil
- end
- key.type = 'local'
- key.effect = effect
- key.value = value
- key.attrs = attrs
- if value then
- key.range = value.finish
- end
- return key
-end
-
-local function createCall(args, start, finish)
- if args then
- args.type = 'callargs'
- args.start = start
- args.finish = finish
- end
- return {
- type = 'call',
- start = start,
- finish = finish,
- args = args,
- }
-end
-
-local function packList(start, list, finish)
- local lastFinish = start
- local wantName = true
- local count = 0
- for i = 1, #list do
- local ast = list[i]
- if ast.type == ',' then
- if wantName or i == #list then
- PushError {
- type = 'UNEXPECT_SYMBOL',
- start = ast.start,
- finish = ast.finish,
- info = {
- symbol = ',',
- }
- }
- end
- wantName = true
- else
- if not wantName then
- PushError {
- type = 'MISS_SYMBOL',
- start = lastFinish,
- finish = ast.start - 1,
- info = {
- symbol = ',',
- }
- }
- end
- wantName = false
- count = count + 1
- list[count] = list[i]
- end
- lastFinish = ast.finish + 1
- end
- for i = count + 1, #list do
- list[i] = nil
- end
- list.type = 'list'
- list.start = start
- list.finish = finish - 1
- return list
-end
-
-local BinaryLevel = {
- ['or'] = 1,
- ['and'] = 2,
- ['<='] = 3,
- ['>='] = 3,
- ['<'] = 3,
- ['>'] = 3,
- ['~='] = 3,
- ['=='] = 3,
- ['|'] = 4,
- ['~'] = 5,
- ['&'] = 6,
- ['<<'] = 7,
- ['>>'] = 7,
- ['..'] = 8,
- ['+'] = 9,
- ['-'] = 9,
- ['*'] = 10,
- ['//'] = 10,
- ['/'] = 10,
- ['%'] = 10,
- ['^'] = 11,
-}
-
-local BinaryForward = {
- [01] = true,
- [02] = true,
- [03] = true,
- [04] = true,
- [05] = true,
- [06] = true,
- [07] = true,
- [08] = false,
- [09] = true,
- [10] = true,
- [11] = false,
-}
-
-local Defs = {
- Nil = function (pos)
- return {
- type = 'nil',
- start = pos,
- finish = pos + 2,
- }
- end,
- True = function (pos)
- return {
- type = 'boolean',
- start = pos,
- finish = pos + 3,
- [1] = true,
- }
- end,
- False = function (pos)
- return {
- type = 'boolean',
- start = pos,
- finish = pos + 4,
- [1] = false,
- }
- end,
- LongComment = function (beforeEq, afterEq, str, missPos)
- if missPos then
- local endSymbol = ']' .. ('='):rep(afterEq-beforeEq) .. ']'
- local s, _, w = str:find('(%][%=]*%])[%c%s]*$')
- if s then
- PushError {
- type = 'ERR_LCOMMENT_END',
- start = missPos - #str + s - 1,
- finish = missPos - #str + s + #w - 2,
- info = {
- symbol = endSymbol,
- },
- fix = {
- title = 'FIX_LCOMMENT_END',
- {
- start = missPos - #str + s - 1,
- finish = missPos - #str + s + #w - 2,
- text = endSymbol,
- }
- },
- }
- end
- PushError {
- type = 'MISS_SYMBOL',
- start = missPos,
- finish = missPos,
- info = {
- symbol = endSymbol,
- },
- fix = {
- title = 'ADD_LCOMMENT_END',
- {
- start = missPos,
- finish = missPos,
- text = endSymbol,
- }
- },
- }
- end
- end,
- CLongComment = function (start1, finish1, start2, finish2)
- PushError {
- type = 'ERR_C_LONG_COMMENT',
- start = start1,
- finish = finish2 - 1,
- fix = {
- title = 'FIX_C_LONG_COMMENT',
- {
- start = start1,
- finish = finish1 - 1,
- text = '--[[',
- },
- {
- start = start2,
- finish = finish2 - 1,
- text = '--]]'
- },
- }
- }
- end,
- CCommentPrefix = function (start, finish)
- PushError {
- type = 'ERR_COMMENT_PREFIX',
- start = start,
- finish = finish - 1,
- fix = {
- title = 'FIX_COMMENT_PREFIX',
- {
- start = start,
- finish = finish - 1,
- text = '--',
- },
- }
- }
- end,
- String = function (start, quote, str, finish)
- return {
- type = 'string',
- start = start,
- finish = finish - 1,
- [1] = str,
- [2] = quote,
- }
- end,
- LongString = function (beforeEq, afterEq, str, missPos)
- if missPos then
- local endSymbol = ']' .. ('='):rep(afterEq-beforeEq) .. ']'
- local s, _, w = str:find('(%][%=]*%])[%c%s]*$')
- if s then
- PushError {
- type = 'ERR_LSTRING_END',
- start = missPos - #str + s - 1,
- finish = missPos - #str + s + #w - 2,
- info = {
- symbol = endSymbol,
- },
- fix = {
- title = 'FIX_LSTRING_END',
- {
- start = missPos - #str + s - 1,
- finish = missPos - #str + s + #w - 2,
- text = endSymbol,
- }
- },
- }
- end
- PushError {
- type = 'MISS_SYMBOL',
- start = missPos,
- finish = missPos,
- info = {
- symbol = endSymbol,
- },
- fix = {
- title = 'ADD_LSTRING_END',
- {
- start = missPos,
- finish = missPos,
- text = endSymbol,
- }
- },
- }
- end
- return '[' .. ('='):rep(afterEq-beforeEq) .. '[', str
- end,
- Char10 = function (char)
- char = tonumber(char)
- if not char or char < 0 or char > 255 then
- return ''
- end
- return stringChar(char)
- end,
- Char16 = function (pos, char)
- if State.version == 'Lua 5.1' then
- PushError {
- type = 'ERR_ESC',
- start = pos-1,
- finish = pos,
- version = {'Lua 5.2', 'Lua 5.3', 'Lua 5.4', 'LuaJIT'},
- info = {
- version = State.version,
- }
- }
- return char
- end
- return stringChar(tonumber(char, 16))
- end,
- CharUtf8 = function (pos, char)
- if State.version ~= 'Lua 5.3'
- and State.version ~= 'Lua 5.4'
- and State.version ~= 'LuaJIT'
- then
- PushError {
- type = 'ERR_ESC',
- start = pos-3,
- finish = pos-2,
- version = {'Lua 5.3', 'Lua 5.4', 'LuaJIT'},
- info = {
- version = State.version,
- }
- }
- return char
- end
- if #char == 0 then
- PushError {
- type = 'UTF8_SMALL',
- start = pos-3,
- finish = pos,
- }
- return ''
- end
- local v = tonumber(char, 16)
- if not v then
- for i = 1, #char do
- if not tonumber(char:sub(i, i), 16) then
- PushError {
- type = 'MUST_X16',
- start = pos + i - 1,
- finish = pos + i - 1,
- }
- end
- end
- return ''
- end
- if State.version == 'Lua 5.4' then
- if v < 0 or v > 0x7FFFFFFF then
- PushError {
- type = 'UTF8_MAX',
- start = pos-3,
- finish = pos+#char,
- info = {
- min = '00000000',
- max = '7FFFFFFF',
- }
- }
- end
- else
- if v < 0 or v > 0x10FFFF then
- PushError {
- type = 'UTF8_MAX',
- start = pos-3,
- finish = pos+#char,
- version = v <= 0x7FFFFFFF and 'Lua 5.4' or nil,
- info = {
- min = '000000',
- max = '10FFFF',
- }
- }
- end
- end
- if v >= 0 and v <= 0x10FFFF then
- return utf8Char(v)
- end
- return ''
- end,
- Number = function (start, number, finish)
- local n = tonumber(number)
- if n then
- State.LastNumber = {
- type = 'number',
- start = start,
- finish = finish - 1,
- [1] = n,
- }
- return State.LastNumber
- else
- PushError {
- type = 'MALFORMED_NUMBER',
- start = start,
- finish = finish - 1,
- }
- State.LastNumber = {
- type = 'number',
- start = start,
- finish = finish - 1,
- [1] = 0,
- }
- return State.LastNumber
- end
- end,
- FFINumber = function (start, symbol)
- local lastNumber = State.LastNumber
- if mathType(lastNumber[1]) == 'float' then
- PushError {
- type = 'UNKNOWN_SYMBOL',
- start = start,
- finish = start + #symbol - 1,
- info = {
- symbol = symbol,
- }
- }
- lastNumber[1] = 0
- return
- end
- if State.version ~= 'LuaJIT' then
- PushError {
- type = 'UNSUPPORT_SYMBOL',
- start = start,
- finish = start + #symbol - 1,
- version = 'LuaJIT',
- info = {
- version = State.version,
- }
- }
- lastNumber[1] = 0
- end
- end,
- ImaginaryNumber = function (start, symbol)
- local lastNumber = State.LastNumber
- if State.version ~= 'LuaJIT' then
- PushError {
- type = 'UNSUPPORT_SYMBOL',
- start = start,
- finish = start + #symbol - 1,
- version = 'LuaJIT',
- info = {
- version = State.version,
- }
- }
- end
- lastNumber[1] = 0
- end,
- Name = function (start, str, finish)
- local isKeyWord
- if RESERVED[str] then
- isKeyWord = true
- elseif str == 'goto' then
- if State.version ~= 'Lua 5.1' and State.version ~= 'LuaJIT' then
- isKeyWord = true
- end
- end
- if isKeyWord then
- PushError {
- type = 'KEYWORD',
- start = start,
- finish = finish - 1,
- }
- end
- return {
- type = 'name',
- start = start,
- finish = finish - 1,
- [1] = str,
- }
- end,
- GetField = function (dot, field)
- local obj = {
- type = 'getfield',
- field = field,
- dot = dot,
- start = dot.start,
- finish = (field or dot).finish,
- }
- if field then
- field.type = 'field'
- field.parent = obj
- end
- return obj
- end,
- GetIndex = function (start, index, finish)
- local obj = {
- type = 'getindex',
- start = start,
- finish = finish - 1,
- index = index,
- }
- if index then
- index.parent = obj
- end
- return obj
- end,
- GetMethod = function (colon, method)
- local obj = {
- type = 'getmethod',
- method = method,
- colon = colon,
- start = colon.start,
- finish = (method or colon).finish,
- }
- if method then
- method.type = 'method'
- method.parent = obj
- end
- return obj
- end,
- Single = function (unit)
- unit.type = 'getname'
- return unit
- end,
- Simple = function (units)
- local last = units[1]
- for i = 2, #units do
- local current = units[i]
- current.node = last
- current.start = last.start
- last.next = current
- last = units[i]
- end
- return last
- end,
- SimpleCall = function (call)
- if call.type ~= 'call' and call.type ~= 'getmethod' then
- PushError {
- type = 'EXP_IN_ACTION',
- start = call.start,
- finish = call.finish,
- }
- end
- return call
- end,
- BinaryOp = function (start, op)
- return {
- type = op,
- start = start,
- finish = start + #op - 1,
- }
- end,
- UnaryOp = function (start, op)
- return {
- type = op,
- start = start,
- finish = start + #op - 1,
- }
- end,
- Unary = function (first, ...)
- if not ... then
- return nil
- end
- local list = {first, ...}
- local e = list[#list]
- for i = #list - 1, 1, -1 do
- local op = list[i]
- checkOpVersion(op)
- e = {
- type = 'unary',
- op = op,
- start = op.start,
- finish = e.finish,
- [1] = e,
- }
- end
- return e
- end,
- SubBinary = function (op, symb)
- if symb then
- return op, symb
- end
- PushError {
- type = 'MISS_EXP',
- start = op.start,
- finish = op.finish,
- }
- end,
- Binary = function (first, op, second, ...)
- if not first then
- return second
- end
- if not op then
- return first
- end
- if not ... then
- checkOpVersion(op)
- return {
- type = 'binary',
- op = op,
- start = first.start,
- finish = second.finish,
- [1] = first,
- [2] = second,
- }
- end
- local list = {first, op, second, ...}
- local ops = {}
- for i = 2, #list, 2 do
- ops[#ops+1] = i
- end
- tableSort(ops, function (a, b)
- local op1 = list[a]
- local op2 = list[b]
- local lv1 = BinaryLevel[op1.type]
- local lv2 = BinaryLevel[op2.type]
- if lv1 == lv2 then
- local forward = BinaryForward[lv1]
- if forward then
- return op1.start > op2.start
- else
- return op1.start < op2.start
- end
- else
- return lv1 < lv2
- end
- end)
- local final
- for i = #ops, 1, -1 do
- local n = ops[i]
- local op = list[n]
- local left = list[n-1]
- local right = list[n+1]
- local exp = {
- type = 'binary',
- op = op,
- start = left.start,
- finish = right and right.finish or op.finish,
- [1] = left,
- [2] = right,
- }
- local leftIndex, rightIndex
- if list[left] then
- leftIndex = list[left[1]]
- else
- leftIndex = n - 1
- end
- if list[right] then
- rightIndex = list[right[2]]
- else
- rightIndex = n + 1
- end
-
- list[leftIndex] = exp
- list[rightIndex] = exp
- list[left] = leftIndex
- list[right] = rightIndex
- list[exp] = n
- final = exp
-
- checkOpVersion(op)
- end
- return final
- end,
- Paren = function (start, exp, finish)
- if exp and exp.type == 'paren' then
- exp.start = start
- exp.finish = finish - 1
- return exp
- end
- return {
- type = 'paren',
- start = start,
- finish = finish - 1,
- exp = exp
- }
- end,
- VarArgs = function (dots)
- dots.type = 'varargs'
- return dots
- end,
- PackLoopArgs = function (start, list, finish)
- local list = packList(start, list, finish)
- if #list == 0 then
- PushError {
- type = 'MISS_LOOP_MIN',
- start = finish,
- finish = finish,
- }
- elseif #list == 1 then
- PushError {
- type = 'MISS_LOOP_MAX',
- start = finish,
- finish = finish,
- }
- end
- return list
- end,
- PackInNameList = function (start, list, finish)
- local list = packList(start, list, finish)
- if #list == 0 then
- PushError {
- type = 'MISS_NAME',
- start = start,
- finish = finish,
- }
- end
- return list
- end,
- PackInExpList = function (start, list, finish)
- local list = packList(start, list, finish)
- if #list == 0 then
- PushError {
- type = 'MISS_EXP',
- start = start,
- finish = finish,
- }
- end
- return list
- end,
- PackExpList = function (start, list, finish)
- local list = packList(start, list, finish)
- return list
- end,
- PackNameList = function (start, list, finish)
- local list = packList(start, list, finish)
- return list
- end,
- Call = function (start, args, finish)
- return createCall(args, start, finish-1)
- end,
- COMMA = function (start)
- return {
- type = ',',
- start = start,
- finish = start,
- }
- end,
- SEMICOLON = function (start)
- return {
- type = ';',
- start = start,
- finish = start,
- }
- end,
- DOTS = function (start)
- return {
- type = '...',
- start = start,
- finish = start + 2,
- }
- end,
- COLON = function (start)
- return {
- type = ':',
- start = start,
- finish = start,
- }
- end,
- DOT = function (start)
- return {
- type = '.',
- start = start,
- finish = start,
- }
- end,
- Function = function (functionStart, functionFinish, args, actions, endStart, endFinish)
- actions.type = 'function'
- actions.start = functionStart
- actions.finish = endFinish - 1
- actions.args = args
- actions.keyword= {
- functionStart, functionFinish - 1,
- endStart, endFinish - 1,
- }
- checkMissEnd(functionStart)
- return actions
- end,
- NamedFunction = function (functionStart, functionFinish, name, args, actions, endStart, endFinish)
- actions.type = 'function'
- actions.start = functionStart
- actions.finish = endFinish - 1
- actions.args = args
- actions.keyword= {
- functionStart, functionFinish - 1,
- endStart, endFinish - 1,
- }
- checkMissEnd(functionStart)
- if not name then
- return
- end
- if name.type == 'getname' then
- name.type = 'setname'
- name.value = actions
- elseif name.type == 'getfield' then
- name.type = 'setfield'
- name.value = actions
- elseif name.type == 'getmethod' then
- name.type = 'setmethod'
- name.value = actions
- end
- name.range = actions.finish
- name.vstart = functionStart
- return name
- end,
- LocalFunction = function (start, functionStart, functionFinish, name, args, actions, endStart, endFinish)
- actions.type = 'function'
- actions.start = start
- actions.finish = endFinish - 1
- actions.args = args
- actions.keyword= {
- functionStart, functionFinish - 1,
- endStart, endFinish - 1,
- }
- checkMissEnd(start)
-
- if not name then
- return
- end
-
- if name.type ~= 'getname' then
- PushError {
- type = 'UNEXPECT_LFUNC_NAME',
- start = name.start,
- finish = name.finish,
- }
- return
- end
-
- local loc = createLocal(name, name.start, actions)
- loc.localfunction = true
- loc.vstart = functionStart
-
- return loc
- end,
- Table = function (start, tbl, finish)
- tbl.type = 'table'
- tbl.start = start
- tbl.finish = finish - 1
- local wantField = true
- local lastStart = start + 1
- local fieldCount = 0
- for i = 1, #tbl do
- local field = tbl[i]
- if field.type == ',' or field.type == ';' then
- if wantField then
- PushError {
- type = 'MISS_EXP',
- start = lastStart,
- finish = field.start - 1,
- }
- end
- wantField = true
- lastStart = field.finish + 1
- else
- if not wantField then
- PushError {
- type = 'MISS_SEP_IN_TABLE',
- start = lastStart,
- finish = field.start - 1,
- }
- end
- wantField = false
- lastStart = field.finish + 1
- fieldCount = fieldCount + 1
- tbl[fieldCount] = field
- end
- end
- for i = fieldCount + 1, #tbl do
- tbl[i] = nil
- end
- return tbl
- end,
- NewField = function (start, field, value, finish)
- local obj = {
- type = 'tablefield',
- start = start,
- finish = finish-1,
- field = field,
- value = value,
- }
- if field then
- field.type = 'field'
- field.parent = obj
- end
- return obj
- end,
- NewIndex = function (start, index, value, finish)
- local obj = {
- type = 'tableindex',
- start = start,
- finish = finish-1,
- index = index,
- value = value,
- }
- if index then
- index.parent = obj
- end
- return obj
- end,
- FuncArgs = function (start, args, finish)
- args.type = 'funcargs'
- args.start = start
- args.finish = finish - 1
- local lastStart = start + 1
- local wantName = true
- local argCount = 0
- for i = 1, #args do
- local arg = args[i]
- local argAst = arg
- if argAst.type == ',' then
- if wantName then
- PushError {
- type = 'MISS_NAME',
- start = lastStart,
- finish = argAst.start-1,
- }
- end
- wantName = true
- else
- if not wantName then
- PushError {
- type = 'MISS_SYMBOL',
- start = lastStart-1,
- finish = argAst.start-1,
- info = {
- symbol = ',',
- }
- }
- end
- wantName = false
- argCount = argCount + 1
-
- if argAst.type == '...' then
- args[argCount] = arg
- if i < #args then
- local a = args[i+1]
- local b = args[#args]
- PushError {
- type = 'ARGS_AFTER_DOTS',
- start = a.start,
- finish = b.finish,
- }
- end
- break
- else
- args[argCount] = createLocal(arg, arg.start)
- end
- end
- lastStart = argAst.finish + 1
- end
- for i = argCount + 1, #args do
- args[i] = nil
- end
- if wantName and argCount > 0 then
- PushError {
- type = 'MISS_NAME',
- start = lastStart,
- finish = finish - 1,
- }
- end
- return args
- end,
- Set = function (start, keys, values, finish)
- for i = 1, #keys do
- local key = keys[i]
- if key.type == 'getname' then
- key.type = 'setname'
- key.value = getValue(values, i)
- elseif key.type == 'getfield' then
- key.type = 'setfield'
- key.value = getValue(values, i)
- elseif key.type == 'getindex' then
- key.type = 'setindex'
- key.value = getValue(values, i)
- end
- if key.value then
- key.range = key.value.finish
- end
- end
- if values then
- for i = #keys+1, #values do
- local value = values[i]
- PushDiag('redundant-value', {
- start = value.start,
- finish = value.finish,
- max = #keys,
- passed = #values,
- })
- end
- end
- return tableUnpack(keys)
- end,
- LocalAttr = function (attrs)
- for i = 1, #attrs do
- local attr = attrs[i]
- local attrAst = attr
- attrAst.type = 'localattr'
- if State.version ~= 'Lua 5.4' then
- PushError {
- type = 'UNSUPPORT_SYMBOL',
- start = attrAst.start,
- finish = attrAst.finish,
- version = 'Lua 5.4',
- info = {
- version = State.version,
- }
- }
- elseif attrAst[1] ~= 'const' and attrAst[1] ~= 'close' then
- PushError {
- type = 'UNKNOWN_TAG',
- start = attrAst.start,
- finish = attrAst.finish,
- info = {
- tag = attrAst[1],
- }
- }
- elseif i > 1 then
- PushError {
- type = 'MULTI_TAG',
- start = attrAst.start,
- finish = attrAst.finish,
- info = {
- tag = attrAst[1],
- }
- }
- end
- end
- return attrs
- end,
- LocalName = function (name, attrs)
- if not name then
- return name
- end
- name.attrs = attrs
- return name
- end,
- Local = function (start, keys, values, finish)
- for i = 1, #keys do
- local key = keys[i]
- local attrs = key.attrs
- key.attrs = nil
- local value = getValue(values, i)
- createLocal(key, finish, value, attrs)
- end
- if values then
- for i = #keys+1, #values do
- local value = values[i]
- PushDiag('redundant-value', {
- start = value.start,
- finish = value.finish,
- max = #keys,
- passed = #values,
- })
- end
- end
- return tableUnpack(keys)
- end,
- Do = function (start, actions, endA, endB)
- actions.type = 'do'
- actions.start = start
- actions.finish = endB - 1
- actions.keyword= {
- start, start + #'do' - 1,
- endA , endB - 1,
- }
- checkMissEnd(start)
- return actions
- end,
- Break = function (start, finish)
- return {
- type = 'break',
- start = start,
- finish = finish - 1,
- }
- end,
- Return = function (start, exps, finish)
- exps.type = 'return'
- exps.start = start
- exps.finish = finish - 1
- return exps
- end,
- Label = function (start, name, finish)
- if State.version == 'Lua 5.1' then
- PushError {
- type = 'UNSUPPORT_SYMBOL',
- start = start,
- finish = finish - 1,
- version = {'Lua 5.2', 'Lua 5.3', 'Lua 5.4', 'LuaJIT'},
- info = {
- version = State.version,
- }
- }
- return
- end
- if not name then
- return nil
- end
- name.type = 'label'
- return name
- end,
- GoTo = function (start, name, finish)
- if State.version == 'Lua 5.1' then
- PushError {
- type = 'UNSUPPORT_SYMBOL',
- start = start,
- finish = finish - 1,
- version = {'Lua 5.2', 'Lua 5.3', 'Lua 5.4', 'LuaJIT'},
- info = {
- version = State.version,
- }
- }
- return
- end
- if not name then
- return nil
- end
- name.type = 'goto'
- return name
- end,
- IfBlock = function (ifStart, ifFinish, exp, thenStart, thenFinish, actions, finish)
- actions.type = 'ifblock'
- actions.start = ifStart
- actions.finish = finish - 1
- actions.filter = exp
- actions.keyword= {
- ifStart, ifFinish - 1,
- thenStart, thenFinish - 1,
- }
- return actions
- end,
- ElseIfBlock = function (elseifStart, elseifFinish, exp, thenStart, thenFinish, actions, finish)
- actions.type = 'elseifblock'
- actions.start = elseifStart
- actions.finish = finish - 1
- actions.filter = exp
- actions.keyword= {
- elseifStart, elseifFinish - 1,
- thenStart, thenFinish - 1,
- }
- return actions
- end,
- ElseBlock = function (elseStart, elseFinish, actions, finish)
- actions.type = 'elseblock'
- actions.start = elseStart
- actions.finish = finish - 1
- actions.keyword= {
- elseStart, elseFinish - 1,
- }
- return actions
- end,
- If = function (start, blocks, endStart, endFinish)
- blocks.type = 'if'
- blocks.start = start
- blocks.finish = endFinish - 1
- local hasElse
- for i = 1, #blocks do
- local block = blocks[i]
- if i == 1 and block.type ~= 'ifblock' then
- PushError {
- type = 'MISS_SYMBOL',
- start = block.start,
- finish = block.start,
- info = {
- symbol = 'if',
- }
- }
- end
- if hasElse then
- PushError {
- type = 'BLOCK_AFTER_ELSE',
- start = block.start,
- finish = block.finish,
- }
- end
- if block.type == 'elseblock' then
- hasElse = true
- end
- end
- checkMissEnd(start)
- return blocks
- end,
- Loop = function (forA, forB, arg, steps, doA, doB, blockStart, block, endA, endB)
- local loc = createLocal(arg, blockStart, steps[1])
- block.type = 'loop'
- block.start = forA
- block.finish = endB - 1
- block.loc = loc
- block.max = steps[2]
- block.step = steps[3]
- block.keyword= {
- forA, forB - 1,
- doA , doB - 1,
- endA, endB - 1,
- }
- checkMissEnd(forA)
- return block
- end,
- In = function (forA, forB, keys, inA, inB, exp, doA, doB, blockStart, block, endA, endB)
- local func = tableRemove(exp, 1)
- block.type = 'in'
- block.start = forA
- block.finish = endB - 1
- block.keys = keys
- block.keyword= {
- forA, forB - 1,
- inA , inB - 1,
- doA , doB - 1,
- endA, endB - 1,
- }
-
- local values
- if func then
- local call = createCall(exp, func.finish + 1, exp.finish)
- call.node = func
- call.start = func.start
- func.next = call
- values = { call }
- keys.range = call.finish
- end
- for i = 1, #keys do
- local loc = keys[i]
- if values then
- createLocal(loc, blockStart, getValue(values, i))
- else
- createLocal(loc, blockStart)
- end
- end
- checkMissEnd(forA)
- return block
- end,
- While = function (whileA, whileB, filter, doA, doB, block, endA, endB)
- block.type = 'while'
- block.start = whileA
- block.finish = endB - 1
- block.filter = filter
- block.keyword= {
- whileA, whileB - 1,
- doA , doB - 1,
- endA , endB - 1,
- }
- checkMissEnd(whileA)
- return block
- end,
- Repeat = function (repeatA, repeatB, block, untilA, untilB, filter, finish)
- block.type = 'repeat'
- block.start = repeatA
- block.finish = finish
- block.filter = filter
- block.keyword= {
- repeatA, repeatB - 1,
- untilA , untilB - 1,
- }
- return block
- end,
- Lua = function (start, actions, finish)
- actions.type = 'main'
- actions.start = start
- actions.finish = finish - 1
- return actions
- end,
-
- -- 捕获错误
- UnknownSymbol = function (start, symbol)
- PushError {
- type = 'UNKNOWN_SYMBOL',
- start = start,
- finish = start + #symbol - 1,
- info = {
- symbol = symbol,
- }
- }
- return
- end,
- UnknownAction = function (start, symbol)
- PushError {
- type = 'UNKNOWN_SYMBOL',
- start = start,
- finish = start + #symbol - 1,
- info = {
- symbol = symbol,
- }
- }
- end,
- DirtyName = function (pos)
- PushError {
- type = 'MISS_NAME',
- start = pos,
- finish = pos,
- }
- return nil
- end,
- DirtyExp = function (pos)
- PushError {
- type = 'MISS_EXP',
- start = pos,
- finish = pos,
- }
- return nil
- end,
- MissExp = function (pos)
- PushError {
- type = 'MISS_EXP',
- start = pos,
- finish = pos,
- }
- end,
- MissExponent = function (start, finish)
- PushError {
- type = 'MISS_EXPONENT',
- start = start,
- finish = finish - 1,
- }
- end,
- MissQuote1 = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = '"'
- }
- }
- end,
- MissQuote2 = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = "'"
- }
- }
- end,
- MissEscX = function (pos)
- PushError {
- type = 'MISS_ESC_X',
- start = pos-2,
- finish = pos+1,
- }
- end,
- MissTL = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = '{',
- }
- }
- end,
- MissTR = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = '}',
- }
- }
- end,
- MissBR = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = ']',
- }
- }
- end,
- MissPL = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = '(',
- }
- }
- end,
- MissPR = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = ')',
- }
- }
- end,
- ErrEsc = function (pos)
- PushError {
- type = 'ERR_ESC',
- start = pos-1,
- finish = pos,
- }
- end,
- MustX16 = function (pos, str)
- PushError {
- type = 'MUST_X16',
- start = pos,
- finish = pos + #str - 1,
- }
- end,
- MissAssign = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = '=',
- }
- }
- end,
- MissTableSep = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = ','
- }
- }
- end,
- MissField = function (pos)
- PushError {
- type = 'MISS_FIELD',
- start = pos,
- finish = pos,
- }
- end,
- MissMethod = function (pos)
- PushError {
- type = 'MISS_METHOD',
- start = pos,
- finish = pos,
- }
- end,
- MissLabel = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = '::',
- }
- }
- end,
- MissEnd = function (pos)
- State.MissEndErr = PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = 'end',
- }
- }
- return pos, pos
- end,
- MissDo = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = 'do',
- }
- }
- return pos, pos
- end,
- MissComma = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = ',',
- }
- }
- end,
- MissIn = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = 'in',
- }
- }
- return pos, pos
- end,
- MissUntil = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = 'until',
- }
- }
- return pos, pos
- end,
- MissThen = function (pos)
- PushError {
- type = 'MISS_SYMBOL',
- start = pos,
- finish = pos,
- info = {
- symbol = 'then',
- }
- }
- return pos, pos
- end,
- MissName = function (pos)
- PushError {
- type = 'MISS_NAME',
- start = pos,
- finish = pos,
- }
- end,
- ExpInAction = function (start, exp, finish)
- PushError {
- type = 'EXP_IN_ACTION',
- start = start,
- finish = finish - 1,
- }
- return exp
- end,
- MissIf = function (start, block)
- PushError {
- type = 'MISS_SYMBOL',
- start = start,
- finish = start,
- info = {
- symbol = 'if',
- }
- }
- return block
- end,
- MissGT = function (start)
- PushError {
- type = 'MISS_SYMBOL',
- start = start,
- finish = start,
- info = {
- symbol = '>'
- }
- }
- end,
- ErrAssign = function (start, finish)
- PushError {
- type = 'ERR_ASSIGN_AS_EQ',
- start = start,
- finish = finish - 1,
- fix = {
- title = 'FIX_ASSIGN_AS_EQ',
- {
- start = start,
- finish = finish - 1,
- text = '=',
- }
- }
- }
- end,
- ErrEQ = function (start, finish)
- PushError {
- type = 'ERR_EQ_AS_ASSIGN',
- start = start,
- finish = finish - 1,
- fix = {
- title = 'FIX_EQ_AS_ASSIGN',
- {
- start = start,
- finish = finish - 1,
- text = '==',
- }
- }
- }
- return '=='
- end,
- ErrUEQ = function (start, finish)
- PushError {
- type = 'ERR_UEQ',
- start = start,
- finish = finish - 1,
- fix = {
- title = 'FIX_UEQ',
- {
- start = start,
- finish = finish - 1,
- text = '~=',
- }
- }
- }
- return '=='
- end,
- ErrThen = function (start, finish)
- PushError {
- type = 'ERR_THEN_AS_DO',
- start = start,
- finish = finish - 1,
- fix = {
- title = 'FIX_THEN_AS_DO',
- {
- start = start,
- finish = finish - 1,
- text = 'then',
- }
- }
- }
- return start, finish
- end,
- ErrDo = function (start, finish)
- PushError {
- type = 'ERR_DO_AS_THEN',
- start = start,
- finish = finish - 1,
- fix = {
- title = 'FIX_DO_AS_THEN',
- {
- start = start,
- finish = finish - 1,
- text = 'do',
- }
- }
- }
- return start, finish
- end,
-}
-
---for k, v in pairs(emmy.ast) do
--- Defs[k] = v
---end
-
-local function init(state)
- State = state
- PushError = state.pushError
- PushDiag = state.pushDiag
- emmy.init(State)
-end
-
-local function close()
- State = nil
- PushError = nil
- PushDiag = nil
-end
-
-return {
- defs = Defs,
- init = init,
- close = close,
-}
diff --git a/server-beta/src/parser/calcline.lua b/server-beta/src/parser/calcline.lua
deleted file mode 100644
index 26f475d9..00000000
--- a/server-beta/src/parser/calcline.lua
+++ /dev/null
@@ -1,93 +0,0 @@
-local m = require 'lpeglabel'
-
-local row
-local fl
-local NL = (m.P'\r\n' + m.S'\r\n') * m.Cp() / function (pos)
- row = row + 1
- fl = pos
-end
-local ROWCOL = (NL + m.P(1))^0
-local function rowcol(str, n)
- row = 1
- fl = 1
- ROWCOL:match(str:sub(1, n))
- local col = n - fl + 1
- return row, col
-end
-
-local function rowcol_utf8(str, n)
- row = 1
- fl = 1
- ROWCOL:match(str:sub(1, n))
- return row, utf8.len(str, fl, n)
-end
-
-local function position(str, _row, _col)
- local cur = 1
- local row = 1
- while true do
- if row == _row then
- return cur + _col - 1
- elseif row > _row then
- return cur - 1
- end
- local pos = str:find('[\r\n]', cur)
- if not pos then
- return #str
- end
- row = row + 1
- if str:sub(pos, pos+1) == '\r\n' then
- cur = pos + 2
- else
- cur = pos + 1
- end
- end
-end
-
-local function position_utf8(str, _row, _col)
- local cur = 1
- local row = 1
- while true do
- if row == _row then
- return utf8.offset(str, _col, cur)
- elseif row > _row then
- return cur - 1
- end
- local pos = str:find('[\r\n]', cur)
- if not pos then
- return #str
- end
- row = row + 1
- if str:sub(pos, pos+1) == '\r\n' then
- cur = pos + 2
- else
- cur = pos + 1
- end
- end
-end
-
-local NL = m.P'\r\n' + m.S'\r\n'
-
-local function line(str, row)
- local count = 0
- local res
- local LINE = m.Cmt((1 - NL)^0, function (_, _, c)
- count = count + 1
- if count == row then
- res = c
- return false
- end
- return true
- end)
- local MATCH = (LINE * NL)^0 * LINE
- MATCH:match(str)
- return res
-end
-
-return {
- rowcol = rowcol,
- rowcol_utf8 = rowcol_utf8,
- position = position,
- position_utf8 = position_utf8,
- line = line,
-}
diff --git a/server-beta/src/parser/compile.lua b/server-beta/src/parser/compile.lua
deleted file mode 100644
index bcd9ecc8..00000000
--- a/server-beta/src/parser/compile.lua
+++ /dev/null
@@ -1,549 +0,0 @@
-local guide = require 'parser.guide'
-local type = type
-
-local specials = {
- ['_G'] = true,
- ['rawset'] = true,
- ['rawget'] = true,
- ['setmetatable'] = true,
- ['require'] = true,
- ['dofile'] = true,
- ['loadfile'] = true,
- ['pcall'] = true,
- ['xpcall'] = true,
-}
-
-_ENV = nil
-
-local LocalLimit = 200
-local pushError, Compile, CompileBlock, Block, GoToTag, ENVMode, Compiled, LocalCount, Version, Root
-
-local function addRef(node, obj)
- if not node.ref then
- node.ref = {}
- end
- node.ref[#node.ref+1] = obj
- obj.node = node
-end
-
-local function addSpecial(name, obj)
- 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
-
-local vmMap = {
- ['getname'] = function (obj)
- local loc = guide.getLocal(obj, obj[1], obj.start)
- if loc then
- obj.type = 'getlocal'
- obj.loc = loc
- addRef(loc, obj)
- if loc.special then
- addSpecial(loc.special, obj)
- end
- else
- obj.type = 'getglobal'
- if ENVMode == '_ENV' then
- local node = guide.getLocal(obj, '_ENV', obj.start)
- if node then
- addRef(node, obj)
- end
- end
- local name = obj[1]
- if specials[name] then
- addSpecial(name, obj)
- end
- end
- return obj
- end,
- ['getfield'] = function (obj)
- Compile(obj.node, obj)
- end,
- ['call'] = function (obj)
- Compile(obj.node, obj)
- Compile(obj.args, obj)
- end,
- ['callargs'] = function (obj)
- for i = 1, #obj do
- Compile(obj[i], obj)
- end
- end,
- ['binary'] = function (obj)
- Compile(obj[1], obj)
- Compile(obj[2], obj)
- end,
- ['unary'] = function (obj)
- Compile(obj[1], obj)
- end,
- ['varargs'] = function (obj)
- local func = guide.getParentFunction(obj)
- if func then
- local index, vararg = guide.getFunctionVarArgs(func)
- if not index then
- pushError {
- type = 'UNEXPECT_DOTS',
- start = obj.start,
- finish = obj.finish,
- }
- end
- if vararg then
- if not vararg.ref then
- vararg.ref = {}
- end
- vararg.ref[#vararg.ref+1] = obj
- end
- end
- end,
- ['paren'] = function (obj)
- Compile(obj.exp, obj)
- end,
- ['getindex'] = function (obj)
- Compile(obj.node, obj)
- Compile(obj.index, obj)
- end,
- ['setindex'] = function (obj)
- Compile(obj.node, obj)
- Compile(obj.index, obj)
- Compile(obj.value, obj)
- end,
- ['getmethod'] = function (obj)
- Compile(obj.node, obj)
- Compile(obj.method, obj)
- end,
- ['setmethod'] = function (obj)
- Compile(obj.node, obj)
- Compile(obj.method, obj)
- local value = obj.value
- value.localself = {
- type = 'local',
- start = 0,
- finish = 0,
- method = obj,
- effect = obj.finish,
- tag = 'self',
- [1] = 'self',
- }
- Compile(value, obj)
- end,
- ['function'] = function (obj)
- local lastBlock = Block
- local LastLocalCount = LocalCount
- Block = obj
- LocalCount = 0
- if obj.localself then
- Compile(obj.localself, obj)
- obj.localself = nil
- end
- Compile(obj.args, obj)
- for i = 1, #obj do
- Compile(obj[i], obj)
- end
- Block = lastBlock
- LocalCount = LastLocalCount
- end,
- ['funcargs'] = function (obj)
- for i = 1, #obj do
- Compile(obj[i], obj)
- end
- end,
- ['table'] = function (obj)
- for i = 1, #obj do
- Compile(obj[i], obj)
- end
- end,
- ['tablefield'] = function (obj)
- Compile(obj.value, obj)
- end,
- ['tableindex'] = function (obj)
- Compile(obj.index, obj)
- Compile(obj.value, obj)
- end,
- ['index'] = function (obj)
- Compile(obj.index, obj)
- end,
- ['select'] = function (obj)
- local vararg = obj.vararg
- if vararg.parent then
- if not vararg.extParent then
- vararg.extParent = {}
- end
- vararg.extParent[#vararg.extParent+1] = obj
- else
- Compile(vararg, obj)
- end
- end,
- ['setname'] = function (obj)
- Compile(obj.value, obj)
- local loc = guide.getLocal(obj, obj[1], obj.start)
- if loc then
- obj.type = 'setlocal'
- obj.loc = loc
- addRef(loc, obj)
- if loc.attrs then
- local const
- for i = 1, #loc.attrs do
- local attr = loc.attrs[i][1]
- if attr == 'const'
- or attr == 'close' then
- const = true
- break
- end
- end
- if const then
- pushError {
- type = 'SET_CONST',
- start = obj.start,
- finish = obj.finish,
- }
- end
- end
- else
- obj.type = 'setglobal'
- if ENVMode == '_ENV' then
- local node = guide.getLocal(obj, '_ENV', obj.start)
- if node then
- addRef(node, obj)
- end
- end
- end
- end,
- ['local'] = function (obj)
- local attrs = obj.attrs
- if attrs then
- for i = 1, #attrs do
- Compile(attrs[i], obj)
- end
- end
- if Block then
- if not Block.locals then
- Block.locals = {}
- end
- Block.locals[#Block.locals+1] = obj
- LocalCount = LocalCount + 1
- if LocalCount > LocalLimit then
- pushError {
- type = 'LOCAL_LIMIT',
- start = obj.start,
- finish = obj.finish,
- }
- end
- end
- if obj.localfunction then
- obj.localfunction = nil
- end
- Compile(obj.value, obj)
- if obj.value and obj.value.special then
- addSpecial(obj.value.special, obj)
- end
- end,
- ['setfield'] = function (obj)
- Compile(obj.node, obj)
- Compile(obj.value, obj)
- end,
- ['do'] = function (obj)
- local lastBlock = Block
- Block = obj
- CompileBlock(obj, obj)
- if Block.locals then
- LocalCount = LocalCount - #Block.locals
- end
- Block = lastBlock
- end,
- ['return'] = function (obj)
- for i = 1, #obj do
- Compile(obj[i], obj)
- end
- if Block and Block[#Block] ~= obj then
- pushError {
- type = 'ACTION_AFTER_RETURN',
- start = obj.start,
- finish = obj.finish,
- }
- end
- local func = guide.getParentFunction(obj)
- if func then
- if not func.returns then
- func.returns = {}
- end
- func.returns[#func.returns+1] = obj
- end
- end,
- ['label'] = function (obj)
- local block = guide.getBlock(obj)
- if block then
- if not block.labels then
- block.labels = {}
- end
- local name = obj[1]
- local label = guide.getLabel(block, name)
- if label then
- if Version == 'Lua 5.4'
- or block == guide.getBlock(label) then
- pushError {
- type = 'REDEFINED_LABEL',
- start = obj.start,
- finish = obj.finish,
- relative = {
- {
- label.start,
- label.finish,
- }
- }
- }
- end
- end
- block.labels[name] = obj
- end
- end,
- ['goto'] = function (obj)
- GoToTag[#GoToTag+1] = obj
- end,
- ['if'] = function (obj)
- for i = 1, #obj do
- Compile(obj[i], obj)
- end
- end,
- ['ifblock'] = function (obj)
- local lastBlock = Block
- Block = obj
- Compile(obj.filter, obj)
- CompileBlock(obj, obj)
- if Block.locals then
- LocalCount = LocalCount - #Block.locals
- end
- Block = lastBlock
- end,
- ['elseifblock'] = function (obj)
- local lastBlock = Block
- Block = obj
- Compile(obj.filter, obj)
- CompileBlock(obj, obj)
- if Block.locals then
- LocalCount = LocalCount - #Block.locals
- end
- Block = lastBlock
- end,
- ['elseblock'] = function (obj)
- local lastBlock = Block
- Block = obj
- CompileBlock(obj, obj)
- if Block.locals then
- LocalCount = LocalCount - #Block.locals
- end
- Block = lastBlock
- end,
- ['loop'] = function (obj)
- local lastBlock = Block
- Block = obj
- Compile(obj.loc, obj)
- Compile(obj.max, obj)
- Compile(obj.step, obj)
- CompileBlock(obj, obj)
- if Block.locals then
- LocalCount = LocalCount - #Block.locals
- end
- Block = lastBlock
- end,
- ['in'] = function (obj)
- local lastBlock = Block
- Block = obj
- local keys = obj.keys
- for i = 1, #keys do
- Compile(keys[i], obj)
- end
- CompileBlock(obj, obj)
- if Block.locals then
- LocalCount = LocalCount - #Block.locals
- end
- Block = lastBlock
- end,
- ['while'] = function (obj)
- local lastBlock = Block
- Block = obj
- Compile(obj.filter, obj)
- CompileBlock(obj, obj)
- if Block.locals then
- LocalCount = LocalCount - #Block.locals
- end
- Block = lastBlock
- end,
- ['repeat'] = function (obj)
- local lastBlock = Block
- Block = obj
- CompileBlock(obj, obj)
- Compile(obj.filter, obj)
- if Block.locals then
- LocalCount = LocalCount - #Block.locals
- end
- Block = lastBlock
- end,
- ['break'] = function (obj)
- local block = guide.getBreakBlock(obj)
- if block then
- if not block.breaks then
- block.breaks = {}
- end
- block.breaks[#block.breaks+1] = obj
- else
- pushError {
- type = 'BREAK_OUTSIDE',
- start = obj.start,
- finish = obj.finish,
- }
- end
- end,
- ['main'] = function (obj)
- Block = obj
- if ENVMode == '_ENV' then
- Compile({
- type = 'local',
- start = 0,
- finish = 0,
- effect = 0,
- tag = '_ENV',
- special= '_G',
- [1] = '_ENV',
- }, obj)
- end
- --- _ENV 是上值,不计入局部变量计数
- LocalCount = 0
- CompileBlock(obj, obj)
- Block = nil
- end,
-}
-
-function CompileBlock(obj, parent)
- for i = 1, #obj do
- local act = obj[i]
- local f = vmMap[act.type]
- if f then
- act.parent = parent
- f(act)
- end
- end
-end
-
-function Compile(obj, parent)
- if not obj then
- return nil
- end
- if Compiled[obj] then
- return
- end
- Compiled[obj] = true
- obj.parent = parent
- local f = vmMap[obj.type]
- if not f then
- return
- end
- f(obj)
-end
-
-local function compileGoTo(obj)
- local name = obj[1]
- local label = guide.getLabel(obj, name)
- if not label then
- pushError {
- type = 'NO_VISIBLE_LABEL',
- start = obj.start,
- finish = obj.finish,
- info = {
- label = name,
- }
- }
- return
- end
- if not label.ref then
- label.ref = {}
- end
- label.ref[#label.ref+1] = obj
-
- -- 如果有局部变量在 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 PostCompile()
- for i = 1, #GoToTag do
- compileGoTo(GoToTag[i])
- end
-end
-
-return function (self, lua, mode, version)
- local state, err = self:parse(lua, mode, version)
- if not state then
- return nil, err
- end
- pushError = state.pushError
- if version == 'Lua 5.1' or version == 'LuaJIT' then
- ENVMode = 'fenv'
- else
- ENVMode = '_ENV'
- end
- Compiled = {}
- GoToTag = {}
- LocalCount = 0
- Version = version
- Root = state.ast
- if type(state.ast) == 'table' then
- Compile(state.ast)
- end
- PostCompile()
- Compiled = nil
- GoToTag = nil
- return state
-end
diff --git a/server-beta/src/parser/emmy.lua b/server-beta/src/parser/emmy.lua
deleted file mode 100644
index 4c1e087a..00000000
--- a/server-beta/src/parser/emmy.lua
+++ /dev/null
@@ -1,321 +0,0 @@
-local State
-local pushError
-
-local grammar = [[
-EmmyLua <- ({} '---' EmmyBody {} ShortComment)
- -> EmmyLua
-EmmySp <- (!'---@' !'---' Comment / %s / %nl)*
-EmmyComments <- (EmmyComment (%nl EmmyComMulti / %nl EmmyComSingle)*)
-EmmyComment <- EmmySp %s* {(!%nl .)*}
-EmmyComMulti <- EmmySp '---|' {} -> en {(!%nl .)*}
-EmmyComSingle <- EmmySp '---' !'@' %s* {} -> ' ' {(!%nl .)*}
-EmmyBody <- '@class' %s+ EmmyClass -> EmmyClass
- / '@type' %s+ EmmyType -> EmmyType
- / '@alias' %s+ EmmyAlias -> EmmyAlias
- / '@param' %s+ EmmyParam -> EmmyParam
- / '@return' %s+ EmmyReturn -> EmmyReturn
- / '@field' %s+ EmmyField -> EmmyField
- / '@generic' %s+ EmmyGeneric -> EmmyGeneric
- / '@vararg' %s+ EmmyVararg -> EmmyVararg
- / '@language' %s+ EmmyLanguage -> EmmyLanguage
- / '@see' %s+ EmmySee -> EmmySee
- / '@overload' %s+ EmmyOverLoad -> EmmyOverLoad
- / %s* EmmyComments -> EmmyComment
- / EmmyIncomplete
-
-EmmyName <- ({} {[a-zA-Z_] [a-zA-Z0-9_]*})
- -> EmmyName
-MustEmmyName <- EmmyName / DirtyEmmyName
-DirtyEmmyName <- {} -> DirtyEmmyName
-EmmyLongName <- ({} {(!%nl .)+})
- -> EmmyName
-EmmyIncomplete <- MustEmmyName
- -> EmmyIncomplete
-
-EmmyClass <- (MustEmmyName EmmyParentClass?)
-EmmyParentClass <- %s* {} ':' %s* MustEmmyName
-
-EmmyType <- EmmyTypeUnits EmmyTypeEnums
-EmmyTypeUnits <- {|
- EmmyTypeUnit?
- (%s* '|' %s* !String EmmyTypeUnit)*
- |}
-EmmyTypeEnums <- {| EmmyTypeEnum* |}
-EmmyTypeUnit <- EmmyFunctionType
- / EmmyTableType
- / EmmyArrayType
- / EmmyCommonType
-EmmyCommonType <- EmmyName
- -> EmmyCommonType
-EmmyTypeEnum <- %s* (%nl %s* '---')? '|'? EmmyEnum
- -> EmmyTypeEnum
-EmmyEnum <- %s* {'>'?} %s* String (EmmyEnumComment / (!%nl !'|' .)*)
-EmmyEnumComment <- %s* '#' %s* {(!%nl .)*}
-
-EmmyAlias <- MustEmmyName %s* EmmyType EmmyTypeEnum*
-
-EmmyParam <- MustEmmyName %s* EmmyType %s* EmmyOption %s* EmmyTypeEnum*
-EmmyOption <- Table?
- -> EmmyOption
-
-EmmyReturn <- {} %nil {} Table -> EmmyOption
- / {} EmmyType {} EmmyOption
-
-EmmyField <- (EmmyFieldAccess MustEmmyName %s* EmmyType)
-EmmyFieldAccess <- ({'public'} Cut %s*)
- / ({'protected'} Cut %s*)
- / ({'private'} Cut %s*)
- / {} -> 'public'
-
-EmmyGeneric <- EmmyGenericBlock
- (%s* ',' %s* EmmyGenericBlock)*
-EmmyGenericBlock<- (MustEmmyName %s* (':' %s* EmmyType)?)
- -> EmmyGenericBlock
-
-EmmyVararg <- EmmyType
-
-EmmyLanguage <- MustEmmyName
-
-EmmyArrayType <- ({} MustEmmyName -> EmmyCommonType {} '[' DirtyBR)
- -> EmmyArrayType
- / ({} PL EmmyCommonType DirtyPR '[' DirtyBR)
- -> EmmyArrayType
-
-EmmyTableType <- ({} 'table' Cut '<' %s* EmmyType %s* ',' %s* EmmyType %s* '>' {})
- -> EmmyTableType
-
-EmmyFunctionType<- ({} 'fun' Cut %s* EmmyFunctionArgs %s* EmmyFunctionRtns {})
- -> EmmyFunctionType
-EmmyFunctionArgs<- ('(' %s* EmmyFunctionArg %s* (',' %s* EmmyFunctionArg %s*)* DirtyPR)
- -> EmmyFunctionArgs
- / '(' %nil DirtyPR -> None
- / %nil
-EmmyFunctionRtns<- (':' %s* EmmyType (%s* ',' %s* EmmyType)*)
- -> EmmyFunctionRtns
- / %nil
-EmmyFunctionArg <- MustEmmyName %s* ':' %s* EmmyType
-
-EmmySee <- {} MustEmmyName %s* '#' %s* MustEmmyName {}
-EmmyOverLoad <- EmmyFunctionType
-]]
-
-local ast = {
- EmmyLua = function (start, emmy, finish)
- emmy.start = start
- emmy.finish = finish - 1
- State.emmy[#State.emmy+1] = emmy
- end,
- EmmyName = function (start, str)
- return {
- type = 'name',
- start = start,
- finish = start + #str - 1,
- [1] = str,
- }
- end,
- DirtyEmmyName = function (pos)
- pushError {
- type = 'MISS_NAME',
- level = 'warning',
- start = pos,
- finish = pos,
- }
- return {
- type = 'emmyName',
- start = pos-1,
- finish = pos-1,
- [1] = ''
- }
- end,
- EmmyClass = function (class, startPos, extends)
- if extends and extends[1] == '' then
- extends.start = startPos
- end
- return {
- type = 'class',
- class = class,
- extends = extends,
- }
- end,
- EmmyType = function (types, enums)
- local result = {
- type = 'type',
- types = types,
- enums = enums,
- }
- return result
- end,
- EmmyCommonType = function (name)
- return {
- type = 'common',
- start = name.start,
- finish = name.finish,
- name = name,
- }
- end,
- EmmyArrayType = function (start, emmy, _, finish)
- emmy.type = 'emmyArrayType'
- emmy.start = start
- emmy.finish = finish - 1
- return emmy
- end,
- EmmyTableType = function (start, keyType, valueType, finish)
- return {
- type = 'emmyTableType',
- start = start,
- finish = finish - 1,
- [1] = keyType,
- [2] = valueType,
- }
- end,
- EmmyFunctionType = function (start, args, returns, finish)
- local result = {
- start = start,
- finish = finish - 1,
- type = 'emmyFunctionType',
- args = args,
- returns = returns,
- }
- return result
- end,
- EmmyFunctionRtns = function (...)
- return {...}
- end,
- EmmyFunctionArgs = function (...)
- local args = {...}
- args[#args] = nil
- return args
- end,
- EmmyAlias = function (name, emmyName, ...)
- return {
- type = 'emmyAlias',
- start = name.start,
- finish = emmyName.finish,
- name,
- emmyName,
- ...
- }
- end,
- EmmyParam = function (argName, emmyName, option, ...)
- local emmy = {
- type = 'emmyParam',
- option = option,
- argName,
- emmyName,
- ...
- }
- emmy.start = emmy[1].start
- emmy.finish = emmy[#emmy].finish
- return emmy
- end,
- EmmyReturn = function (start, type, finish, option)
- local emmy = {
- type = 'emmyReturn',
- option = option,
- start = start,
- finish = finish - 1,
- [1] = type,
- }
- return emmy
- end,
- EmmyField = function (access, fieldName, ...)
- local obj = {
- type = 'emmyField',
- access, fieldName,
- ...
- }
- obj.start = obj[2].start
- obj.finish = obj[3].finish
- return obj
- end,
- EmmyGenericBlock = function (genericName, parentName)
- return {
- start = genericName.start,
- finish = parentName and parentName.finish or genericName.finish,
- genericName,
- parentName,
- }
- end,
- EmmyGeneric = function (...)
- local emmy = {
- type = 'emmyGeneric',
- ...
- }
- emmy.start = emmy[1].start
- emmy.finish = emmy[#emmy].finish
- return emmy
- end,
- EmmyVararg = function (typeName)
- return {
- type = 'emmyVararg',
- start = typeName.start,
- finish = typeName.finish,
- typeName,
- }
- end,
- EmmyLanguage = function (language)
- return {
- type = 'emmyLanguage',
- start = language.start,
- finish = language.finish,
- language,
- }
- end,
- EmmySee = function (start, className, methodName, finish)
- return {
- type = 'emmySee',
- start = start,
- finish = finish - 1,
- className, methodName
- }
- end,
- EmmyOverLoad = function (EmmyFunctionType)
- EmmyFunctionType.type = 'emmyOverLoad'
- return EmmyFunctionType
- end,
- EmmyIncomplete = function (emmyName)
- emmyName.type = 'emmyIncomplete'
- return emmyName
- end,
- EmmyComment = function (...)
- return {
- type = 'emmyComment',
- [1] = table.concat({...}),
- }
- end,
- EmmyOption = function (options)
- if not options or options == '' then
- return nil
- end
- local option = {}
- for _, pair in ipairs(options) do
- if pair.type == 'pair' then
- local key = pair[1]
- local value = pair[2]
- if key.type == 'name' then
- option[key[1]] = value[1]
- end
- end
- end
- return option
- end,
- EmmyTypeEnum = function (default, enum, comment)
- enum.type = 'enum'
- if default ~= '' then
- enum.default = true
- end
- enum.comment = comment
- return enum
- end,
-}
-
-local function init(state)
- State = state
- pushError = state.pushError
-end
-
-return {
- grammar = grammar,
- ast = ast,
- init = init,
-}
diff --git a/server-beta/src/parser/grammar.lua b/server-beta/src/parser/grammar.lua
deleted file mode 100644
index fd699bd4..00000000
--- a/server-beta/src/parser/grammar.lua
+++ /dev/null
@@ -1,537 +0,0 @@
-local re = require 'parser.relabel'
-local m = require 'lpeglabel'
-local emmy = require 'parser.emmy'
-local ast = require 'parser.ast'
-
-local scriptBuf = ''
-local compiled = {}
-local defs = ast.defs
-
--- goto 可以作为名字,合法性之后处理
-local RESERVED = {
- ['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,
-}
-
-defs.nl = (m.P'\r\n' + m.S'\r\n')
-defs.s = m.S' \t'
-defs.S = - defs.s
-defs.ea = '\a'
-defs.eb = '\b'
-defs.ef = '\f'
-defs.en = '\n'
-defs.er = '\r'
-defs.et = '\t'
-defs.ev = '\v'
-defs['nil'] = m.Cp() / function () return nil end
-defs['false'] = m.Cp() / function () return false end
-defs.NotReserved = function (_, _, str)
- if RESERVED[str] then
- return false
- end
- return true
-end
-defs.Reserved = function (_, _, str)
- if RESERVED[str] then
- return true
- end
- return false
-end
-defs.None = function () end
-defs.np = m.Cp() / function (n) return n+1 end
-
-m.setmaxstack(1000)
-
-local eof = re.compile '!. / %{SYNTAX_ERROR}'
-
-local function grammar(tag)
- return function (script)
- scriptBuf = script .. '\r\n' .. scriptBuf
- compiled[tag] = re.compile(scriptBuf, defs) * eof
- end
-end
-
-local function errorpos(pos, err)
- return {
- type = 'UNKNOWN',
- start = pos or 0,
- finish = pos or 0,
- err = err,
- }
-end
-
-grammar 'Comment' [[
-Comment <- LongComment
- / '--' ShortComment
-LongComment <- ('--[' {} {:eq: '='* :} {} '['
- {(!CommentClose .)*}
- (CommentClose / {}))
- -> LongComment
- / (
- {} '/*' {}
- (!'*/' .)*
- {} '*/' {}
- )
- -> CLongComment
-CommentClose <- ']' =eq ']'
-ShortComment <- (!%nl .)*
-]]
-
-grammar 'Sp' [[
-Sp <- (EmmyLua / Comment / %nl / %s)*
-Sps <- (EmmyLua / Comment / %nl / %s)+
-
--- 占位
-EmmyLua <- !. .
-]]
-
-grammar 'Common' [[
-Word <- [a-zA-Z0-9_]
-Cut <- !Word
-X16 <- [a-fA-F0-9]
-Rest <- (!%nl .)*
-
-AND <- Sp {'and'} Cut
-BREAK <- Sp 'break' Cut
-FALSE <- Sp 'false' Cut
-GOTO <- Sp 'goto' Cut
-LOCAL <- Sp 'local' Cut
-NIL <- Sp 'nil' Cut
-NOT <- Sp 'not' Cut
-OR <- Sp {'or'} Cut
-RETURN <- Sp 'return' Cut
-TRUE <- Sp 'true' Cut
-
-DO <- Sp {} 'do' {} Cut
- / Sp({} 'then' {} Cut) -> ErrDo
-IF <- Sp {} 'if' {} Cut
-ELSE <- Sp {} 'else' {} Cut
-ELSEIF <- Sp {} 'elseif' {} Cut
-END <- Sp {} 'end' {} Cut
-FOR <- Sp {} 'for' {} Cut
-FUNCTION <- Sp {} 'function' {} Cut
-IN <- Sp {} 'in' {} Cut
-REPEAT <- Sp {} 'repeat' {} Cut
-THEN <- Sp {} 'then' {} Cut
- / Sp({} 'do' {} Cut) -> ErrThen
-UNTIL <- Sp {} 'until' {} Cut
-WHILE <- Sp {} 'while' {} Cut
-
-
-Esc <- '\' -> ''
- EChar
-EChar <- 'a' -> ea
- / 'b' -> eb
- / 'f' -> ef
- / 'n' -> en
- / 'r' -> er
- / 't' -> et
- / 'v' -> ev
- / '\'
- / '"'
- / "'"
- / %nl
- / ('z' (%nl / %s)*) -> ''
- / ({} 'x' {X16 X16}) -> Char16
- / ([0-9] [0-9]? [0-9]?) -> Char10
- / ('u{' {} {Word*} '}') -> CharUtf8
- -- 错误处理
- / 'x' {} -> MissEscX
- / 'u' !'{' {} -> MissTL
- / 'u{' Word* !'}' {} -> MissTR
- / {} -> ErrEsc
-
-BOR <- Sp {'|'}
-BXOR <- Sp {'~'} !'='
-BAND <- Sp {'&'}
-Bshift <- Sp {BshiftList}
-BshiftList <- '<<'
- / '>>'
-Concat <- Sp {'..'}
-Adds <- Sp {AddsList}
-AddsList <- '+'
- / '-'
-Muls <- Sp {MulsList}
-MulsList <- '*'
- / '//'
- / '/'
- / '%'
-Unary <- Sp {} {UnaryList}
-UnaryList <- NOT
- / '#'
- / '-'
- / '~' !'='
-POWER <- Sp {'^'}
-
-BinaryOp <-( Sp {} {'or'} Cut
- / Sp {} {'and'} Cut
- / Sp {} {'<=' / '>=' / '<'!'<' / '>'!'>' / '~=' / '=='}
- / Sp {} ({} '=' {}) -> ErrEQ
- / Sp {} ({} '!=' {}) -> ErrUEQ
- / Sp {} {'|'}
- / Sp {} {'~'}
- / Sp {} {'&'}
- / Sp {} {'<<' / '>>'}
- / Sp {} {'..'} !'.'
- / Sp {} {'+' / '-'}
- / Sp {} {'*' / '//' / '/' / '%'}
- / Sp {} {'^'}
- )-> BinaryOp
-UnaryOp <-( Sp {} {'not' Cut / '#' / '~' !'=' / '-' !'-'}
- )-> UnaryOp
-
-PL <- Sp '('
-PR <- Sp ')'
-BL <- Sp '[' !'[' !'='
-BR <- Sp ']'
-TL <- Sp '{'
-TR <- Sp '}'
-COMMA <- Sp ({} ',')
- -> COMMA
-SEMICOLON <- Sp ({} ';')
- -> SEMICOLON
-DOTS <- Sp ({} '...')
- -> DOTS
-DOT <- Sp ({} '.' !'.')
- -> DOT
-COLON <- Sp ({} ':' !':')
- -> COLON
-LABEL <- Sp '::'
-ASSIGN <- Sp '=' !'='
-AssignOrEQ <- Sp ({} '==' {})
- -> ErrAssign
- / Sp '='
-
-DirtyBR <- BR / {} -> MissBR
-DirtyTR <- TR / {} -> MissTR
-DirtyPR <- PR / {} -> MissPR
-DirtyLabel <- LABEL / {} -> MissLabel
-NeedEnd <- END / {} -> MissEnd
-NeedDo <- DO / {} -> MissDo
-NeedAssign <- ASSIGN / {} -> MissAssign
-NeedComma <- COMMA / {} -> MissComma
-NeedIn <- IN / {} -> MissIn
-NeedUntil <- UNTIL / {} -> MissUntil
-NeedThen <- THEN / {} -> MissThen
-]]
-
-grammar 'Nil' [[
-Nil <- Sp ({} -> Nil) NIL
-]]
-
-grammar 'Boolean' [[
-Boolean <- Sp ({} -> True) TRUE
- / Sp ({} -> False) FALSE
-]]
-
-grammar 'String' [[
-String <- Sp ({} StringDef {})
- -> String
-StringDef <- {'"'}
- {~(Esc / !%nl !'"' .)*~} -> 1
- ('"' / {} -> MissQuote1)
- / {"'"}
- {~(Esc / !%nl !"'" .)*~} -> 1
- ("'" / {} -> MissQuote2)
- / ('[' {} {:eq: '='* :} {} '[' %nl?
- {(!StringClose .)*} -> 1
- (StringClose / {}))
- -> LongString
-StringClose <- ']' =eq ']'
-]]
-
-grammar 'Number' [[
-Number <- Sp ({} {NumberDef} {}) -> Number
- NumberSuffix?
- ErrNumber?
-NumberDef <- Number16 / Number10
-NumberSuffix<- ({} {[uU]? [lL] [lL]}) -> FFINumber
- / ({} {[iI]}) -> ImaginaryNumber
-ErrNumber <- ({} {([0-9a-zA-Z] / '.')+}) -> UnknownSymbol
-
-Number10 <- Float10 Float10Exp?
- / Integer10 Float10? Float10Exp?
-Integer10 <- [0-9]+ ('.' [0-9]*)?
-Float10 <- '.' [0-9]+
-Float10Exp <- [eE] [+-]? [0-9]+
- / ({} [eE] [+-]? {}) -> MissExponent
-
-Number16 <- '0' [xX] Float16 Float16Exp?
- / '0' [xX] Integer16 Float16? Float16Exp?
-Integer16 <- X16+ ('.' X16*)?
- / ({} {Word*}) -> MustX16
-Float16 <- '.' X16+
- / '.' ({} {Word*}) -> MustX16
-Float16Exp <- [pP] [+-]? [0-9]+
- / ({} [pP] [+-]? {}) -> MissExponent
-]]
-
-grammar 'Name' [[
-Name <- Sp ({} NameBody {})
- -> Name
-NameBody <- {[a-zA-Z_] [a-zA-Z0-9_]*}
-FreeName <- Sp ({} {NameBody=>NotReserved} {})
- -> Name
-KeyWord <- Sp NameBody=>Reserved
-MustName <- Name / DirtyName
-DirtyName <- {} -> DirtyName
-]]
-
-grammar 'Exp' [[
-Exp <- (UnUnit BinUnit*)
- -> Binary
-BinUnit <- (BinaryOp UnUnit?)
- -> SubBinary
-UnUnit <- ExpUnit
- / (UnaryOp+ (ExpUnit / MissExp))
- -> Unary
-ExpUnit <- Nil
- / Boolean
- / String
- / Number
- / Dots
- / Table
- / Function
- / Simple
-
-Simple <- {| Prefix (Sp Suffix)* |}
- -> Simple
-Prefix <- Sp ({} PL DirtyExp DirtyPR {})
- -> Paren
- / Single
-Single <- FreeName
- -> Single
-Suffix <- SuffixWithoutCall
- / ({} PL SuffixCall DirtyPR {})
- -> Call
-SuffixCall <- Sp ({} {| (COMMA / Exp)+ |} {})
- -> PackExpList
- / %nil
-SuffixWithoutCall
- <- (DOT (Name / MissField))
- -> GetField
- / ({} BL DirtyExp DirtyBR {})
- -> GetIndex
- / (COLON (Name / MissMethod) NeedCall)
- -> GetMethod
- / ({} {| Table |} {})
- -> Call
- / ({} {| String |} {})
- -> Call
-NeedCall <- (!(Sp CallStart) {} -> MissPL)?
-MissField <- {} -> MissField
-MissMethod <- {} -> MissMethod
-CallStart <- PL
- / TL
- / '"'
- / "'"
- / '[' '='* '['
-
-DirtyExp <- Exp
- / {} -> DirtyExp
-MaybeExp <- Exp / MissExp
-MissExp <- {} -> MissExp
-ExpList <- Sp {| MaybeExp (Sp ',' MaybeExp)* |}
-
-Dots <- DOTS
- -> VarArgs
-
-Table <- Sp ({} TL {| TableField* |} DirtyTR {})
- -> Table
-TableField <- COMMA
- / SEMICOLON
- / NewIndex
- / NewField
- / Exp
-Index <- BL DirtyExp DirtyBR
-NewIndex <- Sp ({} Index NeedAssign DirtyExp {})
- -> NewIndex
-NewField <- Sp ({} MustName ASSIGN DirtyExp {})
- -> NewField
-
-Function <- FunctionBody
- -> Function
-FuncArgs <- Sp ({} PL {| FuncArg+ |} DirtyPR {})
- -> FuncArgs
- / PL DirtyPR %nil
- / {} -> MissPL DirtyPR %nil
-FuncArg <- DOTS
- / Name
- / COMMA
-FunctionBody<- FUNCTION FuncArgs
- {| (!END Action)* |}
- NeedEnd
-
--- 纯占位,修改了 `relabel.lua` 使重复定义不抛错
-Action <- !END .
-]]
-
-grammar 'Action' [[
-Action <- Sp (CrtAction / UnkAction)
-CrtAction <- Semicolon
- / Do
- / Break
- / Return
- / Label
- / GoTo
- / If
- / For
- / While
- / Repeat
- / NamedFunction
- / LocalFunction
- / Local
- / Set
- / Call
- / ExpInAction
-UnkAction <- ({} {Word+})
- -> UnknownAction
- / ({} '//' {} (LongComment / ShortComment))
- -> CCommentPrefix
- / ({} {. (!Sps !CrtAction .)*})
- -> UnknownAction
-ExpInAction <- Sp ({} Exp {})
- -> ExpInAction
-
-Semicolon <- Sp ';'
-SimpleList <- {| Simple (Sp ',' Simple)* |}
-
-Do <- Sp ({}
- 'do' Cut
- {| (!END Action)* |}
- NeedEnd)
- -> Do
-
-Break <- Sp ({} BREAK {})
- -> Break
-
-Return <- Sp ({} RETURN ReturnExpList {})
- -> Return
-ReturnExpList
- <- Sp {| Exp (Sp ',' MaybeExp)* |}
- / Sp {| !Exp !',' |}
- / ExpList
-
-Label <- Sp ({} LABEL MustName DirtyLabel {})
- -> Label
-
-GoTo <- Sp ({} GOTO MustName {})
- -> GoTo
-
-If <- Sp ({} {| IfHead IfBody* |} NeedEnd)
- -> If
-
-IfHead <- Sp (IfPart {}) -> IfBlock
- / Sp (ElseIfPart {}) -> ElseIfBlock
- / Sp (ElsePart {}) -> ElseBlock
-IfBody <- Sp (ElseIfPart {}) -> ElseIfBlock
- / Sp (ElsePart {}) -> ElseBlock
-IfPart <- IF DirtyExp NeedThen
- {| (!ELSEIF !ELSE !END Action)* |}
-ElseIfPart <- ELSEIF DirtyExp NeedThen
- {| (!ELSEIF !ELSE !END Action)* |}
-ElsePart <- ELSE
- {| (!ELSEIF !ELSE !END Action)* |}
-
-For <- Loop / In
-
-Loop <- LoopBody
- -> Loop
-LoopBody <- FOR LoopArgs NeedDo
- {} {| (!END Action)* |}
- NeedEnd
-LoopArgs <- MustName AssignOrEQ
- ({} {| (COMMA / !DO !END Exp)* |} {})
- -> PackLoopArgs
-
-In <- InBody
- -> In
-InBody <- FOR InNameList NeedIn InExpList NeedDo
- {} {| (!END Action)* |}
- NeedEnd
-InNameList <- ({} {| (COMMA / !IN !DO !END Name)* |} {})
- -> PackInNameList
-InExpList <- ({} {| (COMMA / !DO !DO !END Exp)* |} {})
- -> PackInExpList
-
-While <- WhileBody
- -> While
-WhileBody <- WHILE DirtyExp NeedDo
- {| (!END Action)* |}
- NeedEnd
-
-Repeat <- (RepeatBody {})
- -> Repeat
-RepeatBody <- REPEAT
- {| (!UNTIL Action)* |}
- NeedUntil DirtyExp
-
-LocalAttr <- {| (Sp '<' Sp MustName Sp LocalAttrEnd)+ |}
- -> LocalAttr
-LocalAttrEnd<- '>' / {} -> MissGT
-Local <- Sp ({} LOCAL LocalNameList ((AssignOrEQ ExpList) / %nil) {})
- -> Local
-Set <- Sp ({} SimpleList AssignOrEQ ExpList {})
- -> Set
-LocalNameList
- <- {| LocalName (Sp ',' LocalName)* |}
-LocalName <- (MustName LocalAttr?)
- -> LocalName
-
-Call <- Simple
- -> SimpleCall
-
-LocalFunction
- <- Sp ({} LOCAL FunctionNamedBody)
- -> LocalFunction
-
-NamedFunction
- <- FunctionNamedBody
- -> NamedFunction
-FunctionNamedBody
- <- FUNCTION FuncName FuncArgs
- {| (!END Action)* |}
- NeedEnd
-FuncName <- {| Single (Sp SuffixWithoutCall)* |}
- -> Simple
- / {} -> MissName %nil
-]]
-
---grammar 'EmmyLua' (emmy.grammar)
-
-grammar 'Lua' [[
-Lua <- Head?
- ({} {| Action* |} {}) -> Lua
- Sp
-Head <- '#' (!%nl .)*
-]]
-
-return function (self, lua, mode)
- local gram = compiled[mode] or compiled['Lua']
- local r, _, pos = gram:match(lua)
- if not r then
- local err = errorpos(pos)
- return nil, err
- end
-
- return r
-end
diff --git a/server-beta/src/parser/guide.lua b/server-beta/src/parser/guide.lua
deleted file mode 100644
index af511555..00000000
--- a/server-beta/src/parser/guide.lua
+++ /dev/null
@@ -1,621 +0,0 @@
-local error = error
-local type = type
-local next = next
-local tostring = tostring
-
-_ENV = nil
-
-local m = {}
-
-local blockTypes = {
- ['while'] = true,
- ['in'] = true,
- ['loop'] = true,
- ['repeat'] = true,
- ['do'] = true,
- ['function'] = true,
- ['ifblock'] = true,
- ['elseblock'] = true,
- ['elseifblock'] = true,
- ['main'] = true,
-}
-
-local breakBlockTypes = {
- ['while'] = true,
- ['in'] = true,
- ['loop'] = true,
- ['repeat'] = true,
-}
-
-m.childMap = {
- ['main'] = {'#'},
- ['repeat'] = {'#', 'filter'},
- ['while'] = {'filter', '#'},
- ['in'] = {'keys', '#'},
- ['loop'] = {'loc', 'max', 'step', '#'},
- ['if'] = {'#'},
- ['ifblock'] = {'filter', '#'},
- ['elseifblock'] = {'filter', '#'},
- ['elseblock'] = {'#'},
- ['setfield'] = {'node', 'field', 'value'},
- ['setglobal'] = {'value'},
- ['local'] = {'attrs', 'value'},
- ['setlocal'] = {'value'},
- ['return'] = {'#'},
- ['do'] = {'#'},
- ['select'] = {'vararg'},
- ['table'] = {'#'},
- ['tableindex'] = {'index', 'value'},
- ['tablefield'] = {'field', 'value'},
- ['function'] = {'args', '#'},
- ['funcargs'] = {'#'},
- ['setmethod'] = {'node', 'method', 'value'},
- ['getmethod'] = {'node', 'method'},
- ['setindex'] = {'node', 'index', 'value'},
- ['getindex'] = {'node', 'index'},
- ['paren'] = {'exp'},
- ['call'] = {'node', 'args'},
- ['callargs'] = {'#'},
- ['getfield'] = {'node', 'field'},
- ['list'] = {'#'},
- ['binary'] = {1, 2},
- ['unary'] = {1}
-}
-
-m.actionMap = {
- ['main'] = {'#'},
- ['repeat'] = {'#'},
- ['while'] = {'#'},
- ['in'] = {'#'},
- ['loop'] = {'#'},
- ['if'] = {'#'},
- ['ifblock'] = {'#'},
- ['elseifblock'] = {'#'},
- ['elseblock'] = {'#'},
- ['do'] = {'#'},
- ['function'] = {'#'},
- ['funcargs'] = {'#'},
-}
-
---- 是否是字面量
-function m.isLiteral(obj)
- local tp = obj.type
- return tp == 'nil'
- or tp == 'boolean'
- or tp == 'string'
- or tp == 'number'
- or tp == 'table'
-end
-
---- 获取字面量
-function m.getLiteral(obj)
- local tp = obj.type
- if tp == 'boolean' then
- return obj[1]
- elseif tp == 'string' then
- return obj[1]
- elseif tp == 'number' then
- return obj[1]
- end
- return nil
-end
-
---- 寻找父函数
-function m.getParentFunction(obj)
- for _ = 1, 1000 do
- obj = obj.parent
- if not obj then
- break
- end
- local tp = obj.type
- if tp == 'function' or tp == 'main' then
- return obj
- end
- end
- return nil
-end
-
---- 寻找所在区块
-function m.getBlock(obj)
- for _ = 1, 1000 do
- if not obj then
- return nil
- end
- local tp = obj.type
- if blockTypes[tp] then
- return obj
- end
- obj = obj.parent
- end
- error('guide.getBlock overstack')
-end
-
---- 寻找所在父区块
-function m.getParentBlock(obj)
- for _ = 1, 1000 do
- obj = obj.parent
- if not obj then
- return nil
- end
- local tp = obj.type
- if blockTypes[tp] then
- return obj
- end
- end
- error('guide.getParentBlock overstack')
-end
-
---- 寻找所在可break的父区块
-function m.getBreakBlock(obj)
- for _ = 1, 1000 do
- obj = obj.parent
- if not obj then
- return nil
- end
- local tp = obj.type
- if breakBlockTypes[tp] then
- return obj
- end
- if tp == 'function' then
- return nil
- end
- end
- error('guide.getBreakBlock overstack')
-end
-
---- 寻找根区块
-function m.getRoot(obj)
- for _ = 1, 1000 do
- local parent = obj.parent
- if not parent then
- return obj
- end
- obj = parent
- end
- error('guide.getRoot overstack')
-end
-
---- 寻找函数的不定参数,返回不定参在第几个参数上,以及该参数对象。
---- 如果函数是主函数,则返回`0, nil`。
----@return table
----@return integer
-function m.getFunctionVarArgs(func)
- if func.type == 'main' then
- return 0, nil
- end
- if func.type ~= 'function' then
- return nil, nil
- end
- local args = func.args
- if not args then
- return nil, nil
- end
- for i = 1, #args do
- local arg = args[i]
- if arg.type == '...' then
- return i, arg
- end
- end
- return nil, nil
-end
-
---- 获取指定区块中可见的局部变量
----@param block table
----@param name string {comment = '变量名'}
----@param pos integer {comment = '可见位置'}
-function m.getLocal(block, name, pos)
- block = m.getBlock(block)
- for _ = 1, 1000 do
- if not block then
- return nil
- end
- local locals = block.locals
- local res
- if not locals then
- goto CONTINUE
- end
- for i = 1, #locals do
- local loc = locals[i]
- 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, res
- end
- ::CONTINUE::
- block = m.getParentBlock(block)
- end
- error('guide.getLocal overstack')
-end
-
---- 获取指定区块中可见的标签
----@param block table
----@param name string {comment = '标签名'}
-function m.getLabel(block, name)
- block = m.getBlock(block)
- for _ = 1, 1000 do
- if not block then
- return nil
- end
- local labels = block.labels
- if labels then
- local label = labels[name]
- if label then
- return label
- end
- end
- if block.type == 'function' then
- return nil
- end
- block = m.getParentBlock(block)
- end
- error('guide.getLocal overstack')
-end
-
---- 判断source是否包含offset
-function m.isContain(source, offset)
- return source.start <= offset and source.finish >= offset - 1
-end
-
---- 判断offset在source的影响范围内
----
---- 主要针对赋值等语句时,key包含value
-function m.isInRange(source, offset)
- return (source.vstart or source.start) <= offset and (source.range or source.finish) >= offset - 1
-end
-
---- 添加child
-function m.addChilds(list, obj, map)
- local keys = map[obj.type]
- if keys then
- for i = 1, #keys do
- local key = keys[i]
- if key == '#' then
- for i = 1, #obj do
- list[#list+1] = obj[i]
- end
- else
- list[#list+1] = obj[key]
- end
- end
- end
-end
-
---- 遍历所有包含offset的source
-function m.eachSourceContain(ast, offset, callback)
- local list = { ast }
- while true do
- local len = #list
- if len == 0 then
- return
- end
- local obj = list[len]
- list[len] = nil
- if m.isInRange(obj, offset) then
- if m.isContain(obj, offset) then
- local res = callback(obj)
- if res ~= nil then
- return res
- end
- end
- m.addChilds(list, obj, m.childMap)
- end
- end
-end
-
---- 遍历所有指定类型的source
-function m.eachSourceType(ast, type, callback)
- local cache = ast.typeCache
- if not cache then
- local mark = {}
- cache = {}
- ast.typeCache = cache
- m.eachSource(ast, function (source)
- if mark[source] then
- return
- end
- mark[source] = true
- local tp = source.type
- if not tp then
- return
- end
- local myCache = cache[tp]
- if not myCache then
- myCache = {}
- cache[tp] = myCache
- end
- myCache[#myCache+1] = source
- end)
- end
- local myCache = cache[type]
- if not myCache then
- return
- end
- for i = 1, #myCache do
- callback(myCache[i])
- end
-end
-
---- 遍历所有的source
-function m.eachSource(ast, callback)
- local list = { ast }
- while true do
- local len = #list
- if len == 0 then
- return
- end
- local obj = list[len]
- list[len] = nil
- callback(obj)
- m.addChilds(list, obj, m.childMap)
- end
-end
-
---- 获取指定的 special
-function m.eachSpecialOf(ast, name, callback)
- local root = m.getRoot(ast)
- if not root.specials then
- return
- end
- local specials = root.specials[name]
- if not specials then
- return
- end
- for i = 1, #specials do
- callback(specials[i])
- end
-end
-
---- 获取偏移对应的坐标
----@param lines table
----@return integer {name = 'row'}
----@return integer {name = 'col'}
-function m.positionOf(lines, offset)
- if offset < 1 then
- return 0, 0
- end
- local lastLine = lines[#lines]
- if offset > lastLine.finish then
- return #lines, lastLine.finish - lastLine.start + 1
- end
- local min = 1
- local max = #lines
- for _ = 1, 100 do
- if max <= min then
- local line = lines[min]
- return min, offset - line.start + 1
- 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 + 1
- end
- end
- error('Stack overflow!')
-end
-
---- 获取坐标对应的偏移
----@param lines table
----@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.finish - line.start + 1
- if col < 0 then
- return line.start
- elseif col > len then
- return line.finish
- else
- return line.start + col - 1
- end
-end
-
-function m.lineContent(lines, text, row)
- local line = lines[row]
- if not line then
- return ''
- end
- return text:sub(line.start, line.finish)
-end
-
-function m.lineRange(lines, row)
- local line = lines[row]
- if not line then
- return 0, 0
- end
- return line.start, line.finish
-end
-
-function m.getName(obj)
- local tp = obj.type
- if tp == 'getglobal'
- or tp == 'setglobal' then
- return obj[1]
- elseif tp == 'local'
- or tp == 'getlocal'
- or tp == 'setlocal' then
- return obj[1]
- elseif tp == 'getfield'
- or tp == 'setfield'
- or tp == 'tablefield' then
- return obj.field[1]
- elseif tp == 'getmethod'
- or tp == 'setmethod' then
- return obj.method[1]
- elseif tp == 'getindex'
- or tp == 'setindex'
- or tp == 'tableindex' then
- return m.getName(obj.index)
- elseif tp == 'field'
- or tp == 'method' then
- return obj[1]
- elseif tp == 'index' then
- return m.getName(obj.index)
- elseif tp == 'string' then
- return obj[1]
- end
- return nil
-end
-
-function m.getKeyName(obj)
- local tp = obj.type
- if tp == 'getglobal'
- or tp == 'setglobal' then
- return 's|' .. obj[1]
- elseif tp == 'getfield'
- or tp == 'setfield'
- or tp == 'tablefield' then
- if obj.field then
- return 's|' .. obj.field[1]
- end
- elseif tp == 'getmethod'
- or tp == 'setmethod' then
- if obj.method then
- return 's|' .. obj.method[1]
- end
- elseif tp == 'getindex'
- or tp == 'setindex'
- or tp == 'tableindex' then
- if obj.index then
- return m.getKeyName(obj.index)
- end
- elseif tp == 'field'
- or tp == 'method' then
- return 's|' .. obj[1]
- elseif tp == 'string' then
- local s = obj[1]
- if s then
- return 's|' .. s
- else
- return s
- end
- elseif tp == 'number' then
- local n = obj[1]
- if n then
- return ('n|%q'):format(obj[1])
- else
- return 'n'
- end
- elseif tp == 'boolean' then
- local b = obj[1]
- if b then
- return 'b|' .. tostring(b)
- else
- return 'b'
- end
- end
- return nil
-end
-
-function m.getENV(ast)
- if ast.type ~= 'main' then
- return nil
- end
- return ast.locals[1]
-end
-
---- 测试 a 到 b 的路径(不经过函数,不考虑 goto),
---- 每个路径是一个 block 。
----
---- 如果 a 在 b 的前面,返回 `"before"` 加上 2个`list<block>`
----
---- 如果 a 在 b 的后面,返回 `"after"` 加上 2个`list<block>`
----
---- 否则返回 `false`
----
---- 返回的2个 `list` 分别为基准block到达 a 与 b 的路径。
----@param a table
----@param b table
----@return string|boolean mode
----@return table|nil pathA
----@return table|nil pathB
-function m.getPath(a, b)
- --- 首先测试双方在同一个函数内
- if m.getParentFunction(a) ~= m.getParentFunction(b) then
- return false
- end
- local mode
- local objA
- local objB
- if a.finish < b.start then
- mode = 'before'
- objA = a
- objB = b
- elseif a.start > b.finish then
- mode = 'after'
- objA = b
- objB = a
- else
- return 'equal', {}, {}
- end
- local pathA = {}
- local pathB = {}
- for _ = 1, 1000 do
- objA = m.getParentBlock(objA)
- pathA[#pathA+1] = objA
- if objA.type == 'function' or objA.type == 'main' then
- break
- end
- end
- for _ = 1, 1000 do
- objB = m.getParentBlock(objB)
- pathB[#pathB+1] = objB
- if objB.type == 'function' or objB.type == 'main' then
- break
- end
- end
- -- pathA: {1, 2, 3, 4, 5}
- -- pathB: {5, 6, 2, 3}
- local top = #pathB
- local start
- for i = #pathA, 1, -1 do
- local currentBlock = pathA[i]
- if currentBlock == pathB[top] then
- start = i
- break
- end
- end
- -- pathA: { 1, 2, 3}
- -- pathB: {5, 6, 2, 3}
- local extra = 0
- local align = top - start
- for i = start, 1, -1 do
- local currentA = pathA[i]
- local currentB = pathB[i+align]
- if currentA ~= currentB then
- extra = i
- break
- end
- end
- -- pathA: {1}
- local resultA = {}
- for i = extra, 1, -1 do
- resultA[#resultA+1] = pathA[i]
- end
- -- pathB: {5, 6}
- local resultB = {}
- for i = extra + align, 1, -1 do
- resultB[#resultB+1] = pathB[i]
- end
- return mode, resultA, resultB
-end
-
-return m
diff --git a/server-beta/src/parser/init.lua b/server-beta/src/parser/init.lua
deleted file mode 100644
index 5eeb0da2..00000000
--- a/server-beta/src/parser/init.lua
+++ /dev/null
@@ -1,11 +0,0 @@
-local api = {
- grammar = require 'parser.grammar',
- parse = require 'parser.parse',
- compile = require 'parser.compile',
- split = require 'parser.split',
- calcline = require 'parser.calcline',
- lines = require 'parser.lines',
- guide = require 'parser.guide',
-}
-
-return api
diff --git a/server-beta/src/parser/lines.lua b/server-beta/src/parser/lines.lua
deleted file mode 100644
index c7961d13..00000000
--- a/server-beta/src/parser/lines.lua
+++ /dev/null
@@ -1,46 +0,0 @@
-local m = require 'lpeglabel'
-local utf8Len = utf8.len
-
-_ENV = nil
-
-local function Line(start, line, range, finish)
- line.start = start
- line.finish = finish - 1
- line.range = range - 1
- return line
-end
-
-local function Space(...)
- local line = {...}
- local sp = 0
- local tab = 0
- for i = 1, #line do
- if line[i] == ' ' then
- sp = sp + 1
- elseif line[i] == '\t' then
- tab = tab + 1
- end
- line[i] = nil
- end
- line.sp = sp
- line.tab = tab
- return line
-end
-
-local parser = m.P{
-'Lines',
-Lines = m.Ct(m.V'Line'^0 * m.V'LastLine'),
-Line = m.Cp() * m.V'Indent' * (1 - m.V'Nl')^0 * m.Cp() * m.V'Nl' * m.Cp() / Line,
-LastLine= m.Cp() * m.V'Indent' * (1 - m.V'Nl')^0 * m.Cp() * m.Cp() / Line,
-Nl = m.P'\r\n' + m.S'\r\n',
-Indent = m.C(m.S' \t')^0 / Space,
-}
-
-return function (self, text)
- local lines, err = parser:match(text)
- if not lines then
- return nil, err
- end
-
- return lines
-end
diff --git a/server-beta/src/parser/parse.lua b/server-beta/src/parser/parse.lua
deleted file mode 100644
index bbc01b10..00000000
--- a/server-beta/src/parser/parse.lua
+++ /dev/null
@@ -1,45 +0,0 @@
-local ast = require 'parser.ast'
-
-return function (self, lua, mode, version)
- local errs = {}
- local diags = {}
- local state = {
- version = version,
- lua = lua,
- emmy = {},
- root = {},
- errs = errs,
- diags = diags,
- pushError = function (err)
- 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,
- pushDiag = function (code, info)
- if not diags[code] then
- diags[code] = {}
- end
- diags[code][#diags[code]+1] = info
- end
- }
- ast.init(state)
- local suc, res, err = xpcall(self.grammar, debug.traceback, self, lua, mode)
- ast.close()
- if not suc then
- return nil, res
- end
- if not res then
- state.pushError(err)
- end
- state.ast = res
- return state
-end
diff --git a/server-beta/src/parser/relabel.lua b/server-beta/src/parser/relabel.lua
deleted file mode 100644
index ac902403..00000000
--- a/server-beta/src/parser/relabel.lua
+++ /dev/null
@@ -1,361 +0,0 @@
--- $Id: re.lua,v 1.44 2013/03/26 20:11:40 roberto Exp $
-
--- imported functions and modules
-local tonumber, type, print, error = tonumber, type, print, error
-local pcall = pcall
-local setmetatable = setmetatable
-local tinsert, concat = table.insert, table.concat
-local rep = string.rep
-local m = require"lpeglabel"
-
--- 'm' will be used to parse expressions, and 'mm' will be used to
--- create expressions; that is, 're' runs on 'm', creating patterns
--- on 'mm'
-local mm = m
-
--- pattern's metatable
-local mt = getmetatable(mm.P(0))
-
-
-
--- No more global accesses after this point
-_ENV = nil
-
-
-local any = m.P(1)
-local dummy = mm.P(false)
-
-
-local errinfo = {
- NoPatt = "no pattern found",
- ExtraChars = "unexpected characters after the pattern",
-
- ExpPatt1 = "expected a pattern after '/'",
-
- ExpPatt2 = "expected a pattern after '&'",
- ExpPatt3 = "expected a pattern after '!'",
-
- ExpPatt4 = "expected a pattern after '('",
- ExpPatt5 = "expected a pattern after ':'",
- ExpPatt6 = "expected a pattern after '{~'",
- ExpPatt7 = "expected a pattern after '{|'",
-
- ExpPatt8 = "expected a pattern after '<-'",
-
- ExpPattOrClose = "expected a pattern or closing '}' after '{'",
-
- ExpNumName = "expected a number, '+', '-' or a name (no space) after '^'",
- ExpCap = "expected a string, number, '{}' or name after '->'",
-
- ExpName1 = "expected the name of a rule after '=>'",
- ExpName2 = "expected the name of a rule after '=' (no space)",
- ExpName3 = "expected the name of a rule after '<' (no space)",
-
- ExpLab1 = "expected a label after '{'",
-
- ExpNameOrLab = "expected a name or label after '%' (no space)",
-
- ExpItem = "expected at least one item after '[' or '^'",
-
- MisClose1 = "missing closing ')'",
- MisClose2 = "missing closing ':}'",
- MisClose3 = "missing closing '~}'",
- MisClose4 = "missing closing '|}'",
- MisClose5 = "missing closing '}'", -- for the captures
-
- MisClose6 = "missing closing '>'",
- MisClose7 = "missing closing '}'", -- for the labels
-
- MisClose8 = "missing closing ']'",
-
- MisTerm1 = "missing terminating single quote",
- MisTerm2 = "missing terminating double quote",
-}
-
-local function expect (pattern, label)
- return pattern + m.T(label)
-end
-
-
--- Pre-defined names
-local Predef = { nl = m.P"\n" }
-
-
-local mem
-local fmem
-local gmem
-
-
-local function updatelocale ()
- mm.locale(Predef)
- Predef.a = Predef.alpha
- Predef.c = Predef.cntrl
- Predef.d = Predef.digit
- Predef.g = Predef.graph
- Predef.l = Predef.lower
- Predef.p = Predef.punct
- Predef.s = Predef.space
- Predef.u = Predef.upper
- Predef.w = Predef.alnum
- Predef.x = Predef.xdigit
- Predef.A = any - Predef.a
- Predef.C = any - Predef.c
- Predef.D = any - Predef.d
- Predef.G = any - Predef.g
- Predef.L = any - Predef.l
- Predef.P = any - Predef.p
- Predef.S = any - Predef.s
- Predef.U = any - Predef.u
- Predef.W = any - Predef.w
- Predef.X = any - Predef.x
- mem = {} -- restart memoization
- fmem = {}
- gmem = {}
- local mt = {__mode = "v"}
- setmetatable(mem, mt)
- setmetatable(fmem, mt)
- setmetatable(gmem, mt)
-end
-
-
-updatelocale()
-
-
-
-local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end)
-
-
-local function getdef (id, defs)
- local c = defs and defs[id]
- if not c then
- error("undefined name: " .. id)
- end
- return c
-end
-
-
-local function mult (p, n)
- local np = mm.P(true)
- while n >= 1 do
- if n%2 >= 1 then np = np * p end
- p = p * p
- n = n/2
- end
- return np
-end
-
-local function equalcap (s, i, c)
- if type(c) ~= "string" then return nil end
- local e = #c + i
- if s:sub(i, e - 1) == c then return e else return nil end
-end
-
-
-local S = (Predef.space + "--" * (any - Predef.nl)^0)^0
-
-local name = m.C(m.R("AZ", "az", "__") * m.R("AZ", "az", "__", "09")^0)
-
-local arrow = S * "<-"
-
--- a defined name only have meaning in a given environment
-local Def = name * m.Carg(1)
-
-local num = m.C(m.R"09"^1) * S / tonumber
-
-local String = "'" * m.C((any - "'" - m.P"\n")^0) * expect("'", "MisTerm1")
- + '"' * m.C((any - '"' - m.P"\n")^0) * expect('"', "MisTerm2")
-
-
-local defined = "%" * Def / function (c,Defs)
- local cat = Defs and Defs[c] or Predef[c]
- if not cat then
- error("name '" .. c .. "' undefined")
- end
- return cat
-end
-
-local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R
-
-local item = defined + Range + m.C(any - m.P"\n")
-
-local Class =
- "["
- * (m.C(m.P"^"^-1)) -- optional complement symbol
- * m.Cf(expect(item, "ExpItem") * (item - "]")^0, mt.__add)
- / function (c, p) return c == "^" and any - p or p end
- * expect("]", "MisClose8")
-
-local function adddef (t, k, exp)
- if t[k] then
- -- TODO 改了一下这里的代码,重复定义不会抛错
- --error("'"..k.."' already defined as a rule")
- else
- t[k] = exp
- end
- return t
-end
-
-local function firstdef (n, r) return adddef({n}, n, r) end
-
-
-local function NT (n, b)
- if not b then
- error("rule '"..n.."' used outside a grammar")
- else return mm.V(n)
- end
-end
-
-
-local exp = m.P{ "Exp",
- Exp = S * ( m.V"Grammar"
- + m.Cf(m.V"Seq" * (S * "/" * expect(S * m.V"Seq", "ExpPatt1"))^0, mt.__add) );
- Seq = m.Cf(m.Cc(m.P"") * m.V"Prefix" * (S * m.V"Prefix")^0, mt.__mul);
- Prefix = "&" * expect(S * m.V"Prefix", "ExpPatt2") / mt.__len
- + "!" * expect(S * m.V"Prefix", "ExpPatt3") / mt.__unm
- + m.V"Suffix";
- Suffix = m.Cf(m.V"Primary" *
- ( S * ( m.P"+" * m.Cc(1, mt.__pow)
- + m.P"*" * m.Cc(0, mt.__pow)
- + m.P"?" * m.Cc(-1, mt.__pow)
- + "^" * expect( m.Cg(num * m.Cc(mult))
- + m.Cg(m.C(m.S"+-" * m.R"09"^1) * m.Cc(mt.__pow)
- + name * m.Cc"lab"
- ),
- "ExpNumName")
- + "->" * expect(S * ( m.Cg((String + num) * m.Cc(mt.__div))
- + m.P"{}" * m.Cc(nil, m.Ct)
- + m.Cg(Def / getdef * m.Cc(mt.__div))
- ),
- "ExpCap")
- + "=>" * expect(S * m.Cg(Def / getdef * m.Cc(m.Cmt)),
- "ExpName1")
- )
- )^0, function (a,b,f) if f == "lab" then return a + mm.T(b) else return f(a,b) end end );
- Primary = "(" * expect(m.V"Exp", "ExpPatt4") * expect(S * ")", "MisClose1")
- + String / mm.P
- + Class
- + defined
- + "%" * expect(m.P"{", "ExpNameOrLab")
- * expect(S * m.V"Label", "ExpLab1")
- * expect(S * "}", "MisClose7") / mm.T
- + "{:" * (name * ":" + m.Cc(nil)) * expect(m.V"Exp", "ExpPatt5")
- * expect(S * ":}", "MisClose2")
- / function (n, p) return mm.Cg(p, n) end
- + "=" * expect(name, "ExpName2")
- / function (n) return mm.Cmt(mm.Cb(n), equalcap) end
- + m.P"{}" / mm.Cp
- + "{~" * expect(m.V"Exp", "ExpPatt6")
- * expect(S * "~}", "MisClose3") / mm.Cs
- + "{|" * expect(m.V"Exp", "ExpPatt7")
- * expect(S * "|}", "MisClose4") / mm.Ct
- + "{" * expect(m.V"Exp", "ExpPattOrClose")
- * expect(S * "}", "MisClose5") / mm.C
- + m.P"." * m.Cc(any)
- + (name * -arrow + "<" * expect(name, "ExpName3")
- * expect(">", "MisClose6")) * m.Cb("G") / NT;
- Label = num + name;
- Definition = name * arrow * expect(m.V"Exp", "ExpPatt8");
- Grammar = m.Cg(m.Cc(true), "G")
- * m.Cf(m.V"Definition" / firstdef * (S * m.Cg(m.V"Definition"))^0,
- adddef) / mm.P;
-}
-
-local pattern = S * m.Cg(m.Cc(false), "G") * expect(exp, "NoPatt") / mm.P
- * S * expect(-any, "ExtraChars")
-
-local function lineno (s, i)
- if i == 1 then return 1, 1 end
- local adjustment = 0
- -- report the current line if at end of line, not the next
- if s:sub(i,i) == '\n' then
- i = i-1
- adjustment = 1
- end
- local rest, num = s:sub(1,i):gsub("[^\n]*\n", "")
- local r = #rest
- return 1 + num, (r ~= 0 and r or 1) + adjustment
-end
-
-local function calcline (s, i)
- if i == 1 then return 1, 1 end
- local rest, line = s:sub(1,i):gsub("[^\n]*\n", "")
- local col = #rest
- return 1 + line, col ~= 0 and col or 1
-end
-
-
-local function splitlines(str)
- local t = {}
- local function helper(line) tinsert(t, line) return "" end
- helper((str:gsub("(.-)\r?\n", helper)))
- return t
-end
-
-local function compile (p, defs)
- if mm.type(p) == "pattern" then return p end -- already compiled
- p = p .. " " -- for better reporting of column numbers in errors when at EOF
- local ok, cp, label, poserr = pcall(function() return pattern:match(p, 1, defs) end)
- if not ok and cp then
- if type(cp) == "string" then
- cp = cp:gsub("^[^:]+:[^:]+: ", "")
- end
- error(cp, 3)
- end
- if not cp then
- local lines = splitlines(p)
- local line, col = lineno(p, poserr)
- local err = {}
- tinsert(err, "L" .. line .. ":C" .. col .. ": " .. errinfo[label])
- tinsert(err, lines[line])
- tinsert(err, rep(" ", col-1) .. "^")
- error("syntax error(s) in pattern\n" .. concat(err, "\n"), 3)
- end
- return cp
-end
-
-local function match (s, p, i)
- local cp = mem[p]
- if not cp then
- cp = compile(p)
- mem[p] = cp
- end
- return cp:match(s, i or 1)
-end
-
-local function find (s, p, i)
- local cp = fmem[p]
- if not cp then
- cp = compile(p) / 0
- cp = mm.P{ mm.Cp() * cp * mm.Cp() + 1 * mm.V(1) }
- fmem[p] = cp
- end
- local i, e = cp:match(s, i or 1)
- if i then return i, e - 1
- else return i
- end
-end
-
-local function gsub (s, p, rep)
- local g = gmem[p] or {} -- ensure gmem[p] is not collected while here
- gmem[p] = g
- local cp = g[rep]
- if not cp then
- cp = compile(p)
- cp = mm.Cs((cp / rep + 1)^0)
- g[rep] = cp
- end
- return cp:match(s)
-end
-
-
--- exported names
-local re = {
- compile = compile,
- match = match,
- find = find,
- gsub = gsub,
- updatelocale = updatelocale,
- calcline = calcline
-}
-
-return re
diff --git a/server-beta/src/parser/split.lua b/server-beta/src/parser/split.lua
deleted file mode 100644
index 6ce4a4e7..00000000
--- a/server-beta/src/parser/split.lua
+++ /dev/null
@@ -1,9 +0,0 @@
-local m = require 'lpeglabel'
-
-local NL = m.P'\r\n' + m.S'\r\n'
-local LINE = m.C(1 - NL)
-
-return function (str)
- local MATCH = m.Ct((LINE * NL)^0 * LINE)
- return MATCH:match(str)
-end
diff --git a/server-beta/src/proto/define.lua b/server-beta/src/proto/define.lua
deleted file mode 100644
index 61c4037c..00000000
--- a/server-beta/src/proto/define.lua
+++ /dev/null
@@ -1,140 +0,0 @@
-local guide = require 'parser.guide'
-
-local m = {}
-
---- 获取 position 对应的光标位置
----@param lines table
----@param text string
----@param position position
----@return integer
-function m.offset(lines, text, position)
- local row = position.line + 1
- local start = guide.lineRange(lines, row)
- local offset = utf8.offset(text, position.character + 1, start)
- if text:sub(offset-1, offset):match '[%w_][^%w_]' then
- offset = offset - 1
- end
- return offset
-end
-
---- 将光标位置转化为 position
----@alias position table
----@param lines table
----@param text string
----@param offset integer
----@return position
-function m.position(lines, text, offset)
- local row, col = guide.positionOf(lines, offset)
- local start = guide.lineRange(lines, row)
- if start < 1 then
- start = 1
- end
- local ucol = utf8.len(text, start, start + col - 1, true)
- if row < 1 then
- row = 1
- end
- return {
- line = row - 1,
- character = ucol,
- }
-end
-
---- 将起点与终点位置转化为 range
----@alias range table
----@param lines table
----@param text string
----@param offset1 integer
----@param offset2 integer
-function m.range(lines, text, offset1, offset2)
- local range = {
- start = m.position(lines, text, offset1),
- ['end'] = m.position(lines, text, offset2),
- }
- if range.start.character > 0 then
- range.start.character = range.start.character - 1
- end
- return range
-end
-
----@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,
- Warning = 2,
- Information = 3,
- Hint = 4,
-}
-
---- 诊断类型与默认等级
-m.DiagnosticDefaultSeverity = {
- ['unused-local'] = 'Hint',
- ['unused-function'] = 'Hint',
- ['undefined-global'] = 'Warning',
- ['global-in-nil-env'] = 'Warning',
- ['unused-label'] = 'Hint',
- ['unused-vararg'] = 'Hint',
- ['trailing-space'] = 'Hint',
- ['redefined-local'] = 'Hint',
- ['newline-call'] = 'Information',
- ['newfield-call'] = 'Warning',
- ['redundant-parameter'] = 'Hint',
- ['ambiguity-1'] = 'Warning',
- ['lowercase-global'] = 'Information',
- ['undefined-env-child'] = 'Information',
- ['duplicate-index'] = 'Warning',
- ['empty-block'] = 'Hint',
- ['redundant-value'] = 'Hint',
- ['emmy-lua'] = 'Warning',
-}
-
---- 诊断报告标签
-m.DiagnosticTag = {
- Unnecessary = 1,
- Deprecated = 2,
-}
-
-m.DocumentHighlightKind = {
- Text = 1,
- Read = 2,
- Write = 3,
-}
-
-m.MessageType = {
- Error = 1,
- Warning = 2,
- Info = 3,
- Log = 4,
-}
-
-return m
diff --git a/server-beta/src/proto/init.lua b/server-beta/src/proto/init.lua
deleted file mode 100644
index 33e637f6..00000000
--- a/server-beta/src/proto/init.lua
+++ /dev/null
@@ -1,3 +0,0 @@
-local proto = require 'proto.proto'
-
-return proto
diff --git a/server-beta/src/proto/proto.lua b/server-beta/src/proto/proto.lua
deleted file mode 100644
index f04653d5..00000000
--- a/server-beta/src/proto/proto.lua
+++ /dev/null
@@ -1,133 +0,0 @@
-local subprocess = require 'bee.subprocess'
-local util = require 'utility'
-local await = require 'await'
-local pub = require 'pub'
-local jsonrpc = require 'jsonrpc'
-local ErrorCodes = require 'define.ErrorCodes'
-
-local reqCounter = util.counter()
-
-local m = {}
-
-m.ability = {}
-m.waiting = {}
-
-function m.getMethodName(proto)
- if proto.method:sub(1, 2) == '$/' then
- return proto.method:sub(3), true
- else
- return proto.method, false
- end
-end
-
-function m.on(method, callback)
- m.ability[method] = callback
-end
-
-function m.response(id, res)
- if id == nil then
- log.error('Response id is nil!', util.dump(res))
- return
- end
- -- res 可能是nil,为了转成json时保留nil,使用 container 容器
- local data = util.container()
- data.id = id
- data.result = res
- local buf = jsonrpc.encode(data)
- log.debug('Response', id, #buf)
- io.stdout:write(buf)
-end
-
-function m.responseErr(id, code, message)
- if id == nil then
- log.error('Response id is nil!', util.dump(message))
- return
- end
- local buf = jsonrpc.encode {
- id = id,
- error = {
- code = code,
- message = message,
- }
- }
- log.debug('ResponseErr', id, #buf)
- io.stdout:write(buf)
-end
-
-function m.notify(name, params)
- local buf = jsonrpc.encode {
- method = name,
- params = params,
- }
- log.debug('Notify', name, #buf)
- io.stdout:write(buf)
-end
-
-function m.awaitRequest(name, params)
- local id = reqCounter()
- local buf = jsonrpc.encode {
- id = id,
- method = name,
- params = params,
- }
- log.debug('Request', name, #buf)
- io.stdout:write(buf)
- return await.wait(function (waker)
- m.waiting[id] = waker
- end)
-end
-
-function m.doMethod(proto)
- local method, optional = m.getMethodName(proto)
- local abil = m.ability[method]
- if not abil then
- if not optional then
- log.warn('Recieved unknown proto: ' .. method)
- end
- if proto.id then
- m.responseErr(proto.id, ErrorCodes.MethodNotFound, method)
- end
- return
- end
- await.create(function ()
- local clock = os.clock()
- local ok, res = xpcall(abil, log.error, proto.params)
- local passed = os.clock() - clock
- if passed > 0.2 then
- log.debug(('Method [%s] takes [%.3f]sec.'):format(method, passed))
- end
- if not proto.id then
- return
- end
- if ok then
- m.response(proto.id, res)
- else
- m.responseErr(proto.id, ErrorCodes.InternalError, res)
- end
- end)
-end
-
-function m.doResponse(proto)
- local id = proto.id
- local waker = m.waiting[id]
- if not waker then
- log.warn('Response id not found: ' .. util.dump(proto))
- return
- end
- m.waiting[id] = nil
- if proto.error then
- log.warn(('Response error [%d]: %s'):format(proto.error.code, proto.error.message))
- return
- end
- waker(proto.result)
-end
-
-function m.listen()
- subprocess.filemode(io.stdin, 'b')
- subprocess.filemode(io.stdout, 'b')
- io.stdin:setvbuf 'no'
- io.stdout:setvbuf 'no'
- pub.task('loadProto')
-end
-
-return m
diff --git a/server-beta/src/provider/capability.lua b/server-beta/src/provider/capability.lua
deleted file mode 100644
index aa95c758..00000000
--- a/server-beta/src/provider/capability.lua
+++ /dev/null
@@ -1,42 +0,0 @@
-local m = {}
-
-m.initer = {
- -- 文本同步方式
- textDocumentSync = {
- -- 打开关闭文本时通知
- openClose = true,
- -- 文本改变时完全通知 TODO 支持差量更新(2)
- change = 1,
- },
-
- hoverProvider = true,
- definitionProvider = true,
- referencesProvider = true,
- renameProvider = {
- prepareProvider = true,
- },
- --documentSymbolProvider = true,
- documentHighlightProvider = true,
- --codeActionProvider = true,
- --signatureHelpProvider = {
- -- triggerCharacters = { '(', ',' },
- --},
- --workspace = {
- -- workspaceFolders = {
- -- supported = true,
- -- changeNotifications = true,
- -- }
- --},
- --documentOnTypeFormattingProvider = {
- -- firstTriggerCharacter = '}',
- --},
- --executeCommandProvider = {
- -- commands = {
- -- 'config',
- -- 'removeSpace',
- -- 'solve',
- -- },
- --},
-}
-
-return m
diff --git a/server-beta/src/provider/completion.lua b/server-beta/src/provider/completion.lua
deleted file mode 100644
index d2df44d2..00000000
--- a/server-beta/src/provider/completion.lua
+++ /dev/null
@@ -1,53 +0,0 @@
-local proto = require 'proto'
-
-local isEnable = false
-
-local function allWords()
- local str = [[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:('"[,#*@| ]]
- local list = {}
- for c in str:gmatch '.' do
- list[#list+1] = c
- end
- return list
-end
-
-local function enable()
- if isEnable then
- return
- end
- isEnable = true
- log.debug('Enable completion.')
- proto.awaitRequest('client/registerCapability', {
- registrations = {
- {
- id = 'completion',
- method = 'textDocument/completion',
- registerOptions = {
- resolveProvider = false,
- triggerCharacters = allWords(),
- },
- },
- }
- })
-end
-
-local function disable()
- if not isEnable then
- return
- end
- isEnable = false
- log.debug('Disable completion.')
- proto.awaitRequest('client/unregisterCapability', {
- unregisterations = {
- {
- id = 'completion',
- method = 'textDocument/completion',
- },
- }
- })
-end
-
-return {
- enable = enable,
- disable = disable,
-}
diff --git a/server-beta/src/provider/diagnostic.lua b/server-beta/src/provider/diagnostic.lua
deleted file mode 100644
index ba95f2bf..00000000
--- a/server-beta/src/provider/diagnostic.lua
+++ /dev/null
@@ -1,209 +0,0 @@
-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 m = {}
-m._start = false
-m.cache = {}
-
-local function concat(t, sep)
- if type(t) ~= 'table' then
- return t
- end
- return table.concat(t, sep)
-end
-
-local function buildSyntaxError(uri, err)
- local lines = files.getLines(uri)
- local text = files.getText(uri)
- local message = lang.script('PARSER_'..err.type, err.info)
-
- if err.version then
- local version = err.info and err.info.version or config.config.runtime.version
- message = message .. ('(%s)'):format(lang.script('DIAG_NEED_VERSION'
- , concat(err.version, '/')
- , version
- ))
- end
-
- local related = err.info and err.info.related
- local relatedInformation
- if related then
- relatedInformation = {}
- for _, rel in ipairs(related) do
- local rmessage
- if rel.message then
- rmessage = lang.script('PARSER_'..rel.message)
- else
- rmessage = text:sub(rel.start, rel.finish)
- end
- relatedInformation[#relatedInformation+1] = {
- message = rmessage,
- location = define.location(uri, define.range(lines, text, rel.start, rel.finish)),
- }
- end
- end
-
- return {
- range = define.range(lines, text, err.start, err.finish),
- severity = define.DiagnosticSeverity.Error,
- source = lang.script.DIAG_SYNTAX_CHECK,
- message = message,
- relatedInformation = relatedInformation,
- }
-end
-
-local function buildDiagnostic(uri, diag)
- local lines = files.getLines(uri)
- local text = files.getText(uri)
-
- local relatedInformation
- if diag.related then
- relatedInformation = {}
- for _, rel in ipairs(diag.related) do
- local rtext = files.getText(rel.uri)
- local rlines = files.getLines(rel.uri)
- relatedInformation[#relatedInformation+1] = {
- message = rel.message or rtext:sub(rel.start, rel.finish),
- location = define.location(rel.uri, define.range(rlines, rtext, rel.start, rel.finish))
- }
- end
- end
-
- return {
- range = define.range(lines, text, diag.start, diag.finish),
- source = lang.script.DIAG_DIAGNOSTICS,
- severity = diag.level,
- message = diag.message,
- code = diag.code,
- tags = diag.tags,
- relatedInformation = relatedInformation,
- }
-end
-
-local function merge(a, b)
- if not a and not b then
- return nil
- end
- local t = {}
- if a then
- for i = 1, #a do
- t[#t+1] = a[i]
- end
- end
- if b then
- for i = 1, #b do
- t[#t+1] = b[i]
- end
- end
- return t
-end
-
-function m.clear(uri)
- if not m.cache[uri] then
- return
- end
- m.cache[uri] = nil
- proto.notify('textDocument/publishDiagnostics', {
- uri = uri,
- diagnostics = {},
- })
-end
-
-function m.syntaxErrors(uri, ast)
- if #ast.errs == 0 then
- return nil
- end
-
- local results = {}
-
- for _, err in ipairs(ast.errs) do
- results[#results+1] = buildSyntaxError(uri, err)
- end
-
- return results
-end
-
-function m.diagnostics(uri, syntaxOnly)
- if syntaxOnly or not m._start then
- return m.cache[uri]
- end
-
- local diags = core(uri)
- if not diags then
- return nil
- end
-
- local results = {}
- for _, diag in ipairs(diags) do
- results[#results+1] = buildDiagnostic(uri, diag)
- end
-
- return results
-end
-
-function m.doDiagnostic(uri, syntaxOnly)
- local ast = files.getAst(uri)
- if not ast then
- m.clear(uri)
- return
- end
-
- local syntax = m.syntaxErrors(uri, ast)
- local diagnostics = m.diagnostics(uri, syntaxOnly)
- local full = merge(syntax, diagnostics)
- if not full then
- m.clear(uri)
- return
- end
-
- if util.equal(m.cache[uri], full) then
- return
- end
- m.cache[uri] = full
-
- proto.notify('textDocument/publishDiagnostics', {
- uri = uri,
- diagnostics = full,
- })
-end
-
-function m.refresh(uri)
- await.create(function ()
- await.delay(function ()
- return files.globalVersion
- end)
- if uri then
- m.doDiagnostic(uri, true)
- end
- if not m._start then
- return
- end
- local clock = os.clock()
- if uri then
- m.doDiagnostic(uri)
- end
- for destUri in files.eachFile() do
- if destUri ~= uri then
- m.doDiagnostic(files.getOriginUri(destUri))
- await.delay(function ()
- return files.globalVersion
- end)
- end
- end
- local passed = os.clock() - clock
- log.info(('Finish diagnostics, takes [%.3f] sec.'):format(passed))
- end)
-end
-
-function m.start()
- m._start = true
- m.refresh()
-end
-
-return m
diff --git a/server-beta/src/provider/init.lua b/server-beta/src/provider/init.lua
deleted file mode 100644
index 95f4b3d1..00000000
--- a/server-beta/src/provider/init.lua
+++ /dev/null
@@ -1,298 +0,0 @@
-local util = require 'utility'
-local cap = require 'provider.capability'
-local completion= require 'provider.completion'
-local await = require 'await'
-local files = require 'files'
-local proto = require 'proto.proto'
-local define = require 'proto.define'
-local workspace = require 'workspace'
-local config = require 'config'
-local library = require 'library'
-local markdown = require 'provider.markdown'
-
-local function updateConfig()
- local configs = proto.awaitRequest('workspace/configuration', {
- items = {
- {
- scopeUri = workspace.uri,
- section = 'Lua',
- },
- {
- scopeUri = workspace.uri,
- section = 'files.associations',
- },
- {
- scopeUri = workspace.uri,
- section = 'files.exclude',
- }
- },
- })
-
- local updated = configs[1]
- local other = {
- associations = configs[2],
- exclude = configs[3],
- }
-
- local oldConfig = util.deepCopy(config.config)
- local oldOther = util.deepCopy(config.other)
- config.setConfig(updated, other)
- local newConfig = config.config
- local newOther = config.other
- if not util.equal(oldConfig.runtime, newConfig.runtime) then
- library.reload()
- end
- if not util.equal(oldConfig.diagnostics, newConfig.diagnostics) then
- end
- if not util.equal(oldConfig.plugin, newConfig.plugin) then
- end
- if not util.equal(oldConfig.workspace, newConfig.workspace)
- or not util.equal(oldConfig.plugin, newConfig.plugin)
- or not util.equal(oldOther.associations, newOther.associations)
- or not util.equal(oldOther.exclude, newOther.exclude)
- then
- end
-
- if newConfig.completion.enable then
- --completion.enable()
- else
- completion.disable()
- end
-end
-
-proto.on('initialize', function (params)
- --log.debug(util.dump(params))
- if params.workspaceFolders then
- local name = params.workspaceFolders[1].name
- local uri = params.workspaceFolders[1].uri
- workspace.init(name, uri)
- end
- return {
- capabilities = cap.initer,
- }
-end)
-
-proto.on('initialized', function (params)
- updateConfig()
- proto.awaitRequest('client/registerCapability', {
- registrations = {
- -- 监视文件变化
- {
- id = '0',
- method = 'workspace/didChangeWatchedFiles',
- registerOptions = {
- watchers = {
- {
- globPattern = '**/',
- kind = 1 | 2 | 4,
- }
- },
- },
- },
- -- 配置变化
- {
- id = '1',
- method = 'workspace/didChangeConfiguration',
- }
- }
- })
- await.create(workspace.awaitPreload)
- return true
-end)
-
-proto.on('exit', function ()
- log.info('Server exited.')
- os.exit(true)
-end)
-
-proto.on('shutdown', function ()
- log.info('Server shutdown.')
- return true
-end)
-
-proto.on('workspace/configuration', function ()
- updateConfig()
-end)
-
-proto.on('workspace/didChangeWatchedFiles', function (params)
-end)
-
-proto.on('textDocument/didOpen', function (params)
- local doc = params.textDocument
- local uri = doc.uri
- local text = doc.text
- files.open(uri)
- files.setText(uri, text)
-end)
-
-proto.on('textDocument/didClose', function (params)
- local doc = params.textDocument
- local uri = doc.uri
- files.close(uri)
- if not files.isLua(uri) then
- files.remove(uri)
- end
-end)
-
-proto.on('textDocument/didChange', function (params)
- local doc = params.textDocument
- local change = params.contentChanges
- local uri = doc.uri
- local text = change[1].text
- if files.isLua(uri) or files.isOpen(uri) then
- files.setText(uri, text)
- end
-end)
-
-proto.on('textDocument/hover', function (params)
- local core = require 'core.hover'
- local doc = params.textDocument
- local uri = doc.uri
- if not files.exists(uri) then
- return nil
- end
- local lines = files.getLines(uri)
- local text = files.getText(uri)
- local offset = define.offset(lines, text, params.position)
- local hover = core(uri, offset)
- if not hover then
- return nil
- end
- local md = markdown()
- md:add('lua', hover.label)
- return {
- contents = {
- value = md:string(),
- kind = 'markdown',
- },
- range = define.range(lines, text, hover.source.start, hover.source.finish),
- }
-end)
-
-proto.on('textDocument/definition', function (params)
- local core = require 'core.definition'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local lines = files.getLines(uri)
- local text = files.getText(uri)
- local offset = define.offset(lines, text, params.position)
- local result = core(uri, offset)
- if not result then
- return nil
- end
- local response = {}
- for i, info in ipairs(result) do
- local targetUri = info.uri
- local targetLines = files.getLines(targetUri)
- local targetText = files.getText(targetUri)
- response[i] = define.locationLink(targetUri
- , define.range(targetLines, targetText, info.target.start, info.target.finish)
- , define.range(targetLines, targetText, info.target.start, info.target.finish)
- , define.range(lines, text, info.source.start, info.source.finish)
- )
- end
- return response
-end)
-
-proto.on('textDocument/references', function (params)
- local core = require 'core.reference'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local lines = files.getLines(uri)
- local text = files.getText(uri)
- local offset = define.offset(lines, text, params.position)
- local result = core(uri, offset)
- if not result then
- return nil
- end
- local response = {}
- for i, info in ipairs(result) do
- local targetUri = info.uri
- local targetLines = files.getLines(targetUri)
- local targetText = files.getText(targetUri)
- response[i] = define.location(targetUri
- , define.range(targetLines, targetText, info.target.start, info.target.finish)
- )
- end
- return response
-end)
-
-proto.on('textDocument/documentHighlight', function (params)
- local core = require 'core.highlight'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local lines = files.getLines(uri)
- local text = files.getText(uri)
- local offset = define.offset(lines, text, params.position)
- local result = core(uri, offset)
- if not result then
- return nil
- end
- local response = {}
- for _, info in ipairs(result) do
- response[#response+1] = {
- range = define.range(lines, text, info.start, info.finish),
- kind = info.kind,
- }
- end
- return response
-end)
-
-proto.on('textDocument/rename', function (params)
- local core = require 'core.rename'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local lines = files.getLines(uri)
- local text = files.getText(uri)
- local offset = define.offset(lines, text, params.position)
- local result = core.rename(uri, offset, params.newName)
- if not result then
- return nil
- end
- local workspaceEdit = {
- changes = {},
- }
- for _, info in ipairs(result) do
- local ruri = info.uri
- local rlines = files.getLines(ruri)
- local rtext = files.getText(ruri)
- if not workspaceEdit.changes[ruri] then
- workspaceEdit.changes[ruri] = {}
- end
- local textEdit = define.textEdit(define.range(rlines, rtext, info.start, info.finish), info.text)
- workspaceEdit.changes[ruri][#workspaceEdit.changes[ruri]+1] = textEdit
- end
- return workspaceEdit
-end)
-
-proto.on('textDocument/prepareRename', function (params)
- local core = require 'core.rename'
- local uri = params.textDocument.uri
- if not files.exists(uri) then
- return nil
- end
- local lines = files.getLines(uri)
- local text = files.getText(uri)
- local offset = define.offset(lines, text, params.position)
- local result = core.prepareRename(uri, offset)
- if not result then
- return nil
- end
- return {
- range = define.range(lines, text, result.start, result.finish),
- placeholder = result.text,
- }
-end)
-
-proto.on('textDocument/completion', function (params)
- --log.info(util.dump(params))
- return nil
-end)
diff --git a/server-beta/src/provider/markdown.lua b/server-beta/src/provider/markdown.lua
deleted file mode 100644
index 0f69ad87..00000000
--- a/server-beta/src/provider/markdown.lua
+++ /dev/null
@@ -1,22 +0,0 @@
-local mt = {}
-mt.__index = mt
-mt.__name = 'markdown'
-
-function mt:add(language, text)
- if not text then
- return
- end
- if language == 'lua' then
- self[#self+1] = ('```lua\n%s\n```'):format(text)
- else
- self[#self+1] = text:gsub('\n', '\n\n')
- end
-end
-
-function mt:string()
- return table.concat(self, '\n')
-end
-
-return function ()
- return setmetatable({}, mt)
-end
diff --git a/server-beta/src/pub/init.lua b/server-beta/src/pub/init.lua
deleted file mode 100644
index 61b43da7..00000000
--- a/server-beta/src/pub/init.lua
+++ /dev/null
@@ -1,4 +0,0 @@
-local pub = require 'pub.pub'
-require 'pub.report'
-
-return pub
diff --git a/server-beta/src/pub/pub.lua b/server-beta/src/pub/pub.lua
deleted file mode 100644
index 2cb1b4e8..00000000
--- a/server-beta/src/pub/pub.lua
+++ /dev/null
@@ -1,236 +0,0 @@
-local thread = require 'bee.thread'
-local utility = require 'utility'
-local await = require 'await'
-local timer = require 'timer'
-
-local errLog = thread.channel 'errlog'
-local type = type
-local counter = utility.counter()
-
-local braveTemplate = [[
-package.path = %q
-package.cpath = %q
-
-collectgarbage 'generational'
-
-log = require 'brave.log'
-
-dofile(%q)
-local brave = require 'brave'
-brave.register(%d)
-]]
-
----@class pub
-local m = {}
-m.type = 'pub'
-m.braves = {}
-m.ability = {}
-m.taskQueue = {}
-
---- 注册酒馆的功能
-function m.on(name, callback)
- m.ability[name] = callback
-end
-
---- 招募勇者,勇者会从公告板上领取任务,完成任务后到看板娘处交付任务
----@param num integer
-function m.recruitBraves(num)
- for _ = 1, num do
- local id = #m.braves + 1
- log.info('Create brave:', id)
- thread.newchannel('taskpad' .. id)
- thread.newchannel('waiter' .. id)
- m.braves[id] = {
- id = id,
- taskpad = thread.channel('taskpad' .. id),
- waiter = thread.channel('waiter' .. id),
- thread = thread.thread(braveTemplate:format(
- package.path,
- package.cpath,
- (ROOT / 'debugger.lua'):string(),
- id
- )),
- taskMap = {},
- currentTask = nil,
- memory = 0,
- }
- end
-end
-
---- 勇者是否有空
-function m.isIdle(brave)
- return next(brave.taskMap) == nil
-end
-
---- 给勇者推送任务
-function m.pushTask(brave, info)
- if info.removed then
- return false
- end
- brave.taskpad:push(info.name, info.id, info.params)
- brave.taskMap[info.id] = info
- --log.info(('Push task %q(%d) to # %d, queue length %d'):format(info.name, info.id, brave.id, #m.taskQueue))
- return true
-end
-
---- 从勇者处接收任务反馈
-function m.popTask(brave, id, result)
- local info = brave.taskMap[id]
- if not info then
- log.warn(('Brave pushed unknown task result: # %d => [%d]'):format(brave.id, id))
- return
- end
- brave.taskMap[id] = nil
- --log.info(('Pop task %q(%d) from # %d'):format(info.name, info.id, brave.id))
- m.checkWaitingTask(brave)
- if not info.removed then
- info.removed = true
- if info.callback then
- xpcall(info.callback, log.error, result)
- end
- end
-end
-
---- 从勇者处接收报告
-function m.popReport(brave, name, params)
- local abil = m.ability[name]
- if not abil then
- log.warn(('Brave pushed unknown report: # %d => %q'):format(brave.id, name))
- return
- end
- xpcall(abil, log.error, params, brave)
-end
-
---- 发布任务
----@parma name string
----@param params any
-function m.awaitTask(name, params)
- local info = {
- id = counter(),
- name = name,
- params = params,
- }
- for _, brave in ipairs(m.braves) do
- if m.isIdle(brave) then
- if m.pushTask(brave, info) then
- return await.wait(function (waker)
- info.callback = waker
- end)
- else
- return nil
- end
- end
- end
- -- 如果所有勇者都在战斗,那么把任务缓存到队列里
- -- 当有勇者提交任务反馈后,尝试把按顺序将堆积任务
- -- 交给该勇者
- m.taskQueue[#m.taskQueue+1] = info
- --log.info(('Add task %q(%d) in queue, length %d.'):format(name, info.id, #m.taskQueue))
- return await.wait(function (waker)
- info.callback = waker
- end)
-end
-
---- 发布同步任务,如果任务进入了队列,会返回执行器
---- 通过 jumpQueue 可以插队
----@parma name string
----@param params any
----@param callback function
-function m.task(name, params, callback)
- local info = {
- id = counter(),
- name = name,
- params = params,
- callback = callback,
- }
- for _, brave in ipairs(m.braves) do
- if m.isIdle(brave) then
- m.pushTask(brave, info)
- return nil
- end
- end
- -- 如果所有勇者都在战斗,那么把任务缓存到队列里
- -- 当有勇者提交任务反馈后,尝试把按顺序将堆积任务
- -- 交给该勇者
- m.taskQueue[#m.taskQueue+1] = info
- --log.info(('Add task %q(%d) in queue, length %d.'):format(name, info.id, #m.taskQueue))
- return info
-end
-
---- 插队
-function m.jumpQueue(info)
- for i = 2, #m.taskQueue do
- if m.taskQueue[i] == info then
- m.taskQueue[i] = nil
- table.move(m.taskQueue, 1, i - 1, 2)
- m.taskQueue[1] = info
- return
- end
- end
-end
-
---- 移除任务
-function m.remove(info)
- info.removed = true
- for i = 1, #m.taskQueue do
- if m.taskQueue[i] == info then
- table.remove(m.taskQueue[i], i)
- return
- end
- end
-end
-
---- 检查堆积任务
-function m.checkWaitingTask(brave)
- if #m.taskQueue == 0 then
- return
- end
- -- 如果勇者还有其他活要忙,那么让他继续忙去吧
- if next(brave.taskMap) then
- return
- end
- while #m.taskQueue > 0 do
- local info = table.remove(m.taskQueue, 1)
- if m.pushTask(brave, info) then
- break
- end
- end
-end
-
---- 接收反馈
----|返回接收到的反馈数量
----@return integer
-function m.recieve()
- for _, brave in ipairs(m.braves) do
- while true do
- local suc, id, result = brave.waiter:pop()
- if not suc then
- goto CONTINUE
- end
- if type(id) == 'string' then
- m.popReport(brave, id, result)
- else
- m.popTask(brave, id, result)
- end
- end
- ::CONTINUE::
- end
-end
-
---- 检查伤亡情况
-function m.checkDead()
- while true do
- local suc, err = errLog:pop()
- if not suc then
- break
- end
- log.error('Brave is dead!: ' .. err)
- end
-end
-
-function m.step()
- m.checkDead()
- m.recieve()
-end
-
-return m
diff --git a/server-beta/src/pub/report.lua b/server-beta/src/pub/report.lua
deleted file mode 100644
index edd3ee0e..00000000
--- a/server-beta/src/pub/report.lua
+++ /dev/null
@@ -1,21 +0,0 @@
-local pub = require 'pub.pub'
-local await = require 'await'
-
-pub.on('log', function (params, brave)
- log.raw(brave.id, params.level, params.msg, params.src, params.line)
-end)
-
-pub.on('mem', function (count, brave)
- brave.memory = count
-end)
-
-pub.on('proto', function (params)
- local proto = require 'proto'
- await.create(function ()
- if params.method then
- proto.doMethod(params)
- else
- proto.doResponse(params)
- end
- end)
-end)
diff --git a/server-beta/src/service/init.lua b/server-beta/src/service/init.lua
deleted file mode 100644
index eb0bd057..00000000
--- a/server-beta/src/service/init.lua
+++ /dev/null
@@ -1,3 +0,0 @@
-local service = require 'service.service'
-
-return service
diff --git a/server-beta/src/service/service.lua b/server-beta/src/service/service.lua
deleted file mode 100644
index e1cb604b..00000000
--- a/server-beta/src/service/service.lua
+++ /dev/null
@@ -1,137 +0,0 @@
-local pub = require 'pub'
-local thread = require 'bee.thread'
-local await = require 'await'
-local timer = require 'timer'
-local proto = require 'proto'
-local vm = require 'vm'
-
-local m = {}
-m.type = 'service'
-
-local function countMemory()
- local mems = {}
- local total = 0
- mems[0] = collectgarbage 'count'
- total = total + collectgarbage 'count'
- for id, brave in ipairs(pub.braves) do
- mems[id] = brave.memory
- total = total + brave.memory
- end
- return total, mems
-end
-
-function m.reportMemoryCollect()
- local totalMemBefore = countMemory()
- local clock = os.clock()
- collectgarbage()
- local passed = os.clock() - clock
- local totalMemAfter, mems = countMemory()
-
- local lines = {}
- lines[#lines+1] = ' --------------- Memory ---------------'
- lines[#lines+1] = (' Total: %.3f(%.3f) MB'):format(totalMemAfter / 1000.0, totalMemBefore / 1000.0)
- for i = 0, #mems do
- lines[#lines+1] = (' # %02d : %.3f MB'):format(i, mems[i] / 1000.0)
- end
- lines[#lines+1] = (' Collect garbage takes [%.3f] sec'):format(passed)
- return table.concat(lines, '\n')
-end
-
-function m.reportMemory()
- local totalMem, mems = countMemory()
-
- local lines = {}
- lines[#lines+1] = ' --------------- Memory ---------------'
- lines[#lines+1] = (' Total: %.3f MB'):format(totalMem / 1000.0)
- for i = 0, #mems do
- lines[#lines+1] = (' # %02d : %.3f MB'):format(i, mems[i] / 1000.0)
- end
- return table.concat(lines, '\n')
-end
-
-function m.reportTask()
- local total = 0
- local running = 0
- local suspended = 0
- local normal = 0
- local dead = 0
-
- for co in pairs(await.coTracker) do
- total = total + 1
- local status = coroutine.status(co)
- if status == 'running' then
- running = running + 1
- elseif status == 'suspended' then
- suspended = suspended + 1
- elseif status == 'normal' then
- normal = normal + 1
- elseif status == 'dead' then
- dead = dead + 1
- end
- end
-
- local lines = {}
- lines[#lines+1] = ' --------------- Coroutine ---------------'
- lines[#lines+1] = (' Total: %d'):format(total)
- lines[#lines+1] = (' Running: %d'):format(running)
- lines[#lines+1] = (' Suspended: %d'):format(suspended)
- lines[#lines+1] = (' Normal: %d'):format(normal)
- lines[#lines+1] = (' Dead: %d'):format(dead)
- return table.concat(lines, '\n')
-end
-
-function m.reportCache()
- local total = 0
- local dead = 0
-
- for cache in pairs(vm.cacheTracker) do
- total = total + 1
- if cache.dead then
- dead = dead + 1
- end
- end
-
- local lines = {}
- lines[#lines+1] = ' --------------- Cache ---------------'
- lines[#lines+1] = (' Total: %d'):format(total)
- lines[#lines+1] = (' Dead: %d'):format(dead)
- return table.concat(lines, '\n')
-end
-
-function m.report()
- local t = timer.loop(60.0, function ()
- local lines = {}
- lines[#lines+1] = ''
- lines[#lines+1] = '========= Medical Examination Report ========='
- lines[#lines+1] = m.reportMemory()
- lines[#lines+1] = m.reportTask()
- lines[#lines+1] = m.reportCache()
- lines[#lines+1] = '=============================================='
-
- log.debug(table.concat(lines, '\n'))
- end)
- t:onTimer()
-end
-
-function m.startTimer()
- while true do
- pub.step()
- if not await.step() then
- thread.sleep(0.001)
- timer.update()
- end
- end
-end
-
-function m.start()
- await.setErrorHandle(log.error)
- pub.recruitBraves(4)
- proto.listen()
- m.report()
-
- require 'provider'
-
- m.startTimer()
-end
-
-return m
diff --git a/server-beta/src/timer.lua b/server-beta/src/timer.lua
deleted file mode 100644
index 1d4343f1..00000000
--- a/server-beta/src/timer.lua
+++ /dev/null
@@ -1,218 +0,0 @@
-local setmetatable = setmetatable
-local mathMax = math.max
-local mathFloor = math.floor
-local osClock = os.clock
-
-_ENV = nil
-
-local curFrame = 0
-local maxFrame = 0
-local curIndex = 0
-local freeQueue = {}
-local timer = {}
-
-local function allocQueue()
- local n = #freeQueue
- if n > 0 then
- local r = freeQueue[n]
- freeQueue[n] = nil
- return r
- else
- return {}
- end
-end
-
-local function mTimeout(self, timeout)
- if self._pauseRemaining or self._running then
- return
- end
- local ti = curFrame + timeout
- local q = timer[ti]
- if q == nil then
- q = allocQueue()
- timer[ti] = q
- end
- self._timeoutFrame = ti
- self._running = true
- q[#q + 1] = self
-end
-
-local function mWakeup(self)
- if self._removed then
- return
- end
- self._running = false
- if self._onTimer then
- self:_onTimer()
- end
- if self._removed then
- return
- end
- if self._timerCount then
- if self._timerCount > 1 then
- self._timerCount = self._timerCount - 1
- mTimeout(self, self._timeout)
- else
- self._removed = true
- end
- else
- mTimeout(self, self._timeout)
- end
-end
-
-local function getRemaining(self)
- if self._removed then
- return 0
- end
- if self._pauseRemaining then
- return self._pauseRemaining
- end
- if self._timeoutFrame == curFrame then
- return self._timeout or 0
- end
- return self._timeoutFrame - curFrame
-end
-
-local function onTick()
- local q = timer[curFrame]
- if q == nil then
- curIndex = 0
- return
- end
- for i = curIndex + 1, #q do
- local callback = q[i]
- curIndex = i
- q[i] = nil
- if callback then
- mWakeup(callback)
- end
- end
- curIndex = 0
- timer[curFrame] = nil
- freeQueue[#freeQueue + 1] = q
-end
-
-local m = {}
-local mt = {}
-mt.__index = mt
-mt.type = 'timer'
-
-function mt:__tostring()
- return '[table:timer]'
-end
-
-function mt:__call()
- if self._onTimer then
- self:_onTimer()
- end
-end
-
-function mt:remove()
- self._removed = true
-end
-
-function mt:pause()
- if self._removed or self._pauseRemaining then
- return
- end
- self._pauseRemaining = getRemaining(self)
- self._running = false
- local ti = self._timeoutFrame
- local q = timer[ti]
- if q then
- for i = #q, 1, -1 do
- if q[i] == self then
- q[i] = false
- return
- end
- end
- end
-end
-
-function mt:resume()
- if self._removed or not self._pauseRemaining then
- return
- end
- local timeout = self._pauseRemaining
- self._pauseRemaining = nil
- mTimeout(self, timeout)
-end
-
-function mt:restart()
- if self._removed or self._pauseRemaining or not self._running then
- return
- end
- local ti = self._timeoutFrame
- local q = timer[ti]
- if q then
- for i = #q, 1, -1 do
- if q[i] == self then
- q[i] = false
- break
- end
- end
- end
- self._running = false
- mTimeout(self, self._timeout)
-end
-
-function mt:remaining()
- return getRemaining(self) / 1000.0
-end
-
-function mt:onTimer()
- self:_onTimer()
-end
-
-function m.wait(timeout, onTimer)
- local t = setmetatable({
- ['_timeout'] = mathMax(mathFloor(timeout * 1000.0), 1),
- ['_onTimer'] = onTimer,
- ['_timerCount'] = 1,
- }, mt)
- mTimeout(t, t._timeout)
- return t
-end
-
-function m.loop(timeout, onTimer)
- local t = setmetatable({
- ['_timeout'] = mathFloor(timeout * 1000.0),
- ['_onTimer'] = onTimer,
- }, mt)
- mTimeout(t, t._timeout)
- return t
-end
-
-function m.timer(timeout, count, onTimer)
- if count == 0 then
- return m.loop(timeout, onTimer)
- end
- local t = setmetatable({
- ['_timeout'] = mathFloor(timeout * 1000.0),
- ['_onTimer'] = onTimer,
- ['_timerCount'] = count,
- }, mt)
- mTimeout(t, t._timeout)
- return t
-end
-
-function m.clock()
- return curFrame / 1000.0
-end
-
-local lastClock = osClock()
-function m.update()
- local currentClock = osClock()
- local delta = currentClock - lastClock
- lastClock = currentClock
- if curIndex ~= 0 then
- curFrame = curFrame - 1
- end
- maxFrame = maxFrame + delta * 1000.0
- while curFrame < maxFrame do
- curFrame = curFrame + 1
- onTick()
- end
-end
-
-return m
diff --git a/server-beta/src/utility.lua b/server-beta/src/utility.lua
deleted file mode 100644
index c9defebc..00000000
--- a/server-beta/src/utility.lua
+++ /dev/null
@@ -1,452 +0,0 @@
-local tableSort = table.sort
-local stringRep = string.rep
-local tableConcat = table.concat
-local tostring = tostring
-local type = type
-local pairs = pairs
-local ipairs = ipairs
-local next = next
-local rawset = rawset
-local move = table.move
-local setmetatable = setmetatable
-local mathType = math.type
-local mathCeil = math.ceil
-local getmetatable = getmetatable
-local mathAbs = math.abs
-local ioOpen = io.open
-
-_ENV = nil
-
-local function formatNumber(n)
- local str = ('%.10f'):format(n)
- str = str:gsub('%.?0*$', '')
- return str
-end
-
-local function isInteger(n)
- if mathType then
- return mathType(n) == 'integer'
- else
- return type(n) == 'number' and n % 1 == 0
- end
-end
-
-local TAB = setmetatable({}, { __index = function (self, n)
- self[n] = stringRep(' ', n)
- return self[n]
-end})
-
-local RESERVED = {
- ['and'] = true,
- ['break'] = true,
- ['do'] = true,
- ['else'] = true,
- ['elseif'] = true,
- ['end'] = true,
- ['false'] = true,
- ['for'] = true,
- ['function'] = true,
- ['goto'] = 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 m = {}
-
---- 打印表的结构
----@param tbl table
----@param option table {optional = 'self'}
----@return string
-function m.dump(tbl, option)
- if not option then
- option = {}
- end
- if type(tbl) ~= 'table' then
- return ('%s'):format(tbl)
- end
- local lines = {}
- local mark = {}
- lines[#lines+1] = '{'
- local function unpack(tbl, tab)
- mark[tbl] = (mark[tbl] or 0) + 1
- local keys = {}
- local keymap = {}
- local integerFormat = '[%d]'
- local alignment = 0
- if #tbl >= 10 then
- local width = #tostring(#tbl)
- integerFormat = ('[%%0%dd]'):format(mathCeil(width))
- end
- for key in pairs(tbl) do
- if type(key) == 'string' then
- if not key:match('^[%a_][%w_]*$')
- or RESERVED[key]
- or option['longStringKey']
- then
- keymap[key] = ('[%q]'):format(key)
- else
- keymap[key] = ('%s'):format(key)
- end
- elseif isInteger(key) then
- keymap[key] = integerFormat:format(key)
- else
- keymap[key] = ('["<%s>"]'):format(tostring(key))
- end
- keys[#keys+1] = key
- if option['alignment'] then
- if #keymap[key] > alignment then
- alignment = #keymap[key]
- end
- end
- end
- local mt = getmetatable(tbl)
- if not mt or not mt.__pairs then
- if option['sorter'] then
- option['sorter'](keys, keymap)
- else
- tableSort(keys, function (a, b)
- return keymap[a] < keymap[b]
- end)
- end
- end
- for _, key in ipairs(keys) do
- local keyWord = keymap[key]
- if option['noArrayKey']
- and isInteger(key)
- and key <= #tbl
- then
- keyWord = ''
- else
- if #keyWord < alignment then
- keyWord = keyWord .. (' '):rep(alignment - #keyWord) .. ' = '
- else
- keyWord = keyWord .. ' = '
- end
- end
- local value = tbl[key]
- local tp = type(value)
- if option['format'] and option['format'][key] then
- lines[#lines+1] = ('%s%s%s,'):format(TAB[tab+1], keyWord, option['format'][key](value, unpack, tab+1))
- elseif tp == 'table' then
- if mark[value] and mark[value] > 0 then
- lines[#lines+1] = ('%s%s%s,'):format(TAB[tab+1], keyWord, option['loop'] or '"<Loop>"')
- else
- lines[#lines+1] = ('%s%s{'):format(TAB[tab+1], keyWord)
- unpack(value, tab+1)
- lines[#lines+1] = ('%s},'):format(TAB[tab+1])
- end
- elseif tp == 'string' then
- lines[#lines+1] = ('%s%s%q,'):format(TAB[tab+1], keyWord, value)
- elseif tp == 'number' then
- lines[#lines+1] = ('%s%s%s,'):format(TAB[tab+1], keyWord, (option['number'] or formatNumber)(value))
- elseif tp == 'nil' then
- else
- lines[#lines+1] = ('%s%s%s,'):format(TAB[tab+1], keyWord, tostring(value))
- end
- end
- mark[tbl] = mark[tbl] - 1
- end
- unpack(tbl, 0)
- lines[#lines+1] = '}'
- return tableConcat(lines, '\r\n')
-end
-
---- 递归判断A与B是否相等
----@param a any
----@param b any
----@return boolean
-function m.equal(a, b)
- local tp1 = type(a)
- local tp2 = type(b)
- if tp1 ~= tp2 then
- return false
- end
- if tp1 == 'table' then
- local mark = {}
- for k, v in pairs(a) do
- mark[k] = true
- local res = m.equal(v, b[k])
- if not res then
- return false
- end
- end
- for k in pairs(b) do
- if not mark[k] then
- return false
- end
- end
- return true
- elseif tp1 == 'number' then
- return mathAbs(a - b) <= 1e-10
- else
- return a == b
- end
-end
-
-local function sortTable(tbl)
- if not tbl then
- tbl = {}
- end
- local mt = {}
- local keys = {}
- local mark = {}
- local n = 0
- for key in next, tbl do
- n=n+1;keys[n] = key
- mark[key] = true
- end
- tableSort(keys)
- function mt:__newindex(key, value)
- rawset(self, key, value)
- n=n+1;keys[n] = key
- mark[key] = true
- if type(value) == 'table' then
- sortTable(value)
- end
- end
- function mt:__pairs()
- local list = {}
- local m = 0
- for key in next, self do
- if not mark[key] then
- m=m+1;list[m] = key
- end
- end
- if m > 0 then
- move(keys, 1, n, m+1)
- tableSort(list)
- for i = 1, m do
- local key = list[i]
- keys[i] = key
- mark[key] = true
- end
- n = n + m
- end
- local i = 0
- return function ()
- i = i + 1
- local key = keys[i]
- return key, self[key]
- end
- end
-
- return setmetatable(tbl, mt)
-end
-
---- 创建一个有序表
----@param tbl table {optional = 'self'}
----@return table
-function m.container(tbl)
- return sortTable(tbl)
-end
-
---- 读取文件
----@param path string
-function m.loadFile(path)
- local f, e = ioOpen(path, 'rb')
- if not f then
- return nil, e
- end
- if f:read(3) ~= '\xEF\xBB\xBF' then
- f:seek("set")
- end
- local buf = f:read 'a'
- f:close()
- return buf
-end
-
---- 写入文件
----@param path string
----@param content string
-function m.saveFile(path, content)
- local f, e = ioOpen(path, "wb")
-
- if f then
- f:write(content)
- f:close()
- return true
- else
- return false, e
- end
-end
-
---- 计数器
----@param init integer {optional = 'after'}
----@param step integer {optional = 'after'}
----@return fun():integer
-function m.counter(init, step)
- if not step then
- step = 1
- end
- local current = init and (init - 1) or 0
- return function ()
- current = current + step
- return current
- end
-end
-
---- 排序后遍历
----@param t table
-function m.sortPairs(t)
- local keys = {}
- for k in pairs(t) do
- keys[#keys+1] = k
- end
- tableSort(keys)
- local i = 0
- return function ()
- i = i + 1
- local k = keys[i]
- return k, t[k]
- end
-end
-
---- 深拷贝(不处理元表)
----@param source table
----@param target table {optional = 'self'}
-function m.deepCopy(source, target)
- local mark = {}
- local function copy(a, b)
- if type(a) ~= 'table' then
- return a
- end
- if mark[a] then
- return mark[a]
- end
- if not b then
- b = {}
- end
- mark[a] = b
- for k, v in pairs(a) do
- b[copy(k)] = copy(v)
- end
- return b
- end
- return copy(source, target)
-end
-
---- 序列化
-function m.unpack(t)
- local result = {}
- local tid = 0
- local cache = {}
- local function unpack(o)
- local id = cache[o]
- if not id then
- tid = tid + 1
- id = tid
- cache[o] = tid
- if type(o) == 'table' then
- local new = {}
- result[tid] = new
- for k, v in next, o do
- new[unpack(k)] = unpack(v)
- end
- else
- result[id] = o
- end
- end
- return id
- end
- unpack(t)
- return result
-end
-
---- 反序列化
-function m.pack(t)
- local cache = {}
- local function pack(id)
- local o = cache[id]
- if o then
- return o
- end
- o = t[id]
- if type(o) == 'table' then
- local new = {}
- cache[id] = new
- for k, v in next, o do
- new[pack(k)] = pack(v)
- end
- return new
- else
- cache[id] = o
- return o
- end
- end
- return pack(1)
-end
-
---- defer
-local deferMT = { __close = function (self) self[1]() end }
-function m.defer(callback)
- return setmetatable({ callback }, deferMT)
-end
-
-local esc = {
- ["'"] = [[\']],
- ['"'] = [[\"]],
- ['\r'] = [[\r]],
- ['\n'] = '\\\n',
-}
-
-function m.viewString(str, quo)
- if not quo then
- if not str:find("'", 1, true) and str:find('"', 1, true) then
- quo = "'"
- else
- quo = '"'
- end
- end
- if quo == "'" then
- return quo .. str:gsub([=[['\r\n]]=], esc) .. quo
- elseif quo == '"' then
- return quo .. str:gsub([=[["\r\n]]=], esc) .. quo
- else
- if str:find '\r' then
- return m.viewString(str)
- end
- local eqnum = #quo - 2
- local fsymb = ']' .. ('='):rep(eqnum) .. ']'
- if not str:find(fsymb, 1, true) then
- return quo .. str .. fsymb
- end
- for i = 0, 10 do
- local fsymb = ']' .. ('='):rep(i) .. ']'
- if not str:find(fsymb, 1, true) then
- local ssymb = '[' .. ('='):rep(i) .. '['
- return ssymb .. str .. fsymb
- end
- end
- return m.viewString(str)
- end
-end
-
-function m.viewLiteral(v)
- local tp = type(v)
- if tp == 'nil' then
- return 'nil'
- elseif tp == 'string' then
- return m.viewString(v)
- elseif tp == 'boolean' then
- return tostring(v)
- elseif tp == 'number' then
- if isInteger(v) then
- return tostring(v)
- else
- return formatNumber(v)
- end
- end
- return nil
-end
-
-return m
diff --git a/server-beta/src/vm/dummySource.lua b/server-beta/src/vm/dummySource.lua
deleted file mode 100644
index 50ff13e7..00000000
--- a/server-beta/src/vm/dummySource.lua
+++ /dev/null
@@ -1,13 +0,0 @@
-local vm = require 'vm.vm'
-
-vm.librarySourceCache = setmetatable({}, { __mode = 'kv'})
-
-function vm.librarySource(lib)
- if not vm.librarySourceCache[lib] then
- vm.librarySourceCache[lib] = {
- type = 'library',
- library = lib,
- }
- end
- return vm.librarySourceCache[lib]
-end
diff --git a/server-beta/src/vm/eachDef.lua b/server-beta/src/vm/eachDef.lua
deleted file mode 100644
index 0274cbee..00000000
--- a/server-beta/src/vm/eachDef.lua
+++ /dev/null
@@ -1,65 +0,0 @@
-local vm = require 'vm.vm'
-local guide = require 'parser.guide'
-local files = require 'files'
-
-local function checkPath(source, info)
- if source.type == 'goto' then
- return true
- end
- local src = info.source
- local mode = guide.getPath(source, src)
- if not mode then
- return true
- end
- if mode == 'before' then
- return false
- end
- return true
-end
-
-function vm.eachDef(source, callback)
- local results = {}
- local valueUris = {}
- local sourceUri = guide.getRoot(source).uri
- vm.eachRef(source, function (info)
- if info.mode == 'declare'
- or info.mode == 'set'
- or info.mode == 'return'
- or info.mode == 'value' then
- results[#results+1] = info
- local src = info.source
- if info.mode == 'return' then
- local uri = guide.getRoot(src).uri
- valueUris[uri] = info.source
- end
- end
- end)
-
- for _, info in ipairs(results) do
- local src = info.source
- local destUri = guide.getRoot(src).uri
- -- 如果是同一个文件,则检查位置关系后放行
- if sourceUri == destUri then
- if checkPath(source, info) then
- callback(info)
- end
- goto CONTINUE
- end
- -- 如果是global或field,则直接放行(因为无法确定顺序)
- if src.type == 'setindex'
- or src.type == 'setfield'
- or src.type == 'setmethod'
- or src.type == 'tablefield'
- or src.type == 'tableindex'
- or src.type == 'setglobal' then
- callback(info)
- goto CONTINUE
- end
- -- 如果不是同一个文件,则必须在该文件 return 后才放行
- if valueUris[destUri] then
- callback(info)
- goto CONTINUE
- end
- ::CONTINUE::
- end
-end
diff --git a/server-beta/src/vm/eachField.lua b/server-beta/src/vm/eachField.lua
deleted file mode 100644
index 1d3d222d..00000000
--- a/server-beta/src/vm/eachField.lua
+++ /dev/null
@@ -1,169 +0,0 @@
-local guide = require 'parser.guide'
-local vm = require 'vm.vm'
-
-local function ofTabel(value, callback)
- for _, field in ipairs(value) do
- if field.type == 'tablefield'
- or field.type == 'tableindex' then
- callback {
- source = field,
- key = guide.getKeyName(field),
- value = field.value,
- mode = 'set',
- }
- end
- end
-end
-
-local function ofENV(source, callback)
- if source.type == 'getlocal' then
- local parent = source.parent
- if parent.type == 'getfield'
- or parent.type == 'getmethod'
- or parent.type == 'getindex' then
- callback {
- source = parent,
- key = guide.getKeyName(parent),
- mode = 'get',
- }
- end
- elseif source.type == 'getglobal' then
- callback {
- source = source,
- key = guide.getKeyName(source),
- mode = 'get',
- }
- elseif source.type == 'setglobal' then
- callback {
- source = source,
- key = guide.getKeyName(source),
- mode = 'set',
- value = source.value,
- }
- end
-end
-
-local function ofSpecialArg(source, callback)
- local args = source.parent
- local call = args.parent
- local func = call.node
- local name = func.special
- if name == 'rawset' then
- if args[1] == source and args[2] then
- callback {
- source = call,
- key = guide.getKeyName(args[2]),
- value = args[3],
- mode = 'set',
- }
- end
- elseif name == 'rawget' then
- if args[1] == source and args[2] then
- callback {
- source = call,
- key = guide.getKeyName(args[2]),
- mode = 'get',
- }
- end
- elseif name == 'setmetatable' then
- if args[1] == source and args[2] then
- vm.eachField(args[2], function (info)
- if info.key == 's|__index' and info.value then
- vm.eachField(info.value, callback)
- end
- end)
- end
- end
-end
-
-local function ofVar(source, callback)
- local parent = source.parent
- if not parent then
- return
- end
- if parent.type == 'getfield'
- or parent.type == 'getmethod'
- or parent.type == 'getindex' then
- callback {
- source = parent,
- key = guide.getKeyName(parent),
- mode = 'get',
- }
- return
- end
- if parent.type == 'setfield'
- or parent.type == 'setmethod'
- or parent.type == 'setindex' then
- callback {
- source = parent,
- key = guide.getKeyName(parent),
- value = parent.value,
- mode = 'set',
- }
- return
- end
- if parent.type == 'callargs' then
- ofSpecialArg(source, callback)
- end
-end
-
-local function eachField(source, callback)
- vm.eachRef(source, function (info)
- local src = info.source
- if src.tag == '_ENV' then
- if src.ref then
- for _, ref in ipairs(src.ref) do
- ofENV(ref, callback)
- end
- end
- elseif src.type == 'getlocal'
- or src.type == 'getglobal'
- or src.type == 'getfield'
- or src.type == 'getmethod'
- or src.type == 'getindex' then
- ofVar(src, callback)
- elseif src.type == 'table' then
- ofTabel(src, callback)
- end
- end)
-end
-
---- 获取所有的field
-function vm.eachField(source, callback)
- local cache = vm.cache.eachField[source]
- if cache then
- for i = 1, #cache do
- local res = callback(cache[i])
- if res ~= nil then
- return res
- end
- end
- return
- end
- local unlock = vm.lock('eachField', source)
- if not unlock then
- return
- end
- cache = {}
- vm.cache.eachField[source] = cache
- local mark = {}
- eachField(source, function (info)
- local src = info.source
- if mark[src] then
- return
- end
- mark[src] = true
- cache[#cache+1] = info
- end)
- unlock()
- vm.eachRef(source, function (info)
- local src = info.source
- vm.cache.eachField[src] = cache
- end)
- for i = 1, #cache do
- local res = callback(cache[i])
- if res ~= nil then
- return res
- end
- end
-end
diff --git a/server-beta/src/vm/eachRef.lua b/server-beta/src/vm/eachRef.lua
deleted file mode 100644
index cfb2bef8..00000000
--- a/server-beta/src/vm/eachRef.lua
+++ /dev/null
@@ -1,500 +0,0 @@
-local guide = require 'parser.guide'
-local files = require 'files'
-local vm = require 'vm.vm'
-
-local function ofCall(func, index, callback)
- vm.eachRef(func, function (info)
- local src = info.source
- local returns
- if src.type == 'main' or src.type == 'function' then
- returns = src.returns
- end
- if returns then
- -- 搜索函数第 index 个返回值
- for _, rtn in ipairs(returns) do
- local val = rtn[index]
- if val then
- callback {
- source = val,
- mode = 'return',
- }
- vm.eachRef(val, callback)
- end
- end
- end
- end)
-end
-
-local function ofCallSelect(call, index, callback)
- local slc = call.parent
- if slc.index == index then
- vm.eachRef(slc.parent, callback)
- return
- end
- if call.extParent then
- for i = 1, #call.extParent do
- slc = call.extParent[i]
- if slc.index == index then
- vm.eachRef(slc.parent, callback)
- return
- end
- end
- end
-end
-
-local function ofReturn(rtn, index, callback)
- local func = guide.getParentFunction(rtn)
- if not func then
- return
- end
- -- 搜索函数调用的第 index 个接收值
- if func.type == 'main' then
- local myUri = func.uri
- local uris = files.findLinkTo(myUri)
- if not uris then
- return
- end
- for _, uri in ipairs(uris) do
- local ast = files.getAst(uri)
- if ast then
- local links = vm.getLinks(ast.ast)
- if links then
- for linkUri, calls in pairs(links) do
- if files.eq(linkUri, myUri) then
- for i = 1, #calls do
- ofCallSelect(calls[i], 1, callback)
- end
- end
- end
- end
- end
- end
- else
- vm.eachRef(func, function (info)
- local source = info.source
- local call = source.parent
- if not call or call.type ~= 'call' then
- return
- end
- ofCallSelect(call, index, callback)
- end)
- end
-end
-
-local function ofSpecialCall(call, func, index, callback)
- local name = func.special
- if name == 'setmetatable' then
- if index == 1 then
- local args = call.args
- if args[1] then
- vm.eachRef(args[1], callback)
- end
- if args[2] then
- vm.eachField(args[2], function (info)
- if info.key == 's|__index' then
- vm.eachRef(info.source, callback)
- if info.value then
- vm.eachRef(info.value, callback)
- end
- end
- end)
- end
- end
- elseif name == 'require' then
- if index == 1 then
- local result = vm.getLinkUris(call)
- if result then
- local myUri = guide.getRoot(call).uri
- for _, uri in ipairs(result) do
- if not files.eq(uri, myUri) then
- local ast = files.getAst(uri)
- if ast then
- ofCall(ast.ast, 1, callback)
- end
- end
- end
- end
- end
- end
-end
-
-local function ofValue(value, callback)
- if value.type == 'select' then
- -- 检查函数返回值
- local call = value.vararg
- if call.type == 'call' then
- ofCall(call.node, value.index, callback)
- ofSpecialCall(call, call.node, value.index, callback)
- end
- return
- end
-
- if value.type == 'table'
- or value.type == 'string'
- or value.type == 'number'
- or value.type == 'boolean'
- or value.type == 'nil'
- or value.type == 'function' then
- callback {
- source = value,
- mode = 'value',
- }
- end
-
- vm.eachRef(value, callback)
-
- local parent = value.parent
- if parent.type == 'local'
- or parent.type == 'setglobal'
- or parent.type == 'setlocal'
- or parent.type == 'setfield'
- or parent.type == 'setmethod'
- or parent.type == 'setindex'
- or parent.type == 'tablefield'
- or parent.type == 'tableindex' then
- if parent.value == value then
- vm.eachRef(parent, callback)
- end
- end
- if parent.type == 'return' then
- for i = 1, #parent do
- if parent[i] == value then
- ofReturn(parent, i, callback)
- break
- end
- end
- end
-end
-
-local function ofSelf(loc, callback)
- -- self 的2个特殊引用位置:
- -- 1. 当前方法定义时的对象(mt)
- local method = loc.method
- local node = method.node
- vm.eachRef(node, callback)
- -- 2. 调用该方法时传入的对象
-end
-
---- 自己作为赋值的值
-local function asValue(source, callback)
- local parent = source.parent
- if parent and parent.value == source then
- if guide.getName(parent) == '__index' then
- if parent.type == 'tablefield'
- or parent.type == 'tableindex' then
- local t = parent.parent
- local args = t.parent
- if args[2] == t then
- local call = args.parent
- local func = call.node
- if func.special == 'setmetatable' then
- vm.eachRef(args[1], callback)
- end
- end
- end
- end
- end
-end
-
-local function getCallRecvs(call)
- local parent = call.parent
- if parent.type ~= 'select' then
- return nil
- end
- local exParent = call.exParent
- local recvs = {}
- recvs[1] = parent.parent
- if exParent then
- for _, p in ipairs(exParent) do
- recvs[#recvs+1] = p.parent
- end
- end
- return recvs
-end
-
---- 自己作为函数的参数
-local function asArg(source, callback)
- local parent = source.parent
- if not parent then
- return
- end
- if parent.type == 'callargs' then
- local call = parent.parent
- local func = call.node
- local name = func.special
- if name == 'setmetatable' then
- if parent[1] == source then
- if parent[2] then
- vm.eachField(parent[2], function (info)
- if info.key == 's|__index' then
- vm.eachRef(info.source, callback)
- if info.value then
- vm.eachRef(info.value, callback)
- end
- end
- end)
- end
- end
- local recvs = getCallRecvs(call)
- if recvs and recvs[1] then
- vm.eachRef(recvs[1], callback)
- end
- end
- end
-end
-
-local function ofLocal(loc, callback)
- -- 方法中的 self 使用了一个虚拟的定义位置
- if loc.tag ~= 'self' then
- callback {
- source = loc,
- mode = 'declare',
- }
- end
- if loc.ref then
- for _, ref in ipairs(loc.ref) do
- if ref.type == 'getlocal' then
- callback {
- source = ref,
- mode = 'get',
- }
- asValue(ref, callback)
- elseif ref.type == 'setlocal' then
- callback {
- source = ref,
- mode = 'set',
- }
- if ref.value then
- ofValue(ref.value, callback)
- end
- end
- end
- end
- if loc.tag == 'self' then
- ofSelf(loc, callback)
- end
- if loc.value then
- ofValue(loc.value, callback)
- end
- if loc.tag == '_ENV' and loc.ref then
- for _, ref in ipairs(loc.ref) do
- if ref.type == 'getlocal' then
- local parent = ref.parent
- if parent.type == 'getfield'
- or parent.type == 'getindex' then
- if guide.getKeyName(parent) == '_G' then
- callback {
- source = parent,
- mode = 'get',
- }
- end
- end
- elseif ref.type == 'getglobal' then
- if guide.getName(ref) == '_G' then
- callback {
- source = ref,
- mode = 'get',
- }
- end
- end
- end
- end
-end
-
-local function ofGlobal(source, callback)
- local key = guide.getKeyName(source)
- local node = source.node
- if node.tag == '_ENV' then
- local uris = files.findGlobals(key)
- for _, uri in ipairs(uris) do
- local ast = files.getAst(uri)
- local globals = vm.getGlobals(ast.ast)
- if globals[key] then
- for _, info in ipairs(globals[key]) do
- callback(info)
- if info.value then
- ofValue(info.value, callback)
- end
- end
- end
- end
- else
- vm.eachField(node, function (info)
- if key == info.key then
- callback {
- source = info.source,
- mode = info.mode,
- }
- if info.value then
- ofValue(info.value, callback)
- end
- end
- end)
- end
-end
-
-local function ofField(source, callback)
- local parent = source.parent
- local key = guide.getKeyName(source)
- if parent.type == 'tablefield'
- or parent.type == 'tableindex' then
- local tbl = parent.parent
- vm.eachField(tbl, function (info)
- if key == info.key then
- callback {
- source = info.source,
- mode = info.mode,
- }
- if info.value then
- ofValue(info.value, callback)
- end
- end
- end)
- else
- local node = parent.node
- vm.eachField(node, function (info)
- if key == info.key then
- callback {
- source = info.source,
- mode = info.mode,
- }
- if info.value then
- ofValue(info.value, callback)
- end
- end
- end)
- end
-end
-
-local function ofLiteral(source, callback)
- local parent = source.parent
- if not parent then
- return
- end
- if parent.type == 'setindex'
- or parent.type == 'getindex'
- or parent.type == 'tableindex' then
- ofField(source, callback)
- end
-end
-
-local function ofLabel(source, callback)
- callback {
- source = source,
- mode = 'set',
- }
- if source.ref then
- for _, ref in ipairs(source.ref) do
- callback {
- source = ref,
- mode = 'get',
- }
- end
- end
-end
-
-local function ofGoTo(source, callback)
- local name = source[1]
- local label = guide.getLabel(source, name)
- if label then
- ofLabel(label, callback)
- end
-end
-
-local function ofMain(source, callback)
- callback {
- source = source,
- mode = 'main',
- }
-end
-
-local function eachRef(source, callback)
- local stype = source.type
- if stype == 'local' then
- ofLocal(source, callback)
- elseif stype == 'getlocal'
- or stype == 'setlocal' then
- ofLocal(source.node, callback)
- elseif stype == 'setglobal'
- or stype == 'getglobal' then
- ofGlobal(source, callback)
- elseif stype == 'field'
- or stype == 'method' then
- ofField(source, callback)
- elseif stype == 'setfield'
- or stype == 'getfield' then
- ofField(source.field, callback)
- elseif stype == 'setmethod'
- or stype == 'getmethod' then
- ofField(source.method, callback)
- elseif stype == 'number'
- or stype == 'boolean'
- or stype == 'string' then
- ofLiteral(source, callback)
- elseif stype == 'goto' then
- ofGoTo(source, callback)
- elseif stype == 'label' then
- ofLabel(source, callback)
- elseif stype == 'table'
- or stype == 'function' then
- ofValue(source, callback)
- elseif stype == 'main' then
- ofMain(source, callback)
- end
- asArg(source, callback)
-end
-
---- 判断2个对象是否拥有相同的引用
-function vm.isSameRef(a, b)
- local cache = vm.cache.eachRef[a]
- if cache then
- -- 相同引用的source共享同一份cache
- return cache == vm.cache.eachRef[b]
- else
- return vm.eachRef(a, function (info)
- if info.source == b then
- return true
- end
- end) or false
- end
-end
-
---- 获取所有的引用
-function vm.eachRef(source, callback)
- local cache = vm.cache.eachRef[source]
- if cache then
- for i = 1, #cache do
- local res = callback(cache[i])
- if res ~= nil then
- return res
- end
- end
- return
- end
- local unlock = vm.lock('eachRef', source)
- if not unlock then
- return
- end
- cache = {}
- vm.cache.eachRef[source] = cache
- local mark = {}
- eachRef(source, function (info)
- local src = info.source
- if mark[src] then
- return
- end
- mark[src] = true
- cache[#cache+1] = info
- end)
- unlock()
- for i = 1, #cache do
- local src = cache[i].source
- vm.cache.eachRef[src] = cache
- end
- for i = 1, #cache do
- local res = callback(cache[i])
- if res ~= nil then
- return res
- end
- end
-end
diff --git a/server-beta/src/vm/getGlobal.lua b/server-beta/src/vm/getGlobal.lua
deleted file mode 100644
index 373c907e..00000000
--- a/server-beta/src/vm/getGlobal.lua
+++ /dev/null
@@ -1,6 +0,0 @@
-local vm = require 'vm.vm'
-
-function vm.getGlobal(source)
- vm.getGlobals(source)
- return vm.cache.getGlobal[source]
-end
diff --git a/server-beta/src/vm/getGlobals.lua b/server-beta/src/vm/getGlobals.lua
deleted file mode 100644
index 699dd270..00000000
--- a/server-beta/src/vm/getGlobals.lua
+++ /dev/null
@@ -1,45 +0,0 @@
-local guide = require 'parser.guide'
-local vm = require 'vm.vm'
-
-local function getGlobals(root)
- local env = guide.getENV(root)
- local cache = {}
- local mark = {}
- vm.eachField(env, function (info)
- local src = info.source
- if mark[src] then
- return
- end
- mark[src] = true
- local name = info.key
- if not name then
- return
- end
- if not cache[name] then
- cache[name] = {
- key = name,
- mode = {},
- }
- end
- cache[name][#cache[name]+1] = info
- cache[name].mode[info.mode] = true
- vm.cache.getGlobal[src] = name
- end)
- return cache
-end
-
-function vm.getGlobals(source)
- source = guide.getRoot(source)
- local cache = vm.cache.getGlobals[source]
- if cache ~= nil then
- return cache
- end
- local unlock = vm.lock('getGlobals', source)
- if not unlock then
- return nil
- end
- cache = getGlobals(source) or false
- vm.cache.getGlobals[source] = cache
- unlock()
- return cache
-end
diff --git a/server-beta/src/vm/getLibrary.lua b/server-beta/src/vm/getLibrary.lua
deleted file mode 100644
index fd05347e..00000000
--- a/server-beta/src/vm/getLibrary.lua
+++ /dev/null
@@ -1,89 +0,0 @@
-local vm = require 'vm.vm'
-local library = require 'library'
-local guide = require 'parser.guide'
-
-local function checkStdLibrary(source)
- local globalName = vm.getGlobal(source)
- if not globalName then
- return nil
- end
- local name = globalName:match '^s|(.+)$'
- if library.global[name] then
- return library.global[name]
- end
-end
-
-local function getLibInNode(source, nodeLib)
- if not nodeLib then
- return nil
- end
- if not nodeLib.child then
- return nil
- end
- local key = guide.getName(source)
- local defLib = nodeLib.child[key]
- return defLib
-end
-
-local function getNodeAsTable(source)
- local node = source.node
- local nodeGlobalName = vm.getGlobal(node)
- if not nodeGlobalName then
- return nil
- end
- local nodeName = nodeGlobalName:match '^s|(.+)$'
- return getLibInNode(source, library.global[nodeName])
-end
-
-local function getNodeAsObject(source)
- local node = source.node
- local values = vm.getValue(node)
- if not values then
- return nil
- end
- for i = 1, #values do
- local value = values[i]
- local type = value.type
- local nodeLib = library.object[type]
- local lib = getLibInNode(source, nodeLib)
- if lib then
- return lib
- end
- end
- return nil
-end
-
-local function checkNode(source)
- if source.type ~= 'getfield'
- and source.type ~= 'getmethod'
- and source.type ~= 'getindex' then
- return nil
- end
- return getNodeAsTable(source)
- or getNodeAsObject(source)
-end
-
-local function getLibrary(source)
- local lib = checkStdLibrary(source)
- if lib then
- return lib
- end
- return checkNode(source) or vm.eachRef(source, function (info)
- return checkNode(info.source)
- end)
-end
-
-function vm.getLibrary(source)
- local cache = vm.cache.getLibrary[source]
- if cache ~= nil then
- return cache
- end
- local unlock = vm.lock('getLibrary', source)
- if not unlock then
- return
- end
- cache = getLibrary(source) or false
- vm.cache.getLibrary[source] = cache
- unlock()
- return cache
-end
diff --git a/server-beta/src/vm/getLinks.lua b/server-beta/src/vm/getLinks.lua
deleted file mode 100644
index 6875771f..00000000
--- a/server-beta/src/vm/getLinks.lua
+++ /dev/null
@@ -1,48 +0,0 @@
-local guide = require 'parser.guide'
-local vm = require 'vm.vm'
-
-local function getLinks(root)
- local cache = {}
- local ok
- guide.eachSpecialOf(root, 'require', function (source)
- local call = source.parent
- if call.type == 'call' then
- local uris = vm.getLinkUris(call)
- if uris then
- ok = true
- for i = 1, #uris do
- local uri = uris[i]
- if not cache[uri] then
- cache[uri] = {}
- end
- cache[uri][#cache[uri]+1] = call
- end
- end
- end
- end)
- if not ok then
- return nil
- end
- return cache
-end
-
-function vm.getLinks(source)
- source = guide.getRoot(source)
- local cache = vm.cache.getLinks[source]
- if cache ~= nil then
- return cache
- end
- local unlock = vm.lock('getLinks', source)
- if not unlock then
- return nil
- end
- local clock = os.clock()
- cache = getLinks(source) or false
- local passed = os.clock() - clock
- if passed > 0.1 then
- log.warn(('getLinks takes [%.3f] sec!'):format(passed))
- end
- vm.cache.getLinks[source] = cache
- unlock()
- return cache
-end
diff --git a/server-beta/src/vm/getValue.lua b/server-beta/src/vm/getValue.lua
deleted file mode 100644
index ee486a54..00000000
--- a/server-beta/src/vm/getValue.lua
+++ /dev/null
@@ -1,895 +0,0 @@
-local vm = require 'vm.vm'
-
-local typeSort = {
- ['boolean'] = 1,
- ['string'] = 2,
- ['integer'] = 3,
- ['number'] = 4,
- ['table'] = 5,
- ['function'] = 6,
- ['nil'] = math.maxinteger,
-}
-
-NIL = setmetatable({'<nil>'}, { __tostring = function () return 'nil' end })
-
-local function merge(t, b)
- if not t then
- t = {}
- end
- if not b then
- return t
- end
- for i = 1, #b do
- local o = b[i]
- if not t[o] then
- t[o] = true
- t[#t+1] = o
- end
- end
- return t
-end
-
-local function alloc(o)
- -- TODO
- assert(o.type)
- if type(o.type) == 'table' then
- local values = {}
- for i = 1, #o.type do
- local sub = {
- type = o.type[i],
- value = o.value,
- source = o.source,
- }
- values[i] = sub
- values[sub] = true
- end
- return values
- else
- return {
- [1] = o,
- [o] = true,
- }
- end
-end
-
-local function insert(t, o)
- if not o then
- return
- end
- if not t[o] then
- t[o] = true
- t[#t+1] = o
- end
- return t
-end
-
-local function checkLiteral(source)
- if source.type == 'string' then
- return alloc {
- type = 'string',
- value = source[1],
- source = source,
- }
- elseif source.type == 'nil' then
- return alloc {
- type = 'nil',
- value = NIL,
- source = source,
- }
- elseif source.type == 'boolean' then
- return alloc {
- type = 'boolean',
- value = source[1],
- source = source,
- }
- elseif source.type == 'number' then
- if math.type(source[1]) == 'integer' then
- return alloc {
- type = 'integer',
- value = source[1],
- source = source,
- }
- else
- return alloc {
- type = 'number',
- value = source[1],
- source = source,
- }
- end
- elseif source.type == 'table' then
- return alloc {
- type = 'table',
- source = source,
- }
- elseif source.type == 'function' then
- return alloc {
- type = 'function',
- source = source,
- }
- end
-end
-
-local function checkUnary(source)
- if source.type ~= 'unary' then
- return
- end
- local op = source.op
- if op.type == 'not' then
- local checkTrue = vm.checkTrue(source[1])
- local value = nil
- if checkTrue == true then
- value = false
- elseif checkTrue == false then
- value = true
- end
- return alloc {
- type = 'boolean',
- value = value,
- source = source,
- }
- elseif op.type == '#' then
- return alloc {
- type = 'integer',
- source = source,
- }
- elseif op.type == '~' then
- local l = vm.getLiteral(source[1], 'integer')
- return alloc {
- type = 'integer',
- value = l and ~l or nil,
- source = source,
- }
- elseif op.type == '-' then
- local v = vm.getLiteral(source[1], 'integer')
- if v then
- return alloc {
- type = 'integer',
- value = - v,
- source = source,
- }
- end
- v = vm.getLiteral(source[1], 'number')
- return alloc {
- type = 'number',
- value = v and -v or nil,
- source = source,
- }
- end
-end
-
-local function checkBinary(source)
- if source.type ~= 'binary' then
- return
- end
- local op = source.op
- if op.type == 'and' then
- local isTrue = vm.checkTrue(source[1])
- if isTrue == true then
- return vm.getValue(source[2])
- elseif isTrue == false then
- return vm.getValue(source[1])
- else
- return merge(
- vm.getValue(source[1]),
- vm.getValue(source[2])
- )
- end
- elseif op.type == 'or' then
- local isTrue = vm.checkTrue(source[1])
- if isTrue == true then
- return vm.getValue(source[1])
- elseif isTrue == false then
- return vm.getValue(source[2])
- else
- return merge(
- vm.getValue(source[1]),
- vm.getValue(source[2])
- )
- end
- elseif op.type == '==' then
- local value = vm.isSameValue(source[1], source[2])
- if value ~= nil then
- return alloc {
- type = 'boolean',
- value = value,
- source = source,
- }
- end
- local isSame = vm.isSameRef(source[1], source[2])
- if isSame == true then
- value = true
- else
- value = nil
- end
- return alloc {
- type = 'boolean',
- value = value,
- source = source,
- }
- elseif op.type == '~=' then
- local value = vm.isSameValue(source[1], source[2])
- if value ~= nil then
- return alloc {
- type = 'boolean',
- value = not value,
- source = source,
- }
- end
- local isSame = vm.isSameRef(source[1], source[2])
- if isSame == true then
- value = false
- else
- value = nil
- end
- return alloc {
- type = 'boolean',
- value = value,
- source = source,
- }
- elseif op.type == '<=' then
- local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
- local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
- local v
- if v1 and v2 then
- v = v1 <= v2
- end
- return alloc {
- type = 'boolean',
- value = v,
- source = source,
- }
- elseif op.type == '>=' then
- local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
- local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
- local v
- if v1 and v2 then
- v = v1 >= v2
- end
- return alloc {
- type = 'boolean',
- value = v,
- source = source,
- }
- elseif op.type == '<' then
- local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
- local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
- local v
- if v1 and v2 then
- v = v1 < v2
- end
- return alloc {
- type = 'boolean',
- value = v,
- source = source,
- }
- elseif op.type == '>' then
- local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
- local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
- local v
- if v1 and v2 then
- v = v1 > v2
- end
- return alloc {
- type = 'boolean',
- value = v,
- source = source,
- }
- elseif op.type == '|' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- local v
- if v1 and v2 then
- v = v1 | v2
- end
- return alloc {
- type = 'integer',
- value = v,
- source = source,
- }
- elseif op.type == '~' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- local v
- if v1 and v2 then
- v = v1 ~ v2
- end
- return alloc {
- type = 'integer',
- value = v,
- source = source,
- }
- elseif op.type == '&' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- local v
- if v1 and v2 then
- v = v1 & v2
- end
- return alloc {
- type = 'integer',
- value = v,
- source = source,
- }
- elseif op.type == '<<' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- local v
- if v1 and v2 then
- v = v1 << v2
- end
- return alloc {
- type = 'integer',
- value = v,
- source = source,
- }
- elseif op.type == '>>' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- local v
- if v1 and v2 then
- v = v1 >> v2
- end
- return alloc {
- type = 'integer',
- value = v,
- source = source,
- }
- elseif op.type == '..' then
- local v1 = vm.getLiteral(source[1], 'string')
- local v2 = vm.getLiteral(source[2], 'string')
- local v
- if v1 and v2 then
- v = v1 .. v2
- end
- return alloc {
- type = 'string',
- value = v,
- source = source,
- }
- elseif op.type == '^' then
- local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
- local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
- local v
- if v1 and v2 then
- v = v1 ^ v2
- end
- return alloc {
- type = 'number',
- value = v,
- source = source,
- }
- elseif op.type == '/' then
- local v1 = vm.getLiteral(source[1], 'integer') or vm.getLiteral(source[1], 'number')
- local v2 = vm.getLiteral(source[2], 'integer') or vm.getLiteral(source[2], 'number')
- local v
- if v1 and v2 then
- v = v1 > v2
- end
- return alloc {
- type = 'number',
- value = v,
- source = source,
- }
- -- 其他数学运算根据2侧的值决定,当2侧的值均为整数时返回整数
- elseif op.type == '+' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- if v1 and v2 then
- return alloc {
- type = 'integer',
- value = v1 + v2,
- source = source,
- }
- end
- v1 = v1 or vm.getLiteral(source[1], 'number')
- v2 = v2 or vm.getLiteral(source[1], 'number')
- return alloc {
- type = 'number',
- value = (v1 and v2) and (v1 + v2) or nil,
- source = source,
- }
- elseif op.type == '-' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- if v1 and v2 then
- return alloc {
- type = 'integer',
- value = v1 - v2,
- source = source,
- }
- end
- v1 = v1 or vm.getLiteral(source[1], 'number')
- v2 = v2 or vm.getLiteral(source[1], 'number')
- return alloc {
- type = 'number',
- value = (v1 and v2) and (v1 - v2) or nil,
- source = source,
- }
- elseif op.type == '*' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- if v1 and v2 then
- return alloc {
- type = 'integer',
- value = v1 * v2,
- source = source,
- }
- end
- v1 = v1 or vm.getLiteral(source[1], 'number')
- v2 = v2 or vm.getLiteral(source[1], 'number')
- return alloc {
- type = 'number',
- value = (v1 and v2) and (v1 * v2) or nil,
- source = source,
- }
- elseif op.type == '%' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- if v1 and v2 then
- return alloc {
- type = 'integer',
- value = v1 % v2,
- source = source,
- }
- end
- v1 = v1 or vm.getLiteral(source[1], 'number')
- v2 = v2 or vm.getLiteral(source[1], 'number')
- return alloc {
- type = 'number',
- value = (v1 and v2) and (v1 % v2) or nil,
- source = source,
- }
- elseif op.type == '//' then
- local v1 = vm.getLiteral(source[1], 'integer')
- local v2 = vm.getLiteral(source[2], 'integer')
- if v1 and v2 then
- return alloc {
- type = 'integer',
- value = v1 // v2,
- source = source,
- }
- end
- v1 = v1 or vm.getLiteral(source[1], 'number')
- v2 = v2 or vm.getLiteral(source[1], 'number')
- return alloc {
- type = 'number',
- value = (v1 and v2) and (v1 // v2) or nil,
- source = source,
- }
- end
-end
-
-local function checkValue(source)
- if source.value then
- return vm.getValue(source.value)
- end
- if source.type == 'paren' then
- return vm.getValue(source.exp)
- end
-end
-
-local function hasTypeInResults(results, type)
- for i = 1, #results do
- if results[i].type == type then
- return true
- end
- end
- return false
-end
-
-local function inferByCall(results, source)
- if #results ~= 0 then
- return
- end
- if not source.parent then
- return
- end
- if source.parent.type ~= 'call' then
- return
- end
- if source.parent.node == source then
- insert(results, {
- type = 'function',
- source = source,
- })
- return
- end
-end
-
-local function inferByGetTable(results, source)
- if #results ~= 0 then
- return
- end
- local next = source.next
- if not next then
- return
- end
- if next.type == 'getfield'
- or next.type == 'getindex'
- or next.type == 'getmethod'
- or next.type == 'setfield'
- or next.type == 'setindex'
- or next.type == 'setmethod' then
- insert(results, {
- type = 'table',
- source = source,
- })
- end
-end
-
-local function checkDef(results, source)
- vm.eachDef(source, function (info)
- local src = info.source
- local tp = vm.getValue(src)
- if tp then
- merge(results, tp)
- end
- end)
-end
-
-local function checkLibrary(source)
- local lib = vm.getLibrary(source)
- if not lib then
- return nil
- end
- return alloc {
- type = lib.type,
- value = lib.value,
- source = vm.librarySource(lib),
- }
-end
-
-local function checkLibraryReturn(source)
- if source.type ~= 'select' then
- return nil
- end
- local index = source.index
- local call = source.vararg
- if call.type ~= 'call' then
- return nil
- end
- local func = call.node
- local lib = vm.getLibrary(func)
- if not lib then
- return nil
- end
- if lib.type ~= 'function' then
- return nil
- end
- if not lib.returns then
- return nil
- end
- local rtn = lib.returns[index]
- if not rtn then
- return nil
- end
- return alloc {
- type = rtn.type,
- value = rtn.value,
- source = vm.librarySource(rtn),
- }
-end
-
-local function checkLibraryArg(source)
- local args = source.parent
- if not args then
- return
- end
- if args.type ~= 'callargs' then
- return
- end
- local call = args.parent
- if not call then
- return
- end
- local func = call.node
- local index
- for i = 1, #args do
- if args[i] == source then
- index = i
- break
- end
- end
- if not index then
- return
- end
- local lib = vm.getLibrary(func)
- local arg = lib and lib.args and lib.args[index]
- if not arg then
- return
- end
- if arg.type == '...' then
- return
- end
- return alloc {
- type = arg.type,
- value = arg.value,
- source = vm.librarySource(arg),
- }
-end
-
-local function inferByUnary(results, source)
- if #results ~= 0 then
- return
- end
- local parent = source.parent
- if not parent or parent.type ~= 'unary' then
- return
- end
- local op = parent.op
- if op.type == '#' then
- insert(results, {
- type = 'string',
- source = vm.librarySource(source)
- })
- insert(results, {
- type = 'table',
- source = vm.librarySource(source)
- })
- elseif op.type == '~' then
- insert(results, {
- type = 'integer',
- source = vm.librarySource(source)
- })
- elseif op.type == '-' then
- insert(results, {
- type = 'number',
- source = vm.librarySource(source)
- })
- end
-end
-
-local function inferByBinary(results, source)
- if #results ~= 0 then
- return
- end
- local parent = source.parent
- if not parent or parent.type ~= 'binary' then
- return
- end
- local op = parent.op
- if op.type == '<='
- or op.type == '>='
- or op.type == '<'
- or op.type == '>'
- or op.type == '^'
- or op.type == '/'
- or op.type == '+'
- or op.type == '-'
- or op.type == '*'
- or op.type == '%' then
- insert(results, {
- type = 'number',
- source = vm.librarySource(source)
- })
- elseif op.type == '|'
- or op.type == '~'
- or op.type == '&'
- or op.type == '<<'
- or op.type == '>>'
- -- 整数的可能性比较高
- or op.type == '//' then
- insert(results, {
- type = 'integer',
- source = vm.librarySource(source)
- })
- elseif op.type == '..' then
- insert(results, {
- type = 'string',
- source = vm.librarySource(source)
- })
- end
-end
-
-local function inferBySetOfLocal(results, source)
- if source.ref then
- for i = 1, #source.ref do
- local ref = source.ref[i]
- if ref.type == 'setlocal' then
- break
- end
- merge(results, vm.getValue(ref))
- end
- end
-end
-
-local function inferBySet(results, source)
- if #results ~= 0 then
- return
- end
- if source.type == 'local' then
- inferBySetOfLocal(results, source)
- elseif source.type == 'setlocal'
- or source.type == 'getlocal' then
- inferBySetOfLocal(results, source.node)
- end
-end
-
-local function getValue(source)
- local results = checkLiteral(source)
- or checkValue(source)
- or checkUnary(source)
- or checkBinary(source)
- or checkLibrary(source)
- or checkLibraryReturn(source)
- or checkLibraryArg(source)
- if results then
- return results
- end
-
- results = {}
- checkDef(results, source)
- inferBySet(results, source)
- inferByCall(results, source)
- inferByGetTable(results, source)
- inferByUnary(results, source)
- inferByBinary(results, source)
-
- if #results == 0 then
- return nil
- end
-
- return results
-end
-
-function vm.checkTrue(source)
- local values = vm.getValue(source)
- if not values then
- return
- end
- -- 当前认为的结果
- local current
- for i = 1, #values do
- -- 新的结果
- local new
- local v = values[i]
- if v.type == 'nil' then
- new = false
- elseif v.type == 'boolean' then
- if v.value == true then
- new = true
- elseif v.value == false then
- new = false
- end
- end
- if new ~= nil then
- if current == nil then
- current = new
- else
- -- 如果2个结果完全相反,则返回 nil 表示不确定
- if new ~= current then
- return nil
- end
- end
- end
- end
- return current
-end
-
---- 获取特定类型的字面量值
-function vm.getLiteral(source, type)
- local values = vm.getValue(source)
- if not values then
- return nil
- end
- for i = 1, #values do
- local v = values[i]
- if v.value ~= nil then
- if type == nil or v.type == type then
- return v.value
- end
- end
- end
- return nil
-end
-
-function vm.isSameValue(a, b)
- local valuesA = vm.getValue(a)
- local valuesB = vm.getValue(b)
- if not valuesA or not valuesB then
- return false
- end
- if valuesA == valuesB then
- return true
- end
- local values = {}
- for i = 1, #valuesA do
- local value = valuesA[i]
- local literal = value.value
- if literal then
- values[literal] = false
- end
- end
- for i = 1, #valuesB do
- local value = valuesA[i]
- local literal = value.value
- if literal then
- if values[literal] == nil then
- return false
- end
- values[literal] = true
- end
- end
- for k, v in pairs(values) do
- if v == false then
- return false
- end
- end
- return true
-end
-
---- 是否包含某种类型
-function vm.hasType(source, type)
- local values = vm.getValue(source)
- if not values then
- return false
- end
- for i = 1, #values do
- local value = values[i]
- if value.type == type then
- return true
- end
- end
- return false
-end
-
-function vm.viewType(values)
- if not values then
- return 'any'
- end
- local types = {}
- for i = 1, #values do
- local tp = values[i].type
- if not types[tp] then
- types[tp] = true
- types[#types+1] = tp
- end
- end
- if #types == 0 then
- return 'any'
- end
- if #types == 1 then
- return types[1]
- end
- table.sort(types, function (a, b)
- local sa = typeSort[a]
- local sb = typeSort[b]
- if sa and sb then
- return sa < sb
- end
- if not sa and not sb then
- return a < b
- end
- if sa and not sb then
- return true
- end
- if not sa and sb then
- return false
- end
- return false
- end)
- return table.concat(types, '|')
-end
-
-function vm.getType(source)
- local values = vm.getValue(source)
- return vm.viewType(values)
-end
-
-function vm.getValue(source)
- if not source then
- return
- end
- local cache = vm.cache.getValue[source]
- if cache ~= nil then
- return cache
- end
- local unlock = vm.lock('getValue', source)
- if not unlock then
- return
- end
- cache = getValue(source) or false
- vm.cache.getValue[source] = cache
- unlock()
- return cache
-end
diff --git a/server-beta/src/vm/init.lua b/server-beta/src/vm/init.lua
deleted file mode 100644
index 4249de3d..00000000
--- a/server-beta/src/vm/init.lua
+++ /dev/null
@@ -1,11 +0,0 @@
-local vm = require 'vm.vm'
-require 'vm.eachField'
-require 'vm.eachRef'
-require 'vm.eachDef'
-require 'vm.getGlobals'
-require 'vm.getLinks'
-require 'vm.getGlobal'
-require 'vm.getLibrary'
-require 'vm.getValue'
-require 'vm.dummySource'
-return vm
diff --git a/server-beta/src/vm/special.lua b/server-beta/src/vm/special.lua
deleted file mode 100644
index e69de29b..00000000
--- a/server-beta/src/vm/special.lua
+++ /dev/null
diff --git a/server-beta/src/vm/vm.lua b/server-beta/src/vm/vm.lua
deleted file mode 100644
index 23a691df..00000000
--- a/server-beta/src/vm/vm.lua
+++ /dev/null
@@ -1,81 +0,0 @@
-local guide = require 'parser.guide'
-local util = require 'utility'
-
-local setmetatable = setmetatable
-local assert = assert
-local require = require
-local type = type
-
-_ENV = nil
-
-local specials = {
- ['_G'] = true,
- ['rawset'] = true,
- ['rawget'] = true,
- ['setmetatable'] = true,
- ['require'] = true,
- ['dofile'] = true,
- ['loadfile'] = true,
-}
-
----@class vm
-local m = {}
-
-function m.lock(tp, source)
- if m.locked[tp][source] then
- return nil
- end
- m.locked[tp][source] = true
- return function ()
- m.locked[tp][source] = nil
- end
-end
-
---- 获取link的uri
-function m.getLinkUris(call)
- local workspace = require 'workspace'
- local func = call.node
- local name = func.special
- if name == 'require' then
- local args = call.args
- if not args[1] then
- return nil
- end
- local literal = guide.getLiteral(args[1])
- if type(literal) ~= 'string' then
- return nil
- end
- return workspace.findUrisByRequirePath(literal, true)
- end
-end
-
-m.cacheTracker = setmetatable({}, { __mode = 'kv' })
-
---- 刷新缓存
-function m.refreshCache()
- if m.cache then
- m.cache.dead = true
- end
- m.cache = {
- eachRef = {},
- eachField = {},
- getGlobals = {},
- getLinks = {},
- getGlobal = {},
- specialName = {},
- getLibrary = {},
- getValue = {},
- specials = nil,
- }
- m.locked = {
- eachRef = {},
- eachField = {},
- getGlobals = {},
- getLinks = {},
- getLibrary = {},
- getValue = {},
- }
- m.cacheTracker[m.cache] = true
-end
-
-return m
diff --git a/server-beta/src/workspace/init.lua b/server-beta/src/workspace/init.lua
deleted file mode 100644
index 7cbe15d7..00000000
--- a/server-beta/src/workspace/init.lua
+++ /dev/null
@@ -1,3 +0,0 @@
-local workspace = require 'workspace.workspace'
-
-return workspace
diff --git a/server-beta/src/workspace/workspace.lua b/server-beta/src/workspace/workspace.lua
deleted file mode 100644
index 37ec2d7b..00000000
--- a/server-beta/src/workspace/workspace.lua
+++ /dev/null
@@ -1,194 +0,0 @@
-local pub = require 'pub'
-local fs = require 'bee.filesystem'
-local furi = require 'file-uri'
-local files = require 'files'
-local config = require 'config'
-local glob = require 'glob'
-local platform = require 'bee.platform'
-local await = require 'await'
-local diagnostic = require 'provider.diagnostic'
-
-local m = {}
-m.type = 'workspace'
-m.ignoreVersion = -1
-m.ignoreMatcher = nil
-
---- 初始化工作区
-function m.init(name, uri)
- m.name = name
- m.uri = uri
- m.path = furi.decode(uri)
- log.info('Workspace inited: ', uri)
- local logPath = ROOT / 'log' / (uri:gsub('[/:]+', '_') .. '.log')
- log.info('Log path: ', logPath)
- log.init(ROOT, logPath)
-end
-
---- 创建排除文件匹配器
-function m.getIgnoreMatcher()
- if m.ignoreVersion == config.version then
- return m.ignoreMatcher
- end
-
- local pattern = {}
- -- config.workspace.ignoreDir
- for path in pairs(config.config.workspace.ignoreDir) do
- log.info('Ignore directory:', path)
- pattern[#pattern+1] = path
- end
- -- config.files.exclude
- for path, ignore in pairs(config.other.exclude) do
- if ignore then
- log.info('Ignore by exclude:', path)
- pattern[#pattern+1] = path
- end
- end
- -- config.workspace.ignoreSubmodules
- if config.config.workspace.ignoreSubmodules then
- local buf = pub.awaitTask('loadFile', furi.encode(m.path .. '/.gitmodules'))
- if buf then
- for path in buf:gmatch('path = ([^\r\n]+)') do
- log.info('Ignore by .gitmodules:', path)
- pattern[#pattern+1] = path
- end
- end
- end
- -- config.workspace.useGitIgnore
- if config.config.workspace.useGitIgnore then
- local buf = pub.awaitTask('loadFile', furi.encode(m.path .. '/.gitignore'))
- if buf then
- for line in buf:gmatch '[^\r\n]+' do
- log.info('Ignore by .gitignore:', line)
- pattern[#pattern+1] = line
- end
- end
- end
- -- config.workspace.library
- for path in pairs(config.config.workspace.library) do
- log.info('Ignore by library:', path)
- pattern[#pattern+1] = path
- end
-
- m.ignoreMatcher = glob.gitignore(pattern)
-
- if platform.OS == "Windows" then
- m.ignoreMatcher:setOption 'ignoreCase'
- end
-
- m.ignoreVersion = config.version
- return m.ignoreMatcher
-end
-
---- 文件是否被忽略
-function m.isIgnored(uri)
- local path = furi.decode(uri)
- local ignore = m.getIgnoreMatcher()
- return ignore(path)
-end
-
---- 预读工作区内所有文件
-function m.awaitPreload()
- if not m.uri then
- return
- end
- local max = 0
- local read = 0
- log.info('Preload start.')
- local ignore = m.getIgnoreMatcher()
-
- ignore:setInterface('type', function (path)
- if fs.is_directory(fs.path(m.path .. '/' .. path)) then
- return 'directory'
- else
- return 'file'
- end
- end)
-
- ignore:setInterface('list', function (path)
- local paths = {}
- for fullpath in fs.path(m.path .. '/' .. path):list_directory() do
- paths[#paths+1] = fullpath:string()
- end
- return paths
- end)
-
- ignore:scan(function (path)
- local uri = furi.encode(m.path .. '/' .. path)
- if not files.isLua(uri) then
- return
- end
- max = max + 1
- pub.task('loadFile', uri, function (text)
- read = read + 1
- --log.info(('Preload file at: %s , size = %.3f KB'):format(uri, #text / 1000.0))
- files.setText(uri, text)
- end)
- end)
-
- log.info(('Found %d files.'):format(max))
- while true do
- log.info(('Loaded %d/%d files'):format(read, max))
- if read >= max then
- break
- end
- await.sleep(0.1)
- end
-
- log.info('Preload finish.')
- diagnostic.start()
-end
-
---- 查找符合指定file path的所有uri
----@param path string
----@param whole boolean
-function m.findUrisByFilePath(path, whole)
- local results = {}
- for uri in files.eachFile() do
- local pathLen = #path
- local uriLen = #uri
- if whole then
- local seg = uri:sub(uriLen - pathLen, uriLen - pathLen)
- if seg == '/' or seg == '\\' or seg == '' then
- local see = uri:sub(uriLen - pathLen + 1, uriLen)
- if files.eq(see, path) then
- results[#results+1] = uri
- end
- end
- else
- for i = uriLen, uriLen - pathLen + 1, -1 do
- local see = uri:sub(i - pathLen + 1, i)
- if files.eq(see, path) then
- results[#results+1] = uri
- end
- end
- end
- end
- return results
-end
-
---- 查找符合指定require path的所有uri
----@param path string
----@param whole boolean
-function m.findUrisByRequirePath(path, whole)
- local results = {}
- local mark = {}
- local input = path:gsub('%.', '/')
- for _, luapath in ipairs(config.config.runtime.path) do
- local part = luapath:gsub('%?', input)
- local uris = m.findUrisByFilePath(part, whole)
- for _, uri in ipairs(uris) do
- if not mark[uri] then
- mark[uri] = true
- results[#results+1] = uri
- end
- end
- end
- return results
-end
-
-function m.getRelativePath(uri)
- local path = furi.decode(uri)
- return fs.relative(fs.path(path), fs.path(m.path)):string()
-end
-
-return m