import type { VmValue } from '@mirascript/mirascript'; import type { Tagged } from 'type-fest'; import type { LegacyType, TsTypeOf, TypeInfo } from './type.js'; import type { Scope } from './scope.js'; import type { Evaluator } from './main.js'; const { defineProperty } = Object; /** 表达式的标记属性 */ export const ExpressionTag = 'ɵexp' as const; // 使用 `type` 确保 Expression 是一个 VmRecord /** 表示一个表达式 */ export type Expression = { /** 标记,表示求值结果的类型,"" 表示无需转换类型 */ readonly [ExpressionTag]: TypeInfo | LegacyType | ''; /** 表达式内容 */ readonly source: ExpressionSource; }; /** 编译后的表达式 */ export type CompiledExpression = Expression & ExpressionFunction; /** 包装一个 {@link ExpressionFunction} */ export function CompiledExpression>>( fn: F, source: string, returnType: S, ): F & Expression>; /** 包装一个 {@link ExpressionFunction} */ export function CompiledExpression>( fn: F, source: string, returnType?: TypeInfo | LegacyType | '', ): F & Expression; /** 包装一个 {@link ExpressionFunction} */ export function CompiledExpression>( fn: F, source: string, returnType: TypeInfo | LegacyType | '' = '', ): F & Expression { if (typeof fn != 'function') { throw new TypeError(`Invalid compiled expression function ${String(fn)}`); } if (isExpression(fn)) { fn = fn.bind(null) as F; } defineProperty(fn, ExpressionTag, { value: returnType || '' }); defineProperty(fn, 'source', { value: source }); return fn as F & Expression; } /** 表示一个表达式内容 */ export type ExpressionSource = Tagged; /** 表示表达式或值 */ export type ExpressionOrValue = Expression | T; /** 创建一个指定类型的表达式 */ export function Expression( source: string | Expression>, returnType: S, ): Expression>; /** 创建一个不转换结果类型的表达式 */ export function Expression(source: string | Expression): Expression; /** 创建一个表达式 */ export function Expression( source: string | Expression, returnType: TypeInfo | LegacyType | '' = '', ): Expression { if (source == null) throw new TypeError(`Invalid expression ${String(source)}`); const s = isExpression(source) ? source.source : source; if (typeof s != 'string') throw new TypeError(`Invalid expression ${String(s)}`); return { [ExpressionTag]: returnType || '', source: s as ExpressionSource }; } /** 检查是否为表达式 */ export function isExpression(value: unknown): value is Expression | CompiledExpression { if (value == null || (typeof value != 'object' && typeof value != 'function')) return false; return typeof (value as Expression)[ExpressionTag] == 'string'; } /** 表示一个表达式求值的结果 */ export type ExpressionResult = T extends Expression ? R : T; /** 表示一个含表达式对象求值的结果 */ export type ExpressionResultObject = { [K in keyof T]: ExpressionResult; }; /** * 表示一个具有类似表达式功能的 JS 函数 */ export type ExpressionFunction = ( /** 当前作用域 */ scope: Scope, /** 当前求值器 */ evaluator: Evaluator, ) => T | null;