-
-
Save langyo/f76b519d3060d7347435e9b1a7dd549f to your computer and use it in GitHub Desktop.
syntax builder old code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// [ 常量值定义区 ] | |
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