
我们来看一个示例1 var s 2 static int n 10; // 直接执行不参与编译 3 static x n * 2; // 直接执行不参与编译 4 int y static n * 2; // 编译结果y 20 5 /* 6 int m20; 7 int a static m * 2; // 报错variable m is not exists 8 */ 9 int z n * 2; // 编译结果z n * 2 10 xyz; 11 ; 12 var script new Script(); 13 // 编译 14 var func script.Compileint(s); 15 Assert.AreEqual(10, script.Context.EvalVar(n)); 16 Assert.AreEqual(20, script.Context.EvalVar(x)); 17 Assert.IsNull(script.Context.EvalVar(y)); 18 Assert.IsNull(script.Context.EvalVar(z)); 19 // 执行 20 Assert.AreEqual(60, func());static语句中的变量必须是在static语句中定义的由于变量n、x是在static语句中定义的脚本执行前就已经计算出结果了上面示例编译结果为1 int y 20; 2 int z n * 2; 3 xyz;那么基于static语法的特性我们可以在哪些场景中使用呢场景一eval函数在之前一篇文章《AScript之eval函数详解》中介绍过eval函数的功能和运行机制。1 int n10; 2 var sn20; 3 eval(s); // 结果为20如上示例在编译执行模式下计算结果并不是我们预期的30我们使用static语法试试1 int n10; 2 static var sn20; 3 eval(static s); // 结果为30结果是预期的30了我们可以在static语句中对字符串进行拼接处理然后给到eval来执行。场景二编译委托1 string s 2 static { 3 min10; 4 max5; 5 } 6 n min n max 7 ; 8 var script new Script(); 9 script.Context.SetVar(min, 20); 10 script.Context.SetVar(max, 50); 11 var func script.Compileint, bool(s, n); 12 int total 0; 13 for (int i 0; i 10000; i) 14 { 15 if (func(i)) total; 16 } 17 Assert.AreEqual(26, total);我们可以利用static语法的特性在脚本中做一些初始化逻辑比如从数据库中获取配置等。实现原理最后我们来看看static语法是如何实现的吧1 public class StaticTokenHandler : ITokenHandler 2 { 3 public static readonly StaticTokenHandler Instance new StaticTokenHandler(); 4 5 public void Build(DefaultSyntaxAnalyzer analyzer, TokenAnalyzingArgs e) 6 { 7 e.IsHandled true; 8 if (e.TreeBuilder.IsFullStatement()) 9 { 10 e.End true; 11 e.TokenReader.Push(e.CurrentToken); 12 return; 13 } 14 var options e.Options; 15 // 如果当前为编译模式则改为使用执行模式 16 if ((options.CompileMode?? ECompileMode.None) ECompileMode.All) 17 { 18 options new BuildOptions(e.Options) { CompileMode ECompileMode.None }; 19 } 20 var node analyzer.BuildOneStatement2(e.BuildContext, e.ScriptContext, options, e.TokenReader, e.Control, e.Ignore, noblock: true); 21 if (node ! null !e.Ignore) 22 { 23 // 执行并返回结果 24 var v node.Eval(e.ScriptContext, options, e.Control, out var type); 25 e.TreeBuilder.AddData(e.BuildContext, e.ScriptContext, e.Options, e.Control, PoolManage.CreateObjectNode(v, type)); 26 } 27 } 28 }然后在CSharpLang中注册 AddTokenHandler(static, StaticTokenHandler.Instance); 几行代码就实现了一个有意思语法。说点什么