|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
-
- 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);
- }
- }
- };
-
|