Skip to main content
建议按“解析 → 分派 → 数据 → 并发”分层排查。 先用错误类型快速定位,再补齐现场信息(target/参数/变量/线程)以缩小范围。

快速定位

下面列出各阶段的典型错误与立即检查项:
  • 解析MultipleParseException
    • 立即检查:ex.formatDiagnostic() 打印源码摘录
    • REPL:语句前加 $ 输出 AST
  • 分派FunctionNotFoundError / EvaluatorNotFoundError
    • 立即检查:Environment#getRootFunctions() / getRootExtensionFunctions()
    • 命名空间与 target 类型是否匹配
  • 数据ArgumentTypeMismatchError / VariableNotFoundError / IndexAccessError / VoidError
    • 立即检查:FunctionContext#toString()(函数名/target/参数)
    • 参考:availableVariablesIndexErrorType
  • 并发:主线程函数跑在后台 / 异步任务堆积
    • 立即检查:registerPrimarySyncFunction 用法
    • 观察:ThreadPoolManager#getActiveTaskCount() 与执行器配置

解析错误(MultipleParseException)

  • Parser#parse 聚合所有语法错误;ex.formatDiagnostic() 可直接打印行列与源码摘录。
  • REPL 语句前加 $,控制台会输出词法/语法树,便于确认括号、then/else 是否成对。
  • 网络/数据库来源的脚本注意行尾统一,否则列号可能偏移。

调用分派问题

FunctionNotFoundError

  • 注册是否生效:Environment#getRootFunctions() / getRootExtensionFunctions() 查看。 缺失则重新注册并调用 runtime.newEnvironment() 触发 bake。
  • 命名空间:registerFunction("fs", "readText", …) 对应脚本 fs:readText,漏前缀会直接失败。
  • target 类型:扩展函数要求 target 与注册类型一致;null::fn() 会因 target 为空而匹配不到。
  • 目录一致性:必要时重跑 ./gradlew :core:dumpFluxonCatalog,确认导出的签名与预期一致。

EvaluatorNotFoundError

  • 新增语法未提供求值器导致。
  • 检查是否在 runtime.function / index 注册 evaluator。
  • 如果语法应被禁止,在解析阶段直接抛 ParseException,避免运行时才失败。

数据与类型问题

ArgumentTypeMismatchError

  • FunctionContext#getNumber/getArgumentByType 会在消息中标注参数索引与实际值;先核实脚本入参是否符合签名。
  • 多参数版本只检查参数个数,不会自动装箱;需要在实现内区分 Number/String 等类型。
  • 扩展函数建议先用 hasArgument(idx) 判空,避免 null 触发类型错误。

VariableNotFoundError

  • :vars(REPL)或 Environment#getRootVariables() 查看当前可见变量;确认作用域与命名是否一致。
  • 函数体中新增局部变量时,确保解析器同步更新 localVariableNames,否则赋值索引会错位。

IndexAccessError

  • OUT_OF_BOUNDS:检查索引与集合大小。
  • UNSUPPORTED_TYPE / UNSUPPORTED_SET_TYPE:该类型未实现 IndexAccessor,需要添加实现或更换访问方式。
  • NULL_TARGET:目标为 null;脚本侧加判空或默认值(Elvis)再访问。

VoidError

函数返回 Function.VOID 却继续参与运算时触发。仅在确实无需返回值的路径返回 VOID,其他场景返回真实结果或 null

并发与执行器

  • 主线程函数:仅通过 registerPrimarySyncFunction / registerSyncExtensionFunction 标记。
  • 执行器:使用 FluxonRuntime#setPrimaryThreadExecutor 指向宿主主线程。
  • 异步任务:ThreadPoolManager#getActiveTaskCount() 观察堆积。
  • 若出现 CallerRunsPolicy,表示队列满,新任务会落到调用线程;需要拆批或扩容。
  • 关闭:ThreadPoolManager#shutdown() 前最好等待 awaitTermination,避免异步任务被硬中断。

现场信息速查

  • Environment#getRootFunctions()/getRootExtensionFunctions()/getRootVariables():注册表与可见符号。
  • FunctionContext#toString():函数名、target、参数实参。
  • FluxonRuntime#getSystemFunctions() / #getExtensionFunctions():宿主侧直接查看注册状态。
  • ./gradlew :core:dumpFluxonCatalog + vscode-extension/scripts/sync-catalog.js:当补全或文档与运行时不一致时优先刷新。
按上述顺序(定位异常 → 获取现场 → 修正注册/类型/线程配置)即可快速收敛问题,减少反复试错。

相关链接