Skip to content

l2060/AuroraScript

Repository files navigation

Aurora Script

这是一个轻量级的弱类型脚本执行引擎,他没有引用任何第三方组件,它通过将脚本编译为字节码然后通过虚拟机来解释运行

它目前还是个玩具,速度可能会很慢,但是它可以正常的跑起来还可以输出一些东西,还支持异常的调用堆栈获取 。

设计它时借鉴了javascript的一些机制和语法但它不是javascript,它不会遵守ECMA规范。

对脚本的VM做了性能方面的优化,目前的性能已经可以满足大部分业务场景的需求。

如果你也喜欢它,请给它一个Star⭐️ 欢迎PR和Issue

Benchmark Results

Benchmark Script

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.7462/25H2/2025Update/HudsonValley2)
13th Gen Intel Core i7-13700KF 3.40GHz, 1 CPU, 24 logical and 16 physical cores
.NET SDK 10.0.101
  [Host]     : .NET 10.0.1 (10.0.1, 10.0.125.57005), X64 RyuJIT x86-64-v3
  DefaultJob : .NET 10.0.1 (10.0.1, 10.0.125.57005), X64 RyuJIT x86-64-v3
Method Mean Error StdDev Min Max Gen0 Gen1 Gen2 Allocated
TestIfTrue 225.1 ns 0.21 ns 0.19 ns 224.8 ns 225.5 ns - - - -
TestIfFalse 227.0 ns 0.54 ns 0.51 ns 225.6 ns 227.5 ns - - - -
TestNegate 230.9 ns 0.57 ns 0.54 ns 230.1 ns 231.9 ns - - - -
TestExecuteEmpty 233.6 ns 1.16 ns 1.08 ns 231.3 ns 235.6 ns - - - -
TestMulVar 238.0 ns 0.39 ns 0.36 ns 237.4 ns 238.7 ns - - - -
TestDivVar 240.3 ns 0.74 ns 0.69 ns 238.8 ns 241.3 ns - - - -
TestAddVar 240.6 ns 0.54 ns 0.50 ns 239.7 ns 241.3 ns - - - -
TestLessThan 243.2 ns 0.50 ns 0.45 ns 242.5 ns 244.1 ns - - - -
TestGetVar 243.5 ns 0.39 ns 0.37 ns 242.8 ns 244.1 ns - - - -
TestBitXor 244.8 ns 0.37 ns 0.35 ns 244.1 ns 245.4 ns - - - -
TestNot 247.4 ns 0.30 ns 0.27 ns 247.0 ns 247.9 ns - - - -
TestDecerment 247.6 ns 0.58 ns 0.54 ns 246.7 ns 248.3 ns - - - -
TestEqual 248.0 ns 0.20 ns 0.19 ns 247.7 ns 248.2 ns - - - -
TestSubVar 248.9 ns 0.57 ns 0.53 ns 248.3 ns 249.8 ns - - - -
TestTypeOf 249.1 ns 0.31 ns 0.29 ns 248.7 ns 249.6 ns - - - -
TestNotEqual 249.9 ns 0.94 ns 0.88 ns 249.0 ns 251.4 ns - - - -
TestAndVar 250.4 ns 0.23 ns 0.20 ns 250.0 ns 250.8 ns - - - -
TestSetVar 250.7 ns 0.41 ns 0.39 ns 250.3 ns 251.4 ns - - - -
TestIncerment 250.8 ns 0.31 ns 0.27 ns 250.3 ns 251.2 ns - - - -
TestLessEqual 251.1 ns 0.80 ns 0.75 ns 249.9 ns 252.0 ns - - - -
TestGreaterEqual 252.2 ns 0.78 ns 0.73 ns 251.0 ns 253.1 ns - - - -
TestBitOr 252.5 ns 0.32 ns 0.29 ns 252.0 ns 253.1 ns - - - -
TestGreaterThan 253.7 ns 0.31 ns 0.29 ns 253.1 ns 254.1 ns - - - -
TestBitNot 254.8 ns 0.41 ns 0.38 ns 254.1 ns 255.4 ns - - - -
TestMod 255.0 ns 0.46 ns 0.41 ns 254.1 ns 255.7 ns - - - -
TestOrVar 256.9 ns 0.86 ns 0.77 ns 255.9 ns 258.3 ns - - - -
TestSetProperty 257.0 ns 1.13 ns 1.05 ns 255.7 ns 259.3 ns 0.0029 - - 48 B
TestSetElement 257.9 ns 0.38 ns 0.35 ns 257.0 ns 258.4 ns - - - -
TestGetElement 260.6 ns 0.70 ns 0.66 ns 259.8 ns 261.9 ns - - - -
TestGetProperty 269.3 ns 0.47 ns 0.44 ns 268.6 ns 270.2 ns - - - -
TestAddSI 283.6 ns 1.02 ns 0.95 ns 282.3 ns 285.6 ns 0.0076 - - 120 B
TestGetModule 328.5 ns 1.36 ns 1.20 ns 327.5 ns 331.4 ns 0.0091 - - 144 B
TestClone 515.6 ns 1.43 ns 1.34 ns 512.7 ns 517.6 ns 0.0677 - - 1072 B
TestIterator 822.1 ns 2.24 ns 2.09 ns 818.8 ns 825.1 ns 0.0668 - - 1056 B
TestDeConstruct 919.2 ns 2.12 ns 1.98 ns 915.2 ns 922.7 ns 0.2718 0.0029 - 4264 B
TestDatetime 1,159.9 ns 7.61 ns 7.11 ns 1,148.1 ns 1,171.5 ns 0.1202 - - 1888 B
TestJson 1,907.2 ns 6.98 ns 6.53 ns 1,898.5 ns 1,920.3 ns 0.2861 - - 4520 B
TestRegex 3,604.4 ns 8.77 ns 7.77 ns 3,594.0 ns 3,620.1 ns 0.5531 0.0038 - 8696 B
TestClrType 6,812.7 ns 12.54 ns 11.11 ns 6,784.6 ns 6,832.1 ns 0.1221 - - 1944 B
TestStringBuffer 37,419.4 ns 105.17 ns 93.23 ns 37,245.9 ns 37,591.2 ns 4.3945 - - 69584 B
TestMD5Sum 110,246.3 ns 134.53 ns 125.84 ns 109,968.9 ns 110,437.2 ns 0.9766 - - 16936 B
TestStrings 979,702.8 ns 3,497.44 ns 3,271.51 ns 975,041.8 ns 986,709.0 ns 220.7031 - - 3481472 B
TestClosure 1,003,582.0 ns 2,424.35 ns 2,267.74 ns 1,000,014.3 ns 1,007,457.6 ns - - - 496 B
TestObjects 1,383,228.6 ns 5,413.17 ns 5,063.48 ns 1,373,949.8 ns 1,391,253.3 ns 326.1719 - - 5139952 B
TestArrays 1,404,547.1 ns 16,174.92 ns 15,130.03 ns 1,351,338.7 ns 1,413,918.4 ns 199.2188 199.2188 199.2188 2227105 B
TestFor100W 10,255,789.1 ns 127,175.07 ns 112,737.38 ns 10,024,128.1 ns 10,384,582.8 ns - - - -
TestMD5Sum100 11,206,236.6 ns 24,191.28 ns 22,628.54 ns 11,157,268.8 ns 11,242,393.8 ns 93.7500 - - 1693600 B

脚本特性

  • Domain
  • 模块
  • 方法+闭包
  • 方法调用/Clr方法调用
  • 脚本执行 中断/继续
  • where for
  • export 导出模块方法和变量
  • Import
  • MD5函数与Javascript输出一致
  • 迭代器 Iterator
  • for in
  • 调试符号表、闭包方法名、行号、列号、调用者行号
  • 导出属性的访问权限 export const, 变量编译期间检测,属性运行时检测
  • 固定大小的本地变量表测量
  • CallFrame 和 ExecuteContext复用 降内存
  • 脚本对象NumberValue、StringValue的优化
  • Regex 正则表达式
  • JSON 序列化支持
  • CLR类型定义, 支持在脚本中创建对象
  • CLR类型自动解析
  • 闭包方法的引用、回调。
  • 脚本用户上下文
  • Date 日期对象实现
  • 数组和对象的解构(仅实现合并)
  • const常量编译期间折叠优化
  • import 'constant.as' 语法,直接包含脚本文件,仅引入constant定义
  • Enum 枚举类型支持,已完成语法解析,未实现编译支持

Domain

隔离的脚本环境,Domain之间的执行环境是隔离的,但是他们共用了AuroraEngine的Global对象

Domain也有自己的Global对象,他继承了AuroraEngine的Global对象

Module

每个脚本文件为一个Module,可以理解为一个对象。

Module内的root方法和root变量作为 Module的Property,他们是可以被外部访问的。

在脚本头部可以通过使用@module("MODULENAME");定义Module名字,如果未定义则使用文件的相对路径作为Module名字

Module之间可以通过 Import xxx from 'modulefile'; 进行引用,这里会将modulefile作为当前module的xxx变量,这样你可以通过xxx.yy来访问modulefile的导出方法或属性。

Function

方法调用支持闭包方法(支持function|func关键字)、Lambda方法、方法指针,你可以发挥你的想象。

Interruption & Continue

脚本中可以通过yield指令进行中断,中断后Execute方法会立即返回,可以通过ExecuteContext的Continue方法从中断位置继续执行。

