Lua语言上下文/作用域的实现

我正在用C#实现一个Lua解释器,遇到了性能问题,我觉得这是因为设计有误:

在我的实现中,作用域是以层次结构排列的,每个作用域都有一个父作用域,可能为空;每次设置或请求变量时,作用域都会检查指定的变量是否包含在其中。如果没有,则要求其父级执行相同的操作,或者如果没有父级,则创建它/返回nil。

问题是作用域在底层使用Dictionary<string, LuaObject>,Get/Set函数是递归的。有更好的方法吗?我考虑了不同的方法,并找到了这个方法,它不是非常优雅,也不太高效(受V8和C#闭包的启发):

  • 使用类型和字段作为变量。

  • 每次请求以前未声明的变量时,使用反射创建一个继承前一个类型的新类型。

  • 如果声明了函数,请检查它是否使用在外部作用域中声明的变量。如果是,请重新创建该类型的字段,并使外部变量指向新变量。

是否有更简单/更优雅的解决方案?Lua内部是如何实现的?

点赞
用户88888888
用户88888888

参考实现和许多类似语言的其他实现中,它是这样完成的:

在编译时,

  • 在编译时找出哪个名称引用哪个作用域。
  • 对于每个作用域(除了全局作用域),枚举变量并为每个变量分配索引。
  • 而非在字节码中提到变量名,使用前一步中的索引。

然后在执行期间,

  • 在数组(每个激活记录)中存储局部变量的值。读取和写入操作码携带必要的索引。
  • 实现全局变量如同Lua表格(且没有定义的变量为nil)。

这比搞弄动态创建类型的方法要简单、更容易,且更容易移植。它可能会更快,但肯定不会慢太多。

闭包支持的大部分是正交的。所谓的Upvalue在数组中引用一个插槽,同时它仍然存在,当局部数组死亡时将封闭的值继承下来。你可以使用你的原始设计来做类似的事情。为了正确性,必须注意每个封闭变量只创建一个upvalue,并且扁平化闭包。在下面的代码中,g也必须封闭x,这样当h闭包被创建时,它仍然存在:

function f()
  local x = 1
  function g()
    function h()
      return x
    end
    return h
  end
  return g
end

print(f()()())
2014-01-19 16:04:05