1. 引言

Daslang 是一种高性能、强大的静态类型脚本语言,旨在作为实时应用程序(如游戏)的可嵌入“脚本”语言实现高性能。

Daslang 提供了广泛的功能,例如强静态类型、具有迭代类型推理的泛型编程、类似 Ruby 的块、语义缩进、本机机器类型、到 C++ 的提前“编译”,以及到 C++ 程序的快速和简化的绑定。

它的理念是围绕修改后的 Python Zen 构建的。

  • *性能很重要。

  • *但不能以安全为代价。

  • *除非 explicitly 不安全才能执行。

  • *可读性很重要。

  • *显式优于隐式。

  • *简单胜于复杂。

  • *复杂比复杂好。

  • *平坦比嵌套好。

Daslang 应该作为“主机数据处理者”工作。 虽然从技术上讲,可以在脚本上下文中保持持久状态(设置了某个选项), Daslang 旨在转换主机 (C++) 数据/实现脚本化行为。

从某种意义上说,它是纯粹的函数式 - 即所有持久状态都超出了脚本上下文的范围,并且脚本的状态本质上是临时的。 因此,内存模型和持久状态的管理是应用程序的责任。 这导致了 Daslang 本身的极其简单和快速的内存模型。

1.1. 性能

在实际场景中,它的解释比没有 JIT 的 LuaJIT 快 10+ 倍(甚至可能比有 JIT 的 LuaJIT 快)。 对于嵌入式脚本语言来说,更重要的是,它与 C++ 的互作非常快(双向),比大多数其他流行的脚本语言快一个数量级。 从 C++ 到 Daslang 的快速调用允许您将 Daslang 用于简单的存储过程,并使其成为一种 ECS/面向数据的设计友好语言。 通过 Daslang 对 C++ 的快速调用,您可以编写处理主机 (C++) 数据并依赖绑定主机 (C++) 函数的高性能脚本。

它还允许 Ahead-of-Time 编译,这不仅在所有平台上都是可能的(与 JIT 不同),而且总是更快/不慢(众所周知 JIT 有时会减慢脚本的速度)。

Daslang 已经实现了 AoT(C++ 转译器),它生成的代码或多或少与同一程序的 C++11 性能相似。

合成样本/基准性能比较表.

1.2. 它看起来怎么样?

强制性斐波那契样本:

def fibR(n) {
    if (n < 2) {
        return n
    } else {
        return fibR(n - 1) + fibR(n - 2)
    }
}

def fibI(n) {
    var last = 0
    var cur = 1
    for ( i in 0..n-1 ) {
        let tmp = cur
        cur += last
        last = tmp
    }
    return cur
}

具有大量空格(python 样式)的相同示例,适合喜欢此类语法的用户:

options gen2=false

def fibR(n)
   if n < 2
       return n
   else
       return fibR(n - 1) + fibR(n - 2)

def fibI(n)
   var last = 0
   var cur = 1
   for i in 0 .. n-1
       let tmp = cur
       cur += last
       last = tmp
   return cur

此时 gen2 风格的语法 (带卷曲的护腕) 是默认的,但你可以把`gen2`选项设为 false 来切换到 gen1 风格 (带缩进)。

1.3. 泛型编程和类型系统

尽管上面的示例看起来是动态类型的,但它实际上是泛型编程。 fibI/fibR 函数的实际实例是强类型的,基本上只是接受并返回一个``int``。这类似于 C++ 中的模板(尽管 C++ 不是强类型语言)或 ML。 Daslang 中的泛型编程允许非常强大的编译时类型反射机制,从而显著简化编写最佳和清晰的代码。 与具有 SFINAE 的 C++ 不同,您可以使用通用条件 (if) 来根据其参数的类型信息来更改函数的实例。 请考虑以下示例:

def setSomeField(var obj; val) {
    static_if ( typeinfo has_field<someField>(obj) ) {
        obj.someField = val
    }
}

此函数在提供的参数中设置`someField` 如果它是一个具有 `someField` 成员的结构体

(有关更多信息,请参阅 Generic programming).

1.4. 编译时宏

Daslang 在编译时执行大量繁重的工作,因此它不必在运行时执行。 事实上,Daslang 编译器为每个模块运行 Daslang 解释器,并拥有整个 AST。

以下示例在编译时修改函数调用,以添加常量字符串参数的预计算哈希值:

[tag_function_macro(tag="get_hint_tag")]
class GetHintFnMacro : AstFunctionAnnotation {
    def override transform(var call : smart_ptr<ExprCallFunc>; var errors : das_string) : ExpressionPtr {
        if (call.arguments[1] is ExprConstString) {
            unsafe {
                var new_call := call // <- clone_expression(call)
                let arg2 = reinterpret<ExprConstString?>(call.arguments[1])
                let hint = hash("{arg2.value}")
                emplace_new(new_call.arguments, new ExprConstUInt64(at = arg2.at, value = hint))
                return new_call
            }
        }
        return <- default<ExpressionPtr>
    }
}

1.5. 特征

其(非)完整功能列表包括:

  • 强类型

  • 类似 Ruby 的块和 lambda

  • 数组

  • 字符串生成器

  • 本机(C++ 友好)互作

  • 泛型

  • 宏,包括 Reader 宏

  • 语义缩进

  • ECS 友好的互作

  • 易于扩展的类型系统