也可以通过ExecuteOptions选项禁用yield指令,或通过AutoInterruption字段定义自动中断机制。

在异常上下文上调用Continue可能会导致不可预料的结果,在计算类的脚本执行过程中出现异常应拒绝Continue继续执行,异常继续的机制适用于在面向方法的脚本中。

支持的类型 通过 typeof 关键字获取

  • Null
  • Boolean
  • Number
  • String
  • Object
  • Array
  • Regex
  • Date
  • Function
  • ClrType
  • ClrFunction
  • ClrBonding

扩展

  • StringBuffer
  • console
  • JSON
  • Math

Script Internal Key Words

this 始终指向当前模块对象

global 指向Domain的Global对象

$state 指向当前执行上下文 用户State

$args 获取当前方法的参数数组

$('modulename') 动态获取模块名 TODO

创建环境 & 编译脚本

// 创建一个脚本环境
var engine = new AuroraEngine(new EngineOptions() { BaseDirectory = "./tests/" });
// 编译脚本,编译器会扫描工作目录下所有脚本文件,并根据Import语句自动编译依赖的脚本
await engine.BuildAsync();

定义全局变量

// 1. 普通方法,直接设置属性值, 可读性、可写性、可枚举性都为true
engine.Global.SetPropertyValue("PI", g.GetPropertyValue("PI"))

// 2. 高级方法,支持设置属性的可读性、可写性、可枚举性
engine.Global.Define("PI", g.GetPropertyValue("PI"));

// 3. 定义CLR方法
engine.Global.Define("debug", new ClrFunction(LOG), writeable: false, enumerable: false);

// CLR方法
public static ScriptObject LOG(ExecuteContext context, ScriptObject thisObject, Span<ScriptDatum> args)
{
    if (args != null && args.Length > 0)
    {
        Console.WriteLine(string.Join(", ", args.Select(a => a.ToObject()?.ToString() ?? "null")));
    }
    return ScriptObject.Null;
}

// 注册 CLR 类型别名,供脚本侧使用
engine.RegisterClrType("Math", typeof(System.Math));
engine.RegisterClrType("StringBuilder", typeof(System.Text.StringBuilder));

// 脚本侧可直接调用:
// let sb = StringBuilder("seed");
// console.log(Math.Abs(-42));

// 获取全局变量
var pi = engine.Global.GetPropertyValue("PI");

// Domain 的全局变量
domain.Global.SetPropertyValue("PI", g.GetPropertyValue("PI"))
domain.Global.Define("PI", g.GetPropertyValue("PI"));
var pi = domain.Global.GetPropertyValue("PI");

创建Domain

// 1. 如果你的模块脚本顶级语句使用了全局变量,那么你需要提前创建好Global环境。
var g = engine.NewEnvironment();
g.Define("PI", new NumberValue(Math.PI), readable: true, writeable: false, enumerable: false);
var domain = engine.CreateDomain(g);

// 2. 如果你的模块脚本顶级语句没有使用模块以外的变量,可以直接创建一个Domain
var domain = engine.CreateDomain();
domain.Global.Define("PI", new NumberValue(Math.PI), readable: true, writeable: false, enumerable: false);

执行脚本方法

var forCount = 10000000;
// 执行UNIT_LIB中的  forTest 方法 并传入参数 10000000
var testFor = domain.Execute("UNIT_LIB", "forTest", new NumberValue(forCount));
Console.WriteLine($"for:{forCount} UsedTime {testFor.UsedTime}ms");

继续中断的上下文

// 1. 手动控制中断继续
var testContinue = domain.Execute("UNIT_LIB", "testContinue");
if (testContinue.Status  == ExecuteStatus.Interrupted)
{
    testContinue.Continue();
}

// 2. 自动完成,如遇到中断自动继续直到完成,如果遇到异常则返回
var testContinue = domain.Execute("UNIT_LIB", "testContinue").Done();

// 3. 自动完成,不管异常还是中断都可以继续执行直到完成
var testContinue = domain.Execute("UNIT_LIB", "testContinue").Done(AbnormalStrategy.Continue);

文本模板

// 1. 双引号
log("Hello");

// 2. 单引号
log('Wrold');


// 3. 多行文本
log(`1. 这是一个特殊的字符串模板
2. 支持多行文本
3. 它会让代码看起来更舒服
4. <Buy/@Buy> <Close/@Close>`);


// 4. 多行文本
log(
    |> 1. 这是一个特殊的字符串模板
    |> 2. 支持多行文本
    |> 3. 它会让代码看起来更舒服
    |> 4. <Buy/@Buy> <Close/@Close> 
);

About

lightweight weakly typed script compiler runtime

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published