
、自定义语法AScript底层解析脚本生成token流语法解析器对token流进行处理就会调用ITokenHandler处理器该接口定义如下1 public interface ITokenHandler 2 { 3 /// summary 4 /// token处理 5 /// /summary 6 /// param nameanalyzer语法分析器/param 7 /// param namee当前token、语法树及上下文信息/param 8 void Build(DefaultSyntaxAnalyzer analyzer, TokenAnalyzingArgs e); 9 }DefaultSyntaxAnalyzer参数为语法分析器可以调用其中的BuildOneStatement或者BuildMultiStatement方法来读取一条或多条语句。自定义语法就是对当前token以及前后语句进行处理将结果添加到语法树来实现期望的逻辑功能。示例定义sql条件语句的and语法1 /// summary 2 /// ![CDATA[age20 and age50]] 3 /// /summary 4 public class AndTokenHandler : ITokenHandler 5 { 6 public static readonly AndTokenHandler Instance new AndTokenHandler(); 7 8 public void Build(DefaultSyntaxAnalyzer analyzer, TokenAnalyzingArgs e) 9 { 10 e.IsHandled true; 11 if (!e.Ignore) 12 { 13 var op new OperatorNode(and, DefaultSyntaxAnalyzer.OperatorPriorities[], 2); 14 e.TreeBuilder.AddOperator(e.BuildContext, e.ScriptContext, e.Options, e.Control, op); 15 } 16 } 17 }sql中的and语法等效于C#中的操作符所以优先级取操作符的优先级同时sql语言环境中需要注册and函数 AddFunc(and, AndAlsoOperator.Instance);二、定义语言AScript中提供了ScriptLang类来扩展语言该类包含类型、变量、函数、语法解析ITokenHandler管理。多语言势必会带来语法兼容问题比如sql条件中的号是相等的意思等效于C#中的跟C#中的赋值符号有冲突可设置属性Compatiblefalse表示不兼容默认语言在脚本或ScriptContext上下文中需要指定语言才能执行。示例定义Sql语言这里只实现一个简单的条件判断功能1 public class SqlLang : ScriptLang 2 { 3 public static readonly SqlLang Instance new SqlLang(); 4 5 public SqlLang() 6 { 7 this.Compatible false; 8 9 AddFunc(., DotOperator.Instance); 10 AddFunc(!, BoolNotOperator.Instance); 11 AddFunc(, LessThanOperator.Instance); 12 AddFunc(, GreaterThanOperator.Instance); 13 AddFunc(, EqualOperator.Instance); 14 AddFunc(, GreaterThanOrEqualOperator.Instance); 15 AddFunc(, LessThanOrEqualOperator.Instance); 16 AddFunc(!, NotEqualOperator.Instance); 17 AddFunc(and, AndAlsoOperator.Instance); 18 AddFunc(or, OrElseOperator.Instance); 19 20 AddTokenHandler(and, AndTokenHandler.Instance); 21 AddTokenHandler(AND, AndTokenHandler.Instance); 22 AddTokenHandler(or, OrTokenHandler.Instance); 23 AddTokenHandler(OR, OrTokenHandler.Instance); 24 AddTokenHandler(, EqualTokenHandler.Instance); 25 AddTokenHandler(like, LikeTokenHandler.Instance); 26 AddTokenHandler(LIKE, LikeTokenHandler.Instance); 27 } 28 }由于AScript是区分大小写的注册token时大小写都注册一下便于sql语句中支持大小写语法示例中的or、like等语法代码不一一列出了感兴趣的同学可以到开源项目的单元测试中查看后续可能会开发一个比较完备的sql语言脚本。注册SqlLang Script.Langs[sql] SqlLang.Instance;三、执行指定语言脚本如果不指定语言则使用默认且兼容的语言来执行脚本。1、ScriptContext中设置Langs属性来指定脚本语言1 string s p.Name like to% or p.Age20 and p.Age50; 2 var script new Script(); 3 script.Context.Langs new[] { sql }; 4 var matchFunc script.CompilePerson, bool(s, p); 5 var list new ListPerson 6 { 7 new Person(jim, 18), 8 new Person(tony, 60), 9 new Person(tom, 19), 10 new Person(san, 25), 11 new Person(lin, 70) 12 }; 13 var matchedList list.Where(matchFunc).ToList(); 14 Assert.AreEqual(3, matchedList.Count); 15 Assert.AreEqual(tony, matchedList[0].Name); 16 Assert.AreEqual(tom, matchedList[1].Name); 17 Assert.AreEqual(san, matchedList[2].Name);2、脚本中通过#lang语法嵌入其他语言指定多个语言使用逗号,分隔如 #lang 中文,CSharp1 string s 2 bool isMatch(Person p) { 3 #lang sql 4 p.Age20 and p.Age50 or p.Name like to% or p.Namepen; 5 #end 6 } 7 var matchedList new ListPerson(); 8 foreach(var item in list) { 9 if (isMatch(item)) matchedList.Add(item); 10 } 11 matchedList; 12 ; 13 var list new ListPerson 14 { 15 new Person(jim, 18), 16 new Person(tony, 60), 17 new Person(tom, 19), 18 new Person(san, 25) 19 }; 20 var script new Script(); 21 script.Context.AddTypePerson(); 22 script.Context.SetVar(list, list); 23 var matchedList script.EvalListPerson(s); 24 Assert.AreEqual(3, matchedList.Count); 25 Assert.AreEqual(tony, matchedList[0].Name); 26 Assert.AreEqual(tom, matchedList[1].Name); 27 Assert.AreEqual(san, matchedList[2].Name);四、结语AScript 的多语言扩展能力在同一脚本中嵌入不同脚本语言让开发者和用户可以使用最合适的语言进行脚本配置