AScript是一个开源的C#动态脚本解析执行引擎,支持扩展多种脚本语言,2026年8月12日正式发布了lua脚本语言AScript.Lang.Lua,快来试试吧!
一、介绍
支持 Lua 基础语法和数据类型,以及表、元表、面向对象、模块等功能。
二、安装
1 install-package AScript
2 install-package AScript.Lang.Lua
三、使用说明
- 命名空间:using AScript.Lang.Lua;
- 常用数据类型:
nil: 空值boolean: 布尔值 (true,false)number: 数值 (整数和浮点数)string: 字符串table: 表 (数组)
- 运算符
- 算术运算符:
+,-,*,/,%,^(幂),//(整数除法) - 关系运算符:
<,>,<=,>=,==,~= - 逻辑运算符:
and,or,not - 连接运算符:
..(字符串连接),#(长度) - 赋值运算符:
=,+=,-=,*=,/=,%=,^=,..=
- 算术运算符:
- 控制结构
- 条件语句:
if ... then ... elseif ... then ... else ... end - while循环:
while ... do ... end - repeat循环:
repeat ... until ... - 数值for循环:
for i = start, end, step do ... end - 泛型for循环:
for v in expr do ... end - 泛型for循环:
for i,v in expr do ... end
- 条件语句:
- 函数定义:
function name(args) ... end - 匿名函数:
local f = function(args) ... end - 局部变量:
local var = value - 表构造器
- 数组风格:
{ value1, value2, value3 } - 字典风格:
{ key1 = value1, key2 = value2 } - 混合风格:
{ 1, 2, name = "test" }
- 数组风格:
1、注册语言
1 Script.Langs.Set("lua", LuaLang.Instance);
2 // 可全局设置为默认语言
3 // Script.Langs.Set("lua", LuaLang.Instance, setDefault: true);
2、字符串连接
两个字符串连接使用..操作符而不是+操作符。
1 var script = new Script();
2 script.Context.Langs = new[] { "lua" };
3 Assert.AreEqual("hello123", script.Eval("'hello'..123"));
3、数据打包/解包
1 // 打包
2 string s = @"
3 local format='<i4i4fc10'
4 local hp=12500
5 local mp=8700
6 local atk=156.5
7 local name='john'
8 local data = string.pack(format, hp, mp, atk, name)
9 print(#data) -- 控制台输出data长度
10 ";
11 var script = new Script();
12 script.Context.Langs = new[] { "lua" };
13 script.Eval(s);
14 // 解包
15 script.Eval("local a,b,c,d=string.unpack(format, data)");
16 Assert.AreEqual(12500, script.Eval("a"));
17 Assert.AreEqual(8700, script.Eval("b"));
18 Assert.AreEqual(156.5, script.Eval("c"));
19 Assert.AreEqual("john", script.Eval("d"));
4、条件语句
1 string code = @"
2 local x = 10
3 if x >= 10 and x < 50 then
4 local a = 5
5 local b = 15
6 x = a + b + 80
7 elseif x >= 50 and x < 100 then
8 x = 200
9 else
10 x = 300
11 end
12 x
13 ";
14 var script = new Script();
15 script.Context.Langs = new[] { "lua" };
16 Assert.AreEqual(100L, script.Eval(code));
5、while循环
1 string code = @"
2 local i = 0
3 local sum = 0
4 while i < 5 do
5 i = i + 1
6 sum = sum + i
7 end
8 sum
9 ";
10 var script = new Script();
11 script.Context.Langs = new[] { "lua" };
12 Assert.AreEqual(15L, script.Eval(code));
6、数值for循环
- 语法:
for i=start,end[,step] do ... end,其中step默认为1 - 注:循环体内部改变循环变量i的值,不影响循环次数
1 string code = @"
2 local sum = 0
3 for i = 1, 5 do
4 i = i + 10
5 sum = sum + i
6 end
7 sum
8 ";
9 var script = new Script();
10 script.Context.Langs = new[] { "lua" };
11 Assert.AreEqual(65L, script.Eval(code));
7、泛型for循环
1 string code = @"
2 local sum = 0
3 -- for v in ipairs({1, 2, 3, 4, 5}) do
4 for i, v in ipairs({1, 2, 3, 4, 5}) do
5 sum = sum + v
6 end
7 sum
8 ";
9 var script = new Script();
10 script.Context.Langs = new[] { "lua" };
11 Assert.AreEqual(15L, script.Eval(code));
8、函数
1 string code = @"
2 function factorial(n)
3 if n <= 1 then
4 return 1
5 end
6 return n * factorial(n - 1)
7 end
8 factorial(5)
9 ";
10 var script = new Script();
11 script.Context.Langs = new[] { "lua" };
12 Assert.AreEqual(120L, script.Eval(code));
9、表(数组)
1 string code = @"
2 local arr = {10, 20, 30}
3 arr[1] + arr[2] + arr[3]
4 ";
5 var script = new Script();
6 script.Context.Langs = new[] { "lua" };
7 Assert.AreEqual(60L, script.Eval(code));
10、表(字典)
1 string code = @"
2 local t = { x = 3, y = 5 }
3 t.sum = function(a,b)
4 print(a,b)
5 return a+b
6 end
7 t.sum(t.x,t.y)
8 ";
9 var script = new Script();
10 script.Context.Langs = new[] { "lua" };
11 Assert.AreEqual(8L, script.Eval(code));
11、元表
1 string code = @"
2 local t = {}
3 local metatable = { __index = { name = 'tom' } }
4 setmetatable(t, metatable)
5 t.name
6 ";
7 var script = new Script();
8 script.Context.Langs = new[] { "lua" };
9 Assert.AreEqual("tom", script.Eval(code));
12、面向对象(OOP)
1 string code = @"
2 -- 定义动物类(Animal)
3 Animal = {name = 'Unknown'}
4
5 -- Animal 类的构造函数
6 function Animal:new(name)
7 local o = {}
8 setmetatable(o, self) -- 设置元表,使其继承 Animal 的方法
9 self.__index = self -- 让对象可以访问 Animal 的方法
10 o.name = name or 'Unknown' -- 设置名称,默认为 'Unknown'
11 return o
12 end
13
14 -- Animal 类的方法:叫声
15 function Animal:speak()
16 return self.name .. ' makes a sound.'
17 end
18
19 -- 定义狗类(Dog),继承自 Animal
20 Dog = Animal:new() -- Dog 继承 Animal 类
21
22 -- 重写狗类的构造函数
23 function Dog:new(name, breed)
24 local o = {}
25 setmetatable(o, self) -- 设置元表,使其继承 Dog 和 Animal 的方法
26 self.__index = self -- 让对象可以访问 Dog 的方法
27 o.name = name or 'Unknown'
28 o.breed = breed or 'Unknown'
29 return o
30 end
31
32 -- 重写狗类的叫声方法(重写 Animal 的 speak 方法)
33 function Dog:speak()
34 return self.name .. ' barks.'
35 end
36
37 -- 创建 Animal 对象
38 local animal = Animal:new('Generic Animal')
39 local s1 = animal:speak() -- 输出 'Generic Animal makes a sound.'
40
41 -- 创建 Dog 对象
42 local dog = Dog:new('Buddy', 'Golden Retriever')
43 local s2 = dog:speak() -- 输出 'Buddy barks.'
44 s1 .. ';' .. s2
45 ";
46 var script = new Script();
47 script.Context.Langs = new[] { "lua" };
48 Assert.AreEqual("Generic Animal makes a sound.;Buddy barks.", script.Eval(code));
13、模块
使用require引入模块,优先查找IScriptModule模块,再查找模块目录中的模块文件。
1)添加模块目录
1 LuaLang.Instance.Modules.AddDir("./lua/modules");
2)模块目录中添加Person.lua文件
1 Person = {name = '', age = 0}
2
3 function Person:new(name, age)
4 local obj = {} -- 创建一个新的表作为对象
5 setmetatable(obj, self) -- 设置元表,使其成为 Person 的实例
6 self.__index = self -- 设置索引元方法,指向 Person
7 obj.name = name
8 obj.age = age
9 return obj
10 end
11
12 function Person:introduce()
13 return 'My name is ' .. self.name .. ' and I am ' .. self.age .. ' years old.'
14 end
15
16 return Person
3)引入并使用模块
1 string code = @"
2 require 'Person'
3 local person1 = Person:new('Alice', 30)
4 person1:introduce()
5 ";
6 var script = new Script();
7 script.Context.Langs = new[] { "lua" };
8 Assert.AreEqual("My name is Alice and I am 30 years old.", script.Eval(code));
14、io模块
文件操作,服务端请谨慎使用,避免脚本恶意修改、删除文件。
1)安装模块
1 install-package AScript.Lang.Lua.io
2)注册io模块
1 LuaLang.Instance.Modules.Add("io", new AScript.Lang.Lua.io.LuaIOModule());
3)使用io
1 string code = @"
2 require 'io'
3 local f = io.open(file, 'w')
4 f:write('hello')
5 f:close()
6 local f = io.open(file, 'r')
7 local content = f:read()
8 f:close()
9 content
10 ";
11 var script = new Script();
12 script.Context.Langs = new[] { "lua" };
13 script.Context.SetVar("file", "./test.txt");
14 Assert.AreEqual("hello", script.Eval(code));
四、与宿主程序交互
1、脚本调用C#函数
1 var code = @"
2 local a = 10
3 local b = 20
4 sum(a, b)
5 ";
6 var script = new Script();
7 script.Context.Langs = new[] { "lua" };
8 // 注入函数
9 script.Context.AddFunc<long, long, long>("sum", (x, y) => x + y);
10 Assert.AreEqual(30L, script.Eval(code));
2、C#调用脚本中的函数
1 var code = @"
2 function sum(x,y)
3 return x+y
4 end
5 local a = 10
6 local b = 20
7 sum(a, b)
8 ";
9 var script = new Script();
10 script.Context.Langs = new[] { "lua" };
11 Assert.AreEqual(30L, script.Eval(code));
12 // 获取脚本中的函数
13 var sum = script.Context.GetFunc<long, long, long>("sum");
14 Assert.AreEqual(80L, sum(30, 50));
五、结束语
更多语法、功能请参考Lua 教程 | 菜鸟教程。
AScript开源地址:https://gitee.com/rockey627/AScript