https://github.com/yzw7489757/ceval
expression eval
https://github.com/yzw7489757/ceval
calculation ceval eval expression lexical-analysis
Last synced: 5 months ago
JSON representation
expression eval
- Host: GitHub
- URL: https://github.com/yzw7489757/ceval
- Owner: yzw7489757
- Created: 2020-05-28T11:45:08.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2021-05-13T16:36:24.000Z (almost 5 years ago)
- Last Synced: 2025-08-09T03:02:07.632Z (7 months ago)
- Topics: calculation, ceval, eval, expression, lexical-analysis
- Language: TypeScript
- Homepage: https://yzw7489757.github.io/ceval/
- Size: 2.06 MB
- Stars: 10
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README-ZH.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
## Ceval










[online demo](https://yzw7489757.github.io/ceval/);
零依赖,适合表达式运算;
``` ts
┌───────────────────────────────┐
│ │
│ Destination: lib/index.js │
│ Bundle Size: 21.92 KB │
│ Minified Size: 21.89 KB │
│ Gzipped Size: 6.76 KB │
│ │
└───────────────────────────────┘
```
## 使用
``` shell
npm i ceval -S
```
## 介绍

### Options
``` ts
const Parser = require('ceval')
const analysis = new Parser({
/**
* @desc 允许使用操作符,不建议改
* @type {boolean}
*/
endableOperators?: boolean = true;
/**
* @desc 十进制,默认启用多进制,支持二、八、十六进制
* @type {boolean}
*/
endableBitNumber?: boolean = true;
/**
* @desc 允许访问成员 例如 a.b a['b']
* @type {boolean}
*/
allowMemberAccess?: boolean = true;
/**
* @desc 默认情况下允许放大计算
* @see 以兼容处理算术结果 e.g 0.1+0.2 !== 0.3 || 1.0-0.9 !== 0.1
* 边界计算(n > Number.MAX_SAFE_INTEGER || n < Number.MIN_SAFE_INTEGER)不会做处理
* @requires false
* @type {boolean}
*/
allowHandleNumberPrecision?: boolean = true;
/**
* @desc 默认情况下,不允许预设值覆盖运算符
* @see 在某些情况下,如果你希望进行更精确的计算,例如 BigInt、presetValue = {'+': (a, b) => (a+b)|0 }
* @requires false
* @type {boolean}
* @memberof CevalOptions
*/
allowOperatorsCovered?: boolean;
/**
* @desc 当没有返回值或未定义时触发默认返回值
* @type {any}
*/
defaultReturnValues?: any = '' // done
})
```
## API
Parser 实例API
| api | desc | type |
| --- | --- | --- |
| operatorMap | 运算符映射表,可用于覆盖预置值操作 | Record|
| getSupportOperationMap | 查询支持的运算符方法的名称,以支持operatorMap修改 | (ops: string) => null \| Function;|
| parseString | 解析字符串 | (expression: string, values?: Record) => any;|
| getCurrentValues | 获取当前数据池预置+外部+内部声明变量 | () => Record |
| updatePresetValues| 更新预设值 |(values: Record) => void|
| updateOptions| 更新Options | (Options: Partial\) => void|
| getOptions| 获取Options | () => Readonly\|
关于Options示例 [test case](https://github.com/yzw7489757/ceval/blob/master/test/options.test.js);
通过 [TC29/test262](https://github.com/tc39/test262/tree/master/test/language) 大部分测试用例;
## 规则
只有两条规则:
### 结尾分号
e.g.
``` ts
parse('0b01 + 0b01;') // 2
```
虽然在一个简单表达式操作中没必要那么麻烦,但确实是一个好习惯。Parser可以准确地知道结尾在哪里,没有什么限制。
e.g.
```ts
parse(`
function abs(a,b,c) {
let b = 1 /* ⚠️ error, must has semicolon */
c = 2;
return(a+b+c);
};
abs(3,4,8);
`)
```
### 变量
由var句柄申明的变量不影响 "scope",会被放到全局数据池中。
而 "let" 和 "const" 只会分配给当前作用域,如果当前作用域存在则发出警告。但仍然执行复制成功,后续将处理为无视该赋值行为,该变量仍然是赋值前的值。
TODO: 这是个纠结的点,如果你有什么建议欢迎提出。
``` ts
var Parser = require('ceval');
var instance = new Parser({/*...*/});
var parse = instance.parseString;
parse(`
var obj = { foo:'foo', bar: 'bar'};
function abs(a,b,c) {
var d = 'global';
return (a+b+c);
}
abs(1,2,3)
`)
console.log(instance.getCurrentValues().obj); // { foo:'foo', bar: 'bar'}
console.log(instance.getCurrentValues().d); // 'global'
parse(`
let foo = 'foo';
const bar = 'bar';
function abs(a,b,c) {
let d = 'scope';
const e = 'scope';
return (a+b+c);
}
abs(1,2,3)
`)
console.log(instance.getCurrentValues().foo); // undefined
console.log(instance.getCurrentValues().bar); // undefined
console.log(instance.getCurrentValues().d); // undefined
console.log(instance.getCurrentValues().e); // undefined
```
## 基本
``` ts
const { parse: parse } = analysis
```
### Number
``` ts
parse('0b01') // 1
parse('0b11') // 3
parse('0b010101') // 21
parse('01') // 1
parse('077') // 63
parse('01111') // 585
parse('.1') // 1
parse('33') // 33
parse('100.00') // 100
parse('0x01') // 1
parse('0xaf') // 175
parse('0x9fac') // 40876
parse(`1e+308*2 === Infinity`) // true
parse(`
var x = NaN;
var y = NaN;
return (x !== y);
`) // true
parse(`
var x = NaN;
return(typeof(x) === 'number');
`) // true
parse(`
var x = NaN;
var x_geq_0=(x >= 0.0);
return(x_geq_0)
`) // false
parse(`
var x=+Infinity;
return(typeof(x) === 'number')
`) // true
```
More testcase [here](https://github.com/yzw7489757/ceval/blob/master/test/number.test.js)
### 运算
``` ts
const obj = `{ a: 1, b: 2, c: 3, d: { e: 4, f: 5}}`
parse(`1+1`); // 2
parse(`-1-2-3`); // -6
parse(`1*2*3`); // 6
parse(`1/2/4`); // 0.125
parse(`undefined || 2`); // 2
parse(`~-1 || -2 || 3`); // -2
parse(`-0 == +0`); // true
parse(`~1 > 1`); // false
parse(`false > false > 1`); // false
parse(`5 >= 0`); // true
parse(`1 in [1, 2, 3]`); // true
parse(`undefined in [1, 2, true]`); // false
parse(`'a' in ${obj}`); // true
parse(`\'\'a\'\' in ${obj}`); // true ('"a"' === 'a') is Palindrome
parse(`1 === true`); // false
parse(`3%2`); // 1
```
### Function
``` ts
parse(`
function abs(a,b,c) {
var a = 5; /* => inject to presetValues */
let b = 1; /* => inject to current scope */
c = 2;
const d = 4; /* If the current scope contains the variable D, It will trigger warning, but the operation will still be completed, is overlay */
return(a+b+c);
};
abs(3,4,8);
`)
```
### Object & Array
``` ts
parse(`[1*2, false, true, undefined, null]`); // Array[]
parse(`var a = { b: { c: ['a','b','c','d']} };'e' in a.b.c`); // false
parse(`{ a: 1, b: 2, c: { d: undefined, e: { f: false, g: { h: null }}}}`); // object
parse(`var a = { b: 2 };a.b`) //2;
parse(`var a = { b: 2 };a["b"]`) //2;
parse(`var a = { b: 2, c:3 };var b='c';a[b]`) //3;
// data reference
parse(`
var a = { b: 2, c:[1,2,3]};
var b='c';
a[b][0] = '0';
return a[b];
`) // ['0',2,3]
parse(`
var arr = [1,2,3];
arr[0] = 0;
return arr;
`) // [0,2,3]
```
### Variable
``` ts
parse(`
var a = { foo: 1 };
var b = { bar: 2 };
let a = { state: 1 } // ⚠️, Raise warning, current scope exists key
const b = { state: 1 } // ⚠️, Raise warning, current scope exists key
let c = { coo: 1} // success;
const d = { coo: 1} // success;
`)
parse(`
var a = { a: [false, true, undefined, null, ''] };
var b = { b: true, c: undefined, d:{ e: a, f: '1', g: {}}};
`) // Can be obtained from the instance. api: getCurrentValues
```
### this
### 操作符
通过`instance.operatorMap`获取所有操作符;
#### return
`return` 中断当前操作轮询;但它不影响外部。
``` ts
parse(`
return 1;
return 2;
`) // 1
parse(`
var foo = 'foo'
function abs(a,b,c) {
return a;
return b;
}
var bar = abs(1,2,3)
return (bar + foo);
`) // foo1
```
### 其他
请转到测试用例以了解更多信息 [examples](https://github.com/yzw7489757/ceval/tree/master/test)。
### TODO: [Test39](https://github.com/tc39/test262/tree/master/test/language/types) 一些测试用例.
#### speed of progress
2020-06-24 done: number, null, boolean
更多功能扩展中,欢迎参与或提出feature。
## development
### develop
``` shell
npm start
```
### build
``` shell
# webapck build umd module, No compression
npm run build:umd
# rollup build umd module, Compressed version
npm run build:rollup
# webpack build docs
npm run build:docs
```
### publish
```shell
npm publish
```