### 1、SnEL 求值接口说明



| 接口 | 描述 | 
| -------- | -------- | 
| `SnEL.parse(...)`            | 解析求值表达式     | 
| `SnEL.eval(...)`              | 执行求值表达式     | 






### 2、语法与能力说明


| 能力                      | 示例                                   | 备注         |
| --------------- | ---------------------- | -------- |
| 支持常量获取          | `1`, `'name'`, `true`, `[1,2,3]`    | 数字、字符串、布尔、数组 |
| 支持变量获取          | `name`                               |                  |
| 支持字典获取           |  `map['name']`                     |                   |
| 支持集合获取           |  `list[0]`                              |                  |
| 支持对象属性或字段获取     | `user.name`, `user['name']`    | 支持`.` 或 `[]`     |
| 支持对象方法获取     | `order.getUser()`, `list[0].getUser()`    | 支持多级嵌套     |
| 支持对象静态方法获取     | `Math.add(1, 2)`,  `Math.add(a, b)`    |  支持多级嵌套     |
| 支持优先级小括号     |  `(`, `)`    |       |
| 支持算数操作符        |  `+`, `-`, `*`, `/`, `%`    | 加，减，乘，除，模     |
| 支持比较操作符       | `<`, `<=`, `>`, `>=`, `==`, `!=`       | 结果为布尔     |
| 支持like操作符        | `LIKE`, `NOT LIKE`（在相当于包含）       | 结果为布尔     |
| 支持in操作符          | `IN`, `NOT IN`       | 结果为布尔     |
| 支持三元逻辑操作符     | `conditionExpr ? trueExpr: falseExpr`     |      |
| 支持二元逻辑操作符     | `AND`, `OR`     |  与，或（兼容 `&&`、`||` ）    |
| 支持一元逻辑操作符     | `NOT`     |  非（兼容 `!` ）    |
| 支持安全导航表达式<br/>（Elvis操作符）     | `user?.name` （不加`?`效果相同）                    |  如果不为 null 则导航。v2.5.2 后支持   |
| 支持默认值表达式<br/>（Elvis操作符）        | `user.name ?: 'noear'`         |  如果为 null 则用默认值。v3.5.2 后支持    |
| 支持属性表达式        | `${user.name}`, `${user.name:noear}`         |  以 key 的方式取值。v3.5.2 后支持   |
| 支持类型表达式        | `T(java.lang.Integer).valueOf(45)`         |  使用一个类型的静态方法。v3.6.0 后支持   |

虚拟变量（root）说明：

当使用 EnhanceContext 上下文时，支持 `root` 虚拟变量（`SnEL.eval("root == true", new EnhanceContext(true))`）


关键字须使用全大写（未来还可能会增多）：

`LIKE`, `NOT LIKE`, `IN`, `NOT IN` ,`AND`, `OR` ,`NOT` 

数据类型与符号说明：

`1.1F`（单精度）、`1.1D`（双精度）、`1L`（长整型）。`1.1`（双精度）、`1`（整型）


Elvis 操作符号：

`?.`（安全导航表达式）, `?:`（默认值表达式）

属性表达式操作符号：

`${   }` （属性表达式会从 `PropertiesGuidance` 接口优先获取。如果没有？再以 `key` 方式从 `context` 获取）


预留特殊符号：

`#{   }`, 用于模板表达式


### 3、表达式示例

* 常量与算数表达式

```java
System.out.println(SnEL.eval("1"));
System.out.println(SnEL.eval("-1"));
System.out.println(SnEL.eval("1 + 1"));
System.out.println(SnEL.eval("1 * (1 + 2)"));
System.out.println(SnEL.eval("'solon'"));
System.out.println(SnEL.eval("true"));
System.out.println(SnEL.eval("[1,2,3,-4]"));
```

* 变量，字典，集合获取

```java
Map<String, String> map = new HashMap<>();
map.put("code", "world");

List<Integer> list = new ArrayList<>();
list.add(1);

Map<String, Object> context = new HashMap<>();
context.put("name", "solon");
context.put("list", list);
context.put("map", map);

System.out.println(SnEL.eval("name.length()", context)); //顺便调用个函数
System.out.println(SnEL.eval("name.length() > 2 OR true", context)); 
System.out.println(SnEL.eval("name.length() > 2 ? 'A' : 'B'", context)); 
System.out.println(SnEL.eval("map['code']", context));
System.out.println(SnEL.eval("list[0]", context));
System.out.println(SnEL.eval("list[0] == 1", context));
```

* 带优先级的复杂逻辑表达式

```java
Map<String, Object> context = new HashMap<>();
context.put("age", 25);
context.put("salary", 4000);
context.put("isMarried", false);
context.put("label", "aa");
context.put("title", "ee");
context.put("vip", "l3");

String expression = "(((age > 18 AND salary < 5000) OR (NOT isMarried)) AND label IN ['aa','bb'] AND title NOT IN ['cc','dd']) OR vip=='l3'";
System.out.println(SnEL.eval(expression, context));
```

* 静态函数调用表达式

```java
Map<String, Object> context = new HashMap<>();
context.put("Math", Math.class);
System.out.println(SnEL.eval("Math.abs(-5) > 4 ? 'A' : 'B'", context));
```


* Elvis 操作符表达式（v3.5.2 后支持）



```java
//安全导航 和 默认值
System.out.println(SnEL.eval("user?.name ?: 'solon'"));
System.out.println(SnEL.eval("user.name ?: 'solon'")); //两都效果相同
```

* `T(className)` 类型操作符表达式（v3.6.0 后支持）



```java
System.out.println(SnEL.eval("T(java.lang.Integer).parseInt(${user.age:12}) + 13")); //=>25
```

### 4、属性表达式的增强效应

属性表达式参与逻辑运算和比较运算时，可自动转换类型。

* 参与逻辑运算

参与逻辑运行时，会自动转为 bool 型。当非空时为 true, 否则为 false

```java
SnEL.eval("${demo.aaa} && bbb > 2");
```

* 参与比较运算

参与比较运算时，会自动转为比较目标的类型，再进行比较。

```java
SnEL.eval("${demo.aaa:true} == 'true'");  //原始态
SnEL.eval("${demo.aaa:true} == true");    //转为 bool
SnEL.eval("${demo.aaa:12} > 20");         //转为 number
```


### 5、嵌入对象（仅为示例）


```java
Map<String, Object> context = new HashMap<>();
context.put("Solon", Solon.class);
context.put("_sysProps", Solon.cfg()); //顺便别的对象（供参考）
context.put("_sysEnv", System.getenv());

//顺便用三元表达式，模拟下 if 语法
String expr = "Solon.cfg().getInt('demo.type', 0) > _sysProps.getInt('') ? Solon.context().getBean('logService').log(1) : 0";
System.out.println(SnEL.eval(expr, context));
```


属性表达式

```java
//求值
System.out.println(SnEL.eval("${user.name:solon}", Solon.cfg()));
System.out.println(SnEL.eval("'Hello ' + ${user.name:solon}", Solon.cfg()));

//模板
System.out.println(SnEL.evalTmpl("Hello ${user.name:solon}", Solon.cfg()));
```

