text: /**
   * @file lexer.js
   * @author clark-t (clarktanglei@163.com)
   * @description 词法分析器
   */
  
  /**
   * 格式化规则
   *
   * @typedef {Array} Rule
   * @param {Function} Rule[0] 执行规则的方法
   * @param {*} Rule[1] 规则描述对象
   */
  
  /**
   * AST 节点对象
   *
   * @typedef {Object} ASTNode
   * @property {string} type AST 节点类型描述
   */
  
  /**
   * 对字符串解析的结果做缓存处理
   *
   * @param {Function} callback 字符串解析回调
   * @param {Function} 包装好的字符串解析回调
   */
  function memoize (callback) {
    /**
     * 根据规则来处理当前字符串的回调函数
     *
     * @param {Walker} walker 字符串源码读取工具
     * @param {Rule} rule 字符串解析规则
     * @return {ASTNode} 字符串解析得到的 AST 对象
     */
    return (walker, rule) => {
      // 当查询到有解析结果时，直接返回缓存的解析结果
      let index = walker.index
      let record = walker.query(rule, index)
      if (record) {
        return record[3]
      }
      // 否则执行回调处理字符串，并对解析结果进行存储
      let result = callback(walker, rule)
      walker.record(rule, index, walker.index, result)
      return result
    }
  }
  
  /**
   * 当字符串使用当前规则解析失败时，将字符串解析下标恢复到原先的状态
   *
   * @param {Function} callback 字符串解析回调
   * @return {Function} 包装好的字符串解析回调
   */
  function restorable (callback) {
    return (walker, rule) => {
      let index = walker.index
      let result = callback(walker, rule)
      // 解析失败只有 undefined（被动解析失败）false（lexer 规则主动判定失败）两种
      // 遇到解析失败时，直接回滚 index
      if (result === undefined || result === false) {
        walker.index = index
      }
      return result
    }
  }
  
  /**
   * 对规则属性的工厂方法执行结果做缓存处理
   *
   * @param {Function} callback 字符串解析回调
   * @params {Array.<string>} keys 需要缓存的属性列表
   * @return {Function} 包装好的字符串解析回调
   */
  function singleton (callback, keys) {
    let caches = {}
    return (walker, rule) => {
      let cache = caches[rule.type]
      if (!cache) {
        cache = rule
        for (let key of keys) {
          if (typeof cache[key] === 'function') {
            cache[key] = cache[key]()
          }
        }
        caches[rule.type] = cache
      }
      return callback(walker, cache)
    }
  }
  
  /**
   * 对字符串执行解析规则
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {Rule} rule 解析规则
   * @return {ASTNode|undefined|false} 解析得到 AST
   */
  export function run (walker, rule) {
    return rule[0](walker, rule[1])
  }
  
  /**
   * 顺序执行规则列表，当其中某条规则解析错误时，则整体解析失败，同时回滚字符串解析下标
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {Array.<Rule>} rules 解析规则列表
   * @return {ASTNode|false} 解析得到的 AST
   */
  export const seq = restorable((walker, rules) => {
    if (typeof rules[0] === 'function') {
      return run(walker, rules)
    }
    let results = []
    for (let node of rules) {
      let result = run(walker, node)
      if (result === false) {
        return false
      }
      results.push(result)
    }
    return results
  })
  
  /**
   * 顺序执行规则列表，当其中某条规则解析成功时，则直接返回该解析结果，全部规则解析失败时，则整体解析失败，同时回滚字符串解析下标
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {Array.<Rule>} rules 解析规则列表
   * @return {ASTNode|false} 解析得到的 AST
   */
  export const or = (walker, rules) => {
    let index = walker.index
    for (let node of rules) {
      let result = run(walker, node)
      if (result !== false) {
        return result
      }
      walker.index = index
    }
    return false
  }
  
  /**
   * zero or more
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {Rule} rule 解析规则
   * @return {ASTNode|undefined} 解析得到的 AST
   */
  export const any = (walker, rule) => {
    let results = []
    while (!walker.end()) {
      let result = seq(walker, rule)
      if (result === false) {
        break
      }
      results.push(result)
    }
    return results
  }
  
  /**
   * one or more
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {Rule} rule 解析规则
   * @return {ASTNode|false} 解析得到的 AST
   */
  export const some = (walker, rule) => {
    let results = []
    while (!walker.end()) {
      let result = seq(walker, rule)
      if (result === false) {
        break
      }
      results.push(result)
    }
    return results.length ? results : false
  }
  
  /**
   * zero or one
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {Rule} rule 解析规则
   * @return {ASTNode|undefined} 解析得到的 AST
   */
  export const opt = (walker, rule) => {
    return seq(walker, rule) || undefined
  }
  
  /**
   * 当匹配到该规则时，则判定为解析失败，反之则解析成功
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {Rule} rule 解析规则
   * @return {undefined|false} 成功时返回 undefined，反之则返回 false
   */
  export const not = restorable((walker, rule) => {
    let result = seq(walker, rule)
    return result === false ? undefined : false
  })
  
  /**
   * 规则定义描述对象
   *
   * @typedef {Object} RuleDescriptor
   * @property {string} type 规则名称
   * @property {Rule|() => Rule} rule 匹配规则
   * @property {Function} match 规则匹配成功后的回调函数
   * @property {Rule|() => Rule} fallback 规则匹配失败时的降级规则
   */
  
  /**
   * 定义规则
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {RuleDescriptor} descriptor 规则描述对象
   * @return {ASTNode|undefined|false} 解析得到的 AST
   */
  export const def = memoize(singleton(
    (walker, descriptor) => {
      let index = walker.index
      const {rule, match, type, fallback} = descriptor
      let result = seq(walker, rule)
  
      if (result !== false && match) {
        result = match(result, walker)
      }
  
      if (result === false && fallback) {
        walker.index = index
        return seq(walker, fallback)
      }
  
      if (result && !result.type) {
        result.type = type
      }
  
      return result
    },
    ['rule', 'fallback']
  ))
  
  /**
   * 文本匹配
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {string} pattern 要匹配的字符串
   * @return {ASTNode|false} 解析得到的 AST，匹配失败时返回 false
   */
  export const text = memoize(
    (walker, pattern) => {
      let match = walker.matchText(pattern)
      return match ? {raw: pattern} : false
    }
  )
  
  /**
   * 正则匹配
   *
   * @param {Walker} walker 表达式字符串读取工具
   * @param {RegExp} pattern 正则表达式
   * @return {ASTNode|false} 解析得到的 AST，匹配失败时返回 false
   */
  export const regexp = memoize(
    (walker, pattern) => {
      let match = walker.matchRegExp(pattern)
      return match ? {raw: match[0]} : false
    }
  )
  
  /**
   * 字符串词法分析类
   */
  export default class Lexer {
    constructor () {
      this.types = {}
    }
  
    /**
     * 定义规则
     *
     * @param {Descriptor} descriptor 规则描述对象
     * @return {Rule} 结构化规则对象
     */
    set (descriptor) {
      let item = [def, descriptor]
      this.types[descriptor.type] = item
      return item
    }
  
    /**
     * 读取规则
     *
     * @param {string} 规则名称
     * @return {Rule} 结构化规则对象
     */
    get (type) {
      return this.types[type]
    }
  }
  