[识别解析_时序图]: ./assets/识别解析_时序图.png
[识别解析_活动图]: ./assets/识别解析_活动图.png
[对鉴定者列表执行识别]: ./assets/对鉴定者列表执行识别.png
[执行鉴定者]: ./assets/执行鉴定者.png

[识别]: ./assets/识别.png
[执行鉴定者]: ./assets/执行鉴定者.png

[解决]: ./assets/解决.png


**目录：**  

<!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6 orderedList=true} -->

<!-- code_chunk_output -->

1. [类的关系](#-类的关系)
2. [识别解析的逻辑](#-识别解析的逻辑)
    1. [识别的逻辑](#-识别的逻辑)
    2. [解析的逻辑](#-解析的逻辑)

<!-- /code_chunk_output -->



-------


# 类的关系
recogn-parse 包含以下几个主要类：
- `RecognParse`：识别解析，是用户直接操作的主类，提供了完整的 `识别-解析` 机制。
- `Recognizer`：识别器。负责识别操作，所有的识别逻辑都是由该类来完成的。
- `Resolver`：解决者。负责解析操作，所有的解析逻辑都是由该类来完成的。

它们之间的关系如下图：
![识别解析_时序图][]

# 识别解析的逻辑
当需要对目标 `target` 进行识别并解析时，可以调用以下任一方法：
- `recognParse.resolve(target)`
- `recognParse.resolveAsync(target)`

**识别解析的逻辑步骤如下：**  
1. 对目标 `target` 进行识别：这一步的目的是识别出目标 `target` 的类型 `type`；
    1. 前置识别：如果没有前置鉴定者，则跳过此步；否则，依次执行前置鉴定者列表中的鉴定者，直到 鉴定者成功识别出  `target` 的类型 `type` 或者 前置鉴定者列表中的鉴定者执行完毕（详见下图 `对鉴定者列表执行识别`）；
    2. 识别：如果指定了鉴定者的名字，则直接执行对应的鉴定者；否则，将依次执行鉴定者列表中的鉴定者，直到 鉴定者成功识别出  `target` 的类型 `type` 或者 前置鉴定者列表中的鉴定者执行完毕（详见下图 `对鉴定者列表执行识别`）；
    3. 后置识别：如果没有后置鉴定者，则跳过此步；否则，依次执行后置鉴定者列表中的鉴定者，直到 鉴定者成功识别出  `target` 的类型 `type` 或者 后置鉴定者列表中的鉴定者执行完毕（详见下图 `对鉴定者列表执行识别`）；
    4. 经过以上几步，如果最后一步没有返回的识别结果，则终止程序；否则，继续下一步；
2. 对目标 `target` 进行解析：依次对每个识别出来的类型执行以下步骤：
    1. 如果没有对应类型的解析器，则跳过些类型的解析；否则，继续；
    2. 前置解析：如果没有前置解析函数，则跳过此步；否则，依次执行前置解析函数列表中的所有函数，并忽略执行解析函数时抛出的异常；
    3. 解析：获取对应类型的解析器，并执行该解析器；
    4. 后置解析：如果没有后置解析函数，则跳过此步；否则，依次执行后置解析函数列表中的所有函数，并忽略执行解析函数时抛出的异常；
    5. 将以上几步中最后一步的解析结果视作该类型的解析结果；
3. 汇总每个类型的识别结果和解析结果，并返回；

**流程图如下：**  
![识别解析_活动图][]
![对鉴定者列表执行识别][]


其中 `鉴定者` 分为两类：
- `鉴定函数`：类型为 `type Judge<Options = any> = (target: any, targetOptions: Options, preResult: FormatJudgeResult) => JudgeReturn`，用于鉴定 target 的类型 和 格式化数据，如果返回 空，表示鉴定失败，参数如下：
    * @param `target` - 目标
    * @param `targetOptions` - 目标相关的选项
    * @param `preResult` - 上一个鉴定函数的鉴定结果
    * @returns 返回鉴定结果，可以是异步的鉴定结果；鉴定结果是可以是 一个 或 一组 鉴定信息 {@link JudgeInfo}，也可以是空，如果是空 表示鉴定失败

- `串行鉴定者`：类型为 `type SerialJudger<Options = any> = Judge<Options>[]` 串行鉴定者就是一组鉴定函数，所有的鉴定函数都会依次执行，不论中间有没有失败，都会依次执行完所有的鉴定函数，并会以最后一个鉴定函数返回的结果为最终的鉴定结果。
    * 串行鉴定者序列中的任何项识别失败都不会中止 串行鉴定者序列 的执行。即：即使 串行鉴定者序列 `SerialJudger` 中的某一个 `Judge` 返回 null 或者 抛出错误，则仍会执行此 串行鉴定者序列 SerialJudger 中的下一个 Judge

**鉴定者的执行流程如下：**  
![执行鉴定者][]



`解析器`也分为两类：
+ `解析函数`：类型为 `type Parse<Options = any> = (target: any, targetOptions: Options, preResult: any, recognResult: JudgeInfo) => any`，用于对 target 进行解析，参数如下：
    * @param `target` - 目标
    * @param `targetOptions` - 目标相关的选项
    * @param `preResult` - 之前的解析结果
    * @param `recognResult` - 识别结果
    * @returns 解析的结果
+ `串行解析器`： 类型为 `type SerialParser<Options = any> = Parse<Options>[]`，串行解析器就是一组解析函数，这些解析函数会依次执行，并会以最后一个解析函数返回的结果为最终的解析结果。这组解析函数中如果有解析函数抛出错误，则会终止解决流程。

## 识别的逻辑
每次执行识别操作时，会按照如下顺序调用鉴定者：  
1. 依次执行前置鉴定者列表 `preJudgers` 中的鉴定者，如果有鉴定成功的，则会停止后续的前置鉴定者的执行，并将鉴定结果 传给后续流程。
2. 如果提供了 `name`，则会在 命名的鉴定者 中查找 `name` 对应的鉴定者，然后执行指定的鉴定者。然后 跳到 步骤 5。
3. 如果没有提供 `name`，则会执行 匿名的鉴定者列表。如果有鉴定结果，则会 跳到 步骤 5。
4. 否则，则会执行 所有的命名鉴定者。如果有鉴定结果，则会 跳到 步骤 5。
5. 依次执行后置鉴定者列表 `postJudgers` 中的鉴定者，如果有鉴定成功的，则会停止后续的后置鉴定者的执行，并返回 鉴定结果。否则返回 空；

![识别][]
![对鉴定者列表执行识别][]
![执行鉴定者][]

## 解析的逻辑

每次执行解决操作时，会按照如下顺序调用解析器：  
1. 如果找不到对应类型 type 的 解析器，则会终止解决流程。
2. 依次执行前置解析器 `preParses` 中的所有解析函数，即使有抛出错误，也会继续执行，并会以最后一个解析函数返回的结果为最终前置解析器的解析结果，然后将 前置解析的结果 传给后续的解析器。
3. 依次执行根据 类型 type 查找到的解析器序列。如果序列中任意解析器抛出错误，则会终止解决流程。否则，以最后一个解析函数返回的结果为最终的解析结果 并 传递给后续的解析器。
4. 依次执行后置解析器 `postParses` 中的所有解析函数，即使有抛出错误，也会继续执行，并会以最后一个解析函数返回的结果为最终的解析结果。

![解决][]