summaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'server/src')
-rw-r--r--server/src/core/init.lua1
-rw-r--r--server/src/vm/dots.lua6
-rw-r--r--server/src/vm/env.lua (renamed from server/src/core/env.lua)0
-rw-r--r--server/src/vm/function.lua36
-rw-r--r--server/src/vm/global.lua20
-rw-r--r--server/src/vm/init.lua1
-rw-r--r--server/src/vm/library.lua63
-rw-r--r--server/src/vm/local.lua (renamed from server/src/core/local.lua)17
-rw-r--r--server/src/vm/source.lua18
-rw-r--r--server/src/vm/value.lua (renamed from server/src/core/value.lua)28
-rw-r--r--server/src/vm/vm.lua (renamed from server/src/core/vm.lua)249
-rw-r--r--server/src/vm/vm.txt (renamed from server/src/core/vm.txt)0
12 files changed, 260 insertions, 179 deletions
diff --git a/server/src/core/init.lua b/server/src/core/init.lua
index 68898814..148871a1 100644
--- a/server/src/core/init.lua
+++ b/server/src/core/init.lua
@@ -11,7 +11,6 @@ local api = {
signature = require 'core.signature',
documentSymbol = require 'core.document_symbol',
global = require 'core.global',
- vm = require 'core.vm',
}
return api
diff --git a/server/src/vm/dots.lua b/server/src/vm/dots.lua
new file mode 100644
index 00000000..1736de5c
--- /dev/null
+++ b/server/src/vm/dots.lua
@@ -0,0 +1,6 @@
+local mt = {}
+mt.__index = mt
+mt.type = 'dots'
+
+return function ()
+end
diff --git a/server/src/core/env.lua b/server/src/vm/env.lua
index ada26145..ada26145 100644
--- a/server/src/core/env.lua
+++ b/server/src/vm/env.lua
diff --git a/server/src/vm/function.lua b/server/src/vm/function.lua
new file mode 100644
index 00000000..25465398
--- /dev/null
+++ b/server/src/vm/function.lua
@@ -0,0 +1,36 @@
+local env = require 'vm.env'
+local createDots = require 'vm.dots'
+
+local mt = {}
+mt.__index = mt
+mt.type = 'function'
+mt._returnDots = false
+
+function mt:getUri()
+ return self.source.uri
+end
+
+function mt:saveLocal(name, loc)
+ self.locals[name] = loc
+end
+
+function mt:setReturn(index, value)
+ self.returns[index] = value
+end
+
+function mt:returnDots(index, value)
+ self.returns[index] = value
+ self._returnDots = true
+end
+
+return function (source)
+ if not source then
+ error('Function must has a source')
+ end
+ local self = setmetatable({
+ source = source,
+ locals = {},
+ returns = {},
+ }, mt)
+ return self
+end
diff --git a/server/src/vm/global.lua b/server/src/vm/global.lua
new file mode 100644
index 00000000..4e368641
--- /dev/null
+++ b/server/src/vm/global.lua
@@ -0,0 +1,20 @@
+local createValue = require 'vm.value'
+local library = require 'core.library'
+local libraryBuilder = require 'vm.library'
+
+return function (lsp)
+ local global = lsp and lsp.globalValue
+ if not global then
+ global = createValue('table')
+ end
+ for name, lib in pairs(library.global) do
+ if not global:rawGet(name) then
+ local value = libraryBuilder.value(lib)
+ global:rawSet(name, value)
+ end
+ end
+ if lsp then
+ lsp.globalValue = global
+ end
+ return global
+end
diff --git a/server/src/vm/init.lua b/server/src/vm/init.lua
new file mode 100644
index 00000000..87576ba5
--- /dev/null
+++ b/server/src/vm/init.lua
@@ -0,0 +1 @@
+return require 'vm.vm'
diff --git a/server/src/vm/library.lua b/server/src/vm/library.lua
new file mode 100644
index 00000000..a6b9629e
--- /dev/null
+++ b/server/src/vm/library.lua
@@ -0,0 +1,63 @@
+local createValue = require 'vm.value'
+local createFunction = require 'vm.function'
+
+local buildLibValue
+local buildLibChild
+
+local function getDefaultSource()
+ return {
+ start = 0,
+ finish = 0,
+ uri = '',
+ }
+end
+
+function buildLibValue(lib)
+ local tp = lib.type
+ local value
+ if tp == 'table' then
+ value = createValue('table')
+ elseif tp == 'function' then
+ value = createValue('function')
+ local func = createFunction(getDefaultSource())
+ value:setFunction(func)
+ if lib.returns then
+ for i, rtn in ipairs(lib.returns) do
+ if rtn.type == '...' then
+ func:returnDots(i, buildLibValue(rtn))
+ else
+ func:setReturn(i, buildLibValue(rtn))
+ end
+ end
+ end
+ elseif tp == 'string' then
+ value = createValue('string')
+ elseif tp == 'boolean' then
+ value = createValue('boolean')
+ elseif tp == 'number' then
+ value = createValue('number')
+ elseif tp == 'integer' then
+ value = createValue('integer')
+ elseif tp == 'nil' then
+ value = createValue('nil')
+ elseif tp == '...' then
+ value = createValue('any')
+ else
+ value = createValue(tp or 'any')
+ end
+ value:setLib(lib)
+
+ if lib.child then
+ for fName, fLib in pairs(lib.child) do
+ local fValue = buildLibValue(fLib)
+ value:rawSet(fName, fValue)
+ end
+ end
+
+ return value
+end
+
+return {
+ value = buildLibValue,
+ child = buildLibChild,
+}
diff --git a/server/src/core/local.lua b/server/src/vm/local.lua
index 7deac275..f1c33ecf 100644
--- a/server/src/core/local.lua
+++ b/server/src/vm/local.lua
@@ -35,7 +35,24 @@ function mt:eachInfo(callback)
end
end
+function mt:setFlag(name, v)
+ if not self._flag then
+ self._flag = {}
+ end
+ self._flag[name] = v
+end
+
+function mt:getFlag(name)
+ if not self._flag then
+ return nil
+ end
+ return self._flag[name]
+end
+
return function (name, source, value)
+ if not value then
+ error('Local must has a value')
+ end
local self = setmetatable({
name = name,
source = source or getDefaultSource(),
diff --git a/server/src/vm/source.lua b/server/src/vm/source.lua
new file mode 100644
index 00000000..5ec602c6
--- /dev/null
+++ b/server/src/vm/source.lua
@@ -0,0 +1,18 @@
+local mt = {}
+mt.__index = mt
+
+function mt:bindLocal(loc)
+ if loc then
+ self._bindLocal = loc
+ else
+ return self._bindLocal
+ end
+end
+
+function mt:setUri(uri)
+ self._uri = uri
+end
+
+return function (source)
+ return setmetatable(source, mt)
+end
diff --git a/server/src/core/value.lua b/server/src/vm/value.lua
index fdd9d902..21dd4307 100644
--- a/server/src/core/value.lua
+++ b/server/src/vm/value.lua
@@ -21,7 +21,7 @@ end
function mt:setType(tp, rate)
if type(tp) == 'table' then
for _, ctp in ipairs(tp) do
- self:inference(ctp, rate)
+ self:setType(ctp, rate)
end
return
end
@@ -166,11 +166,17 @@ function mt:mergeValue(value)
self._child[k] = v
end
end
+ for _, info in ipairs(value) do
+ self[#self+1] = info
+ end
if value._meta then
self._meta = value._meta
end
- for _, info in ipairs(value) do
- self[#self+1] = info
+ if value._func then
+ self._func = value._func
+ end
+ if value._lib then
+ self._lib = value._lib
end
end
@@ -194,13 +200,25 @@ function mt:eachInfo(callback)
return nil
end
-return function (tp, source, v)
+function mt:setFunction(func)
+ self._func = func
+ self:setType('function', 1.0)
+end
+
+function mt:setLib(lib)
+ self._lib = lib
+end
+
+function mt:getLib()
+ return self._lib
+end
+
+return function (tp, source)
if tp == '...' then
error('Value type cant be ...')
end
local self = setmetatable({
source = source or getDefaultSource(),
- _value = v,
_type = {},
}, mt)
if type(tp) == 'table' then
diff --git a/server/src/core/vm.lua b/server/src/vm/vm.lua
index 66fdd2c6..48d7e038 100644
--- a/server/src/core/vm.lua
+++ b/server/src/vm/vm.lua
@@ -1,9 +1,9 @@
-local env = require 'core.env'
local library = require 'core.library'
-local createValue = require 'core.value'
-
-local LibraryValue = {}
-local LibraryChild = {}
+local createValue = require 'vm.value'
+local createLocal = require 'vm.local'
+local createFunction = require 'vm.function'
+local instantSource = require 'vm.source'
+local buildGlobal = require 'vm.global'
local mt = {}
mt.__index = mt
@@ -12,7 +12,7 @@ function mt:getDefaultSource()
return {
start = 0,
finish = 0,
- uri = self.chunk.func.uri,
+ uri = self:getUri(),
}
end
@@ -36,54 +36,6 @@ function mt:createDummyVar(source, value)
return loc
end
-function mt:createLocal(key, source, value)
- if source and source.bind then
- self.scope.locals[key] = source.bind
- return source.bind
- end
- local loc = {
- type = 'local',
- key = key,
- source = source or self:getDefaultSource(),
- close = self.scope.block.finish,
- }
-
- if source then
- source.bind = loc
- self.results.sources[#self.results.sources+1] = source
- source.isLocal = true
- source.uri = self.chunk.func.uri
- end
-
- local shadow = self.scope.locals[key]
- if shadow then
- if source then
- shadow.close = source.start - 1
- end
- local group
- if shadow.shadow then
- group = shadow.shadow
- else
- group = { shadow }
- shadow.shadow = group
- end
- group[#group+1] = loc
- loc.shadow = group
- end
-
- self.scope.locals[key] = loc
- self.results.locals[#self.results.locals+1] = loc
-
- if source then
- self:addInfo(loc, 'local', source, value)
- if value then
- value:addInfo('local', source)
- end
- end
- self:setValue(loc, value, source)
- return loc
-end
-
function mt:createField(value, index, source)
if source and source.bind then
return source.bind
@@ -637,77 +589,6 @@ function mt:createValue(tp, source, v)
return value
end
-function mt:getLibChild(value, lib, parentType)
- if lib.child then
- if LibraryChild[lib] then
- value:setChild(LibraryChild[lib])
- return
- end
- -- 要先声明缓存,以免死循环
- LibraryChild[lib] = value:getChild()
- for fName, fLib in pairs(lib.child) do
- local fField = self:createField(value, fName)
- local fValue = self:getLibValue(fLib, parentType)
- self:setValue(fField, fValue)
- end
- end
-end
-
-function mt:getLibValue(lib, parentType, v)
- if LibraryValue[lib] then
- return LibraryValue[lib]
- end
- local tp = lib.type
- local value
- if tp == 'table' then
- value = self:createValue('table')
- elseif tp == 'function' then
- value = self:createValue('function')
- if lib.returns then
- local dots
- for i, rtn in ipairs(lib.returns) do
- self:setFunctionReturn(value, i, self:getLibValue(rtn, parentType))
- if rtn.type == '...' then
- dots = true
- end
- end
- if not dots then
- value.maxReturns = #lib.returns
- end
- else
- value.maxReturns = 0
- end
- if lib.args then
- local values = {}
- for i, arg in ipairs(lib.args) do
- values[i] = self:getLibValue(arg, parentType) or self:createValue('any')
- end
- -- TODO 确定参数类型
- end
- elseif tp == 'string' then
- value = self:createValue('string', nil, v or lib.value)
- elseif tp == 'boolean' then
- value = self:createValue('boolean', nil, v or lib.value)
- elseif tp == 'number' then
- value = self:createValue('number', nil, v or lib.value)
- elseif tp == 'integer' then
- value = self:createValue('integer', nil, v or lib.value)
- elseif tp == 'nil' then
- value = self:createValue('nil')
- elseif tp == '...' then
- value = self:createValue('any')
- else
- value = self:createValue(tp or 'any')
- end
- LibraryValue[lib] = value
- value.lib = lib
- value.parentType = parentType
-
- self:getLibChild(value, lib, parentType)
-
- return value
-end
-
function mt:getName(name, source)
if source and source.bind then
return source.bind
@@ -1373,68 +1254,90 @@ function mt:doActions(actions)
end
end
-function mt:getGlobalValue()
- if self.lsp and self.lsp.globalValue then
- return self.lsp.globalValue
+function mt:createFunction(source)
+ local value = createValue('function', source)
+ local func = createFunction(source)
+ value:setFunction(func)
+ if source:getUri() == self.uri then
+ self.funcs[#self.funcs+1] = func
+ end
+ return value
+end
+
+function mt:setCurrentFunction(func)
+ self.currentFunction = func
+end
+
+function mt:saveLocal(name, loc)
+ self.currentFunction:saveLocal(name, loc)
+end
+
+function mt:getUri()
+ return self.currentFunction:getUri()
+end
+
+function mt:instantSource(source)
+ if instantSource(source) then
+ self.sources[#self.sources+1] = source
+ end
+end
+
+function mt:bindLocal(source, loc)
+ if not source then
+ return
+ end
+ self:instantSource(source)
+ if loc then
+ source:bindLocal(loc)
+ source:setUri(self:getUri())
+ else
+ return source:bindLocal()
end
- local globalValue = self:createValue('table')
- globalValue.GLOBAL = true
- for name, lib in pairs(library.global) do
- local field = self:createField(globalValue, name)
- local value = self:getLibValue(lib, 'global')
- self:setValue(field, value)
+end
+
+function mt:createLocal(key, source, value)
+ local loc = self:bindLocal(source)
+ if loc then
+ self:saveLocal(key, loc)
+ return loc
end
- if self.lsp then
- self.lsp.globalValue = globalValue
+
+ if not value then
+ value = createValue('nil', self:getDefaultSource())
end
- return globalValue
+
+ loc = createLocal(key, source, value)
+ self:saveLocal(key, loc)
+ self:bindLocal(source, loc)
+ return loc
end
-function mt:createEnvironment()
- self.scope.block = { start = 0, finish = math.maxinteger }
+function mt:createEnvironment(ast)
-- 整个文件是一个函数
- self.chunk.func = self:buildFunction()
- self.chunk.func.uri = self.uri
- self.results.main = self.chunk.func
- -- 隐藏的上值`_ENV`
- local evnField = self:createLocal('_ENV')
- evnField.hide = true
- -- 隐藏的参数`...`
- self:createDots(1)
+ self.main = self:createFunction(ast)
+ self:setCurrentFunction(self.main)
-- 全局变量`_G`
- local globalValue = self:getGlobalValue()
- -- 使用_G初始化_ENV
- self:setValue(evnField, globalValue)
- self.env = globalValue
+ local global = buildGlobal(self.lsp)
+ -- 隐藏的上值`_ENV`
+ local env = self:createLocal('_ENV', nil, global)
+ env:setFlag('hide', true)
+ self.env = env
end
local function compile(ast, lsp, uri)
local vm = setmetatable({
- scope = env {
- locals = {},
- },
- chunk = env {
- labels = {},
- },
- results = {
- locals = {},
- labels = {},
- funcs = {},
- calls = {},
- strings= {},
- infos = {},
- sources= {},
- main = nil,
- },
- lsp = lsp,
- uri = uri or '',
+ strings= {},
+ sources= {},
+ funcs = {},
+ main = nil,
+ env = nil,
+ lsp = lsp,
+ uri = uri or '',
}, mt)
-- 创建初始环境
- vm:createEnvironment()
-
- -- 执行代码
- vm:doActions(ast)
+ ast.uri = vm.uri
+ vm:createEnvironment(ast)
-- 检查所有没有调用过的函数,调用一遍
vm:callLeftFuncions()
diff --git a/server/src/core/vm.txt b/server/src/vm/vm.txt
index 458a7c81..458a7c81 100644
--- a/server/src/core/vm.txt
+++ b/server/src/vm/vm.txt