// @ts-ignore // import { Parser as GrammarParser } from './grammar/grammar'; // const { Parser: GrammarParser } = require('./grammar/grammar'); // console.log('parser', GrammarParser); import { parser, Parser as GrammarParser } from './grammar/grammar'; import { toNumber, invertNumber } from './helper'; import { evaluateByOperator } from './helper'; import { getExcelError, ERROR, isValidErrorType, ERROR_NAME } from './error'; import functions from '../functions'; import { reAppend, isPlainObject } from 'valor-app-utils'; import { DepType, ParserContext, ParsedResult } from './data'; import * as R from 'rambda'; /** * 合并依赖 * 比如 第一次调用 getCells => {cells:[1]} * 第二次调用 getCells => {cells: [1,3]} * 则最终依赖为: {cells: [1,3]} // 注意已去重 * @param o 老依赖 * @param n 要添加的依赖 * @return 新依赖 */ export function mergeDeps(o: Record, n: Record) { return (Object.keys(n) as DepType[]).reduce( (acc: Record, depType: DepType) => { acc[depType] = !R.isNil(acc[depType]) ? acc[depType].concat(n[depType]) : n[depType]; return { ...acc, [depType]: R.uniq(acc[depType]), }; }, { ...o }, ); } // @ts-ignore class Parser { parser: any; variables: Record = {}; functions: Record = {}; context: ParserContext; deps: Record = { variables: [], // 哪些Cells修改了, 会影响到我 cells: [], }; constructor(context: ParserContext) { this.parser = new GrammarParser(); // console.log('parser', GrammarParser); // this.parser = parser; this.parser.yy = { toNumber, invertNumber, throwError: (errorName: string) => this._throwError(errorName), evaluateByOperator, callFunction: this.callFunction.bind(this), getVariable: this.getVariable.bind(this), }; const { variables, ..._context } = context; this.context = _context; this.setVariable('TRUE', true) .setVariable('FALSE', false) .setVariable('NULL', null); variables && Object.keys(variables).forEach(k => this.setVariable(k, variables[k])); Object.keys(functions).forEach(k => { // @ts-ignore this.setFunction(k, functions[k]); }); } parse(expression: string) { let result = null, error = null; try { if (expression === '') { result = ''; } else { result = this.parser.parse(expression); } } catch (ex) { if (process.env.NODE_ENV === 'development') { console.log(`解析公式失败:${expression}, `, ex); } const message = getExcelError(ex.message); if (message) { error = message; } else { error = getExcelError(ERROR); } } if (result instanceof Error) { error = getExcelError(result.message) || getExcelError(ERROR); result = null; } return { error, result }; } parseWithDeps(express: string): ParsedResult { return { ...this.parse(express), deps: this.deps }; } setVariable(name: string, value: any) { this.variables[name.toLowerCase()] = value; return this; } getVariable(name: string) { const result = this.variables[name.toLowerCase()]; if (result === undefined) throw Error(ERROR_NAME); // 添加依赖 this.deps.variables = reAppend(this.deps.variables, name); return result; } setFunction(name: string, f: Function) { this.functions[name.toLowerCase()] = f; return this; } /** * 直接调用方法 * 与getFunction的区别: 需要在这里处理依赖和错误 * 也就是, 某些function直接返回数据, 而某些将返回ParserResult结构 * **** 注意: 返回依赖的计算, 必定使用些方法, 而不可直接yy.xx *** */ callFunction(name: string, args: any) { const fun = this.functions[name.toLowerCase()] || this.context[name as keyof ParserContext]; if (fun === undefined) throw Error(ERROR_NAME); let result = fun(args); /////////////////// 处理parserResult 结构 ////////// if (isPlainObject(result) && (result.deps || result.error || result.result)) { // 若返回依赖信息, 则需要集成 if (result.deps && !R.isEmpty(result.deps)) { this.deps = mergeDeps(this.deps, result.deps); // result = result.result; } // 若返回错误, 则重新抛出 if (result.error) { // if (result.deps) { // this.deps = mergeDeps(this.deps, result.__deps); // } throw Error(result.error); } } return result.deps ? result.result : result; } /** * @deprecated * 无法搜集依赖, 改用callFunction */ getFunction(name: string) { console.warn('请改用callFunction'); const result = this.functions[name.toLowerCase()]; if (result === undefined) throw Error(ERROR_NAME); return result; } _throwError(errorName: string) { if (isValidErrorType(errorName)) { throw Error(errorName); } throw Error(ERROR); } } export default Parser;