Skip to content

Instantly share code, notes, and snippets.

@langyo
Last active January 5, 2019 05:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save langyo/f76b519d3060d7347435e9b1a7dd549f to your computer and use it in GitHub Desktop.
Save langyo/f76b519d3060d7347435e9b1a7dd549f to your computer and use it in GitHub Desktop.
syntax builder old code
// [ 常量值定义区 ]
const CharTypes = {
// 这里用于存储round类型元素的候选字符集
};
const ErrorType = {
errorSyntax:{
type:"errorSyntax",
message:"不可约的表达式树!"
},
errorName:{
type:"errorName",
message:"非法命名!"
},
undefine:{
type:"undefine",
message:"未定义元素!"
},
mismatching:{
type:"mismatching",
message:"参数不匹配!"
},
unknown:{
type:"unknown",
message:"未知元素!"
},
notSupport:{
type:"notSupport",
message:"特性尚未支持!"
}
};
const ArgTypes = new ConstTypes([ "selection", "repeat", "in_order", "mismatching", "mapping", "reverse" ]);
const ElementTypes = new ConstTypes([ "string", "round", "anon_op", "ref", "mapping", "bytes" ]);
const PathTypes = new ConstTypes([ "operation", "choice", "element" ]);
const LogTypes = new ConstTypes([ "operation", "choice", "element" ]);
// [ 代码区 ]
function SyntaxBuilderError(message, p){
// 定义引擎专属错误类型,可以接收错误位置在脚本中的位置
this.message = message.text;
this.pos = p;
this.type = message.type;
this.stack = (new Error()).stack;
}
SyntaxBuilderError.prototype = Object.create(Error.prototype);
SyntaxBuilderError.prototype.name = "SyntaxBuilderRunnableError";
function ConstTypes(args){
// 定义一个工具类,用于将一些字符串组织为一个数组,并使其有简单的检测方法
let ret = args;
// 定义检查是否有某元素的方法
Object.defineProperty(ret, "has", function(n){
for(let i = 0;i < this.length; ++i) if(this[i] == n) return true;
return false;
});
return ret;
}
function Map(){
// 定义辅助容器类
}
Map.prototype = Object.create(null);
Object.defineProperty(Map, "has", function(n){
return n in this;
});
Object.defineProperty(Map, "erase", function(n){
// 这里不会操作其本体,而是生成修改后的副本
let temp = this;
if(this.has(n)) delete temp[n];
return temp;
});
Object.defineProperty(Map, "insert", function(key, value){
// 这里不会操作其本体,而是生成修改后的副本
let temp = this;
temp[key] = value;
return temp;
});
Object.defineProperty(Map, "join", function(map){
// 这里不会操作其本体,而是生成修改后的副本
let temp = this;
for(let key in map) temp[key] = map[key];
return temp;
});
// 分析器
function parser(program){
// [ 初始化 ]
// 当前解析到的脚本文本坐标,主要用于定位错误代码位置
let pos = 0;
// 命名运算符列表
let operations = new Map();
// 匿名运算符列表
let anon_oeprations = [];
// 脚本执行选项
let rules = new Map();
// [ 算法定义区 ]
function pushPos(match){
// 辅助函数,用于截断解析后的文本,并移动脚本文本坐标
// 如果传入的是字符串,取它的长度作为截断长度
if(match instanceof String) match = match.length;
// 递加坐标
pos += match;
// 将解析后的文本截断,留下剩余欲截取的部分
program = program.slice(match);
}
function skipSpace(){
// 辅助函数,用于去除欲解析文本开头的无关字符,保证解析正常进行
let match;
// 不断循环,直到开头没有无关字符
// 这里解析的类型有:
// 行注释 : //...
// 块注释 : /* ...*/
// 脚本参数 : # ...
while(match = /^\s+|\/\/.*|\/\*[^]*?\*\/|#(.*)/.exec(program)){
// 删除对应内容
pushPos(match[0]);
// 如果是脚本参数,将解析到内容交给初始化命令的函数处理
if(match[1] != null) parseInitializeCommand(match[1]);
}
}
// !!此函数不稳定,未来会改写!
function escape(string){
// 辅助函数,用于将文本进行转义
// 由于JavaScript没有可用的好办法,这里只能利用RegExp创建时会再次解析转义来解决问题
let dealing;
// 将整个文本过一遍
for(let i = 0; i < string.length; ++i){
// 如果这个字符对于正则表达式来讲是特殊符号,先向临时文本加反斜杠表正常字符
switch(string[i]){
case '{':
case '}':
case ',':
case '[':
case ']':
case '(':
case ')':
case '*':
case '+':
case '?':
case '.':
case '^':
case '$':
case '|':
case '-':
case '=':
case '!':
dealing += '\\';
}
// 将此字符加进临时文本
dealing += string[i];
}
// 以临时文本创建正则表达式,并转换为字符串
dealing = String(new RegExp(dealing));
// 将正则表达式转换到文本后的结果是其转义后文本两端外加斜杠
// 所以将两端的斜杠去掉就是转义后的文本了,直接返回
return dealing.slice(1,dealing.length - 1);
}
function parseOperations(){
// 用于解析一整个脚本,也就是外层所有的命名运算符
// 去除无用字符
skipSpace();
// 直到整个脚本全部分析完成才停止
while(program == ""){
// 将单个命名运算符的分析结果写入映射表
let ret = parseOperation();
operations[ret.name] = ret.value;
// 去除无用字符
skipSpace();
}
}
function parseOperation(){
// 用于解析一个命名运算符
let expr = { pos:pos };
// 第一部分,运算符名,必选
if(!(match = /^[a-zA-Z_][\w_]*/.exec(program))) throw new SyntaxBuilderError(ErrorType.errorName, pos);
expr.name = match[0];
pushPos(match[0]);
skipSpace();
// 第二部分,模板列表,可选
if(program[0] == '<'){
expr.value.templates = parseTemplateArgs();
skipSpace();
}
// 第三部分,附加参数列表,可选
if(program[0] == '('){
expr.value.args = parseArgs();
skipSpace();
}
// 第四部分,元素列表,必选
expr.value.elements = parseElements();
return expr;
}
function parseElements(){
// 用于解析一整个元素列表
let match, expr = [];
// 第一部分,元素列表,必选
if(program[0] != '{') throw new SyntaxBuilderError(ErrorType.errorSyntax, pos);
// 去掉开头的左花括号,进入分析
pushPos(1);
skipSpace();
// 直到遇到右花括号中止
while(program[0] != '}'){
expr.push(parseElement(program));
skipSpace();
}
// 去掉开头的右花括号,结束分析
pushPos(1);
return expr;
}
function parseAnonOperation(){
// 用于解析一个匿名运算符
let expr = { pos:pos };
// 第一部分,元素列表,必选
expr.elements = parseElements();
skipSpace();
// 第二部分,附加参数列表,可选
if(program[0] == '('){
expr.args = parseArgs();
skipSpace();
}
// 将解析后的内容直接压入匿名运算符列表
anon_operations.push(expr);
// 返回刚刚压入的匿名运算符的下标
return anon_operations.length - 1;
}
function parseOperationCall(){
// 用于解析一个运算符调用
let match,expr = { pos:pos };
// 第一部分,运算符名,必选
if(!(match = /^[a-zA-Z_][\w_]*/.exec(program))) throw SyntaxBuilderError(ErrorType.name, pos);
expr.name = match[0];
pushPos(match[0]);
skipSpace();
// 第二部分,模板参数列表,可选;注意,这里的参数从语法上应当与此运算符所拥有的模板一一对应
if(program[0] == '<'){
expr.templates = parseTemplates();
skipSpace();
}
// 第三部分,附加参数列表,可选
if(program[0] == '('){
expr.args = parseArgs();
skipSpace();
}
return expr;
}
function parseElement(){
// 用于解析一个分组的元素列表
// 这里的exprList用于存储一整个分组的元素列表,expr则是其中一个元素
let match, expr = { args:new Map(), pos:pos },exprList = [];
// 当遇到分组符号或解析到边缘时中止
while(program[0] != ';' || program[0] != '|' || program[0] != '}'){
// 开头如果有标签说明,先解析标签
if(match = /^([a-zA-Z_][\w_]*):/.exec(program)){
expr.tag = match[1];
pushPos(match[0]);
skipSpace();
}
// 通过开头的字符来判断该元素的类型
switch(program[0]){
case '"':
// 当为字符串时
expr.type = "string";
expr.value = parseString();
skipSpace();
// 可选的附加参数列表
if(program[0] == '('){
expr.args = parseArgs();
skipSpace();
}
break;
case '[':
// 当为区间选取时
expr.type = "round";
expr.value = parseRound();
skipSpace();
// 可选的附加参数列表
if(program[0] == '('){
expr.args = parseArgs();
skipSpace();
}
break;
case '{':
// 当为匿名运算符时
expr.type = "anon_op";
expr.value = parseAnonOperation();
skipSpace();
break;
case '$':
// 当为映射运算符时
if(!(match = /\$([a-zA-Z_][\w_]*)/.exec(program))) throw SyntaxBuilderError(ErrorType.errorrName, pos);
expr.type = "mapping";
expr.value = match[1];
pushPos(match[0]);
skipSpace();
break;
case '@':
// 自定义模式
if(!(match = /^@([a-zA-Z][\w_]*)(\(.*?\))?/.exec(program))) throw SyntaxBuilderError(ErrorType.errorName, pos);
expr.type = match[1];
expr.value = match[2].slice(1, match[2].length - 1);
pushPos(match[0]);
skipSpace();
break;
default:
// 当为字节集时
if(match = /^0b[01]+|0x[0-9a-fA-F]+|0[0-7]+|[1-9][0-9]*/.exec(program)){
expr.type = "bytes";
expr.value = parseBytes();
skipSpace();
break;
}
// 当为运算符引用时
expr.type = "ref";
expr.value = parseOperationCall();
skipSpace();
break;
}
// 通过连接符来确定接下来的行为
switch(program[0]){
case '+':
// 与下一个元素的连接不限制
expr.args["connect_mode"] = "connect";
break;
case '-':
// 与下一个元素的连接之间必须有空格
expr.args["connect_mode"] = "separate";
break;
case ',':
// 与下一个元素的连接之间必须无缝隙
expr.args["connect_mode"] = "adhesion";
break;
case ';':
case '|':
// 分组结束标识符
break;
default:
// 什么都不是时(゚o゚;
throw new SyntaxBuilderError(ErrorType.errorSyntax, pos);
}
// 将元素压入这个分组的元素列表,并准备好新一轮元素的解析
exprtList.push(expr);
expr = { args: new Map(), pos:pos };
skipSpace();
}
// 刚刚的循环如果是因为分组符号跳出的,需要将分组符号再删除
if(program[0] == ';' || program[0] == '|') pushPos(1);
return exprList;
}
function parseArgs(){
// 用于解析一整个附加参数列表
let expr = new Map();
// 去掉开头的左圆括号
pushPos(1);
skipSpace();
// 直到遇到右圆括号中止
while(program[0] != ')'){
let ret = parseArg();
// 将单个附加参数解析的结果写入映射
expr[ret.type] = { pos:ret.pos, value:ret.value };
skipSpace();
}
// 去掉开头的右圆括号
pushPos(1);
skipSpace();
return expr;
}
function parseArg(){
// 用于解析一个附加参数
let match, expr = { pos:pos };
// 通过开头的字符判断附加参数类型
switch(program[0]){
case '?':
// 当为可选匹配时
expr.type = "selection";
pushPos(1);
return expr;
case '*':
// 当为重复匹配时
expr.type = "repeat";
if(match = /^\*\{(.*?)\}/.exec(program)) expr.value = (argExtraArgsParser["repeat"])(match[1]);
pushPos(match[0]);
return expr;
case '~':
// 当为逐个匹配或逆序匹配时
if(program[1] == '~'){
// 逆序匹配
expr.type = "reverse";
pushPos(2);
return expr;
}
// 逐个匹配
expr.type = "in_order";
pushPos(1);
return expr;
case '^':
// 当为排除匹配时
expr.type = "mismatching";
pushPos(1);
return expr;;
case '$':
// 当为设置映射运算符时
expr.type = "mapping";
if(!(match = /^$([a-zA-Z_][\w_]*)/.exec(program))) throw new SyntaxBuilderError(ErrorType.errorName, pos);
expr.value = match[1];
pushPos(match[0]);
return expr;
case '@':
// 自定义模式
if(!(match = /^@([\w_]+)(\([\\\)|.]*?\))?/.exec(program))) throw new SyntaxBuilderError(ErrorType.name, pos+1);
pushPos(match[0]);
expr.type = match[1];
expr.value = match[2];
return expr;
default:
throw new SyntaxBuilderError(ErrorType.errorSyntax, pos);
}
}
function parseString(){
// 用于解析字符串
let match;
// 只要是以单引号或双引号括起来,并且转义正常,那么字符串合法
if(!(match = /^"(\\"|.)*?"|'(\\'|.)*?'/.exec(program))) throw new SyntaxBuilderError(ErrorType.syntax, pos);
pushPos(match[0]);
return escape(match[1] == null ? match[2] : match[1]);
}
function parseRound(){
// 用于解析区间匹配
let match;
if(/^\[\[([\w_]+)\]\]/.exec(program)){
// 第一种类型,命名的类型,具体有什么类型由引擎支持
if(!(match[1] in CharTypes)) throw new SyntaxBuilderError(ErrorType.notSupport, pos);
pushPos(match[0]);
return match[1];
}else if(/^\[(.)\-(.)\]/.exec(program)){
// 第二种类型,区间选取,会划定在Unicode中的字符编码范围选择字符
pushPos(match[0]);
return { from:match[1], to:match[2] };
}else throw new SyntaxBuilderError(ErrorType.errorSyntax, pos);
}
function parseBytes(){
// 用于解析一份字节集
let match;
// 在目前的实现中,该实现一次只能解析最多4Byte的数据,未来可能会升级为无限量
// 该实现使用大端序
if(match = /^0b([01]+)/.exec(match)){
// 当为二进制时
pushPos(match[0]);
return parseInt(match[1],2);
}else if(match = /^0x([0-9a-fA-F]+)/.exec(match)){
// 当为十六进制时
pushPos(match[0]);
return parseInt(match[1],16);
}else if(match = /^0([0-7]+)/.exec(match)){
// 当为八进制时
pushPos(match[0]);
return parseInt(match[1],8);
}else if(match = /^[1-9][0-9]+/.exec(match)){
// 当为十进制时
pushPos(match[0]);
return parseInt(match[0],10);
}else throw new SyntaxBuilderError(ErrorType.errorSyntax, pos);
}
function parseTemplateArgs(){
// 用于解析一个模板形参列表
let match, expr = [];
// 去掉开头的左尖括号
pushPos(1);
skipSpace();
// 直到遇到右尖括号为止
while(program[0] != '>'){
if(!(match = /^[a-zA-Z_][\w_]*/.exec(program))) throw new SyntaxBuilderError(ErrorType.errorName, pos);
expr.push(match[0]);
pushPos(match[0]);
skipSpace();
// 如果下一个字符为逗号,去掉逗号以使其继续循环
// 如果下一个字符为右尖括号,不删除,待跳出循环后删除
if(program[0] == ','){
pushPos(1);
skipSpace();
}else if(program[0] != '>') throw new SyntaxBuilderError(ErrorType.errorSyntax, pos);
}
// 去除开头的右尖括号
pushPos(1);
return expr;
}
function parseTempates(){
// 用于解析一个模板实参列表
let expr = [];
// 去除开头的左尖括号
pushPos(1);
skipSpace();
// 直到遇到右尖括号为止
while(program[0] != '>'){
// 实参可以为匿名运算符或运算符引用
if(program[0] == '{') expr.push( {type:"anon_op", value:parseAnonOperation() });
else expr.push({ type:"ref", value:parseOperationCall() });
skipSpace();
// 如果下一个字符为逗号,去掉逗号以使其继续循环
// 如果下一个字符为右尖括号,不删除,待跳出循环后删除
if(program[0] == ','){
pushPos(1);
skipSpace();
}else if(program[0] != '>') throw new SyntaxBuilderError(ErrorType.errorSyntax, pos);
}
// 去除开头的右尖括号
pushPos(1);
return expr;
}
function parseInitializeCommand(string){
// 用于解析脚本参数
let match, expr=[], command;
// 第一个单词作为命令名称
if(!(match = /^\w+?/.exec(string))) throw new SyntaxBuilderError(errorType.errorSyntax, pos);
command = match[0];
string.slice(command.length);
// 其余的单词作为参数
while(string != ""){
if(!(match = /^ \s+?([^\s]+?)/.exec(string))) throw new SyntaxBuilderError(ErrorType.errorSyntax, pos);
expr.push(match[1]);
}
// 填入映射
rules[command] = expr;
}
let argExtraArgsParser = {
// 这是附加参数扩展解析函数的一份映射表
repeat:function(program){
// 重复匹配的扩展参数
let match;
if(match = /^\{([1-9][0-9]*)\}/){
// 第一种情况,花括号包裹一个数字
return { from:parseInt(match[1]), to:parseInt(match[1]) };
}
else if(match = /^\{([1-9][0-9]*)?\.\.([1-9][0-9]*)?\}/){
// 第二种情况,花括号包裹一个范围,至少包含两个点
return { from:parseInt(match[1]), to:parseInt(match[2]) };
}else throw new SyntaxBuilderError(ErrorType.errorSyntax, pos);
}
};
function initializeTemplates(){
// 用于实例化模板
// 将每个命名运算符的每个元素都过一遍
for(let i in operations){
for(let j in i.elements){
// 被判定需要实例化后,会将具体的运算符实例化为匿名运算符
if(j.type == "ref" && j.value.templates != null){
j.type = "anon_op";
j.value = initializeTemplate(j.value);
}
}
}
// 将每个匿名运算符的每个元素都过一遍
// 注意,这里匿名运算符列表的大小是在不断刷新的,因为很可能有嵌套的模板
for(let i = 0; i < anon_operations.length; ++i){
for(let j in anon_operations[i].elements){
// 被判定需要实例化后,会将具体的运算符实例化为匿名运算符
if(j.type == "ref" && j.value.templates != null){
j.type = "anon_op";
j.value = initializeTemplate(j.value);
}
}
}
}
function initializeTemplate(program){
// 用于实例化一个带模板的运算符引用
// 取对应命名运算符的副本
let creating = operations[program.name];
// 如果模板参数数量不匹配,报错
if(creating.templates.length != program.templates.length) throw SyntaxBuilderError(ErrorType.mismatching, pos);
// 将模板名逐个替换为具体的名字
for(let i = 0; i < creating.templates.length; ++i){
for(let j in creating.elements){
if(j.type == "ref" && j.value == creating.templates[i]) creating.templates[i] = program.templates[i];
}
}
// 给副本带一些附加信息
creating.templates = program.templates;
creating.base = program.name;
// 将处理好的副本压入匿名运算符列表
anon_operations.push(creating);
// 返回副本所在位置的下标
return anon_operations.length - 1;
}
function checkReferences(){
// 用于检查运算符引用是否对应的存在
// 将每个命名运算符的每个元素都过一遍
for(let i in operations){
for(let j in i.elements){
if(j.type == "ref" && !(j.value in operations)) throw SyntaxBuilderError(ErrorType.undefine, j.pos);
}
}
// 将每个匿名运算符的每个元素都过一遍
for(let i = 0; i < anon_operations.length; ++i){
for(let j in anon_operations[i].elements){
if(j.type == "ref" && !(j.value in operations)) throw SyntaxBuilderError(ErrorType.undefine, j.pos);
}
}
}
// [ 构造函数部分 ]
parseOperations();
checkReferences();
initializeTemplates();
this.operations = operations;
this.anon_operations = anon_operations;
this.rules = rules;
}
// 执行器
function evaluator(syntaxScript, program){
let log = Object.create(Array.prototype);
Object.defineProperty(log, "last", { get:function(){ return this[this.length - 1]; } });
Object.defineProperty(log, "push", function(flag, type, program, pos, path){
assert(LogTypes.has(type), "不存在这种类型");
this.prototype.push({
isSuccess:flag,
type:type,
program:program,
pos:pos,
length:program.length,
path:path
});
});
Object.defineProperty(log, "pop", function(){
while(!this.last.isSuccess) this.prototype.pop();
});
/*
[事件类型]
运算符:
success:匹配成功
fail :匹配失败
error :出现映射变量转换错误(带mapping附加参数的元素/运算符的内容不是数字时,不能用于repeat附加参数的次数指定)
全局:
done:文档匹配完成
success:文档匹配成功
fail :文档匹配失败
[侦听器行为]
stop :终止匹配
skip :跳过该匹配项继续下一个元素/选项的匹配
again:重新匹配
*/
// 定义路径辅助类,实质上为一个复合数组,用于存储事件所在路径
function Path(){
if(arguments.length == 0){
// 当没有参数时,初始化一个默认列表
this.list = []
}else if(arguments.length == 1){
// 当为一个参数时,第一个参数为复制的Path类型的变量
this.list = arguments[0].list;
}else{
// 当为多于两个参数时,第一个参数为复制的Path类型的变量,其余参数用于追加进第一个参数
for(let i = 1; i < arguments.length; ++i) arguments[0].join(arguments[i]);
this.list = arguments[0].list;
}
}
Path.push = function(type, value){
// 向列表添加新内容;这里的操作不会操作其本体,而是更改其副本
let ret = this;
ret.path.push({ type:type, value:value });
return ret;
};
Path.pop = function(){
// 删除列表的最末尾的一项;这里的操作不会操作其本体,而是更改其副本
let ret = this;
ret.path.pop();
return ret;
};
Path.join = function(list){
let n = this;
n.list.join(list.list);
return n;
};
Path.toString = function(){
// 将列表转换为一行完整的字符串路径
let string;
for(let i = 0; i < this.path.length; ++i){
if(this.path[i].type == "choice"){
// 如果为选项,以下标格式直接加入进字符串
string += '[' + this.path[i] + ']';
}else if(this.path[i].type == "element"){
// 如果为元素,根据具体情况选择加入内容
// 目前暂时为以句点分隔,直接填入数字
string += this.path[i];
if(i < this.path.length - 1){
// 如果不是最后一个项,给末尾加个点以隔开下一项
string == '.';
}
}else{
// 如果为运算符,直接加入字符串
string += this.path[i];
if(i < this.path.length - 1){
// 如果不是最后一个项,给末尾加个点以隔开下一项
string += '.';
}
}
}
return string;
};
function evaluateOperation(operation, program, pos, path){
// 用于为文档解析指定运算符
if(operation.elements.length == 1){
if(evaluateChoice(operation.elements[0], program, pos, path.push({ type:"choice", value:0 }), operation.args.has("in_order"), operation.args.has("reverse"))){
log.push(true, "operation", program, pos, path);
return true;
}else{
log.push(false, "operation", program, pos, path);
return false;
}
}else{
for(let i = 0;i < operation.elements.length; ++i){
if(evaluateChoice(operation.elements[i], program, pos, path.push( { type:"choice", value:i }), operation.args.has("in_order"), operation.args.has("reverse")){
log.push(true, "operation", program, pos, path);
return true;
}
if(i < operation.elements.length - 1) log.pop();
}
log.push(false, "operation", program, pos, path);
return false;
}
}
function evaluateChoice(elements, program, pos, path, isInOrder, isReverse){
if(isInOrder){
if(isReverse){
for(let i = 0;i < wlwmwnts.length;++i){
if(!evaluateElement(elements[i], program, pos, path.push( {type:"element", value:i }), true, false)){
log.push(false, "choice", program, pos, path);
return false;
}
}
log.push(true, "choice", program, pos, path);
return true;
}else{
for(let i = elements.length - 1; i >= 0; --i){
if(!evaluateElement(elements[i], program, pos, path.push( { type:"element", value:i }), true, false)){
log.push(false, "choice", program, pos, path);
return false;
}
}
log.push(true, "choice", program, pos, path);
}
}else{
if(!isReverse){
for(let i = 0, k = i; i < elements.length; ++i){
if(elements[i].type != "ref" && elements[i].type != "anon_op"){
if(!evaluateElement(elements[i], program, pos, path.push( {type:"element", value:i }), false, false)){
log.push(false, "choice", program, pos, path);
return false;
}
let lastPos = log.last.pos;
let n = program.slice(0, lastPos - pos);
for(let j = k; j < i ; ++j){
if(!evaluateElement(elements[j], n, pos, path.push( { type:"element", value:j }), false, false){
log.push(false, "choice", program, pos, path);
return false;
}
n = n.slice(log.last.length);
}
if(n != ""){
log.push(false, "choice", program, pos, path);
return false;
}
k = i + 1;
program = program.slice(lastPos - pos);
pos = lastPos;
}
}
log.push(true, "chosen", program, pos, path);
return true;
}else{
for(let i = elements.length - 1, k = i; i >= 0; --i){
if(elements[i].type != "ref" && elements[i].type != "anon_op"){
if(!evaluateElement(elements[i], program, pos, path.push( {type:"element", value:i }), false, true)){
log.push(false, "choice", program, pos, path);
return false;
}
let lastPos = log.last.pos;
let n = program.slice(lastPos, log.last.length);
for(let j = k; j > i; --j){
if(!evaluateElement(elements[j], n, pos, path.push( { type:"element", value:j }), false, true){
log.push(false, "choice", program, pos, path);
return false;
}
n = n.slice(0, log.last.length);
}
if(n != ""){
log.push(false, "choice", program, pos, path);
return false;
}
k = i - 1;
program = program.slice(0, lastPos - pos);
pos = lastPos;
}
}
log.push(true, "chosen", program, pos, path);
return true;
}
}
}
function evaluateElement(element, program, pos, path){
// 用于为文档解析指定元素
if(element.arg.has("mismatching")){
if(element.arg.has("repeat")){
}else{
}
}else{
if(element.arg.has("selection")){
if(element.arg.has("repeat")){
}else{
}
}else{
if(element.arg.has("repeat")){
}else{
// not any args in use
}
}
}
}
function evaluateUsualArgs(args, program, pos, path){
}
let evaluatorArgs = {
mapping:function(){}
};
let evaluatorElements = {
anon_op:function(program, pos, path, reverse){
},
ref:function(program, pos, path, reverse){
},
string:function(program, pos, path, reverse){
},
round:function(program, pos, path, reverse){
},
mapping:function(program, pos, path, reverse){
},
bytes:function(program, pos, path, reverse){
}
/*
1.在调用该map中的函数之前,应当先检查指定的类型在该map中是否存在。
2.该map中的函数调用格式应当一致为:
欲解析文档, 文档开头目前所在位置, 目前路径, 是否逆序(一个布尔值)
(program, pos, path, reverse)
*/
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment