与 Squirrel 语言的区别

自 2006 年以来,所有 Gaijin 项目中都大量使用Squirrel。 Gaijin 之前使用过 Lua,但发现 Lua 太不安全且难以调试,而且由于缺少类型,有时也很难与原生代码绑定。 这是众所周知的,互联网上有很多关于这方面的信息。 Squirrel 不仅具有类似 C++ 的语法(有时对 C++ 程序员有帮助),而且具有更接近 C:C++ 代码的类型系统。 它还具有更安全的语法和语义。 然而,在大量使用过程中,我们发现语言的某些功能并未在我们 10+ 平台、20+ 项目中数百万个 LoC 的真实代码库中使用。 一些语言功能也不是很安全,或者不一致。我们需要更严格的语言和工具,以便更轻松地重构和支持。 当然,在游戏开发中,任何额外的性能总是受欢迎的。 基本上,毫无疑问,我们使用了“Python 的 Zen”。

我们将 language 从 Squirrel 重命名为 Quirrel 以避免歧义。

新功能

  • 检查冲突的局部变量、局部函数、函数参数和常量名称

  • 检查是否存在冲突的 slot 声明

  • Null 传播、Null 调用和 Null 合并运算符

  • ‘not in’运算法

  • 解构赋值

  • ES2015 风格的速记表初始化

  • 字符串插值

  • 现在可以命名表达式中声明的函数 (local foo = function foo() {})

  • 命名绑定声明 (‘let’)

  • 支持类的 call()/acall() 委托

  • 将min(), max(), clamp()全局函数添加到 Base 库

  • string默认委托: 添加了.subst(), .replace(), .join(), .split(), .concat()方法

  • table默认委托: 添加了 .map(), .each(), .findindex(), .findvalue(), .reduce(), __merge(), .__update() 方法

  • 数组默认委托: 添加了 .each(), .findvalue(), .replace()方法

  • 在 array.slice() 中支持负索引

  • 类方法提示(可以在 nonJIT 模式下提供 LuaJIT 的性能)

  • 编译器指令,用于更严格且更安全的语言(其中一些可用于测试即将发生或计划的语言更改)

  • 添加了不使用堆栈推送/弹出的 C API

  • 变量更改跟踪

  • 函数’freeze()’用于实例、表、数组。使对象不可变。可以使用’is_frozen’方法检查

删除的功能

  • 删除了对逗号运算符的支持(从未使用过,但容易出错,例如 table = {[“foo”, “bar”] = null} 而不是 [[“foo”,”bar”] = null])

  • 删除了 class 和 member 属性(从未在任何实际代码中使用过)

  • 不允许使用 class::method 语法糖添加表格/类方法(因为应该有一种 – 最好只是一种 – 明显的方法可以做到这一点。

  • # 删除了单行注释(因为应该有一个 – 最好只有一个 – 明显的方法来做到这一点。

  • 删除了对 post-initializer 语法的支持(不明确,特别是因为可选的逗号)

  • 删除了对八进制数的支持(容易出错)

变更

  • 函数和类是本地作用域的

  • 引用闭包环境对象(‘this’)是显式的

  • 未声明的变量没有回退到全局根表,现在需要使用`::` 运算符

  • 常量和枚举现在默认在本地范围

  • ‘global’ 关键字,用于显式声明全局常量和枚举

  • 数组/字符串 .find() 默认委托重命名为 .indexof()

  • getinfos() 已重命名为 getfuncinfos(),现在可以应用于可调用对象(实例、表)

  • array.append() 可以接受多个参数

  • 更改了array.filter()的参数顺序以与其他函数统一

  • 类型方法调用的语法(对于表)(table.$rawdelete(“rawdelete”)将适用于表 {rawdelete=@() null})

  • 编译器现在基于 AST,具有一些优化(如 closure 提升)和检查。Analyzer 在同一个 AST 上工作。

  • 使用 Python 样式进行扩展 (let Baz = class(Bar) //(而不是 Baz = class extends Bar)

  • 删除 ‘delete’ 运算符(改用 table.rawdelete() 或 table.$rawdelete())。使用 pragma #forbid-delete-operator #allow-delete-operator 指定的可选行为

  • 许多方法从全局命名空间移动到标准库

  • 已删除 setroottable()。可以用 2 行代码完成(let root=getroottable(); root.each(@(_, k) root.rawdelete(k)); root.__update(newroot))

  • 已删除 setconsttable()。它可以破坏东西。唯一安全的使用它的方法 - 在脚本评估之前设置 const 表(可以对 compilestring() 完成)。

未来可能的变化

请参阅 RFC 页面