export const Expression = function(_str, _flag = 0, _placeholderValueMap = {}) { this.pos = 0; // 当前解析表达式字符串的位置 this.str = _str; // 表达式 this.errno = Expression.NO_ERROR; // 当前错误码 this.placeholderValueMap = _placeholderValueMap; // 占位符值字典 this.flag = _flag | Expression.PARSE_FLAG_ERROR_HANDLE_SCHEME_THROW_EXCEPTION; // 行为标记 this.placeholders = []; } Expression.NO_ERROR = 0; Expression.ERROR = 1; Expression.NULL_STRING = 2; Expression.BY_ZERO = 3; Expression.MISSING_DIGIT = 4; Expression.MISSING_RIGHT_PARENT = 5; Expression.MISSING_OPERATOR = 6; Expression.INVALID_CHARACTER = 7; Expression.MISSING_PLACEHOLDER = 8; Expression.INVALID_DIGIT = 9; Expression.INVALID_PLACEHOLDER = 10; Expression.MISSING_RIGHT_PLACEHOLDER_END = 11; Expression.INVALID_PLACEHOLDER_FUNCTION = 12; Expression.MISSING_COMPARE_OPERATOR = 13; Expression.INVALID_COMPARE_OPERATOR = 14; Expression.INCOMPLETE = 15; Expression.ErrorStr = [ "", "错误", "空字符串", "除0", "缺失数字", "缺失右括号", "缺失运算符", "无效字符", "缺失占位符", "无效数字", "无效占位符", "缺失占位符结尾标识", "无效占位符内置函数", "缺失比较运算符", "无效比较运算符", "表达式不完整", ]; Expression.PARSE_FLAG_NONE = 0; Expression.PARSE_FLAG_ERROR_HANDLE_SCHEME_RETURN_ZERO = 1; // 解析到错误则当前部分返回0 Expression.PARSE_FLAG_ERROR_HANDLE_SCHEME_THROW_EXCEPTION = 1 << 1; // 解析到错误则抛出异常 Expression.PARSE_FLAG_ALL_NUMBER_AS_PLACEHOLDER = 1 << 3; // 所有数字都作为占位符 Expression.PARSE_FLAG_IGNORE_ERROR_MISSING_PLACEHOLDER = 1 << 4; // 忽略占位符缺失 Expression.PARSE_FLAG_IGNORE_ERROR_BY_ZERO = 1 << 5; // 忽略除0 // 是否读取到字符串结尾 Expression.prototype.__EOF = function() { return !this.str || this.pos >= this.str.length; }; // 字符串转为数字 Expression.prototype.__StrTo = function(numStr) { return Number(numStr) }; // 开始解析, 重置状态 Expression.prototype.__Ready = function() { this.pos = 0; this.errno = Expression.NO_ERROR; this.placeholders = []; let err = this.__CheckStr(); return (err === Expression.NO_ERROR); }; // 解析 值 括号 占位符 的优先级最高的表达式 Expression.prototype.__EvalV = function() { if(this.__EOF()) { return this.__FatalError(Expression.INCOMPLETE); } this.__SkipBlank(); let nStr = this.str.substring(this.pos); let p = 0; let nag = false; let result = 0; if(nStr.charAt(p) === '-') { nag = true; this.pos++; p++; } p += this.__SkipBlank(); if(nStr.charAt(p) === '(') // 括号表达式 { p++; this.pos++; result = this.__EvalP(); if(this.str.charAt(this.pos) !== ')') { return this.__FatalError(Expression.MISSING_RIGHT_PARENT); } this.pos++; } else if(nStr.charAt(p) === '{') // 占位符 { p++; this.pos++; p += this.__SkipBlank(); let d = ''; let size = 0; let ch = nStr.charAt(p); while("`~@#%^&*()-+=,/?:;\"'|\\[{]}".indexOf(ch) === -1) // 中文支持 { size++; d += ch; p++; this.pos++; if(p >= nStr.length) { return this.__FatalError(Expression.MISSING_RIGHT_PLACEHOLDER_END); } ch = nStr.charAt(p); } p += this.__SkipBlank(); if(this.str.charAt(this.pos) !== '}') { return this.__FatalError(Expression.MISSING_RIGHT_PLACEHOLDER_END); } this.pos++; if(size > 0) { result = this.__ParsePlaceholder(d); } else { return this.__NormalError(Expression.MISSING_PLACEHOLDER); } } else // 纯数字 { let d = ''; let size = 0; let ch = nStr.charAt(p); while((ch >= '0' && ch <= '9') || ch === '.') { size++; d += ch; p++; this.pos++; if(p >= nStr.length) break; ch = nStr.charAt(p); } if(size > 0) { let m = d.indexOf("."); if(m !== -1) { let n = d.lastIndexOf("."); if(n !== -1 && m !== n) { return this.__FatalError(Expression.INVALID_DIGIT); } if(m === 0 || m === d.length - 1) d = d.substr(0, m) + d.substr(m + 1); } if(this.flag & Expression.PARSE_FLAG_ALL_NUMBER_AS_PLACEHOLDER) result = this.__ParsePlaceholder(d); else result = this.__StrTo(d); } else { return this.__FatalError(Expression.MISSING_DIGIT); } } if(nag) result = -result; return result; }; // 解析* /的优先级相对较高的表达式 Expression.prototype.__EvalM = function() { if(this.__EOF()) { return this.__FatalError(Expression.INCOMPLETE); } let first = this.__EvalV(); let result = first; this.__SkipBlank(); let nStr = this.str.substring(this.pos); while(nStr.length > 0) { let ch = nStr.charAt(0); if(ch !== '*' && ch !== '/') return result; else { this.pos++; let second = this.__EvalV(); if(ch === '*') result = result *second; else { if(second === 0) { return this.__NormalError(Expression.BY_ZERO); } result = result / second; } } nStr = this.str.substring(this.pos); } return result; }; // 解析+ -的优先级最低的表达式 Expression.prototype.__EvalP = function() { if(this.__EOF()) { return this.__FatalError(Expression.INCOMPLETE); } this.__SkipBlank(); let first = this.__EvalM(); let result = first; let nStr = this.str.substring(this.pos); while(nStr.length > 0) { let ch = nStr.charAt(0); if(ch !== '+' && ch !== '-') return result; else { this.pos++; let second = this.__EvalM(); if(ch === '+') result = result + second; else result = result - second; } nStr = this.str.substring(this.pos); } return result; }; // 解析比较运算符 Expression.prototype.__EvalCmp = function() { if(this.__EOF()) { return this.__FatalError(Expression.MISSING_COMPARE_OPERATOR); } this.__SkipBlank(); let result = ''; let nStr = this.str.substring(this.pos); while(nStr.length > 0) { let ch = nStr.charAt(0); if(ch !== '=' && ch !== '!' && ch !== '>' && ch !== '<') break; else { if(result.length === 0) { result += ch; this.pos++; } else // === 1 { if(result !== "=") // 如果第一个字符不是=, 第二个字符必定是= { if(ch !== '=') return this.__FatalError(Expression.INVALID_COMPARE_OPERATOR); } else // 如果第一个字符是=, 第二个字符可以是= { if(ch === '=') result += ch; else { break; } } result += ch; this.pos++; } } if(result.length >= 2) break; nStr = this.str.substring(this.pos); } if(result === "=") result = "=="; return result; }; // 开始计算 Expression.prototype.Calc = function() { if(!this.__Ready()) return this.__OnError(0); return this.__EvalP(); }; // 判断表达式断言 Expression.prototype.Predicate = function() { if(!this.__Ready()) return this.__OnError(false); let a = this.__EvalP(); if(this.HasError()) return this.__OnError(false); let op = this.__EvalCmp(); if(this.HasError()) return this.__OnError(false); let b = this.__EvalP(); if(this.HasError()) return this.__OnError(false); //console.log(a + op + b); return eval(a + op + b); }; Expression.prototype.FLAG = function(flags) { for(let i of arguments) { if((this.flag & i) === i) return true; } return false; } // 普通错误, 仅设置可允许忽略的错误时调用, 错误被忽略时不设置错误码 Expression.prototype.__NormalError = function(err) { switch(err) { case Expression.BY_ZERO: if(this.FLAG(Expression.PARSE_FLAG_IGNORE_ERROR_BY_ZERO)) return 0; break; case Expression.MISSING_PLACEHOLDER: if(this.FLAG(Expression.PARSE_FLAG_IGNORE_ERROR_MISSING_PLACEHOLDER)) return 0; break; case Expression.INVALID_DIGIT: if(this.FLAG(Expression.PARSE_FLAG_IGNORE_ERROR_INVALID_DIGIT)) return 0; break; } return this.__FatalError(err); }; // 全局错误处理 Expression.prototype.__OnError = function(ifError) { if(this.FLAG(Expression.PARSE_FLAG_ERROR_HANDLE_SCHEME_THROW_EXCEPTION)) // 抛异常 { throw new Error(this.Error()); } else // 返回0 { return ifError; } }; // 计算是否有错误 Expression.prototype.HasError = function() { return this.errno !== Expression.NO_ERROR; }; // 返回计算的错误, 并清除错误 Expression.prototype.GetError = function() { let e = this.errno; this.errno = Expression.NO_ERROR; return e; } // 获取当前错误的字符串 Expression.prototype.Error = function() { return Expression.ErrorStr[this.errno]; } // 致命错误 Expression.prototype.__FatalError = function(err) { this.errno = err; throw new Error(this.Error()); }; Expression.prototype.ParsedPlaceholders = function() { return this.placeholders; } // 解析占位符 Expression.prototype.__ParsePlaceholder = function(name) { this.placeholders.push(name); if(!this.placeholderValueMap) { return this.__NormalError(Expression.MISSING_PLACEHOLDER); } if(name.startsWith("$")) // 特殊环境变量 return this.__ParseNumber(this.placeholderValueMap[name]); let ptr = this.placeholderValueMap; let d = null; let notFetch = false; let i = 0; do { let index = name.indexOf(".", i); let s = index === -1 ? name.substring(i) : name.substring(i, index); i += s.length + 1; s = s.trim(); if(s.startsWith("$")) // 函数管线 { if(!notFetch) // 此时当前值应该是数字, 不再继续向下取Object/Map { d = this.__ParseNumber(ptr); // 当前值转换为数字 notFetch = true; // 此时当前值应该是数字, 不再继续向下取Object/Map } switch(s.substring(1).toLowerCase()) { case "abs": d = Math.abs(d); break; case "neg": d = -d; break; case "lt0": if(d >= 0) return 0; break; case "gt0": if(d <= 0) return 0; break; default: return this.__FatalError(Expression.INVALID_PLACEHOLDER_FUNCTION); } } else { if(notFetch/*null != d*/) // TODO: 被管线函数处理过, 占位符表达式书写不应该出现该情况, 管线函数应都在表达式尾部, 并且不在表达式起始 return d; ptr = ptr[s]; if(null === ptr || undefined === ptr) { return this.__NormalError(Expression.MISSING_PLACEHOLDER); } } } while(i < name.length); if(null == d) return this.__ParseNumber(ptr); else return d; }; // 检查表达式字符串 Expression.prototype.__CheckStr = function() { if(!this.str) { return Expression.NULL_STRING; } return Expression.NO_ERROR; }; // 跳过空白符 Expression.prototype.__SkipBlank = function() { let i = 0; for(; (this.pos + i) < this.str.length; i++) { if(!/\s/.test(this.str.charAt(this.pos + i))) break; } this.pos += i; return i; }; // 对象转数字 Expression.prototype.__ParseNumber = function(val) { if(null === val) return this.__NormalError(Expression.INVALID_DIGIT); if(val instanceof Number) return val; else { try { return this.__StrTo(val.toString()); } catch(e) { console.error(e); return this.__NormalError(Expression.INVALID_DIGIT); } } };