summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json1
-rw-r--r--server/libs/lua/basic.lni1
-rw-r--r--server/libs/lua/package.lni7
-rw-r--r--server/locale/en-US/libs/lua/coroutine.lni3
-rw-r--r--server/locale/en-US/libs/lua/package.lni3
-rw-r--r--server/locale/zh-CN/libs/lua/debug.lni3
-rw-r--r--server/locale/zh-CN/libs/lua/math.lni4
-rw-r--r--server/locale/zh-CN/libs/lua/package.lni3
-rw-r--r--server/src/vm/manager.lua5
-rw-r--r--server/src/vm/module.lua56
-rw-r--r--server/src/vm/vm.lua43
11 files changed, 115 insertions, 14 deletions
diff --git a/package.json b/package.json
index 102f73d5..489ac0fc 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
"type": "string",
"default": "Lua 5.3",
"enum": [
+ "Lua 5.1",
"Lua 5.2",
"Lua 5.3",
"Lua 5.4"
diff --git a/server/libs/lua/basic.lni b/server/libs/lua/basic.lni
index a1463c00..9f6c2d75 100644
--- a/server/libs/lua/basic.lni
+++ b/server/libs/lua/basic.lni
@@ -294,6 +294,7 @@ type = 'string'
[module]
version = 'Lua 5.1'
+special = 'module'
[[.args]]
name = name
type = string
diff --git a/server/libs/lua/package.lni b/server/libs/lua/package.lni
index 85234fab..43ae7344 100644
--- a/server/libs/lua/package.lni
+++ b/server/libs/lua/package.lni
@@ -67,3 +67,10 @@ default = '.'
name = 'rep'
type = 'string'
optional = 'self'
+
+[seeall]
+version = 'Lua 5.1'
+special = seeall
+[[.args]]
+name = module
+type = table
diff --git a/server/locale/en-US/libs/lua/coroutine.lni b/server/locale/en-US/libs/lua/coroutine.lni
index ec06f21d..3859ad4e 100644
--- a/server/locale/en-US/libs/lua/coroutine.lni
+++ b/server/locale/en-US/libs/lua/coroutine.lni
@@ -5,8 +5,7 @@ description = 'Creates a new coroutine.'
description = 'Returns true when the running coroutine can yield.'
[kill]
-description = 'Kills coroutine `co` ,
-closing all its pending to-be-closed variables and putting the coroutine in a dead state.'
+description = 'Kills coroutine `co` , closing all its pending to-be-closed variables and putting the coroutine in a dead state.'
[resume]
description = 'Starts or continues the execution of coroutine `co`.'
diff --git a/server/locale/en-US/libs/lua/package.lni b/server/locale/en-US/libs/lua/package.lni
index b0a861a9..3b482ae9 100644
--- a/server/locale/en-US/libs/lua/package.lni
+++ b/server/locale/en-US/libs/lua/package.lni
@@ -24,3 +24,6 @@ description = 'A table used by `require` to control how to load modules.'
[searchpath]
description = 'Searches for the given `name` in the given `path`.'
+
+[seeall]
+describing = 'Sets a metatable for `module` with its `__index` field referring to the global environment, so that this module inherits values from the global environment. To be used as an option to function `module` .
diff --git a/server/locale/zh-CN/libs/lua/debug.lni b/server/locale/zh-CN/libs/lua/debug.lni
index 18c514c9..22e6d3b3 100644
--- a/server/locale/zh-CN/libs/lua/debug.lni
+++ b/server/locale/zh-CN/libs/lua/debug.lni
@@ -2,7 +2,7 @@
description = '进入一个用户交互模式,运行用户输入的每个字符串。'
[getfenv]
-description = '返回对象 `o` 的环境。`
+description = '返回对象 `o` 的环境。'
[gethook]
description = '返回三个表示线程钩子设置的值: 当前钩子函数,当前钩子掩码,当前钩子计数 。'
@@ -85,7 +85,6 @@ description = '将 `value` 设为函数 `f` 的第 `up` 个上值。'
["setuservalue Lua 5.4"]
description = '将 `value` 设为 `udata` 的第 `n` 个关联值。'
-值。'
[setuservalue]
description = '将 `value` 设为 `udata` 的关联值。'
diff --git a/server/locale/zh-CN/libs/lua/math.lni b/server/locale/zh-CN/libs/lua/math.lni
index 2f42b9e8..f1a6768a 100644
--- a/server/locale/zh-CN/libs/lua/math.lni
+++ b/server/locale/zh-CN/libs/lua/math.lni
@@ -50,10 +50,10 @@ description = '返回 `m * (2 ^ e)` 。'
description = '返回以指定底的 `x` 的对数。'
['log Lua 5.1']
-description = '返回 `x` 的自然对数。`
+description = '返回 `x` 的自然对数。'
[log10]
-description = '返回 `x` 的以10为底的对数。
+description = '返回 `x` 的以10为底的对数。'
[max]
description = '返回参数中最大的值, 大小由 Lua 操作 `<` 决定。'
diff --git a/server/locale/zh-CN/libs/lua/package.lni b/server/locale/zh-CN/libs/lua/package.lni
index 74dc0239..209a9dc1 100644
--- a/server/locale/zh-CN/libs/lua/package.lni
+++ b/server/locale/zh-CN/libs/lua/package.lni
@@ -24,3 +24,6 @@ description = '用于 `require` 控制如何加载模块的表。'
[searchpath]
description = '在指定 `path` 中搜索指定的 `name` 。'
+
+[seeall]
+description = '给 `module` 设置一个元表,该元表的 `__index` 域为全局环境,这样模块便会继承全局环境的值。可作为 `module` 函数的选项。'
diff --git a/server/src/vm/manager.lua b/server/src/vm/manager.lua
new file mode 100644
index 00000000..2016465b
--- /dev/null
+++ b/server/src/vm/manager.lua
@@ -0,0 +1,5 @@
+local mt = {}
+mt.__index = mt
+mt.type = 'vm'
+
+return mt
diff --git a/server/src/vm/module.lua b/server/src/vm/module.lua
new file mode 100644
index 00000000..60191bf3
--- /dev/null
+++ b/server/src/vm/module.lua
@@ -0,0 +1,56 @@
+local mt = require 'vm.manager'
+local createMulti = require 'vm.multi'
+
+--[[
+function module(name, ...)
+ local env = {}
+ for _, opt in ipairs {...} do
+ opt(env)
+ end
+ @ENV = env
+end
+--]]
+function mt:callModuel(func, values)
+ local envLoc = self:loadLocal('@ENV')
+ if not envLoc then
+ return
+ end
+ local source = self:getDefaultSource()
+ local newEnvValue = self:createValue('table', source)
+ local args = createMulti()
+
+ args:push(newEnvValue)
+
+ for i = 2, #values do
+ local value = values[i]
+ -- opt(env)
+ self:call(value, args, source)
+ end
+
+ -- @ENV = env
+ envLoc:setValue(newEnvValue)
+end
+
+--[[
+function package.seeall(env)
+ setmetatable(env, { __index = @ENV })
+end
+--]]
+function mt:callSeeAll(func, values)
+ local newEnv = values[1]
+ if not newEnv then
+ return
+ end
+ local envLoc = self:loadLocal('@ENV')
+ if not envLoc then
+ return
+ end
+ local oldEnv = envLoc:getValue()
+ if not oldEnv then
+ return
+ end
+ local source = self:getDefaultSource()
+ local meta = self:createValue('table', source)
+ meta:setChild('__index', oldEnv, source)
+ newEnv:setMetaTable(meta)
+end
diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua
index 02ced843..2a223d42 100644
--- a/server/src/vm/vm.lua
+++ b/server/src/vm/vm.lua
@@ -7,13 +7,14 @@ local sourceMgr = require 'vm.source'
local buildGlobal = require 'vm.global'
local createMulti = require 'vm.multi'
local libraryBuilder = require 'vm.library'
+local config = require 'config'
+local mt = require 'vm.manager'
+
+require 'vm.module'
-- TODO source测试
--rawset(_G, 'CachedSource', setmetatable({}, { __mode = 'kv' }))
-local mt = {}
-mt.__index = mt
-
function mt:getDefaultSource()
return self:instantSource {
start = 0,
@@ -272,6 +273,10 @@ function mt:callLibrary(func, values, source, lib)
self:callLoadFile(func, values)
elseif lib.special == 'dofile' then
self:callDoFile(func, values)
+ elseif lib.special == 'module' then
+ self:callModuel(func, values)
+ elseif lib.special == 'seeall' then
+ self:callSeeAll(func, values)
end
end
end
@@ -324,7 +329,12 @@ function mt:getName(name, source)
if global then
return global
end
- local ENV = self:loadLocal('_ENV')
+ local ENV
+ if self.envType == '_ENV' then
+ ENV = self:loadLocal('_ENV')
+ else
+ ENV = self:loadLocal('@ENV')
+ end
local ENVValue = ENV:getValue()
ENVValue:addInfo('get child', source, name)
global = ENVValue:getChild(name, source)
@@ -351,7 +361,12 @@ function mt:setName(name, source, value)
if global then
return global
end
- local ENV = self:loadLocal('_ENV')
+ local ENV
+ if self.envType == '_ENV' then
+ ENV = self:loadLocal('_ENV')
+ else
+ ENV = self:loadLocal('@ENV')
+ end
local ENVValue = ENV:getValue()
source:bindValue(value, 'set')
ENVValue:setChild(name, value, source)
@@ -1120,8 +1135,15 @@ function mt:createEnvironment(ast)
end
-- 全局变量`_G`
local global = buildGlobal(self.lsp)
- -- 隐藏的上值`_ENV`
- local env = self:createLocal('_ENV', self:getDefaultSource(), global)
+ local env
+ if self.envType == '_ENV' then
+ -- 隐藏的上值`_ENV`
+ env = self:createLocal('_ENV', self:getDefaultSource(), global)
+ else
+ -- 为了实现方便,fenv也使用隐藏上值来实现
+ -- 使用了非法标识符保证用户无法访问
+ env = self:createLocal('@ENV', self:getDefaultSource(), global)
+ end
env:set('hide', true)
self.env = env
end
@@ -1159,9 +1181,14 @@ function mt:remove()
end
local function compile(vm, ast, lsp, uri)
-
-- 创建初始环境
ast.uri = vm.uri
+ -- 根据运行版本决定环境实现方式
+ if config.config.runtime.version == 'Lua 5.1' then
+ vm.envType = 'fenv'
+ else
+ vm.envType = '_ENV'
+ end
vm:instantSource(ast)
vm:createEnvironment(ast)