@isl-lang/evaluator
Advanced tools
| 'use strict'; | ||
| // src/environment.ts | ||
| var Scope = class _Scope { | ||
| constructor(parent) { | ||
| this.parent = parent; | ||
| this.scope = /* @__PURE__ */ new Map(); | ||
| } | ||
| scope; | ||
| /** | ||
| * Get a variable's value, searching up the scope chain | ||
| */ | ||
| get(name) { | ||
| const binding = this.scope.get(name); | ||
| if (binding !== void 0) { | ||
| return binding.value; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.get(name); | ||
| } | ||
| return void 0; | ||
| } | ||
| /** | ||
| * Check if a variable exists in any scope | ||
| */ | ||
| has(name) { | ||
| if (this.scope.has(name)) { | ||
| return true; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.has(name); | ||
| } | ||
| return false; | ||
| } | ||
| /** | ||
| * Set a variable's value (must already exist) | ||
| */ | ||
| set(name, value) { | ||
| const binding = this.findBinding(name); | ||
| if (binding) { | ||
| if (!binding.mutable) { | ||
| throw new Error(`Cannot assign to immutable variable: ${name}`); | ||
| } | ||
| binding.value = value; | ||
| } else { | ||
| this.define(name, value, true); | ||
| } | ||
| } | ||
| /** | ||
| * Define a new variable in the current scope | ||
| */ | ||
| define(name, value, mutable = false) { | ||
| this.scope.set(name, { name, value, mutable }); | ||
| } | ||
| /** | ||
| * Create a child scope | ||
| */ | ||
| child() { | ||
| return new _Scope(this); | ||
| } | ||
| /** | ||
| * Get all bindings from this scope (not including parent) | ||
| */ | ||
| bindings() { | ||
| return new Map(this.scope); | ||
| } | ||
| /** | ||
| * Find a binding in the scope chain | ||
| */ | ||
| findBinding(name) { | ||
| const binding = this.scope.get(name); | ||
| if (binding !== void 0) { | ||
| return binding; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.findBinding(name); | ||
| } | ||
| return void 0; | ||
| } | ||
| }; | ||
| var InMemoryEntityStore = class { | ||
| entities; | ||
| idCounters; | ||
| constructor() { | ||
| this.entities = /* @__PURE__ */ new Map(); | ||
| this.idCounters = /* @__PURE__ */ new Map(); | ||
| } | ||
| /** | ||
| * Get all instances of an entity type | ||
| */ | ||
| getAll(entityName) { | ||
| const instances = this.entities.get(entityName); | ||
| return instances ? Array.from(instances.values()) : []; | ||
| } | ||
| /** | ||
| * Check if any entity matching criteria exists | ||
| */ | ||
| exists(entityName, criteria) { | ||
| const instances = this.entities.get(entityName); | ||
| if (!instances || instances.size === 0) { | ||
| return false; | ||
| } | ||
| if (!criteria || Object.keys(criteria).length === 0) { | ||
| return instances.size > 0; | ||
| } | ||
| return Array.from(instances.values()).some( | ||
| (instance) => this.matchesCriteria(instance, criteria) | ||
| ); | ||
| } | ||
| /** | ||
| * Lookup a single entity by criteria | ||
| */ | ||
| lookup(entityName, criteria) { | ||
| const instances = this.entities.get(entityName); | ||
| if (!instances) { | ||
| return void 0; | ||
| } | ||
| return Array.from(instances.values()).find( | ||
| (instance) => this.matchesCriteria(instance, criteria) | ||
| ); | ||
| } | ||
| /** | ||
| * Count entities matching criteria | ||
| */ | ||
| count(entityName, criteria) { | ||
| const instances = this.entities.get(entityName); | ||
| if (!instances) { | ||
| return 0; | ||
| } | ||
| if (!criteria || Object.keys(criteria).length === 0) { | ||
| return instances.size; | ||
| } | ||
| return Array.from(instances.values()).filter( | ||
| (instance) => this.matchesCriteria(instance, criteria) | ||
| ).length; | ||
| } | ||
| /** | ||
| * Create a new entity instance | ||
| */ | ||
| create(entityName, data) { | ||
| if (!this.entities.has(entityName)) { | ||
| this.entities.set(entityName, /* @__PURE__ */ new Map()); | ||
| } | ||
| const id = data["id"] ?? this.generateId(entityName); | ||
| const instance = { | ||
| __entity__: entityName, | ||
| __id__: id, | ||
| ...data, | ||
| id | ||
| }; | ||
| this.entities.get(entityName).set(id, instance); | ||
| return instance; | ||
| } | ||
| /** | ||
| * Update an entity instance | ||
| */ | ||
| update(entityName, id, data) { | ||
| const instances = this.entities.get(entityName); | ||
| if (!instances) { | ||
| throw new Error(`Entity type not found: ${entityName}`); | ||
| } | ||
| const instance = instances.get(id); | ||
| if (!instance) { | ||
| throw new Error(`Entity instance not found: ${entityName}[${id}]`); | ||
| } | ||
| Object.assign(instance, data); | ||
| } | ||
| /** | ||
| * Delete an entity instance | ||
| */ | ||
| delete(entityName, id) { | ||
| const instances = this.entities.get(entityName); | ||
| if (instances) { | ||
| instances.delete(id); | ||
| } | ||
| } | ||
| /** | ||
| * Take a snapshot of current state | ||
| */ | ||
| snapshot() { | ||
| const snapshotEntities = /* @__PURE__ */ new Map(); | ||
| for (const [entityName, instances] of this.entities) { | ||
| const instancesCopy = /* @__PURE__ */ new Map(); | ||
| for (const [id, instance] of instances) { | ||
| instancesCopy.set(id, this.deepClone(instance)); | ||
| } | ||
| snapshotEntities.set(entityName, instancesCopy); | ||
| } | ||
| return { | ||
| entities: snapshotEntities, | ||
| timestamp: Date.now() | ||
| }; | ||
| } | ||
| /** | ||
| * Restore from a snapshot | ||
| */ | ||
| restore(snapshot) { | ||
| this.entities = /* @__PURE__ */ new Map(); | ||
| for (const [entityName, instances] of snapshot.entities) { | ||
| const instancesCopy = /* @__PURE__ */ new Map(); | ||
| for (const [id, instance] of instances) { | ||
| instancesCopy.set(id, this.deepClone(instance)); | ||
| } | ||
| this.entities.set(entityName, instancesCopy); | ||
| } | ||
| } | ||
| /** | ||
| * Clear all entities (useful for testing) | ||
| */ | ||
| clear() { | ||
| this.entities.clear(); | ||
| this.idCounters.clear(); | ||
| } | ||
| /** | ||
| * Seed with initial data | ||
| */ | ||
| seed(entityName, instances) { | ||
| for (const data of instances) { | ||
| this.create(entityName, data); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // PRIVATE HELPERS | ||
| // ============================================================================ | ||
| matchesCriteria(instance, criteria) { | ||
| return Object.entries(criteria).every(([key, value]) => { | ||
| const instanceValue = instance[key]; | ||
| return this.deepEqual(instanceValue, value); | ||
| }); | ||
| } | ||
| deepEqual(a, b) { | ||
| if (a === b) return true; | ||
| if (a === null || b === null) return a === b; | ||
| if (typeof a !== typeof b) return false; | ||
| if (Array.isArray(a) && Array.isArray(b)) { | ||
| if (a.length !== b.length) return false; | ||
| return a.every((val, i) => this.deepEqual(val, b[i])); | ||
| } | ||
| if (typeof a === "object" && typeof b === "object") { | ||
| const keysA = Object.keys(a); | ||
| const keysB = Object.keys(b); | ||
| if (keysA.length !== keysB.length) return false; | ||
| return keysA.every( | ||
| (key) => this.deepEqual( | ||
| a[key], | ||
| b[key] | ||
| ) | ||
| ); | ||
| } | ||
| return false; | ||
| } | ||
| deepClone(obj) { | ||
| if (obj === null || typeof obj !== "object") { | ||
| return obj; | ||
| } | ||
| if (Array.isArray(obj)) { | ||
| return obj.map((item) => this.deepClone(item)); | ||
| } | ||
| if (obj instanceof Date) { | ||
| return new Date(obj.getTime()); | ||
| } | ||
| if (obj instanceof Map) { | ||
| const clonedMap = /* @__PURE__ */ new Map(); | ||
| for (const [key, value] of obj) { | ||
| clonedMap.set(key, this.deepClone(value)); | ||
| } | ||
| return clonedMap; | ||
| } | ||
| const cloned = {}; | ||
| for (const key of Object.keys(obj)) { | ||
| cloned[key] = this.deepClone(obj[key]); | ||
| } | ||
| return cloned; | ||
| } | ||
| generateId(entityName) { | ||
| const current = this.idCounters.get(entityName) ?? 0; | ||
| this.idCounters.set(entityName, current + 1); | ||
| return `${entityName.toLowerCase()}_${current + 1}`; | ||
| } | ||
| }; | ||
| var SnapshotEntityStore = class { | ||
| _snapshot; | ||
| constructor(snapshot) { | ||
| this._snapshot = snapshot; | ||
| } | ||
| getAll(entityName) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| return entities ? Array.from(entities.values()) : []; | ||
| } | ||
| exists(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities || entities.size === 0) return false; | ||
| if (!criteria) return entities.size > 0; | ||
| return Array.from(entities.values()).some( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ); | ||
| } | ||
| lookup(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities) return void 0; | ||
| return Array.from(entities.values()).find( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ); | ||
| } | ||
| count(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities) return 0; | ||
| if (!criteria) return entities.size; | ||
| return Array.from(entities.values()).filter( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ).length; | ||
| } | ||
| create() { | ||
| throw new Error("Snapshot store is read-only: cannot create entities"); | ||
| } | ||
| update() { | ||
| throw new Error("Snapshot store is read-only: cannot update entities"); | ||
| } | ||
| delete() { | ||
| throw new Error("Snapshot store is read-only: cannot delete entities"); | ||
| } | ||
| snapshot() { | ||
| return this._snapshot; | ||
| } | ||
| restore() { | ||
| throw new Error("Cannot restore snapshot store"); | ||
| } | ||
| }; | ||
| function createScope(parent) { | ||
| return new Scope(parent); | ||
| } | ||
| function createEntityStore() { | ||
| return new InMemoryEntityStore(); | ||
| } | ||
| function createSnapshotStore(snapshot) { | ||
| return new SnapshotEntityStore(snapshot); | ||
| } | ||
| exports.InMemoryEntityStore = InMemoryEntityStore; | ||
| exports.Scope = Scope; | ||
| exports.SnapshotEntityStore = SnapshotEntityStore; | ||
| exports.createEntityStore = createEntityStore; | ||
| exports.createScope = createScope; | ||
| exports.createSnapshotStore = createSnapshotStore; | ||
| //# sourceMappingURL=environment.cjs.map | ||
| //# sourceMappingURL=environment.cjs.map |
| {"version":3,"sources":["../src/environment.ts"],"names":[],"mappings":"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","file":"environment.cjs","sourcesContent":["// ============================================================================\n// ISL Expression Evaluator - Environment / Scope Management\n// ============================================================================\n\nimport type {\n Environment,\n Binding,\n Value,\n EntityStore,\n EntityStoreSnapshot,\n EntityInstance,\n} from './types.js';\n\n// ============================================================================\n// SCOPE IMPLEMENTATION\n// ============================================================================\n\n/**\n * Lexical scope implementation with parent chain lookup\n */\nexport class Scope implements Environment {\n private readonly scope: Map<string, Binding>;\n \n constructor(private readonly parent?: Scope) {\n this.scope = new Map();\n }\n\n /**\n * Get a variable's value, searching up the scope chain\n */\n get(name: string): Value {\n const binding = this.scope.get(name);\n if (binding !== undefined) {\n return binding.value;\n }\n if (this.parent) {\n return this.parent.get(name);\n }\n return undefined;\n }\n\n /**\n * Check if a variable exists in any scope\n */\n has(name: string): boolean {\n if (this.scope.has(name)) {\n return true;\n }\n if (this.parent) {\n return this.parent.has(name);\n }\n return false;\n }\n\n /**\n * Set a variable's value (must already exist)\n */\n set(name: string, value: Value): void {\n const binding = this.findBinding(name);\n if (binding) {\n if (!binding.mutable) {\n throw new Error(`Cannot assign to immutable variable: ${name}`);\n }\n binding.value = value;\n } else {\n // Define in current scope if not found\n this.define(name, value, true);\n }\n }\n\n /**\n * Define a new variable in the current scope\n */\n define(name: string, value: Value, mutable = false): void {\n this.scope.set(name, { name, value, mutable });\n }\n\n /**\n * Create a child scope\n */\n child(): Scope {\n return new Scope(this);\n }\n\n /**\n * Get all bindings from this scope (not including parent)\n */\n bindings(): Map<string, Binding> {\n return new Map(this.scope);\n }\n\n /**\n * Find a binding in the scope chain\n */\n private findBinding(name: string): Binding | undefined {\n const binding = this.scope.get(name);\n if (binding !== undefined) {\n return binding;\n }\n if (this.parent) {\n return this.parent.findBinding(name);\n }\n return undefined;\n }\n}\n\n// ============================================================================\n// IN-MEMORY ENTITY STORE\n// ============================================================================\n\n/**\n * In-memory entity store implementation for testing and verification\n */\nexport class InMemoryEntityStore implements EntityStore {\n private entities: Map<string, Map<string, EntityInstance>>;\n private idCounters: Map<string, number>;\n\n constructor() {\n this.entities = new Map();\n this.idCounters = new Map();\n }\n\n /**\n * Get all instances of an entity type\n */\n getAll(entityName: string): EntityInstance[] {\n const instances = this.entities.get(entityName);\n return instances ? Array.from(instances.values()) : [];\n }\n\n /**\n * Check if any entity matching criteria exists\n */\n exists(entityName: string, criteria?: Record<string, unknown>): boolean {\n const instances = this.entities.get(entityName);\n if (!instances || instances.size === 0) {\n return false;\n }\n if (!criteria || Object.keys(criteria).length === 0) {\n return instances.size > 0;\n }\n return Array.from(instances.values()).some((instance) =>\n this.matchesCriteria(instance, criteria)\n );\n }\n\n /**\n * Lookup a single entity by criteria\n */\n lookup(\n entityName: string,\n criteria: Record<string, unknown>\n ): EntityInstance | undefined {\n const instances = this.entities.get(entityName);\n if (!instances) {\n return undefined;\n }\n return Array.from(instances.values()).find((instance) =>\n this.matchesCriteria(instance, criteria)\n );\n }\n\n /**\n * Count entities matching criteria\n */\n count(entityName: string, criteria?: Record<string, unknown>): number {\n const instances = this.entities.get(entityName);\n if (!instances) {\n return 0;\n }\n if (!criteria || Object.keys(criteria).length === 0) {\n return instances.size;\n }\n return Array.from(instances.values()).filter((instance) =>\n this.matchesCriteria(instance, criteria)\n ).length;\n }\n\n /**\n * Create a new entity instance\n */\n create(entityName: string, data: Record<string, unknown>): EntityInstance {\n if (!this.entities.has(entityName)) {\n this.entities.set(entityName, new Map());\n }\n\n const id = data['id'] as string ?? this.generateId(entityName);\n const instance: EntityInstance = {\n __entity__: entityName,\n __id__: id,\n ...data,\n id,\n };\n\n this.entities.get(entityName)!.set(id, instance);\n return instance;\n }\n\n /**\n * Update an entity instance\n */\n update(entityName: string, id: string, data: Record<string, unknown>): void {\n const instances = this.entities.get(entityName);\n if (!instances) {\n throw new Error(`Entity type not found: ${entityName}`);\n }\n const instance = instances.get(id);\n if (!instance) {\n throw new Error(`Entity instance not found: ${entityName}[${id}]`);\n }\n Object.assign(instance, data);\n }\n\n /**\n * Delete an entity instance\n */\n delete(entityName: string, id: string): void {\n const instances = this.entities.get(entityName);\n if (instances) {\n instances.delete(id);\n }\n }\n\n /**\n * Take a snapshot of current state\n */\n snapshot(): EntityStoreSnapshot {\n const snapshotEntities = new Map<string, Map<string, EntityInstance>>();\n \n for (const [entityName, instances] of this.entities) {\n const instancesCopy = new Map<string, EntityInstance>();\n for (const [id, instance] of instances) {\n // Deep clone the instance\n instancesCopy.set(id, this.deepClone(instance));\n }\n snapshotEntities.set(entityName, instancesCopy);\n }\n\n return {\n entities: snapshotEntities,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Restore from a snapshot\n */\n restore(snapshot: EntityStoreSnapshot): void {\n this.entities = new Map();\n \n for (const [entityName, instances] of snapshot.entities) {\n const instancesCopy = new Map<string, EntityInstance>();\n for (const [id, instance] of instances) {\n instancesCopy.set(id, this.deepClone(instance));\n }\n this.entities.set(entityName, instancesCopy);\n }\n }\n\n /**\n * Clear all entities (useful for testing)\n */\n clear(): void {\n this.entities.clear();\n this.idCounters.clear();\n }\n\n /**\n * Seed with initial data\n */\n seed(entityName: string, instances: Record<string, unknown>[]): void {\n for (const data of instances) {\n this.create(entityName, data);\n }\n }\n\n // ============================================================================\n // PRIVATE HELPERS\n // ============================================================================\n\n private matchesCriteria(\n instance: EntityInstance,\n criteria: Record<string, unknown>\n ): boolean {\n return Object.entries(criteria).every(([key, value]) => {\n const instanceValue = instance[key];\n return this.deepEqual(instanceValue, value);\n });\n }\n\n private deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((val, i) => this.deepEqual(val, b[i]));\n }\n\n if (typeof a === 'object' && typeof b === 'object') {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n return keysA.every((key) =>\n this.deepEqual(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key]\n )\n );\n }\n\n return false;\n }\n\n private deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.deepClone(item)) as T;\n }\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as T;\n }\n if (obj instanceof Map) {\n const clonedMap = new Map();\n for (const [key, value] of obj) {\n clonedMap.set(key, this.deepClone(value));\n }\n return clonedMap as T;\n }\n const cloned: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n cloned[key] = this.deepClone((obj as Record<string, unknown>)[key]);\n }\n return cloned as T;\n }\n\n private generateId(entityName: string): string {\n const current = this.idCounters.get(entityName) ?? 0;\n this.idCounters.set(entityName, current + 1);\n return `${entityName.toLowerCase()}_${current + 1}`;\n }\n}\n\n// ============================================================================\n// READ-ONLY SNAPSHOT STORE\n// ============================================================================\n\n/**\n * Read-only entity store wrapper for old() evaluation\n */\nexport class SnapshotEntityStore implements EntityStore {\n private readonly _snapshot: EntityStoreSnapshot;\n \n constructor(snapshot: EntityStoreSnapshot) {\n this._snapshot = snapshot;\n }\n\n getAll(entityName: string): EntityInstance[] {\n const entities = this._snapshot.entities.get(entityName);\n return entities ? Array.from(entities.values()) : [];\n }\n\n exists(entityName: string, criteria?: Record<string, unknown>): boolean {\n const entities = this._snapshot.entities.get(entityName);\n if (!entities || entities.size === 0) return false;\n if (!criteria) return entities.size > 0;\n return Array.from(entities.values()).some((e) =>\n Object.entries(criteria).every(([k, v]) => e[k] === v)\n );\n }\n\n lookup(\n entityName: string,\n criteria: Record<string, unknown>\n ): EntityInstance | undefined {\n const entities = this._snapshot.entities.get(entityName);\n if (!entities) return undefined;\n return Array.from(entities.values()).find((e) =>\n Object.entries(criteria).every(([k, v]) => e[k] === v)\n );\n }\n\n count(entityName: string, criteria?: Record<string, unknown>): number {\n const entities = this._snapshot.entities.get(entityName);\n if (!entities) return 0;\n if (!criteria) return entities.size;\n return Array.from(entities.values()).filter((e) =>\n Object.entries(criteria).every(([k, v]) => e[k] === v)\n ).length;\n }\n\n create(): EntityInstance {\n throw new Error('Snapshot store is read-only: cannot create entities');\n }\n\n update(): void {\n throw new Error('Snapshot store is read-only: cannot update entities');\n }\n\n delete(): void {\n throw new Error('Snapshot store is read-only: cannot delete entities');\n }\n\n snapshot(): EntityStoreSnapshot {\n return this._snapshot;\n }\n\n restore(): void {\n throw new Error('Cannot restore snapshot store');\n }\n}\n\n// ============================================================================\n// FACTORY FUNCTIONS\n// ============================================================================\n\n/**\n * Create a new scope with optional parent\n */\nexport function createScope(parent?: Scope): Scope {\n return new Scope(parent);\n}\n\n/**\n * Create a new in-memory entity store\n */\nexport function createEntityStore(): InMemoryEntityStore {\n return new InMemoryEntityStore();\n}\n\n/**\n * Create a read-only store from a snapshot\n */\nexport function createSnapshotStore(\n snapshot: EntityStoreSnapshot\n): SnapshotEntityStore {\n return new SnapshotEntityStore(snapshot);\n}\n"]} |
| import { b as EntityStore, j as EntityInstance, E as EntityStoreSnapshot, k as Environment, e as Value, f as Binding } from './types-BP9x1AUL.cjs'; | ||
| /** | ||
| * Lexical scope implementation with parent chain lookup | ||
| */ | ||
| declare class Scope implements Environment { | ||
| private readonly parent?; | ||
| private readonly scope; | ||
| constructor(parent?: Scope | undefined); | ||
| /** | ||
| * Get a variable's value, searching up the scope chain | ||
| */ | ||
| get(name: string): Value; | ||
| /** | ||
| * Check if a variable exists in any scope | ||
| */ | ||
| has(name: string): boolean; | ||
| /** | ||
| * Set a variable's value (must already exist) | ||
| */ | ||
| set(name: string, value: Value): void; | ||
| /** | ||
| * Define a new variable in the current scope | ||
| */ | ||
| define(name: string, value: Value, mutable?: boolean): void; | ||
| /** | ||
| * Create a child scope | ||
| */ | ||
| child(): Scope; | ||
| /** | ||
| * Get all bindings from this scope (not including parent) | ||
| */ | ||
| bindings(): Map<string, Binding>; | ||
| /** | ||
| * Find a binding in the scope chain | ||
| */ | ||
| private findBinding; | ||
| } | ||
| /** | ||
| * In-memory entity store implementation for testing and verification | ||
| */ | ||
| declare class InMemoryEntityStore implements EntityStore { | ||
| private entities; | ||
| private idCounters; | ||
| constructor(); | ||
| /** | ||
| * Get all instances of an entity type | ||
| */ | ||
| getAll(entityName: string): EntityInstance[]; | ||
| /** | ||
| * Check if any entity matching criteria exists | ||
| */ | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| /** | ||
| * Lookup a single entity by criteria | ||
| */ | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| /** | ||
| * Count entities matching criteria | ||
| */ | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| /** | ||
| * Create a new entity instance | ||
| */ | ||
| create(entityName: string, data: Record<string, unknown>): EntityInstance; | ||
| /** | ||
| * Update an entity instance | ||
| */ | ||
| update(entityName: string, id: string, data: Record<string, unknown>): void; | ||
| /** | ||
| * Delete an entity instance | ||
| */ | ||
| delete(entityName: string, id: string): void; | ||
| /** | ||
| * Take a snapshot of current state | ||
| */ | ||
| snapshot(): EntityStoreSnapshot; | ||
| /** | ||
| * Restore from a snapshot | ||
| */ | ||
| restore(snapshot: EntityStoreSnapshot): void; | ||
| /** | ||
| * Clear all entities (useful for testing) | ||
| */ | ||
| clear(): void; | ||
| /** | ||
| * Seed with initial data | ||
| */ | ||
| seed(entityName: string, instances: Record<string, unknown>[]): void; | ||
| private matchesCriteria; | ||
| private deepEqual; | ||
| private deepClone; | ||
| private generateId; | ||
| } | ||
| /** | ||
| * Read-only entity store wrapper for old() evaluation | ||
| */ | ||
| declare class SnapshotEntityStore implements EntityStore { | ||
| private readonly _snapshot; | ||
| constructor(snapshot: EntityStoreSnapshot); | ||
| getAll(entityName: string): EntityInstance[]; | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| create(): EntityInstance; | ||
| update(): void; | ||
| delete(): void; | ||
| snapshot(): EntityStoreSnapshot; | ||
| restore(): void; | ||
| } | ||
| /** | ||
| * Create a new scope with optional parent | ||
| */ | ||
| declare function createScope(parent?: Scope): Scope; | ||
| /** | ||
| * Create a new in-memory entity store | ||
| */ | ||
| declare function createEntityStore(): InMemoryEntityStore; | ||
| /** | ||
| * Create a read-only store from a snapshot | ||
| */ | ||
| declare function createSnapshotStore(snapshot: EntityStoreSnapshot): SnapshotEntityStore; | ||
| export { InMemoryEntityStore, Scope, SnapshotEntityStore, createEntityStore, createScope, createSnapshotStore }; |
| import { b as EntityStore, j as EntityInstance, E as EntityStoreSnapshot, k as Environment, e as Value, f as Binding } from './types-BP9x1AUL.js'; | ||
| /** | ||
| * Lexical scope implementation with parent chain lookup | ||
| */ | ||
| declare class Scope implements Environment { | ||
| private readonly parent?; | ||
| private readonly scope; | ||
| constructor(parent?: Scope | undefined); | ||
| /** | ||
| * Get a variable's value, searching up the scope chain | ||
| */ | ||
| get(name: string): Value; | ||
| /** | ||
| * Check if a variable exists in any scope | ||
| */ | ||
| has(name: string): boolean; | ||
| /** | ||
| * Set a variable's value (must already exist) | ||
| */ | ||
| set(name: string, value: Value): void; | ||
| /** | ||
| * Define a new variable in the current scope | ||
| */ | ||
| define(name: string, value: Value, mutable?: boolean): void; | ||
| /** | ||
| * Create a child scope | ||
| */ | ||
| child(): Scope; | ||
| /** | ||
| * Get all bindings from this scope (not including parent) | ||
| */ | ||
| bindings(): Map<string, Binding>; | ||
| /** | ||
| * Find a binding in the scope chain | ||
| */ | ||
| private findBinding; | ||
| } | ||
| /** | ||
| * In-memory entity store implementation for testing and verification | ||
| */ | ||
| declare class InMemoryEntityStore implements EntityStore { | ||
| private entities; | ||
| private idCounters; | ||
| constructor(); | ||
| /** | ||
| * Get all instances of an entity type | ||
| */ | ||
| getAll(entityName: string): EntityInstance[]; | ||
| /** | ||
| * Check if any entity matching criteria exists | ||
| */ | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| /** | ||
| * Lookup a single entity by criteria | ||
| */ | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| /** | ||
| * Count entities matching criteria | ||
| */ | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| /** | ||
| * Create a new entity instance | ||
| */ | ||
| create(entityName: string, data: Record<string, unknown>): EntityInstance; | ||
| /** | ||
| * Update an entity instance | ||
| */ | ||
| update(entityName: string, id: string, data: Record<string, unknown>): void; | ||
| /** | ||
| * Delete an entity instance | ||
| */ | ||
| delete(entityName: string, id: string): void; | ||
| /** | ||
| * Take a snapshot of current state | ||
| */ | ||
| snapshot(): EntityStoreSnapshot; | ||
| /** | ||
| * Restore from a snapshot | ||
| */ | ||
| restore(snapshot: EntityStoreSnapshot): void; | ||
| /** | ||
| * Clear all entities (useful for testing) | ||
| */ | ||
| clear(): void; | ||
| /** | ||
| * Seed with initial data | ||
| */ | ||
| seed(entityName: string, instances: Record<string, unknown>[]): void; | ||
| private matchesCriteria; | ||
| private deepEqual; | ||
| private deepClone; | ||
| private generateId; | ||
| } | ||
| /** | ||
| * Read-only entity store wrapper for old() evaluation | ||
| */ | ||
| declare class SnapshotEntityStore implements EntityStore { | ||
| private readonly _snapshot; | ||
| constructor(snapshot: EntityStoreSnapshot); | ||
| getAll(entityName: string): EntityInstance[]; | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| create(): EntityInstance; | ||
| update(): void; | ||
| delete(): void; | ||
| snapshot(): EntityStoreSnapshot; | ||
| restore(): void; | ||
| } | ||
| /** | ||
| * Create a new scope with optional parent | ||
| */ | ||
| declare function createScope(parent?: Scope): Scope; | ||
| /** | ||
| * Create a new in-memory entity store | ||
| */ | ||
| declare function createEntityStore(): InMemoryEntityStore; | ||
| /** | ||
| * Create a read-only store from a snapshot | ||
| */ | ||
| declare function createSnapshotStore(snapshot: EntityStoreSnapshot): SnapshotEntityStore; | ||
| export { InMemoryEntityStore, Scope, SnapshotEntityStore, createEntityStore, createScope, createSnapshotStore }; |
| // src/environment.ts | ||
| var Scope = class _Scope { | ||
| constructor(parent) { | ||
| this.parent = parent; | ||
| this.scope = /* @__PURE__ */ new Map(); | ||
| } | ||
| scope; | ||
| /** | ||
| * Get a variable's value, searching up the scope chain | ||
| */ | ||
| get(name) { | ||
| const binding = this.scope.get(name); | ||
| if (binding !== void 0) { | ||
| return binding.value; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.get(name); | ||
| } | ||
| return void 0; | ||
| } | ||
| /** | ||
| * Check if a variable exists in any scope | ||
| */ | ||
| has(name) { | ||
| if (this.scope.has(name)) { | ||
| return true; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.has(name); | ||
| } | ||
| return false; | ||
| } | ||
| /** | ||
| * Set a variable's value (must already exist) | ||
| */ | ||
| set(name, value) { | ||
| const binding = this.findBinding(name); | ||
| if (binding) { | ||
| if (!binding.mutable) { | ||
| throw new Error(`Cannot assign to immutable variable: ${name}`); | ||
| } | ||
| binding.value = value; | ||
| } else { | ||
| this.define(name, value, true); | ||
| } | ||
| } | ||
| /** | ||
| * Define a new variable in the current scope | ||
| */ | ||
| define(name, value, mutable = false) { | ||
| this.scope.set(name, { name, value, mutable }); | ||
| } | ||
| /** | ||
| * Create a child scope | ||
| */ | ||
| child() { | ||
| return new _Scope(this); | ||
| } | ||
| /** | ||
| * Get all bindings from this scope (not including parent) | ||
| */ | ||
| bindings() { | ||
| return new Map(this.scope); | ||
| } | ||
| /** | ||
| * Find a binding in the scope chain | ||
| */ | ||
| findBinding(name) { | ||
| const binding = this.scope.get(name); | ||
| if (binding !== void 0) { | ||
| return binding; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.findBinding(name); | ||
| } | ||
| return void 0; | ||
| } | ||
| }; | ||
| var InMemoryEntityStore = class { | ||
| entities; | ||
| idCounters; | ||
| constructor() { | ||
| this.entities = /* @__PURE__ */ new Map(); | ||
| this.idCounters = /* @__PURE__ */ new Map(); | ||
| } | ||
| /** | ||
| * Get all instances of an entity type | ||
| */ | ||
| getAll(entityName) { | ||
| const instances = this.entities.get(entityName); | ||
| return instances ? Array.from(instances.values()) : []; | ||
| } | ||
| /** | ||
| * Check if any entity matching criteria exists | ||
| */ | ||
| exists(entityName, criteria) { | ||
| const instances = this.entities.get(entityName); | ||
| if (!instances || instances.size === 0) { | ||
| return false; | ||
| } | ||
| if (!criteria || Object.keys(criteria).length === 0) { | ||
| return instances.size > 0; | ||
| } | ||
| return Array.from(instances.values()).some( | ||
| (instance) => this.matchesCriteria(instance, criteria) | ||
| ); | ||
| } | ||
| /** | ||
| * Lookup a single entity by criteria | ||
| */ | ||
| lookup(entityName, criteria) { | ||
| const instances = this.entities.get(entityName); | ||
| if (!instances) { | ||
| return void 0; | ||
| } | ||
| return Array.from(instances.values()).find( | ||
| (instance) => this.matchesCriteria(instance, criteria) | ||
| ); | ||
| } | ||
| /** | ||
| * Count entities matching criteria | ||
| */ | ||
| count(entityName, criteria) { | ||
| const instances = this.entities.get(entityName); | ||
| if (!instances) { | ||
| return 0; | ||
| } | ||
| if (!criteria || Object.keys(criteria).length === 0) { | ||
| return instances.size; | ||
| } | ||
| return Array.from(instances.values()).filter( | ||
| (instance) => this.matchesCriteria(instance, criteria) | ||
| ).length; | ||
| } | ||
| /** | ||
| * Create a new entity instance | ||
| */ | ||
| create(entityName, data) { | ||
| if (!this.entities.has(entityName)) { | ||
| this.entities.set(entityName, /* @__PURE__ */ new Map()); | ||
| } | ||
| const id = data["id"] ?? this.generateId(entityName); | ||
| const instance = { | ||
| __entity__: entityName, | ||
| __id__: id, | ||
| ...data, | ||
| id | ||
| }; | ||
| this.entities.get(entityName).set(id, instance); | ||
| return instance; | ||
| } | ||
| /** | ||
| * Update an entity instance | ||
| */ | ||
| update(entityName, id, data) { | ||
| const instances = this.entities.get(entityName); | ||
| if (!instances) { | ||
| throw new Error(`Entity type not found: ${entityName}`); | ||
| } | ||
| const instance = instances.get(id); | ||
| if (!instance) { | ||
| throw new Error(`Entity instance not found: ${entityName}[${id}]`); | ||
| } | ||
| Object.assign(instance, data); | ||
| } | ||
| /** | ||
| * Delete an entity instance | ||
| */ | ||
| delete(entityName, id) { | ||
| const instances = this.entities.get(entityName); | ||
| if (instances) { | ||
| instances.delete(id); | ||
| } | ||
| } | ||
| /** | ||
| * Take a snapshot of current state | ||
| */ | ||
| snapshot() { | ||
| const snapshotEntities = /* @__PURE__ */ new Map(); | ||
| for (const [entityName, instances] of this.entities) { | ||
| const instancesCopy = /* @__PURE__ */ new Map(); | ||
| for (const [id, instance] of instances) { | ||
| instancesCopy.set(id, this.deepClone(instance)); | ||
| } | ||
| snapshotEntities.set(entityName, instancesCopy); | ||
| } | ||
| return { | ||
| entities: snapshotEntities, | ||
| timestamp: Date.now() | ||
| }; | ||
| } | ||
| /** | ||
| * Restore from a snapshot | ||
| */ | ||
| restore(snapshot) { | ||
| this.entities = /* @__PURE__ */ new Map(); | ||
| for (const [entityName, instances] of snapshot.entities) { | ||
| const instancesCopy = /* @__PURE__ */ new Map(); | ||
| for (const [id, instance] of instances) { | ||
| instancesCopy.set(id, this.deepClone(instance)); | ||
| } | ||
| this.entities.set(entityName, instancesCopy); | ||
| } | ||
| } | ||
| /** | ||
| * Clear all entities (useful for testing) | ||
| */ | ||
| clear() { | ||
| this.entities.clear(); | ||
| this.idCounters.clear(); | ||
| } | ||
| /** | ||
| * Seed with initial data | ||
| */ | ||
| seed(entityName, instances) { | ||
| for (const data of instances) { | ||
| this.create(entityName, data); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // PRIVATE HELPERS | ||
| // ============================================================================ | ||
| matchesCriteria(instance, criteria) { | ||
| return Object.entries(criteria).every(([key, value]) => { | ||
| const instanceValue = instance[key]; | ||
| return this.deepEqual(instanceValue, value); | ||
| }); | ||
| } | ||
| deepEqual(a, b) { | ||
| if (a === b) return true; | ||
| if (a === null || b === null) return a === b; | ||
| if (typeof a !== typeof b) return false; | ||
| if (Array.isArray(a) && Array.isArray(b)) { | ||
| if (a.length !== b.length) return false; | ||
| return a.every((val, i) => this.deepEqual(val, b[i])); | ||
| } | ||
| if (typeof a === "object" && typeof b === "object") { | ||
| const keysA = Object.keys(a); | ||
| const keysB = Object.keys(b); | ||
| if (keysA.length !== keysB.length) return false; | ||
| return keysA.every( | ||
| (key) => this.deepEqual( | ||
| a[key], | ||
| b[key] | ||
| ) | ||
| ); | ||
| } | ||
| return false; | ||
| } | ||
| deepClone(obj) { | ||
| if (obj === null || typeof obj !== "object") { | ||
| return obj; | ||
| } | ||
| if (Array.isArray(obj)) { | ||
| return obj.map((item) => this.deepClone(item)); | ||
| } | ||
| if (obj instanceof Date) { | ||
| return new Date(obj.getTime()); | ||
| } | ||
| if (obj instanceof Map) { | ||
| const clonedMap = /* @__PURE__ */ new Map(); | ||
| for (const [key, value] of obj) { | ||
| clonedMap.set(key, this.deepClone(value)); | ||
| } | ||
| return clonedMap; | ||
| } | ||
| const cloned = {}; | ||
| for (const key of Object.keys(obj)) { | ||
| cloned[key] = this.deepClone(obj[key]); | ||
| } | ||
| return cloned; | ||
| } | ||
| generateId(entityName) { | ||
| const current = this.idCounters.get(entityName) ?? 0; | ||
| this.idCounters.set(entityName, current + 1); | ||
| return `${entityName.toLowerCase()}_${current + 1}`; | ||
| } | ||
| }; | ||
| var SnapshotEntityStore = class { | ||
| _snapshot; | ||
| constructor(snapshot) { | ||
| this._snapshot = snapshot; | ||
| } | ||
| getAll(entityName) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| return entities ? Array.from(entities.values()) : []; | ||
| } | ||
| exists(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities || entities.size === 0) return false; | ||
| if (!criteria) return entities.size > 0; | ||
| return Array.from(entities.values()).some( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ); | ||
| } | ||
| lookup(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities) return void 0; | ||
| return Array.from(entities.values()).find( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ); | ||
| } | ||
| count(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities) return 0; | ||
| if (!criteria) return entities.size; | ||
| return Array.from(entities.values()).filter( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ).length; | ||
| } | ||
| create() { | ||
| throw new Error("Snapshot store is read-only: cannot create entities"); | ||
| } | ||
| update() { | ||
| throw new Error("Snapshot store is read-only: cannot update entities"); | ||
| } | ||
| delete() { | ||
| throw new Error("Snapshot store is read-only: cannot delete entities"); | ||
| } | ||
| snapshot() { | ||
| return this._snapshot; | ||
| } | ||
| restore() { | ||
| throw new Error("Cannot restore snapshot store"); | ||
| } | ||
| }; | ||
| function createScope(parent) { | ||
| return new Scope(parent); | ||
| } | ||
| function createEntityStore() { | ||
| return new InMemoryEntityStore(); | ||
| } | ||
| function createSnapshotStore(snapshot) { | ||
| return new SnapshotEntityStore(snapshot); | ||
| } | ||
| export { InMemoryEntityStore, Scope, SnapshotEntityStore, createEntityStore, createScope, createSnapshotStore }; | ||
| //# sourceMappingURL=environment.js.map | ||
| //# sourceMappingURL=environment.js.map |
| {"version":3,"sources":["../src/environment.ts"],"names":[],"mappings":"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","file":"environment.js","sourcesContent":["// ============================================================================\n// ISL Expression Evaluator - Environment / Scope Management\n// ============================================================================\n\nimport type {\n Environment,\n Binding,\n Value,\n EntityStore,\n EntityStoreSnapshot,\n EntityInstance,\n} from './types.js';\n\n// ============================================================================\n// SCOPE IMPLEMENTATION\n// ============================================================================\n\n/**\n * Lexical scope implementation with parent chain lookup\n */\nexport class Scope implements Environment {\n private readonly scope: Map<string, Binding>;\n \n constructor(private readonly parent?: Scope) {\n this.scope = new Map();\n }\n\n /**\n * Get a variable's value, searching up the scope chain\n */\n get(name: string): Value {\n const binding = this.scope.get(name);\n if (binding !== undefined) {\n return binding.value;\n }\n if (this.parent) {\n return this.parent.get(name);\n }\n return undefined;\n }\n\n /**\n * Check if a variable exists in any scope\n */\n has(name: string): boolean {\n if (this.scope.has(name)) {\n return true;\n }\n if (this.parent) {\n return this.parent.has(name);\n }\n return false;\n }\n\n /**\n * Set a variable's value (must already exist)\n */\n set(name: string, value: Value): void {\n const binding = this.findBinding(name);\n if (binding) {\n if (!binding.mutable) {\n throw new Error(`Cannot assign to immutable variable: ${name}`);\n }\n binding.value = value;\n } else {\n // Define in current scope if not found\n this.define(name, value, true);\n }\n }\n\n /**\n * Define a new variable in the current scope\n */\n define(name: string, value: Value, mutable = false): void {\n this.scope.set(name, { name, value, mutable });\n }\n\n /**\n * Create a child scope\n */\n child(): Scope {\n return new Scope(this);\n }\n\n /**\n * Get all bindings from this scope (not including parent)\n */\n bindings(): Map<string, Binding> {\n return new Map(this.scope);\n }\n\n /**\n * Find a binding in the scope chain\n */\n private findBinding(name: string): Binding | undefined {\n const binding = this.scope.get(name);\n if (binding !== undefined) {\n return binding;\n }\n if (this.parent) {\n return this.parent.findBinding(name);\n }\n return undefined;\n }\n}\n\n// ============================================================================\n// IN-MEMORY ENTITY STORE\n// ============================================================================\n\n/**\n * In-memory entity store implementation for testing and verification\n */\nexport class InMemoryEntityStore implements EntityStore {\n private entities: Map<string, Map<string, EntityInstance>>;\n private idCounters: Map<string, number>;\n\n constructor() {\n this.entities = new Map();\n this.idCounters = new Map();\n }\n\n /**\n * Get all instances of an entity type\n */\n getAll(entityName: string): EntityInstance[] {\n const instances = this.entities.get(entityName);\n return instances ? Array.from(instances.values()) : [];\n }\n\n /**\n * Check if any entity matching criteria exists\n */\n exists(entityName: string, criteria?: Record<string, unknown>): boolean {\n const instances = this.entities.get(entityName);\n if (!instances || instances.size === 0) {\n return false;\n }\n if (!criteria || Object.keys(criteria).length === 0) {\n return instances.size > 0;\n }\n return Array.from(instances.values()).some((instance) =>\n this.matchesCriteria(instance, criteria)\n );\n }\n\n /**\n * Lookup a single entity by criteria\n */\n lookup(\n entityName: string,\n criteria: Record<string, unknown>\n ): EntityInstance | undefined {\n const instances = this.entities.get(entityName);\n if (!instances) {\n return undefined;\n }\n return Array.from(instances.values()).find((instance) =>\n this.matchesCriteria(instance, criteria)\n );\n }\n\n /**\n * Count entities matching criteria\n */\n count(entityName: string, criteria?: Record<string, unknown>): number {\n const instances = this.entities.get(entityName);\n if (!instances) {\n return 0;\n }\n if (!criteria || Object.keys(criteria).length === 0) {\n return instances.size;\n }\n return Array.from(instances.values()).filter((instance) =>\n this.matchesCriteria(instance, criteria)\n ).length;\n }\n\n /**\n * Create a new entity instance\n */\n create(entityName: string, data: Record<string, unknown>): EntityInstance {\n if (!this.entities.has(entityName)) {\n this.entities.set(entityName, new Map());\n }\n\n const id = data['id'] as string ?? this.generateId(entityName);\n const instance: EntityInstance = {\n __entity__: entityName,\n __id__: id,\n ...data,\n id,\n };\n\n this.entities.get(entityName)!.set(id, instance);\n return instance;\n }\n\n /**\n * Update an entity instance\n */\n update(entityName: string, id: string, data: Record<string, unknown>): void {\n const instances = this.entities.get(entityName);\n if (!instances) {\n throw new Error(`Entity type not found: ${entityName}`);\n }\n const instance = instances.get(id);\n if (!instance) {\n throw new Error(`Entity instance not found: ${entityName}[${id}]`);\n }\n Object.assign(instance, data);\n }\n\n /**\n * Delete an entity instance\n */\n delete(entityName: string, id: string): void {\n const instances = this.entities.get(entityName);\n if (instances) {\n instances.delete(id);\n }\n }\n\n /**\n * Take a snapshot of current state\n */\n snapshot(): EntityStoreSnapshot {\n const snapshotEntities = new Map<string, Map<string, EntityInstance>>();\n \n for (const [entityName, instances] of this.entities) {\n const instancesCopy = new Map<string, EntityInstance>();\n for (const [id, instance] of instances) {\n // Deep clone the instance\n instancesCopy.set(id, this.deepClone(instance));\n }\n snapshotEntities.set(entityName, instancesCopy);\n }\n\n return {\n entities: snapshotEntities,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Restore from a snapshot\n */\n restore(snapshot: EntityStoreSnapshot): void {\n this.entities = new Map();\n \n for (const [entityName, instances] of snapshot.entities) {\n const instancesCopy = new Map<string, EntityInstance>();\n for (const [id, instance] of instances) {\n instancesCopy.set(id, this.deepClone(instance));\n }\n this.entities.set(entityName, instancesCopy);\n }\n }\n\n /**\n * Clear all entities (useful for testing)\n */\n clear(): void {\n this.entities.clear();\n this.idCounters.clear();\n }\n\n /**\n * Seed with initial data\n */\n seed(entityName: string, instances: Record<string, unknown>[]): void {\n for (const data of instances) {\n this.create(entityName, data);\n }\n }\n\n // ============================================================================\n // PRIVATE HELPERS\n // ============================================================================\n\n private matchesCriteria(\n instance: EntityInstance,\n criteria: Record<string, unknown>\n ): boolean {\n return Object.entries(criteria).every(([key, value]) => {\n const instanceValue = instance[key];\n return this.deepEqual(instanceValue, value);\n });\n }\n\n private deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((val, i) => this.deepEqual(val, b[i]));\n }\n\n if (typeof a === 'object' && typeof b === 'object') {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n return keysA.every((key) =>\n this.deepEqual(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key]\n )\n );\n }\n\n return false;\n }\n\n private deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.deepClone(item)) as T;\n }\n if (obj instanceof Date) {\n return new Date(obj.getTime()) as T;\n }\n if (obj instanceof Map) {\n const clonedMap = new Map();\n for (const [key, value] of obj) {\n clonedMap.set(key, this.deepClone(value));\n }\n return clonedMap as T;\n }\n const cloned: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n cloned[key] = this.deepClone((obj as Record<string, unknown>)[key]);\n }\n return cloned as T;\n }\n\n private generateId(entityName: string): string {\n const current = this.idCounters.get(entityName) ?? 0;\n this.idCounters.set(entityName, current + 1);\n return `${entityName.toLowerCase()}_${current + 1}`;\n }\n}\n\n// ============================================================================\n// READ-ONLY SNAPSHOT STORE\n// ============================================================================\n\n/**\n * Read-only entity store wrapper for old() evaluation\n */\nexport class SnapshotEntityStore implements EntityStore {\n private readonly _snapshot: EntityStoreSnapshot;\n \n constructor(snapshot: EntityStoreSnapshot) {\n this._snapshot = snapshot;\n }\n\n getAll(entityName: string): EntityInstance[] {\n const entities = this._snapshot.entities.get(entityName);\n return entities ? Array.from(entities.values()) : [];\n }\n\n exists(entityName: string, criteria?: Record<string, unknown>): boolean {\n const entities = this._snapshot.entities.get(entityName);\n if (!entities || entities.size === 0) return false;\n if (!criteria) return entities.size > 0;\n return Array.from(entities.values()).some((e) =>\n Object.entries(criteria).every(([k, v]) => e[k] === v)\n );\n }\n\n lookup(\n entityName: string,\n criteria: Record<string, unknown>\n ): EntityInstance | undefined {\n const entities = this._snapshot.entities.get(entityName);\n if (!entities) return undefined;\n return Array.from(entities.values()).find((e) =>\n Object.entries(criteria).every(([k, v]) => e[k] === v)\n );\n }\n\n count(entityName: string, criteria?: Record<string, unknown>): number {\n const entities = this._snapshot.entities.get(entityName);\n if (!entities) return 0;\n if (!criteria) return entities.size;\n return Array.from(entities.values()).filter((e) =>\n Object.entries(criteria).every(([k, v]) => e[k] === v)\n ).length;\n }\n\n create(): EntityInstance {\n throw new Error('Snapshot store is read-only: cannot create entities');\n }\n\n update(): void {\n throw new Error('Snapshot store is read-only: cannot update entities');\n }\n\n delete(): void {\n throw new Error('Snapshot store is read-only: cannot delete entities');\n }\n\n snapshot(): EntityStoreSnapshot {\n return this._snapshot;\n }\n\n restore(): void {\n throw new Error('Cannot restore snapshot store');\n }\n}\n\n// ============================================================================\n// FACTORY FUNCTIONS\n// ============================================================================\n\n/**\n * Create a new scope with optional parent\n */\nexport function createScope(parent?: Scope): Scope {\n return new Scope(parent);\n}\n\n/**\n * Create a new in-memory entity store\n */\nexport function createEntityStore(): InMemoryEntityStore {\n return new InMemoryEntityStore();\n}\n\n/**\n * Create a read-only store from a snapshot\n */\nexport function createSnapshotStore(\n snapshot: EntityStoreSnapshot\n): SnapshotEntityStore {\n return new SnapshotEntityStore(snapshot);\n}\n"]} |
+1744
| 'use strict'; | ||
| // src/types.ts | ||
| var EvalErrorCodes = { | ||
| DIVISION_BY_ZERO: "E0400", | ||
| NULL_REFERENCE: "E0401", | ||
| INDEX_OUT_OF_BOUNDS: "E0402", | ||
| ENTITY_NOT_FOUND: "E0410", | ||
| // Legacy codes (for backward compat) | ||
| EVALUATION_ERROR: "E0404", | ||
| TYPE_ERROR: "E0408", | ||
| REFERENCE_ERROR: "E0403", | ||
| RUNTIME_ERROR: "E0404" | ||
| }; | ||
| var EvaluationError = class _EvaluationError extends Error { | ||
| constructor(message, location, expression, code = EvalErrorCodes.EVALUATION_ERROR) { | ||
| super(message); | ||
| this.location = location; | ||
| this.expression = expression; | ||
| this.code = code; | ||
| this.name = "EvaluationError"; | ||
| Object.setPrototypeOf(this, _EvaluationError.prototype); | ||
| } | ||
| notes = []; | ||
| help = []; | ||
| /** | ||
| * Get a formatted error message with location | ||
| */ | ||
| formatMessage() { | ||
| return `${this.code}: ${this.message} at ${this.location.file}:${this.location.line}:${this.location.column}`; | ||
| } | ||
| /** | ||
| * Add a note to the error | ||
| */ | ||
| withNote(note) { | ||
| this.notes.push(note); | ||
| return this; | ||
| } | ||
| /** | ||
| * Add a help suggestion to the error | ||
| */ | ||
| withHelp(help) { | ||
| this.help.push(help); | ||
| return this; | ||
| } | ||
| }; | ||
| var TypeError = class _TypeError extends EvaluationError { | ||
| constructor(message, location, expectedType, actualType, expression) { | ||
| super(message, location, expression, EvalErrorCodes.TYPE_ERROR); | ||
| this.expectedType = expectedType; | ||
| this.actualType = actualType; | ||
| this.name = "TypeError"; | ||
| Object.setPrototypeOf(this, _TypeError.prototype); | ||
| } | ||
| }; | ||
| var ReferenceError = class _ReferenceError extends EvaluationError { | ||
| constructor(message, location, identifier, expression) { | ||
| super(message, location, expression, EvalErrorCodes.REFERENCE_ERROR); | ||
| this.identifier = identifier; | ||
| this.name = "ReferenceError"; | ||
| Object.setPrototypeOf(this, _ReferenceError.prototype); | ||
| } | ||
| }; | ||
| var RuntimeError = class _RuntimeError extends EvaluationError { | ||
| constructor(message, location, expression, code = EvalErrorCodes.RUNTIME_ERROR) { | ||
| super(message, location, expression, code); | ||
| this.name = "RuntimeError"; | ||
| Object.setPrototypeOf(this, _RuntimeError.prototype); | ||
| } | ||
| /** | ||
| * Create a division by zero error | ||
| */ | ||
| static divisionByZero(location, expression) { | ||
| return new _RuntimeError( | ||
| "Division by zero", | ||
| location, | ||
| expression, | ||
| EvalErrorCodes.DIVISION_BY_ZERO | ||
| ).withHelp("Add a precondition to ensure the divisor is non-zero"); | ||
| } | ||
| /** | ||
| * Create a null reference error | ||
| */ | ||
| static nullReference(property, location, expression) { | ||
| return new _RuntimeError( | ||
| `Cannot read property '${property}' of null`, | ||
| location, | ||
| expression, | ||
| EvalErrorCodes.NULL_REFERENCE | ||
| ).withHelp("Check for null before accessing properties, or use optional chaining (?.)"); | ||
| } | ||
| /** | ||
| * Create an index out of bounds error | ||
| */ | ||
| static indexOutOfBounds(index, length, location, expression) { | ||
| return new _RuntimeError( | ||
| `Index ${index} is out of bounds for array of length ${length}`, | ||
| location, | ||
| expression, | ||
| EvalErrorCodes.INDEX_OUT_OF_BOUNDS | ||
| ).withHelp("Ensure the index is within the valid range [0, length)"); | ||
| } | ||
| /** | ||
| * Create an entity not found error | ||
| */ | ||
| static entityNotFound(entityName, id, location) { | ||
| return new _RuntimeError( | ||
| `Entity '${entityName}' with id '${id}' not found`, | ||
| location, | ||
| void 0, | ||
| EvalErrorCodes.ENTITY_NOT_FOUND | ||
| ).withHelp("Check that the entity exists before accessing it, or use exists() first"); | ||
| } | ||
| }; | ||
| var DiagnosticError = class _DiagnosticError extends EvaluationError { | ||
| diagnostic; | ||
| constructor(payload, expression) { | ||
| super(payload.message, payload.span, expression, payload.code); | ||
| this.name = "DiagnosticError"; | ||
| this.diagnostic = payload; | ||
| Object.setPrototypeOf(this, _DiagnosticError.prototype); | ||
| } | ||
| /** | ||
| * Wrap an existing DiagnosticError as the cause of a higher-level diagnostic. | ||
| */ | ||
| static wrap(outerCode, outerMessage, outerSpan, outerSubExpr, innerError, expression) { | ||
| return new _DiagnosticError( | ||
| { | ||
| code: outerCode, | ||
| message: outerMessage, | ||
| span: outerSpan, | ||
| subExpression: outerSubExpr, | ||
| cause: innerError.diagnostic | ||
| }, | ||
| expression | ||
| ); | ||
| } | ||
| }; | ||
| function isEntityInstance(value) { | ||
| return typeof value === "object" && value !== null && "__entity__" in value && "__id__" in value; | ||
| } | ||
| function isLambdaValue(value) { | ||
| return typeof value === "object" && value !== null && "__type__" in value && value.__type__ === "lambda"; | ||
| } | ||
| function getValueType(value) { | ||
| if (value === null) return "null"; | ||
| if (value === void 0) return "undefined"; | ||
| if (Array.isArray(value)) return "array"; | ||
| if (value instanceof Date) return "date"; | ||
| if (value instanceof RegExp) return "regex"; | ||
| if (value instanceof Map) return "map"; | ||
| if (isEntityInstance(value)) return `entity:${value.__entity__}`; | ||
| if (isLambdaValue(value)) return "lambda"; | ||
| return typeof value; | ||
| } | ||
| // src/environment.ts | ||
| var Scope = class _Scope { | ||
| constructor(parent) { | ||
| this.parent = parent; | ||
| this.scope = /* @__PURE__ */ new Map(); | ||
| } | ||
| scope; | ||
| /** | ||
| * Get a variable's value, searching up the scope chain | ||
| */ | ||
| get(name) { | ||
| const binding = this.scope.get(name); | ||
| if (binding !== void 0) { | ||
| return binding.value; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.get(name); | ||
| } | ||
| return void 0; | ||
| } | ||
| /** | ||
| * Check if a variable exists in any scope | ||
| */ | ||
| has(name) { | ||
| if (this.scope.has(name)) { | ||
| return true; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.has(name); | ||
| } | ||
| return false; | ||
| } | ||
| /** | ||
| * Set a variable's value (must already exist) | ||
| */ | ||
| set(name, value) { | ||
| const binding = this.findBinding(name); | ||
| if (binding) { | ||
| if (!binding.mutable) { | ||
| throw new Error(`Cannot assign to immutable variable: ${name}`); | ||
| } | ||
| binding.value = value; | ||
| } else { | ||
| this.define(name, value, true); | ||
| } | ||
| } | ||
| /** | ||
| * Define a new variable in the current scope | ||
| */ | ||
| define(name, value, mutable = false) { | ||
| this.scope.set(name, { name, value, mutable }); | ||
| } | ||
| /** | ||
| * Create a child scope | ||
| */ | ||
| child() { | ||
| return new _Scope(this); | ||
| } | ||
| /** | ||
| * Get all bindings from this scope (not including parent) | ||
| */ | ||
| bindings() { | ||
| return new Map(this.scope); | ||
| } | ||
| /** | ||
| * Find a binding in the scope chain | ||
| */ | ||
| findBinding(name) { | ||
| const binding = this.scope.get(name); | ||
| if (binding !== void 0) { | ||
| return binding; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.findBinding(name); | ||
| } | ||
| return void 0; | ||
| } | ||
| }; | ||
| var SnapshotEntityStore = class { | ||
| _snapshot; | ||
| constructor(snapshot) { | ||
| this._snapshot = snapshot; | ||
| } | ||
| getAll(entityName) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| return entities ? Array.from(entities.values()) : []; | ||
| } | ||
| exists(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities || entities.size === 0) return false; | ||
| if (!criteria) return entities.size > 0; | ||
| return Array.from(entities.values()).some( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ); | ||
| } | ||
| lookup(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities) return void 0; | ||
| return Array.from(entities.values()).find( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ); | ||
| } | ||
| count(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities) return 0; | ||
| if (!criteria) return entities.size; | ||
| return Array.from(entities.values()).filter( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ).length; | ||
| } | ||
| create() { | ||
| throw new Error("Snapshot store is read-only: cannot create entities"); | ||
| } | ||
| update() { | ||
| throw new Error("Snapshot store is read-only: cannot update entities"); | ||
| } | ||
| delete() { | ||
| throw new Error("Snapshot store is read-only: cannot delete entities"); | ||
| } | ||
| snapshot() { | ||
| return this._snapshot; | ||
| } | ||
| restore() { | ||
| throw new Error("Cannot restore snapshot store"); | ||
| } | ||
| }; | ||
| function createScope(parent) { | ||
| return new Scope(parent); | ||
| } | ||
| // src/builtins.ts | ||
| var DefaultBuiltinRegistry = class { | ||
| builtins; | ||
| constructor() { | ||
| this.builtins = /* @__PURE__ */ new Map(); | ||
| this.registerDefaults(); | ||
| } | ||
| get(name) { | ||
| return this.builtins.get(name); | ||
| } | ||
| has(name) { | ||
| return this.builtins.has(name); | ||
| } | ||
| register(name, fn) { | ||
| this.builtins.set(name, fn); | ||
| } | ||
| list() { | ||
| return Array.from(this.builtins.keys()); | ||
| } | ||
| registerDefaults() { | ||
| this.register("now", builtinNow); | ||
| this.register("len", builtinLen); | ||
| this.register("length", builtinLen); | ||
| this.register("count", builtinCount); | ||
| this.register("sum", builtinSum); | ||
| this.register("min", builtinMin); | ||
| this.register("max", builtinMax); | ||
| this.register("avg", builtinAvg); | ||
| this.register("all", builtinAll); | ||
| this.register("forall", builtinAll); | ||
| this.register("any", builtinAny); | ||
| this.register("exists", builtinAny); | ||
| this.register("none", builtinNone); | ||
| this.register("filter", builtinFilter); | ||
| this.register("abs", builtinAbs); | ||
| this.register("round", builtinRound); | ||
| this.register("floor", builtinFloor); | ||
| this.register("ceil", builtinCeil); | ||
| this.register("sqrt", builtinSqrt); | ||
| this.register("pow", builtinPow); | ||
| this.register("concat", builtinConcat); | ||
| this.register("upper", builtinUpper); | ||
| this.register("lower", builtinLower); | ||
| this.register("trim", builtinTrim); | ||
| this.register("split", builtinSplit); | ||
| this.register("substring", builtinSubstring); | ||
| this.register("typeof", builtinTypeof); | ||
| this.register("isNull", builtinIsNull); | ||
| this.register("isNumber", builtinIsNumber); | ||
| this.register("isString", builtinIsString); | ||
| this.register("isArray", builtinIsArray); | ||
| this.register("toNumber", builtinToNumber); | ||
| this.register("toString", builtinToString); | ||
| this.register("toBoolean", builtinToBoolean); | ||
| this.register("implies", builtinImplies); | ||
| this.register("timing_safe_comparison", () => true); | ||
| this.register("never_appears_in", () => true); | ||
| } | ||
| }; | ||
| var builtinNow = (_args, context) => { | ||
| return context.now; | ||
| }; | ||
| var builtinLen = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (Array.isArray(value)) { | ||
| return value.length; | ||
| } | ||
| if (typeof value === "string") { | ||
| return value.length; | ||
| } | ||
| if (value instanceof Map) { | ||
| return value.size; | ||
| } | ||
| if (typeof value === "object" && value !== null) { | ||
| return Object.keys(value).length; | ||
| } | ||
| throw new TypeError( | ||
| `len() requires array, string, map, or object, got ${getValueType(value)}`, | ||
| location, | ||
| "array | string | map | object", | ||
| getValueType(value) | ||
| ); | ||
| }; | ||
| var builtinCount = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `count() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (predicate) { | ||
| return collection.filter(predicate).length; | ||
| } | ||
| return collection.length; | ||
| }; | ||
| var builtinSum = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const selector = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `sum() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (collection.length === 0) { | ||
| return 0; | ||
| } | ||
| if (selector) { | ||
| return collection.reduce((acc, item) => acc + selector(item), 0); | ||
| } | ||
| return collection.reduce((acc, item) => { | ||
| if (typeof item !== "number") { | ||
| throw new TypeError( | ||
| `sum() requires numeric array elements, got ${getValueType(item)}`, | ||
| location, | ||
| "number", | ||
| getValueType(item) | ||
| ); | ||
| } | ||
| return acc + item; | ||
| }, 0); | ||
| }; | ||
| var builtinMin = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| if (Array.isArray(collection)) { | ||
| if (collection.length === 0) { | ||
| return void 0; | ||
| } | ||
| return Math.min(...collection); | ||
| } | ||
| if (args.length > 1) { | ||
| return Math.min(...args); | ||
| } | ||
| throw new TypeError( | ||
| `min() requires array or multiple numbers`, | ||
| location, | ||
| "array | number[]", | ||
| getValueType(collection) | ||
| ); | ||
| }; | ||
| var builtinMax = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| if (Array.isArray(collection)) { | ||
| if (collection.length === 0) { | ||
| return void 0; | ||
| } | ||
| return Math.max(...collection); | ||
| } | ||
| if (args.length > 1) { | ||
| return Math.max(...args); | ||
| } | ||
| throw new TypeError( | ||
| `max() requires array or multiple numbers`, | ||
| location, | ||
| "array | number[]", | ||
| getValueType(collection) | ||
| ); | ||
| }; | ||
| var builtinAvg = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `avg() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (collection.length === 0) { | ||
| return void 0; | ||
| } | ||
| const sum = collection.reduce((acc, item) => { | ||
| if (typeof item !== "number") { | ||
| throw new TypeError( | ||
| `avg() requires numeric array elements`, | ||
| location, | ||
| "number", | ||
| getValueType(item) | ||
| ); | ||
| } | ||
| return acc + item; | ||
| }, 0); | ||
| return sum / collection.length; | ||
| }; | ||
| var builtinAll = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `all() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (!predicate) { | ||
| return collection.every(Boolean); | ||
| } | ||
| return collection.every(predicate); | ||
| }; | ||
| var builtinAny = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `any() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (!predicate) { | ||
| return collection.some(Boolean); | ||
| } | ||
| return collection.some(predicate); | ||
| }; | ||
| var builtinNone = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `none() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (!predicate) { | ||
| return !collection.some(Boolean); | ||
| } | ||
| return !collection.some(predicate); | ||
| }; | ||
| var builtinFilter = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `filter() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (!predicate) { | ||
| return collection.filter(Boolean); | ||
| } | ||
| return collection.filter(predicate); | ||
| }; | ||
| var builtinAbs = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `abs() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return Math.abs(value); | ||
| }; | ||
| var builtinRound = (args, _context, location) => { | ||
| const value = args[0]; | ||
| const decimals = args[1]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `round() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| if (decimals !== void 0) { | ||
| const factor = Math.pow(10, decimals); | ||
| return Math.round(value * factor) / factor; | ||
| } | ||
| return Math.round(value); | ||
| }; | ||
| var builtinFloor = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `floor() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return Math.floor(value); | ||
| }; | ||
| var builtinCeil = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `ceil() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return Math.ceil(value); | ||
| }; | ||
| var builtinSqrt = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `sqrt() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| if (value < 0) { | ||
| throw new RuntimeError( | ||
| `sqrt() of negative number: ${value}`, | ||
| location | ||
| ); | ||
| } | ||
| return Math.sqrt(value); | ||
| }; | ||
| var builtinPow = (args, _context, location) => { | ||
| const base = args[0]; | ||
| const exponent = args[1]; | ||
| if (typeof base !== "number" || typeof exponent !== "number") { | ||
| throw new TypeError( | ||
| `pow() requires two numbers`, | ||
| location, | ||
| "number, number", | ||
| `${getValueType(base)}, ${getValueType(exponent)}` | ||
| ); | ||
| } | ||
| return Math.pow(base, exponent); | ||
| }; | ||
| var builtinConcat = (args) => { | ||
| return args.map(String).join(""); | ||
| }; | ||
| var builtinUpper = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `upper() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.toUpperCase(); | ||
| }; | ||
| var builtinLower = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `lower() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.toLowerCase(); | ||
| }; | ||
| var builtinTrim = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `trim() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.trim(); | ||
| }; | ||
| var builtinSplit = (args, _context, location) => { | ||
| const value = args[0]; | ||
| const separator = args[1] ?? ""; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `split() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.split(separator); | ||
| }; | ||
| var builtinSubstring = (args, _context, location) => { | ||
| const value = args[0]; | ||
| const start = args[1]; | ||
| const end = args[2]; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `substring() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.substring(start, end); | ||
| }; | ||
| var builtinTypeof = (args) => { | ||
| return getValueType(args[0]); | ||
| }; | ||
| var builtinIsNull = (args) => { | ||
| return args[0] === null || args[0] === void 0; | ||
| }; | ||
| var builtinIsNumber = (args) => { | ||
| return typeof args[0] === "number" && !isNaN(args[0]); | ||
| }; | ||
| var builtinIsString = (args) => { | ||
| return typeof args[0] === "string"; | ||
| }; | ||
| var builtinIsArray = (args) => { | ||
| return Array.isArray(args[0]); | ||
| }; | ||
| var builtinToNumber = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value === "number") return value; | ||
| if (typeof value === "string") { | ||
| const num = Number(value); | ||
| if (isNaN(num)) { | ||
| throw new RuntimeError( | ||
| `Cannot convert "${value}" to number`, | ||
| location | ||
| ); | ||
| } | ||
| return num; | ||
| } | ||
| if (typeof value === "boolean") return value ? 1 : 0; | ||
| throw new TypeError( | ||
| `Cannot convert ${getValueType(value)} to number`, | ||
| location, | ||
| "number | string | boolean", | ||
| getValueType(value) | ||
| ); | ||
| }; | ||
| var builtinToString = (args) => { | ||
| const value = args[0]; | ||
| if (value === null) return "null"; | ||
| if (value === void 0) return "undefined"; | ||
| if (typeof value === "object") return JSON.stringify(value); | ||
| return String(value); | ||
| }; | ||
| var builtinToBoolean = (args) => { | ||
| return Boolean(args[0]); | ||
| }; | ||
| var builtinImplies = (args) => { | ||
| const a = Boolean(args[0]); | ||
| const b = Boolean(args[1]); | ||
| return !a || b; | ||
| }; | ||
| function createBuiltinRegistry() { | ||
| return new DefaultBuiltinRegistry(); | ||
| } | ||
| var defaultRegistry = null; | ||
| function getDefaultBuiltins() { | ||
| if (!defaultRegistry) { | ||
| defaultRegistry = createBuiltinRegistry(); | ||
| } | ||
| return defaultRegistry; | ||
| } | ||
| // src/evaluator.ts | ||
| var Evaluator = class { | ||
| builtins; | ||
| strict; | ||
| maxDepth; | ||
| currentDepth = 0; | ||
| startTime = 0; | ||
| timeout; | ||
| constructor(options = {}) { | ||
| this.builtins = options.builtins ?? getDefaultBuiltins(); | ||
| this.strict = options.strict ?? true; | ||
| this.maxDepth = options.maxDepth ?? 1e3; | ||
| this.timeout = options.timeout ?? 5e3; | ||
| } | ||
| /** | ||
| * Evaluate an expression in the given context | ||
| */ | ||
| evaluate(expr, context) { | ||
| this.startTime = Date.now(); | ||
| this.currentDepth = 0; | ||
| return this.eval(expr, context); | ||
| } | ||
| // ============================================================================ | ||
| // MAIN DISPATCH | ||
| // ============================================================================ | ||
| eval(expr, ctx) { | ||
| if (++this.currentDepth > this.maxDepth) { | ||
| throw new RuntimeError( | ||
| `Maximum recursion depth exceeded (${this.maxDepth})`, | ||
| expr.location | ||
| ); | ||
| } | ||
| if (Date.now() - this.startTime > this.timeout) { | ||
| throw new RuntimeError( | ||
| `Evaluation timeout exceeded (${this.timeout}ms)`, | ||
| expr.location | ||
| ); | ||
| } | ||
| try { | ||
| switch (expr.kind) { | ||
| case "Identifier": | ||
| return this.evalIdentifier(expr, ctx); | ||
| case "QualifiedName": | ||
| return this.evalQualifiedName(expr, ctx); | ||
| case "StringLiteral": | ||
| return expr.value; | ||
| case "NumberLiteral": | ||
| return expr.value; | ||
| case "BooleanLiteral": | ||
| return expr.value; | ||
| case "NullLiteral": | ||
| return null; | ||
| case "DurationLiteral": | ||
| return this.evalDuration(expr); | ||
| case "RegexLiteral": | ||
| return new RegExp(expr.pattern, expr.flags); | ||
| case "BinaryExpr": | ||
| return this.evalBinaryExpr(expr, ctx); | ||
| case "UnaryExpr": | ||
| return this.evalUnaryExpr(expr, ctx); | ||
| case "CallExpr": | ||
| return this.evalCallExpr(expr, ctx); | ||
| case "MemberExpr": | ||
| return this.evalMemberExpr(expr, ctx); | ||
| case "OptionalMemberExpr": | ||
| return this.evalOptionalMemberExpr(expr, ctx); | ||
| case "IndexExpr": | ||
| return this.evalIndexExpr(expr, ctx); | ||
| case "QuantifierExpr": | ||
| return this.evalQuantifierExpr(expr, ctx); | ||
| case "ConditionalExpr": | ||
| return this.evalConditionalExpr(expr, ctx); | ||
| case "OldExpr": | ||
| return this.evalOldExpr(expr, ctx); | ||
| case "ResultExpr": | ||
| return this.evalResultExpr(expr, ctx); | ||
| case "InputExpr": | ||
| return this.evalInputExpr(expr, ctx); | ||
| case "LambdaExpr": | ||
| return this.evalLambdaExpr(expr, ctx); | ||
| case "ListExpr": | ||
| return expr.elements.map((el) => this.eval(el, ctx)); | ||
| case "MapExpr": | ||
| return this.evalMapExpr(expr, ctx); | ||
| default: { | ||
| const unknownExpr = expr; | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_UNSUPPORTED_EXPR" /* EVAL_UNSUPPORTED_EXPR */, | ||
| message: `Unsupported expression kind: ${unknownExpr.kind}`, | ||
| span: unknownExpr.location, | ||
| subExpression: `<${unknownExpr.kind}>` | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| throw new EvaluationError( | ||
| `Unsupported expression kind: ${unknownExpr.kind}`, | ||
| unknownExpr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| } finally { | ||
| this.currentDepth--; | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // IDENTIFIER EVALUATION | ||
| // ============================================================================ | ||
| evalIdentifier(expr, ctx) { | ||
| const name = expr.name; | ||
| if (name === "result") return ctx.result; | ||
| if (name === "input") return ctx.input; | ||
| if (name === "now") return ctx.now; | ||
| if (name === "true") return true; | ||
| if (name === "false") return false; | ||
| if (name === "null") return null; | ||
| if (name === "undefined") return void 0; | ||
| if (ctx.variables.has(name)) { | ||
| return ctx.variables.get(name); | ||
| } | ||
| if (ctx.domain?.entities.some((e) => e.name === name)) { | ||
| return this.createEntityProxy(name, ctx.store); | ||
| } | ||
| if (name in ctx.input) { | ||
| return ctx.input[name]; | ||
| } | ||
| if (this.builtins.has(name)) { | ||
| return ((...args) => this.builtins.get(name)(args, ctx, expr.location)); | ||
| } | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_UNDEFINED_VAR" /* EVAL_UNDEFINED_VAR */, | ||
| message: `Unknown identifier: '${name}'`, | ||
| span: expr.location, | ||
| subExpression: name | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| throw new ReferenceError( | ||
| `Unknown identifier: ${name}`, | ||
| expr.location, | ||
| name, | ||
| expr | ||
| ); | ||
| } | ||
| evalQualifiedName(expr, ctx) { | ||
| const parts = expr.parts; | ||
| let value = this.evalIdentifier(parts[0], ctx); | ||
| for (let i = 1; i < parts.length; i++) { | ||
| const part = parts[i].name; | ||
| if (value === null || value === void 0) { | ||
| if (this.strict) { | ||
| const resolvedPath = parts.slice(0, i).map((p) => p.name).join("."); | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_NULL_DEREF" /* EVAL_NULL_DEREF */, | ||
| message: `Cannot access property '${part}' on ${value === null ? "null" : "undefined"} (in path '${resolvedPath}.${part}')`, | ||
| span: expr.location, | ||
| subExpression: parts.map((p) => p.name).join(".") | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| value = value[part]; | ||
| } | ||
| return value; | ||
| } | ||
| // ============================================================================ | ||
| // ENTITY PROXY | ||
| // ============================================================================ | ||
| createEntityProxy(entityName, store) { | ||
| return { | ||
| __entityName__: entityName, | ||
| __isProxy__: true, | ||
| exists: (criteria) => store.exists(entityName, criteria), | ||
| lookup: (criteria) => store.lookup(entityName, criteria), | ||
| count: (criteria) => store.count(entityName, criteria), | ||
| getAll: () => store.getAll(entityName) | ||
| }; | ||
| } | ||
| // ============================================================================ | ||
| // BINARY EXPRESSIONS | ||
| // ============================================================================ | ||
| evalBinaryExpr(expr, ctx) { | ||
| if (expr.operator === "and") { | ||
| const left2 = this.eval(expr.left, ctx); | ||
| if (!left2) return false; | ||
| return Boolean(this.eval(expr.right, ctx)); | ||
| } | ||
| if (expr.operator === "or") { | ||
| const left2 = this.eval(expr.left, ctx); | ||
| if (left2) return true; | ||
| return Boolean(this.eval(expr.right, ctx)); | ||
| } | ||
| if (expr.operator === "implies") { | ||
| const left2 = this.eval(expr.left, ctx); | ||
| if (!left2) return true; | ||
| return Boolean(this.eval(expr.right, ctx)); | ||
| } | ||
| const left = this.eval(expr.left, ctx); | ||
| const right = this.eval(expr.right, ctx); | ||
| switch (expr.operator) { | ||
| case "==": | ||
| return this.deepEqual(left, right); | ||
| case "!=": | ||
| return !this.deepEqual(left, right); | ||
| case "<": | ||
| this.assertNumbers(left, right, expr.location, "<"); | ||
| return left < right; | ||
| case ">": | ||
| this.assertNumbers(left, right, expr.location, ">"); | ||
| return left > right; | ||
| case "<=": | ||
| this.assertNumbers(left, right, expr.location, "<="); | ||
| return left <= right; | ||
| case ">=": | ||
| this.assertNumbers(left, right, expr.location, ">="); | ||
| return left >= right; | ||
| case "+": | ||
| if (typeof left === "string" || typeof right === "string") { | ||
| return String(left) + String(right); | ||
| } | ||
| this.assertNumbers(left, right, expr.location, "+"); | ||
| return left + right; | ||
| case "-": | ||
| this.assertNumbers(left, right, expr.location, "-"); | ||
| return left - right; | ||
| case "*": | ||
| this.assertNumbers(left, right, expr.location, "*"); | ||
| return left * right; | ||
| case "/": | ||
| this.assertNumbers(left, right, expr.location, "/"); | ||
| if (right === 0) { | ||
| throw new RuntimeError("Division by zero", expr.location); | ||
| } | ||
| return left / right; | ||
| case "%": | ||
| this.assertNumbers(left, right, expr.location, "%"); | ||
| if (right === 0) { | ||
| throw new RuntimeError("Modulo by zero", expr.location); | ||
| } | ||
| return left % right; | ||
| case "iff": | ||
| return Boolean(left) === Boolean(right); | ||
| case "in": | ||
| if (Array.isArray(right)) { | ||
| return right.some((item) => this.deepEqual(item, left)); | ||
| } | ||
| if (typeof right === "object" && right !== null) { | ||
| return String(left) in right; | ||
| } | ||
| if (typeof right === "string" && typeof left === "string") { | ||
| return right.includes(left); | ||
| } | ||
| return false; | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown binary operator: ${expr.operator}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // UNARY EXPRESSIONS | ||
| // ============================================================================ | ||
| evalUnaryExpr(expr, ctx) { | ||
| const operand = this.eval(expr.operand, ctx); | ||
| switch (expr.operator) { | ||
| case "not": | ||
| return !operand; | ||
| case "-": | ||
| if (typeof operand !== "number") { | ||
| throw new TypeError( | ||
| `Unary minus requires number, got ${getValueType(operand)}`, | ||
| expr.location, | ||
| "number", | ||
| getValueType(operand), | ||
| expr | ||
| ); | ||
| } | ||
| return -operand; | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown unary operator: ${expr.operator}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // CALL EXPRESSIONS | ||
| // ============================================================================ | ||
| evalCallExpr(expr, ctx) { | ||
| const callee = expr.callee; | ||
| if (callee.kind === "MemberExpr") { | ||
| const obj = this.eval(callee.object, ctx); | ||
| const method = callee.property.name; | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| if (isEntityProxy(obj)) { | ||
| return this.handleEntityMethod(obj, method, args, expr); | ||
| } | ||
| if (Array.isArray(obj)) { | ||
| return this.handleArrayMethod(obj, method, args, expr, ctx); | ||
| } | ||
| if (typeof obj === "string") { | ||
| return this.handleStringMethod(obj, method, args, expr); | ||
| } | ||
| if (typeof obj === "object" && obj !== null) { | ||
| const fn2 = obj[method]; | ||
| if (typeof fn2 === "function") { | ||
| return fn2.apply(obj, args); | ||
| } | ||
| } | ||
| throw new EvaluationError( | ||
| `Cannot call method ${method} on ${getValueType(obj)}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| if (callee.kind === "Identifier") { | ||
| const name = callee.name; | ||
| if (this.builtins.has(name)) { | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| return this.builtins.get(name)(args, ctx, expr.location); | ||
| } | ||
| if (ctx.variables.has(name)) { | ||
| const fn2 = ctx.variables.get(name); | ||
| if (typeof fn2 === "function") { | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| return fn2(...args); | ||
| } | ||
| if (isLambdaValue(fn2)) { | ||
| return this.callLambda(fn2, expr, ctx); | ||
| } | ||
| } | ||
| throw new ReferenceError( | ||
| `Unknown function: ${name}`, | ||
| expr.location, | ||
| name, | ||
| expr | ||
| ); | ||
| } | ||
| const fn = this.eval(callee, ctx); | ||
| if (typeof fn === "function") { | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| return fn(...args); | ||
| } | ||
| if (isLambdaValue(fn)) { | ||
| return this.callLambda(fn, expr, ctx); | ||
| } | ||
| throw new EvaluationError( | ||
| `Cannot call non-function: ${getValueType(fn)}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| callLambda(lambda, expr, ctx) { | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| const newVars = new Map(lambda.closure.bindings()); | ||
| lambda.params.forEach((param, i) => { | ||
| newVars.set(param, { name: param, value: args[i], mutable: false }); | ||
| }); | ||
| const newCtx = { | ||
| ...ctx, | ||
| variables: new Map( | ||
| Array.from(newVars.entries()).map(([k, v]) => [k, v.value]) | ||
| ) | ||
| }; | ||
| return this.eval(lambda.body, newCtx); | ||
| } | ||
| handleEntityMethod(entity, method, args, expr) { | ||
| switch (method) { | ||
| case "exists": | ||
| if (args.length === 0) return entity.exists(); | ||
| return entity.exists(args[0]); | ||
| case "lookup": | ||
| return entity.lookup(args[0]); | ||
| case "count": | ||
| if (args.length === 0) return entity.count(); | ||
| return entity.count(args[0]); | ||
| case "getAll": | ||
| case "all": | ||
| return entity.getAll(); | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown entity method: ${entity.__entityName__}.${method}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| handleArrayMethod(array, method, args, expr, ctx) { | ||
| switch (method) { | ||
| case "length": | ||
| return array.length; | ||
| case "includes": | ||
| case "contains": | ||
| return array.some((item) => this.deepEqual(item, args[0])); | ||
| case "indexOf": | ||
| return array.findIndex((item) => this.deepEqual(item, args[0])); | ||
| case "map": | ||
| if (typeof args[0] === "function") { | ||
| return array.map(args[0]); | ||
| } | ||
| if (isLambdaValue(args[0])) { | ||
| const lambda = args[0]; | ||
| return array.map((item) => { | ||
| const newVars = new Map(ctx.variables); | ||
| newVars.set(lambda.params[0], item); | ||
| return this.eval(lambda.body, { ...ctx, variables: newVars }); | ||
| }); | ||
| } | ||
| throw new TypeError( | ||
| "map() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "filter": | ||
| if (typeof args[0] === "function") { | ||
| return array.filter(args[0]); | ||
| } | ||
| if (isLambdaValue(args[0])) { | ||
| const lambda = args[0]; | ||
| return array.filter((item) => { | ||
| const newVars = new Map(ctx.variables); | ||
| newVars.set(lambda.params[0], item); | ||
| return Boolean(this.eval(lambda.body, { ...ctx, variables: newVars })); | ||
| }); | ||
| } | ||
| throw new TypeError( | ||
| "filter() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "find": | ||
| if (typeof args[0] === "function") { | ||
| return array.find(args[0]) ?? null; | ||
| } | ||
| throw new TypeError( | ||
| "find() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "every": | ||
| if (typeof args[0] === "function") { | ||
| return array.every(args[0]); | ||
| } | ||
| throw new TypeError( | ||
| "every() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "some": | ||
| if (typeof args[0] === "function") { | ||
| return array.some(args[0]); | ||
| } | ||
| throw new TypeError( | ||
| "some() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "reduce": | ||
| if (typeof args[0] === "function") { | ||
| return array.reduce( | ||
| args[0], | ||
| args[1] ?? 0 | ||
| ); | ||
| } | ||
| throw new TypeError( | ||
| "reduce() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "first": | ||
| return array[0] ?? null; | ||
| case "last": | ||
| return array[array.length - 1] ?? null; | ||
| case "slice": | ||
| return array.slice( | ||
| args[0], | ||
| args[1] | ||
| ); | ||
| case "concat": | ||
| if (Array.isArray(args[0])) { | ||
| return [...array, ...args[0]]; | ||
| } | ||
| return [...array, args[0]]; | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown array method: ${method}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| handleStringMethod(str, method, args, expr) { | ||
| switch (method) { | ||
| case "length": | ||
| return str.length; | ||
| case "includes": | ||
| case "contains": | ||
| return str.includes(args[0]); | ||
| case "startsWith": | ||
| return str.startsWith(args[0]); | ||
| case "endsWith": | ||
| return str.endsWith(args[0]); | ||
| case "toLowerCase": | ||
| case "lower": | ||
| return str.toLowerCase(); | ||
| case "toUpperCase": | ||
| case "upper": | ||
| return str.toUpperCase(); | ||
| case "trim": | ||
| return str.trim(); | ||
| case "trimStart": | ||
| return str.trimStart(); | ||
| case "trimEnd": | ||
| return str.trimEnd(); | ||
| case "split": | ||
| return str.split(args[0]); | ||
| case "substring": | ||
| case "substr": | ||
| return str.substring( | ||
| args[0], | ||
| args[1] | ||
| ); | ||
| case "replace": | ||
| return str.replace( | ||
| args[0], | ||
| args[1] | ||
| ); | ||
| case "replaceAll": | ||
| return str.split(args[0]).join(args[1]); | ||
| case "match": | ||
| case "matches": | ||
| if (args[0] instanceof RegExp) { | ||
| return args[0].test(str); | ||
| } | ||
| return new RegExp(args[0]).test(str); | ||
| case "indexOf": | ||
| return str.indexOf(args[0]); | ||
| case "charAt": | ||
| return str.charAt(args[0]); | ||
| case "is_valid": | ||
| case "isValid": | ||
| return str.length > 0; | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown string method: ${method}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // MEMBER EXPRESSIONS | ||
| // ============================================================================ | ||
| evalMemberExpr(expr, ctx) { | ||
| const object = this.eval(expr.object, ctx); | ||
| const property = expr.property.name; | ||
| if (object === null || object === void 0) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_NULL_DEREF" /* EVAL_NULL_DEREF */, | ||
| message: `Cannot access property '${property}' on ${object === null ? "null" : "undefined"}`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| if (isEntityProxy(object)) { | ||
| switch (property) { | ||
| case "exists": | ||
| return ((criteria) => object.exists(criteria)); | ||
| case "lookup": | ||
| return ((criteria) => object.lookup(criteria)); | ||
| case "count": | ||
| return ((criteria) => object.count(criteria)); | ||
| case "getAll": | ||
| case "all": | ||
| return (() => object.getAll()); | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown entity property: ${object.__entityName__}.${property}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| if (Array.isArray(object) && property === "length") { | ||
| return object.length; | ||
| } | ||
| if (typeof object === "string" && property === "length") { | ||
| return object.length; | ||
| } | ||
| return object[property]; | ||
| } | ||
| // ============================================================================ | ||
| // OPTIONAL MEMBER EXPRESSIONS | ||
| // ============================================================================ | ||
| evalOptionalMemberExpr(expr, ctx) { | ||
| const object = this.eval(expr.object, ctx); | ||
| const property = expr.property.name; | ||
| if (object === null || object === void 0) { | ||
| return void 0; | ||
| } | ||
| if (typeof object !== "object" && typeof object !== "string") { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_OPTIONAL_CHAIN_NON_OBJECT" /* EVAL_OPTIONAL_CHAIN_NON_OBJECT */, | ||
| message: `Optional chaining (?.) requires object or null/undefined, got '${getValueType(object)}'`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| if (isEntityProxy(object)) { | ||
| switch (property) { | ||
| case "exists": | ||
| return ((criteria) => object.exists(criteria)); | ||
| case "lookup": | ||
| return ((criteria) => object.lookup(criteria)); | ||
| case "count": | ||
| return ((criteria) => object.count(criteria)); | ||
| case "getAll": | ||
| case "all": | ||
| return (() => object.getAll()); | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown entity property: ${object.__entityName__}.${property}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| if (Array.isArray(object) && property === "length") { | ||
| return object.length; | ||
| } | ||
| if (typeof object === "string" && property === "length") { | ||
| return object.length; | ||
| } | ||
| return object[property]; | ||
| } | ||
| // ============================================================================ | ||
| // INDEX EXPRESSIONS | ||
| // ============================================================================ | ||
| evalIndexExpr(expr, ctx) { | ||
| const object = this.eval(expr.object, ctx); | ||
| const index = this.eval(expr.index, ctx); | ||
| if (object === null || object === void 0) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_NULL_DEREF" /* EVAL_NULL_DEREF */, | ||
| message: `Cannot index into ${object === null ? "null" : "undefined"}`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| if (Array.isArray(object)) { | ||
| const idx = index; | ||
| if (idx < 0 || idx >= object.length) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_OOB_INDEX" /* EVAL_OOB_INDEX */, | ||
| message: `Index ${idx} is out of bounds for array of length ${object.length}`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| return object[idx]; | ||
| } | ||
| if (typeof object === "string") { | ||
| const idx = index; | ||
| if (idx < 0 || idx >= object.length) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_OOB_INDEX" /* EVAL_OOB_INDEX */, | ||
| message: `Index ${idx} is out of bounds for string of length ${object.length}`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| return object[idx]; | ||
| } | ||
| if (typeof object === "object") { | ||
| return object[String(index)]; | ||
| } | ||
| throw new TypeError( | ||
| `Cannot index ${getValueType(object)}`, | ||
| expr.location, | ||
| "array | string | object", | ||
| getValueType(object), | ||
| expr | ||
| ); | ||
| } | ||
| // ============================================================================ | ||
| // QUANTIFIER EXPRESSIONS | ||
| // ============================================================================ | ||
| evalQuantifierExpr(expr, ctx) { | ||
| const collection = this.eval(expr.collection, ctx); | ||
| const variable = expr.variable.name; | ||
| let items; | ||
| if (isEntityProxy(collection)) { | ||
| items = collection.getAll(); | ||
| } else if (Array.isArray(collection)) { | ||
| items = collection; | ||
| } else { | ||
| throw new TypeError( | ||
| `Quantifier requires array or entity, got ${getValueType(collection)}`, | ||
| expr.location, | ||
| "array | entity", | ||
| getValueType(collection), | ||
| expr | ||
| ); | ||
| } | ||
| const evalPredicate = (item) => { | ||
| const newVars = new Map(ctx.variables); | ||
| newVars.set(variable, item); | ||
| const result = this.eval(expr.predicate, { ...ctx, variables: newVars }); | ||
| return Boolean(result); | ||
| }; | ||
| switch (expr.quantifier) { | ||
| case "all": | ||
| return items.every(evalPredicate); | ||
| case "any": | ||
| return items.some(evalPredicate); | ||
| case "none": | ||
| return !items.some(evalPredicate); | ||
| case "count": | ||
| return items.filter(evalPredicate).length; | ||
| case "sum": { | ||
| const evalValue = (item) => { | ||
| const newVars = new Map(ctx.variables); | ||
| newVars.set(variable, item); | ||
| const result = this.eval(expr.predicate, { ...ctx, variables: newVars }); | ||
| if (typeof result !== "number") { | ||
| throw new TypeError( | ||
| `sum quantifier requires numeric predicate result`, | ||
| expr.location, | ||
| "number", | ||
| getValueType(result), | ||
| expr | ||
| ); | ||
| } | ||
| return result; | ||
| }; | ||
| return items.reduce((acc, item) => acc + evalValue(item), 0); | ||
| } | ||
| case "filter": | ||
| return items.filter(evalPredicate); | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown quantifier: ${expr.quantifier}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // SPECIAL EXPRESSIONS | ||
| // ============================================================================ | ||
| evalConditionalExpr(expr, ctx) { | ||
| const condition = this.eval(expr.condition, ctx); | ||
| return condition ? this.eval(expr.thenBranch, ctx) : this.eval(expr.elseBranch, ctx); | ||
| } | ||
| evalOldExpr(expr, ctx) { | ||
| if (!ctx.oldState) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_MISSING_OLD_STATE" /* EVAL_MISSING_OLD_STATE */, | ||
| message: "old() called without previous state snapshot", | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| throw new RuntimeError( | ||
| "old() called without previous state snapshot", | ||
| expr.location | ||
| ); | ||
| } | ||
| const oldStore = new SnapshotEntityStore(ctx.oldState); | ||
| const oldCtx = { | ||
| ...ctx, | ||
| store: oldStore | ||
| }; | ||
| try { | ||
| return this.eval(expr.expression, oldCtx); | ||
| } catch (error) { | ||
| if (this.strict && error instanceof DiagnosticError) { | ||
| throw DiagnosticError.wrap( | ||
| "EVAL_OLD_NESTED_FAIL" /* EVAL_OLD_NESTED_FAIL */, | ||
| `Nested path resolution failed inside old(): ${error.message}`, | ||
| expr.location, | ||
| expressionToString(expr), | ||
| error, | ||
| expr | ||
| ); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| evalResultExpr(expr, ctx) { | ||
| if (expr.property) { | ||
| if (ctx.result === null || ctx.result === void 0) { | ||
| return void 0; | ||
| } | ||
| return ctx.result[expr.property.name]; | ||
| } | ||
| return ctx.result; | ||
| } | ||
| evalInputExpr(expr, ctx) { | ||
| return ctx.input[expr.property.name]; | ||
| } | ||
| evalLambdaExpr(expr, ctx) { | ||
| const closure = createScope(); | ||
| for (const [name, value] of ctx.variables) { | ||
| closure.define(name, value); | ||
| } | ||
| const lambda = { | ||
| __type__: "lambda", | ||
| params: expr.params.map((p) => p.name), | ||
| body: expr.body, | ||
| closure | ||
| }; | ||
| return lambda; | ||
| } | ||
| evalMapExpr(expr, ctx) { | ||
| const result = {}; | ||
| for (const entry of expr.entries) { | ||
| const key = this.eval(entry.key, ctx); | ||
| const value = this.eval(entry.value, ctx); | ||
| result[String(key)] = value; | ||
| } | ||
| return result; | ||
| } | ||
| evalDuration(expr) { | ||
| const value = expr.value; | ||
| switch (expr.unit) { | ||
| case "ms": | ||
| return value; | ||
| case "seconds": | ||
| return value * 1e3; | ||
| case "minutes": | ||
| return value * 60 * 1e3; | ||
| case "hours": | ||
| return value * 60 * 60 * 1e3; | ||
| case "days": | ||
| return value * 24 * 60 * 60 * 1e3; | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // UTILITIES | ||
| // ============================================================================ | ||
| assertNumbers(left, right, location, operator) { | ||
| if (typeof left !== "number" || typeof right !== "number") { | ||
| throw new TypeError( | ||
| `Operator '${operator}' requires numbers, got ${getValueType(left)} and ${getValueType(right)}`, | ||
| location, | ||
| "number", | ||
| `${getValueType(left)}, ${getValueType(right)}` | ||
| ); | ||
| } | ||
| } | ||
| deepEqual(a, b) { | ||
| if (a === b) return true; | ||
| if (a === null || b === null) return a === b; | ||
| if (typeof a !== typeof b) return false; | ||
| if (a instanceof Date && b instanceof Date) { | ||
| return a.getTime() === b.getTime(); | ||
| } | ||
| if (Array.isArray(a) && Array.isArray(b)) { | ||
| if (a.length !== b.length) return false; | ||
| return a.every((val, i) => this.deepEqual(val, b[i])); | ||
| } | ||
| if (typeof a === "object" && typeof b === "object") { | ||
| const keysA = Object.keys(a); | ||
| const keysB = Object.keys(b); | ||
| if (keysA.length !== keysB.length) return false; | ||
| return keysA.every( | ||
| (key) => this.deepEqual( | ||
| a[key], | ||
| b[key] | ||
| ) | ||
| ); | ||
| } | ||
| return false; | ||
| } | ||
| }; | ||
| function isEntityProxy(value) { | ||
| return typeof value === "object" && value !== null && "__isProxy__" in value && value.__isProxy__ === true; | ||
| } | ||
| function evaluate(expr, context, options) { | ||
| const evaluator = new Evaluator(options); | ||
| return evaluator.evaluate(expr, context); | ||
| } | ||
| function expressionToString(expr) { | ||
| const e = expr; | ||
| switch (e.kind) { | ||
| case "Identifier": | ||
| return e.name; | ||
| case "QualifiedName": | ||
| return e.parts.map((p) => p.name).join("."); | ||
| case "StringLiteral": | ||
| return JSON.stringify(e.value); | ||
| case "NumberLiteral": | ||
| return String(e.value); | ||
| case "BooleanLiteral": | ||
| return String(e.value); | ||
| case "NullLiteral": | ||
| return "null"; | ||
| case "DurationLiteral": | ||
| return `${e.value}${e.unit}`; | ||
| case "RegexLiteral": | ||
| return `/${e.pattern}/${e.flags}`; | ||
| case "BinaryExpr": | ||
| return `(${expressionToString(e.left)} ${e.operator} ${expressionToString(e.right)})`; | ||
| case "UnaryExpr": | ||
| return `${e.operator}(${expressionToString(e.operand)})`; | ||
| case "CallExpr": | ||
| return `${expressionToString(e.callee)}(${e.arguments.map(expressionToString).join(", ")})`; | ||
| case "MemberExpr": | ||
| return `${expressionToString(e.object)}.${e.property.name}`; | ||
| case "OptionalMemberExpr": | ||
| return `${expressionToString(e.object)}?.${e.property.name}`; | ||
| case "IndexExpr": | ||
| return `${expressionToString(e.object)}[${expressionToString(e.index)}]`; | ||
| case "OldExpr": | ||
| return `old(${expressionToString(e.expression)})`; | ||
| case "ResultExpr": | ||
| return e.property ? `result.${e.property.name}` : "result"; | ||
| case "InputExpr": | ||
| return `input.${e.property.name}`; | ||
| case "QuantifierExpr": | ||
| return `${e.quantifier} ${e.variable.name} in ${expressionToString(e.collection)}: ${expressionToString(e.predicate)}`; | ||
| case "ConditionalExpr": | ||
| return `${expressionToString(e.condition)} ? ${expressionToString(e.thenBranch)} : ${expressionToString(e.elseBranch)}`; | ||
| case "LambdaExpr": | ||
| return `(${e.params.map((p) => p.name).join(", ")}) => ${expressionToString(e.body)}`; | ||
| case "ListExpr": | ||
| return `[${e.elements.map(expressionToString).join(", ")}]`; | ||
| case "MapExpr": | ||
| return `{${e.entries.map((entry) => `${expressionToString(entry.key)}: ${expressionToString(entry.value)}`).join(", ")}}`; | ||
| default: | ||
| return `<${e.kind}>`; | ||
| } | ||
| } | ||
| exports.Evaluator = Evaluator; | ||
| exports.evaluate = evaluate; | ||
| exports.expressionToString = expressionToString; | ||
| //# sourceMappingURL=evaluator.cjs.map | ||
| //# sourceMappingURL=evaluator.cjs.map |
Sorry, the diff of this file is too big to display
| import { B as BuiltinRegistry, c as EvaluationContext, e as Value } from './types-BP9x1AUL.cjs'; | ||
| interface EvaluatorOptions { | ||
| /** Custom builtin registry */ | ||
| builtins?: BuiltinRegistry; | ||
| /** | ||
| * Enable strict diagnostics mode. | ||
| * When true (default), null-dereferences, OOB indices, and undefined members | ||
| * throw DiagnosticError instead of silently returning undefined. | ||
| */ | ||
| strict?: boolean; | ||
| /** Maximum recursion depth */ | ||
| maxDepth?: number; | ||
| /** Timeout in milliseconds */ | ||
| timeout?: number; | ||
| } | ||
| /** | ||
| * Tree-walking interpreter for ISL expressions | ||
| */ | ||
| declare class Evaluator { | ||
| private readonly builtins; | ||
| private readonly strict; | ||
| private readonly maxDepth; | ||
| private currentDepth; | ||
| private startTime; | ||
| private timeout; | ||
| constructor(options?: EvaluatorOptions); | ||
| /** | ||
| * Evaluate an expression in the given context | ||
| */ | ||
| evaluate(expr: unknown, context: EvaluationContext): Value; | ||
| private eval; | ||
| private evalIdentifier; | ||
| private evalQualifiedName; | ||
| private createEntityProxy; | ||
| private evalBinaryExpr; | ||
| private evalUnaryExpr; | ||
| private evalCallExpr; | ||
| private callLambda; | ||
| private handleEntityMethod; | ||
| private handleArrayMethod; | ||
| private handleStringMethod; | ||
| private evalMemberExpr; | ||
| private evalOptionalMemberExpr; | ||
| private evalIndexExpr; | ||
| private evalQuantifierExpr; | ||
| private evalConditionalExpr; | ||
| private evalOldExpr; | ||
| private evalResultExpr; | ||
| private evalInputExpr; | ||
| private evalLambdaExpr; | ||
| private evalMapExpr; | ||
| private evalDuration; | ||
| private assertNumbers; | ||
| private deepEqual; | ||
| } | ||
| /** | ||
| * Evaluate an expression (convenience wrapper) | ||
| */ | ||
| declare function evaluate(expr: unknown, context: EvaluationContext, options?: EvaluatorOptions): Value; | ||
| /** | ||
| * Convert expression to string representation | ||
| */ | ||
| declare function expressionToString(expr: unknown): string; | ||
| export { Evaluator, type EvaluatorOptions, evaluate, expressionToString }; |
| import { B as BuiltinRegistry, c as EvaluationContext, e as Value } from './types-BP9x1AUL.js'; | ||
| interface EvaluatorOptions { | ||
| /** Custom builtin registry */ | ||
| builtins?: BuiltinRegistry; | ||
| /** | ||
| * Enable strict diagnostics mode. | ||
| * When true (default), null-dereferences, OOB indices, and undefined members | ||
| * throw DiagnosticError instead of silently returning undefined. | ||
| */ | ||
| strict?: boolean; | ||
| /** Maximum recursion depth */ | ||
| maxDepth?: number; | ||
| /** Timeout in milliseconds */ | ||
| timeout?: number; | ||
| } | ||
| /** | ||
| * Tree-walking interpreter for ISL expressions | ||
| */ | ||
| declare class Evaluator { | ||
| private readonly builtins; | ||
| private readonly strict; | ||
| private readonly maxDepth; | ||
| private currentDepth; | ||
| private startTime; | ||
| private timeout; | ||
| constructor(options?: EvaluatorOptions); | ||
| /** | ||
| * Evaluate an expression in the given context | ||
| */ | ||
| evaluate(expr: unknown, context: EvaluationContext): Value; | ||
| private eval; | ||
| private evalIdentifier; | ||
| private evalQualifiedName; | ||
| private createEntityProxy; | ||
| private evalBinaryExpr; | ||
| private evalUnaryExpr; | ||
| private evalCallExpr; | ||
| private callLambda; | ||
| private handleEntityMethod; | ||
| private handleArrayMethod; | ||
| private handleStringMethod; | ||
| private evalMemberExpr; | ||
| private evalOptionalMemberExpr; | ||
| private evalIndexExpr; | ||
| private evalQuantifierExpr; | ||
| private evalConditionalExpr; | ||
| private evalOldExpr; | ||
| private evalResultExpr; | ||
| private evalInputExpr; | ||
| private evalLambdaExpr; | ||
| private evalMapExpr; | ||
| private evalDuration; | ||
| private assertNumbers; | ||
| private deepEqual; | ||
| } | ||
| /** | ||
| * Evaluate an expression (convenience wrapper) | ||
| */ | ||
| declare function evaluate(expr: unknown, context: EvaluationContext, options?: EvaluatorOptions): Value; | ||
| /** | ||
| * Convert expression to string representation | ||
| */ | ||
| declare function expressionToString(expr: unknown): string; | ||
| export { Evaluator, type EvaluatorOptions, evaluate, expressionToString }; |
+1740
| // src/types.ts | ||
| var EvalErrorCodes = { | ||
| DIVISION_BY_ZERO: "E0400", | ||
| NULL_REFERENCE: "E0401", | ||
| INDEX_OUT_OF_BOUNDS: "E0402", | ||
| ENTITY_NOT_FOUND: "E0410", | ||
| // Legacy codes (for backward compat) | ||
| EVALUATION_ERROR: "E0404", | ||
| TYPE_ERROR: "E0408", | ||
| REFERENCE_ERROR: "E0403", | ||
| RUNTIME_ERROR: "E0404" | ||
| }; | ||
| var EvaluationError = class _EvaluationError extends Error { | ||
| constructor(message, location, expression, code = EvalErrorCodes.EVALUATION_ERROR) { | ||
| super(message); | ||
| this.location = location; | ||
| this.expression = expression; | ||
| this.code = code; | ||
| this.name = "EvaluationError"; | ||
| Object.setPrototypeOf(this, _EvaluationError.prototype); | ||
| } | ||
| notes = []; | ||
| help = []; | ||
| /** | ||
| * Get a formatted error message with location | ||
| */ | ||
| formatMessage() { | ||
| return `${this.code}: ${this.message} at ${this.location.file}:${this.location.line}:${this.location.column}`; | ||
| } | ||
| /** | ||
| * Add a note to the error | ||
| */ | ||
| withNote(note) { | ||
| this.notes.push(note); | ||
| return this; | ||
| } | ||
| /** | ||
| * Add a help suggestion to the error | ||
| */ | ||
| withHelp(help) { | ||
| this.help.push(help); | ||
| return this; | ||
| } | ||
| }; | ||
| var TypeError = class _TypeError extends EvaluationError { | ||
| constructor(message, location, expectedType, actualType, expression) { | ||
| super(message, location, expression, EvalErrorCodes.TYPE_ERROR); | ||
| this.expectedType = expectedType; | ||
| this.actualType = actualType; | ||
| this.name = "TypeError"; | ||
| Object.setPrototypeOf(this, _TypeError.prototype); | ||
| } | ||
| }; | ||
| var ReferenceError = class _ReferenceError extends EvaluationError { | ||
| constructor(message, location, identifier, expression) { | ||
| super(message, location, expression, EvalErrorCodes.REFERENCE_ERROR); | ||
| this.identifier = identifier; | ||
| this.name = "ReferenceError"; | ||
| Object.setPrototypeOf(this, _ReferenceError.prototype); | ||
| } | ||
| }; | ||
| var RuntimeError = class _RuntimeError extends EvaluationError { | ||
| constructor(message, location, expression, code = EvalErrorCodes.RUNTIME_ERROR) { | ||
| super(message, location, expression, code); | ||
| this.name = "RuntimeError"; | ||
| Object.setPrototypeOf(this, _RuntimeError.prototype); | ||
| } | ||
| /** | ||
| * Create a division by zero error | ||
| */ | ||
| static divisionByZero(location, expression) { | ||
| return new _RuntimeError( | ||
| "Division by zero", | ||
| location, | ||
| expression, | ||
| EvalErrorCodes.DIVISION_BY_ZERO | ||
| ).withHelp("Add a precondition to ensure the divisor is non-zero"); | ||
| } | ||
| /** | ||
| * Create a null reference error | ||
| */ | ||
| static nullReference(property, location, expression) { | ||
| return new _RuntimeError( | ||
| `Cannot read property '${property}' of null`, | ||
| location, | ||
| expression, | ||
| EvalErrorCodes.NULL_REFERENCE | ||
| ).withHelp("Check for null before accessing properties, or use optional chaining (?.)"); | ||
| } | ||
| /** | ||
| * Create an index out of bounds error | ||
| */ | ||
| static indexOutOfBounds(index, length, location, expression) { | ||
| return new _RuntimeError( | ||
| `Index ${index} is out of bounds for array of length ${length}`, | ||
| location, | ||
| expression, | ||
| EvalErrorCodes.INDEX_OUT_OF_BOUNDS | ||
| ).withHelp("Ensure the index is within the valid range [0, length)"); | ||
| } | ||
| /** | ||
| * Create an entity not found error | ||
| */ | ||
| static entityNotFound(entityName, id, location) { | ||
| return new _RuntimeError( | ||
| `Entity '${entityName}' with id '${id}' not found`, | ||
| location, | ||
| void 0, | ||
| EvalErrorCodes.ENTITY_NOT_FOUND | ||
| ).withHelp("Check that the entity exists before accessing it, or use exists() first"); | ||
| } | ||
| }; | ||
| var DiagnosticError = class _DiagnosticError extends EvaluationError { | ||
| diagnostic; | ||
| constructor(payload, expression) { | ||
| super(payload.message, payload.span, expression, payload.code); | ||
| this.name = "DiagnosticError"; | ||
| this.diagnostic = payload; | ||
| Object.setPrototypeOf(this, _DiagnosticError.prototype); | ||
| } | ||
| /** | ||
| * Wrap an existing DiagnosticError as the cause of a higher-level diagnostic. | ||
| */ | ||
| static wrap(outerCode, outerMessage, outerSpan, outerSubExpr, innerError, expression) { | ||
| return new _DiagnosticError( | ||
| { | ||
| code: outerCode, | ||
| message: outerMessage, | ||
| span: outerSpan, | ||
| subExpression: outerSubExpr, | ||
| cause: innerError.diagnostic | ||
| }, | ||
| expression | ||
| ); | ||
| } | ||
| }; | ||
| function isEntityInstance(value) { | ||
| return typeof value === "object" && value !== null && "__entity__" in value && "__id__" in value; | ||
| } | ||
| function isLambdaValue(value) { | ||
| return typeof value === "object" && value !== null && "__type__" in value && value.__type__ === "lambda"; | ||
| } | ||
| function getValueType(value) { | ||
| if (value === null) return "null"; | ||
| if (value === void 0) return "undefined"; | ||
| if (Array.isArray(value)) return "array"; | ||
| if (value instanceof Date) return "date"; | ||
| if (value instanceof RegExp) return "regex"; | ||
| if (value instanceof Map) return "map"; | ||
| if (isEntityInstance(value)) return `entity:${value.__entity__}`; | ||
| if (isLambdaValue(value)) return "lambda"; | ||
| return typeof value; | ||
| } | ||
| // src/environment.ts | ||
| var Scope = class _Scope { | ||
| constructor(parent) { | ||
| this.parent = parent; | ||
| this.scope = /* @__PURE__ */ new Map(); | ||
| } | ||
| scope; | ||
| /** | ||
| * Get a variable's value, searching up the scope chain | ||
| */ | ||
| get(name) { | ||
| const binding = this.scope.get(name); | ||
| if (binding !== void 0) { | ||
| return binding.value; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.get(name); | ||
| } | ||
| return void 0; | ||
| } | ||
| /** | ||
| * Check if a variable exists in any scope | ||
| */ | ||
| has(name) { | ||
| if (this.scope.has(name)) { | ||
| return true; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.has(name); | ||
| } | ||
| return false; | ||
| } | ||
| /** | ||
| * Set a variable's value (must already exist) | ||
| */ | ||
| set(name, value) { | ||
| const binding = this.findBinding(name); | ||
| if (binding) { | ||
| if (!binding.mutable) { | ||
| throw new Error(`Cannot assign to immutable variable: ${name}`); | ||
| } | ||
| binding.value = value; | ||
| } else { | ||
| this.define(name, value, true); | ||
| } | ||
| } | ||
| /** | ||
| * Define a new variable in the current scope | ||
| */ | ||
| define(name, value, mutable = false) { | ||
| this.scope.set(name, { name, value, mutable }); | ||
| } | ||
| /** | ||
| * Create a child scope | ||
| */ | ||
| child() { | ||
| return new _Scope(this); | ||
| } | ||
| /** | ||
| * Get all bindings from this scope (not including parent) | ||
| */ | ||
| bindings() { | ||
| return new Map(this.scope); | ||
| } | ||
| /** | ||
| * Find a binding in the scope chain | ||
| */ | ||
| findBinding(name) { | ||
| const binding = this.scope.get(name); | ||
| if (binding !== void 0) { | ||
| return binding; | ||
| } | ||
| if (this.parent) { | ||
| return this.parent.findBinding(name); | ||
| } | ||
| return void 0; | ||
| } | ||
| }; | ||
| var SnapshotEntityStore = class { | ||
| _snapshot; | ||
| constructor(snapshot) { | ||
| this._snapshot = snapshot; | ||
| } | ||
| getAll(entityName) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| return entities ? Array.from(entities.values()) : []; | ||
| } | ||
| exists(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities || entities.size === 0) return false; | ||
| if (!criteria) return entities.size > 0; | ||
| return Array.from(entities.values()).some( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ); | ||
| } | ||
| lookup(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities) return void 0; | ||
| return Array.from(entities.values()).find( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ); | ||
| } | ||
| count(entityName, criteria) { | ||
| const entities = this._snapshot.entities.get(entityName); | ||
| if (!entities) return 0; | ||
| if (!criteria) return entities.size; | ||
| return Array.from(entities.values()).filter( | ||
| (e) => Object.entries(criteria).every(([k, v]) => e[k] === v) | ||
| ).length; | ||
| } | ||
| create() { | ||
| throw new Error("Snapshot store is read-only: cannot create entities"); | ||
| } | ||
| update() { | ||
| throw new Error("Snapshot store is read-only: cannot update entities"); | ||
| } | ||
| delete() { | ||
| throw new Error("Snapshot store is read-only: cannot delete entities"); | ||
| } | ||
| snapshot() { | ||
| return this._snapshot; | ||
| } | ||
| restore() { | ||
| throw new Error("Cannot restore snapshot store"); | ||
| } | ||
| }; | ||
| function createScope(parent) { | ||
| return new Scope(parent); | ||
| } | ||
| // src/builtins.ts | ||
| var DefaultBuiltinRegistry = class { | ||
| builtins; | ||
| constructor() { | ||
| this.builtins = /* @__PURE__ */ new Map(); | ||
| this.registerDefaults(); | ||
| } | ||
| get(name) { | ||
| return this.builtins.get(name); | ||
| } | ||
| has(name) { | ||
| return this.builtins.has(name); | ||
| } | ||
| register(name, fn) { | ||
| this.builtins.set(name, fn); | ||
| } | ||
| list() { | ||
| return Array.from(this.builtins.keys()); | ||
| } | ||
| registerDefaults() { | ||
| this.register("now", builtinNow); | ||
| this.register("len", builtinLen); | ||
| this.register("length", builtinLen); | ||
| this.register("count", builtinCount); | ||
| this.register("sum", builtinSum); | ||
| this.register("min", builtinMin); | ||
| this.register("max", builtinMax); | ||
| this.register("avg", builtinAvg); | ||
| this.register("all", builtinAll); | ||
| this.register("forall", builtinAll); | ||
| this.register("any", builtinAny); | ||
| this.register("exists", builtinAny); | ||
| this.register("none", builtinNone); | ||
| this.register("filter", builtinFilter); | ||
| this.register("abs", builtinAbs); | ||
| this.register("round", builtinRound); | ||
| this.register("floor", builtinFloor); | ||
| this.register("ceil", builtinCeil); | ||
| this.register("sqrt", builtinSqrt); | ||
| this.register("pow", builtinPow); | ||
| this.register("concat", builtinConcat); | ||
| this.register("upper", builtinUpper); | ||
| this.register("lower", builtinLower); | ||
| this.register("trim", builtinTrim); | ||
| this.register("split", builtinSplit); | ||
| this.register("substring", builtinSubstring); | ||
| this.register("typeof", builtinTypeof); | ||
| this.register("isNull", builtinIsNull); | ||
| this.register("isNumber", builtinIsNumber); | ||
| this.register("isString", builtinIsString); | ||
| this.register("isArray", builtinIsArray); | ||
| this.register("toNumber", builtinToNumber); | ||
| this.register("toString", builtinToString); | ||
| this.register("toBoolean", builtinToBoolean); | ||
| this.register("implies", builtinImplies); | ||
| this.register("timing_safe_comparison", () => true); | ||
| this.register("never_appears_in", () => true); | ||
| } | ||
| }; | ||
| var builtinNow = (_args, context) => { | ||
| return context.now; | ||
| }; | ||
| var builtinLen = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (Array.isArray(value)) { | ||
| return value.length; | ||
| } | ||
| if (typeof value === "string") { | ||
| return value.length; | ||
| } | ||
| if (value instanceof Map) { | ||
| return value.size; | ||
| } | ||
| if (typeof value === "object" && value !== null) { | ||
| return Object.keys(value).length; | ||
| } | ||
| throw new TypeError( | ||
| `len() requires array, string, map, or object, got ${getValueType(value)}`, | ||
| location, | ||
| "array | string | map | object", | ||
| getValueType(value) | ||
| ); | ||
| }; | ||
| var builtinCount = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `count() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (predicate) { | ||
| return collection.filter(predicate).length; | ||
| } | ||
| return collection.length; | ||
| }; | ||
| var builtinSum = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const selector = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `sum() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (collection.length === 0) { | ||
| return 0; | ||
| } | ||
| if (selector) { | ||
| return collection.reduce((acc, item) => acc + selector(item), 0); | ||
| } | ||
| return collection.reduce((acc, item) => { | ||
| if (typeof item !== "number") { | ||
| throw new TypeError( | ||
| `sum() requires numeric array elements, got ${getValueType(item)}`, | ||
| location, | ||
| "number", | ||
| getValueType(item) | ||
| ); | ||
| } | ||
| return acc + item; | ||
| }, 0); | ||
| }; | ||
| var builtinMin = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| if (Array.isArray(collection)) { | ||
| if (collection.length === 0) { | ||
| return void 0; | ||
| } | ||
| return Math.min(...collection); | ||
| } | ||
| if (args.length > 1) { | ||
| return Math.min(...args); | ||
| } | ||
| throw new TypeError( | ||
| `min() requires array or multiple numbers`, | ||
| location, | ||
| "array | number[]", | ||
| getValueType(collection) | ||
| ); | ||
| }; | ||
| var builtinMax = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| if (Array.isArray(collection)) { | ||
| if (collection.length === 0) { | ||
| return void 0; | ||
| } | ||
| return Math.max(...collection); | ||
| } | ||
| if (args.length > 1) { | ||
| return Math.max(...args); | ||
| } | ||
| throw new TypeError( | ||
| `max() requires array or multiple numbers`, | ||
| location, | ||
| "array | number[]", | ||
| getValueType(collection) | ||
| ); | ||
| }; | ||
| var builtinAvg = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `avg() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (collection.length === 0) { | ||
| return void 0; | ||
| } | ||
| const sum = collection.reduce((acc, item) => { | ||
| if (typeof item !== "number") { | ||
| throw new TypeError( | ||
| `avg() requires numeric array elements`, | ||
| location, | ||
| "number", | ||
| getValueType(item) | ||
| ); | ||
| } | ||
| return acc + item; | ||
| }, 0); | ||
| return sum / collection.length; | ||
| }; | ||
| var builtinAll = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `all() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (!predicate) { | ||
| return collection.every(Boolean); | ||
| } | ||
| return collection.every(predicate); | ||
| }; | ||
| var builtinAny = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `any() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (!predicate) { | ||
| return collection.some(Boolean); | ||
| } | ||
| return collection.some(predicate); | ||
| }; | ||
| var builtinNone = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `none() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (!predicate) { | ||
| return !collection.some(Boolean); | ||
| } | ||
| return !collection.some(predicate); | ||
| }; | ||
| var builtinFilter = (args, _context, location) => { | ||
| const collection = args[0]; | ||
| const predicate = args[1]; | ||
| if (!Array.isArray(collection)) { | ||
| throw new TypeError( | ||
| `filter() requires array, got ${getValueType(collection)}`, | ||
| location, | ||
| "array", | ||
| getValueType(collection) | ||
| ); | ||
| } | ||
| if (!predicate) { | ||
| return collection.filter(Boolean); | ||
| } | ||
| return collection.filter(predicate); | ||
| }; | ||
| var builtinAbs = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `abs() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return Math.abs(value); | ||
| }; | ||
| var builtinRound = (args, _context, location) => { | ||
| const value = args[0]; | ||
| const decimals = args[1]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `round() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| if (decimals !== void 0) { | ||
| const factor = Math.pow(10, decimals); | ||
| return Math.round(value * factor) / factor; | ||
| } | ||
| return Math.round(value); | ||
| }; | ||
| var builtinFloor = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `floor() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return Math.floor(value); | ||
| }; | ||
| var builtinCeil = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `ceil() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return Math.ceil(value); | ||
| }; | ||
| var builtinSqrt = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "number") { | ||
| throw new TypeError( | ||
| `sqrt() requires number, got ${getValueType(value)}`, | ||
| location, | ||
| "number", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| if (value < 0) { | ||
| throw new RuntimeError( | ||
| `sqrt() of negative number: ${value}`, | ||
| location | ||
| ); | ||
| } | ||
| return Math.sqrt(value); | ||
| }; | ||
| var builtinPow = (args, _context, location) => { | ||
| const base = args[0]; | ||
| const exponent = args[1]; | ||
| if (typeof base !== "number" || typeof exponent !== "number") { | ||
| throw new TypeError( | ||
| `pow() requires two numbers`, | ||
| location, | ||
| "number, number", | ||
| `${getValueType(base)}, ${getValueType(exponent)}` | ||
| ); | ||
| } | ||
| return Math.pow(base, exponent); | ||
| }; | ||
| var builtinConcat = (args) => { | ||
| return args.map(String).join(""); | ||
| }; | ||
| var builtinUpper = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `upper() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.toUpperCase(); | ||
| }; | ||
| var builtinLower = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `lower() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.toLowerCase(); | ||
| }; | ||
| var builtinTrim = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `trim() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.trim(); | ||
| }; | ||
| var builtinSplit = (args, _context, location) => { | ||
| const value = args[0]; | ||
| const separator = args[1] ?? ""; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `split() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.split(separator); | ||
| }; | ||
| var builtinSubstring = (args, _context, location) => { | ||
| const value = args[0]; | ||
| const start = args[1]; | ||
| const end = args[2]; | ||
| if (typeof value !== "string") { | ||
| throw new TypeError( | ||
| `substring() requires string, got ${getValueType(value)}`, | ||
| location, | ||
| "string", | ||
| getValueType(value) | ||
| ); | ||
| } | ||
| return value.substring(start, end); | ||
| }; | ||
| var builtinTypeof = (args) => { | ||
| return getValueType(args[0]); | ||
| }; | ||
| var builtinIsNull = (args) => { | ||
| return args[0] === null || args[0] === void 0; | ||
| }; | ||
| var builtinIsNumber = (args) => { | ||
| return typeof args[0] === "number" && !isNaN(args[0]); | ||
| }; | ||
| var builtinIsString = (args) => { | ||
| return typeof args[0] === "string"; | ||
| }; | ||
| var builtinIsArray = (args) => { | ||
| return Array.isArray(args[0]); | ||
| }; | ||
| var builtinToNumber = (args, _context, location) => { | ||
| const value = args[0]; | ||
| if (typeof value === "number") return value; | ||
| if (typeof value === "string") { | ||
| const num = Number(value); | ||
| if (isNaN(num)) { | ||
| throw new RuntimeError( | ||
| `Cannot convert "${value}" to number`, | ||
| location | ||
| ); | ||
| } | ||
| return num; | ||
| } | ||
| if (typeof value === "boolean") return value ? 1 : 0; | ||
| throw new TypeError( | ||
| `Cannot convert ${getValueType(value)} to number`, | ||
| location, | ||
| "number | string | boolean", | ||
| getValueType(value) | ||
| ); | ||
| }; | ||
| var builtinToString = (args) => { | ||
| const value = args[0]; | ||
| if (value === null) return "null"; | ||
| if (value === void 0) return "undefined"; | ||
| if (typeof value === "object") return JSON.stringify(value); | ||
| return String(value); | ||
| }; | ||
| var builtinToBoolean = (args) => { | ||
| return Boolean(args[0]); | ||
| }; | ||
| var builtinImplies = (args) => { | ||
| const a = Boolean(args[0]); | ||
| const b = Boolean(args[1]); | ||
| return !a || b; | ||
| }; | ||
| function createBuiltinRegistry() { | ||
| return new DefaultBuiltinRegistry(); | ||
| } | ||
| var defaultRegistry = null; | ||
| function getDefaultBuiltins() { | ||
| if (!defaultRegistry) { | ||
| defaultRegistry = createBuiltinRegistry(); | ||
| } | ||
| return defaultRegistry; | ||
| } | ||
| // src/evaluator.ts | ||
| var Evaluator = class { | ||
| builtins; | ||
| strict; | ||
| maxDepth; | ||
| currentDepth = 0; | ||
| startTime = 0; | ||
| timeout; | ||
| constructor(options = {}) { | ||
| this.builtins = options.builtins ?? getDefaultBuiltins(); | ||
| this.strict = options.strict ?? true; | ||
| this.maxDepth = options.maxDepth ?? 1e3; | ||
| this.timeout = options.timeout ?? 5e3; | ||
| } | ||
| /** | ||
| * Evaluate an expression in the given context | ||
| */ | ||
| evaluate(expr, context) { | ||
| this.startTime = Date.now(); | ||
| this.currentDepth = 0; | ||
| return this.eval(expr, context); | ||
| } | ||
| // ============================================================================ | ||
| // MAIN DISPATCH | ||
| // ============================================================================ | ||
| eval(expr, ctx) { | ||
| if (++this.currentDepth > this.maxDepth) { | ||
| throw new RuntimeError( | ||
| `Maximum recursion depth exceeded (${this.maxDepth})`, | ||
| expr.location | ||
| ); | ||
| } | ||
| if (Date.now() - this.startTime > this.timeout) { | ||
| throw new RuntimeError( | ||
| `Evaluation timeout exceeded (${this.timeout}ms)`, | ||
| expr.location | ||
| ); | ||
| } | ||
| try { | ||
| switch (expr.kind) { | ||
| case "Identifier": | ||
| return this.evalIdentifier(expr, ctx); | ||
| case "QualifiedName": | ||
| return this.evalQualifiedName(expr, ctx); | ||
| case "StringLiteral": | ||
| return expr.value; | ||
| case "NumberLiteral": | ||
| return expr.value; | ||
| case "BooleanLiteral": | ||
| return expr.value; | ||
| case "NullLiteral": | ||
| return null; | ||
| case "DurationLiteral": | ||
| return this.evalDuration(expr); | ||
| case "RegexLiteral": | ||
| return new RegExp(expr.pattern, expr.flags); | ||
| case "BinaryExpr": | ||
| return this.evalBinaryExpr(expr, ctx); | ||
| case "UnaryExpr": | ||
| return this.evalUnaryExpr(expr, ctx); | ||
| case "CallExpr": | ||
| return this.evalCallExpr(expr, ctx); | ||
| case "MemberExpr": | ||
| return this.evalMemberExpr(expr, ctx); | ||
| case "OptionalMemberExpr": | ||
| return this.evalOptionalMemberExpr(expr, ctx); | ||
| case "IndexExpr": | ||
| return this.evalIndexExpr(expr, ctx); | ||
| case "QuantifierExpr": | ||
| return this.evalQuantifierExpr(expr, ctx); | ||
| case "ConditionalExpr": | ||
| return this.evalConditionalExpr(expr, ctx); | ||
| case "OldExpr": | ||
| return this.evalOldExpr(expr, ctx); | ||
| case "ResultExpr": | ||
| return this.evalResultExpr(expr, ctx); | ||
| case "InputExpr": | ||
| return this.evalInputExpr(expr, ctx); | ||
| case "LambdaExpr": | ||
| return this.evalLambdaExpr(expr, ctx); | ||
| case "ListExpr": | ||
| return expr.elements.map((el) => this.eval(el, ctx)); | ||
| case "MapExpr": | ||
| return this.evalMapExpr(expr, ctx); | ||
| default: { | ||
| const unknownExpr = expr; | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_UNSUPPORTED_EXPR" /* EVAL_UNSUPPORTED_EXPR */, | ||
| message: `Unsupported expression kind: ${unknownExpr.kind}`, | ||
| span: unknownExpr.location, | ||
| subExpression: `<${unknownExpr.kind}>` | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| throw new EvaluationError( | ||
| `Unsupported expression kind: ${unknownExpr.kind}`, | ||
| unknownExpr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| } finally { | ||
| this.currentDepth--; | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // IDENTIFIER EVALUATION | ||
| // ============================================================================ | ||
| evalIdentifier(expr, ctx) { | ||
| const name = expr.name; | ||
| if (name === "result") return ctx.result; | ||
| if (name === "input") return ctx.input; | ||
| if (name === "now") return ctx.now; | ||
| if (name === "true") return true; | ||
| if (name === "false") return false; | ||
| if (name === "null") return null; | ||
| if (name === "undefined") return void 0; | ||
| if (ctx.variables.has(name)) { | ||
| return ctx.variables.get(name); | ||
| } | ||
| if (ctx.domain?.entities.some((e) => e.name === name)) { | ||
| return this.createEntityProxy(name, ctx.store); | ||
| } | ||
| if (name in ctx.input) { | ||
| return ctx.input[name]; | ||
| } | ||
| if (this.builtins.has(name)) { | ||
| return ((...args) => this.builtins.get(name)(args, ctx, expr.location)); | ||
| } | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_UNDEFINED_VAR" /* EVAL_UNDEFINED_VAR */, | ||
| message: `Unknown identifier: '${name}'`, | ||
| span: expr.location, | ||
| subExpression: name | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| throw new ReferenceError( | ||
| `Unknown identifier: ${name}`, | ||
| expr.location, | ||
| name, | ||
| expr | ||
| ); | ||
| } | ||
| evalQualifiedName(expr, ctx) { | ||
| const parts = expr.parts; | ||
| let value = this.evalIdentifier(parts[0], ctx); | ||
| for (let i = 1; i < parts.length; i++) { | ||
| const part = parts[i].name; | ||
| if (value === null || value === void 0) { | ||
| if (this.strict) { | ||
| const resolvedPath = parts.slice(0, i).map((p) => p.name).join("."); | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_NULL_DEREF" /* EVAL_NULL_DEREF */, | ||
| message: `Cannot access property '${part}' on ${value === null ? "null" : "undefined"} (in path '${resolvedPath}.${part}')`, | ||
| span: expr.location, | ||
| subExpression: parts.map((p) => p.name).join(".") | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| value = value[part]; | ||
| } | ||
| return value; | ||
| } | ||
| // ============================================================================ | ||
| // ENTITY PROXY | ||
| // ============================================================================ | ||
| createEntityProxy(entityName, store) { | ||
| return { | ||
| __entityName__: entityName, | ||
| __isProxy__: true, | ||
| exists: (criteria) => store.exists(entityName, criteria), | ||
| lookup: (criteria) => store.lookup(entityName, criteria), | ||
| count: (criteria) => store.count(entityName, criteria), | ||
| getAll: () => store.getAll(entityName) | ||
| }; | ||
| } | ||
| // ============================================================================ | ||
| // BINARY EXPRESSIONS | ||
| // ============================================================================ | ||
| evalBinaryExpr(expr, ctx) { | ||
| if (expr.operator === "and") { | ||
| const left2 = this.eval(expr.left, ctx); | ||
| if (!left2) return false; | ||
| return Boolean(this.eval(expr.right, ctx)); | ||
| } | ||
| if (expr.operator === "or") { | ||
| const left2 = this.eval(expr.left, ctx); | ||
| if (left2) return true; | ||
| return Boolean(this.eval(expr.right, ctx)); | ||
| } | ||
| if (expr.operator === "implies") { | ||
| const left2 = this.eval(expr.left, ctx); | ||
| if (!left2) return true; | ||
| return Boolean(this.eval(expr.right, ctx)); | ||
| } | ||
| const left = this.eval(expr.left, ctx); | ||
| const right = this.eval(expr.right, ctx); | ||
| switch (expr.operator) { | ||
| case "==": | ||
| return this.deepEqual(left, right); | ||
| case "!=": | ||
| return !this.deepEqual(left, right); | ||
| case "<": | ||
| this.assertNumbers(left, right, expr.location, "<"); | ||
| return left < right; | ||
| case ">": | ||
| this.assertNumbers(left, right, expr.location, ">"); | ||
| return left > right; | ||
| case "<=": | ||
| this.assertNumbers(left, right, expr.location, "<="); | ||
| return left <= right; | ||
| case ">=": | ||
| this.assertNumbers(left, right, expr.location, ">="); | ||
| return left >= right; | ||
| case "+": | ||
| if (typeof left === "string" || typeof right === "string") { | ||
| return String(left) + String(right); | ||
| } | ||
| this.assertNumbers(left, right, expr.location, "+"); | ||
| return left + right; | ||
| case "-": | ||
| this.assertNumbers(left, right, expr.location, "-"); | ||
| return left - right; | ||
| case "*": | ||
| this.assertNumbers(left, right, expr.location, "*"); | ||
| return left * right; | ||
| case "/": | ||
| this.assertNumbers(left, right, expr.location, "/"); | ||
| if (right === 0) { | ||
| throw new RuntimeError("Division by zero", expr.location); | ||
| } | ||
| return left / right; | ||
| case "%": | ||
| this.assertNumbers(left, right, expr.location, "%"); | ||
| if (right === 0) { | ||
| throw new RuntimeError("Modulo by zero", expr.location); | ||
| } | ||
| return left % right; | ||
| case "iff": | ||
| return Boolean(left) === Boolean(right); | ||
| case "in": | ||
| if (Array.isArray(right)) { | ||
| return right.some((item) => this.deepEqual(item, left)); | ||
| } | ||
| if (typeof right === "object" && right !== null) { | ||
| return String(left) in right; | ||
| } | ||
| if (typeof right === "string" && typeof left === "string") { | ||
| return right.includes(left); | ||
| } | ||
| return false; | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown binary operator: ${expr.operator}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // UNARY EXPRESSIONS | ||
| // ============================================================================ | ||
| evalUnaryExpr(expr, ctx) { | ||
| const operand = this.eval(expr.operand, ctx); | ||
| switch (expr.operator) { | ||
| case "not": | ||
| return !operand; | ||
| case "-": | ||
| if (typeof operand !== "number") { | ||
| throw new TypeError( | ||
| `Unary minus requires number, got ${getValueType(operand)}`, | ||
| expr.location, | ||
| "number", | ||
| getValueType(operand), | ||
| expr | ||
| ); | ||
| } | ||
| return -operand; | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown unary operator: ${expr.operator}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // CALL EXPRESSIONS | ||
| // ============================================================================ | ||
| evalCallExpr(expr, ctx) { | ||
| const callee = expr.callee; | ||
| if (callee.kind === "MemberExpr") { | ||
| const obj = this.eval(callee.object, ctx); | ||
| const method = callee.property.name; | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| if (isEntityProxy(obj)) { | ||
| return this.handleEntityMethod(obj, method, args, expr); | ||
| } | ||
| if (Array.isArray(obj)) { | ||
| return this.handleArrayMethod(obj, method, args, expr, ctx); | ||
| } | ||
| if (typeof obj === "string") { | ||
| return this.handleStringMethod(obj, method, args, expr); | ||
| } | ||
| if (typeof obj === "object" && obj !== null) { | ||
| const fn2 = obj[method]; | ||
| if (typeof fn2 === "function") { | ||
| return fn2.apply(obj, args); | ||
| } | ||
| } | ||
| throw new EvaluationError( | ||
| `Cannot call method ${method} on ${getValueType(obj)}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| if (callee.kind === "Identifier") { | ||
| const name = callee.name; | ||
| if (this.builtins.has(name)) { | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| return this.builtins.get(name)(args, ctx, expr.location); | ||
| } | ||
| if (ctx.variables.has(name)) { | ||
| const fn2 = ctx.variables.get(name); | ||
| if (typeof fn2 === "function") { | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| return fn2(...args); | ||
| } | ||
| if (isLambdaValue(fn2)) { | ||
| return this.callLambda(fn2, expr, ctx); | ||
| } | ||
| } | ||
| throw new ReferenceError( | ||
| `Unknown function: ${name}`, | ||
| expr.location, | ||
| name, | ||
| expr | ||
| ); | ||
| } | ||
| const fn = this.eval(callee, ctx); | ||
| if (typeof fn === "function") { | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| return fn(...args); | ||
| } | ||
| if (isLambdaValue(fn)) { | ||
| return this.callLambda(fn, expr, ctx); | ||
| } | ||
| throw new EvaluationError( | ||
| `Cannot call non-function: ${getValueType(fn)}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| callLambda(lambda, expr, ctx) { | ||
| const args = expr.arguments.map((arg) => this.eval(arg, ctx)); | ||
| const newVars = new Map(lambda.closure.bindings()); | ||
| lambda.params.forEach((param, i) => { | ||
| newVars.set(param, { name: param, value: args[i], mutable: false }); | ||
| }); | ||
| const newCtx = { | ||
| ...ctx, | ||
| variables: new Map( | ||
| Array.from(newVars.entries()).map(([k, v]) => [k, v.value]) | ||
| ) | ||
| }; | ||
| return this.eval(lambda.body, newCtx); | ||
| } | ||
| handleEntityMethod(entity, method, args, expr) { | ||
| switch (method) { | ||
| case "exists": | ||
| if (args.length === 0) return entity.exists(); | ||
| return entity.exists(args[0]); | ||
| case "lookup": | ||
| return entity.lookup(args[0]); | ||
| case "count": | ||
| if (args.length === 0) return entity.count(); | ||
| return entity.count(args[0]); | ||
| case "getAll": | ||
| case "all": | ||
| return entity.getAll(); | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown entity method: ${entity.__entityName__}.${method}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| handleArrayMethod(array, method, args, expr, ctx) { | ||
| switch (method) { | ||
| case "length": | ||
| return array.length; | ||
| case "includes": | ||
| case "contains": | ||
| return array.some((item) => this.deepEqual(item, args[0])); | ||
| case "indexOf": | ||
| return array.findIndex((item) => this.deepEqual(item, args[0])); | ||
| case "map": | ||
| if (typeof args[0] === "function") { | ||
| return array.map(args[0]); | ||
| } | ||
| if (isLambdaValue(args[0])) { | ||
| const lambda = args[0]; | ||
| return array.map((item) => { | ||
| const newVars = new Map(ctx.variables); | ||
| newVars.set(lambda.params[0], item); | ||
| return this.eval(lambda.body, { ...ctx, variables: newVars }); | ||
| }); | ||
| } | ||
| throw new TypeError( | ||
| "map() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "filter": | ||
| if (typeof args[0] === "function") { | ||
| return array.filter(args[0]); | ||
| } | ||
| if (isLambdaValue(args[0])) { | ||
| const lambda = args[0]; | ||
| return array.filter((item) => { | ||
| const newVars = new Map(ctx.variables); | ||
| newVars.set(lambda.params[0], item); | ||
| return Boolean(this.eval(lambda.body, { ...ctx, variables: newVars })); | ||
| }); | ||
| } | ||
| throw new TypeError( | ||
| "filter() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "find": | ||
| if (typeof args[0] === "function") { | ||
| return array.find(args[0]) ?? null; | ||
| } | ||
| throw new TypeError( | ||
| "find() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "every": | ||
| if (typeof args[0] === "function") { | ||
| return array.every(args[0]); | ||
| } | ||
| throw new TypeError( | ||
| "every() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "some": | ||
| if (typeof args[0] === "function") { | ||
| return array.some(args[0]); | ||
| } | ||
| throw new TypeError( | ||
| "some() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "reduce": | ||
| if (typeof args[0] === "function") { | ||
| return array.reduce( | ||
| args[0], | ||
| args[1] ?? 0 | ||
| ); | ||
| } | ||
| throw new TypeError( | ||
| "reduce() requires a function", | ||
| expr.location, | ||
| "function", | ||
| getValueType(args[0]) | ||
| ); | ||
| case "first": | ||
| return array[0] ?? null; | ||
| case "last": | ||
| return array[array.length - 1] ?? null; | ||
| case "slice": | ||
| return array.slice( | ||
| args[0], | ||
| args[1] | ||
| ); | ||
| case "concat": | ||
| if (Array.isArray(args[0])) { | ||
| return [...array, ...args[0]]; | ||
| } | ||
| return [...array, args[0]]; | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown array method: ${method}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| handleStringMethod(str, method, args, expr) { | ||
| switch (method) { | ||
| case "length": | ||
| return str.length; | ||
| case "includes": | ||
| case "contains": | ||
| return str.includes(args[0]); | ||
| case "startsWith": | ||
| return str.startsWith(args[0]); | ||
| case "endsWith": | ||
| return str.endsWith(args[0]); | ||
| case "toLowerCase": | ||
| case "lower": | ||
| return str.toLowerCase(); | ||
| case "toUpperCase": | ||
| case "upper": | ||
| return str.toUpperCase(); | ||
| case "trim": | ||
| return str.trim(); | ||
| case "trimStart": | ||
| return str.trimStart(); | ||
| case "trimEnd": | ||
| return str.trimEnd(); | ||
| case "split": | ||
| return str.split(args[0]); | ||
| case "substring": | ||
| case "substr": | ||
| return str.substring( | ||
| args[0], | ||
| args[1] | ||
| ); | ||
| case "replace": | ||
| return str.replace( | ||
| args[0], | ||
| args[1] | ||
| ); | ||
| case "replaceAll": | ||
| return str.split(args[0]).join(args[1]); | ||
| case "match": | ||
| case "matches": | ||
| if (args[0] instanceof RegExp) { | ||
| return args[0].test(str); | ||
| } | ||
| return new RegExp(args[0]).test(str); | ||
| case "indexOf": | ||
| return str.indexOf(args[0]); | ||
| case "charAt": | ||
| return str.charAt(args[0]); | ||
| case "is_valid": | ||
| case "isValid": | ||
| return str.length > 0; | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown string method: ${method}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // MEMBER EXPRESSIONS | ||
| // ============================================================================ | ||
| evalMemberExpr(expr, ctx) { | ||
| const object = this.eval(expr.object, ctx); | ||
| const property = expr.property.name; | ||
| if (object === null || object === void 0) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_NULL_DEREF" /* EVAL_NULL_DEREF */, | ||
| message: `Cannot access property '${property}' on ${object === null ? "null" : "undefined"}`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| if (isEntityProxy(object)) { | ||
| switch (property) { | ||
| case "exists": | ||
| return ((criteria) => object.exists(criteria)); | ||
| case "lookup": | ||
| return ((criteria) => object.lookup(criteria)); | ||
| case "count": | ||
| return ((criteria) => object.count(criteria)); | ||
| case "getAll": | ||
| case "all": | ||
| return (() => object.getAll()); | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown entity property: ${object.__entityName__}.${property}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| if (Array.isArray(object) && property === "length") { | ||
| return object.length; | ||
| } | ||
| if (typeof object === "string" && property === "length") { | ||
| return object.length; | ||
| } | ||
| return object[property]; | ||
| } | ||
| // ============================================================================ | ||
| // OPTIONAL MEMBER EXPRESSIONS | ||
| // ============================================================================ | ||
| evalOptionalMemberExpr(expr, ctx) { | ||
| const object = this.eval(expr.object, ctx); | ||
| const property = expr.property.name; | ||
| if (object === null || object === void 0) { | ||
| return void 0; | ||
| } | ||
| if (typeof object !== "object" && typeof object !== "string") { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_OPTIONAL_CHAIN_NON_OBJECT" /* EVAL_OPTIONAL_CHAIN_NON_OBJECT */, | ||
| message: `Optional chaining (?.) requires object or null/undefined, got '${getValueType(object)}'`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| if (isEntityProxy(object)) { | ||
| switch (property) { | ||
| case "exists": | ||
| return ((criteria) => object.exists(criteria)); | ||
| case "lookup": | ||
| return ((criteria) => object.lookup(criteria)); | ||
| case "count": | ||
| return ((criteria) => object.count(criteria)); | ||
| case "getAll": | ||
| case "all": | ||
| return (() => object.getAll()); | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown entity property: ${object.__entityName__}.${property}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| if (Array.isArray(object) && property === "length") { | ||
| return object.length; | ||
| } | ||
| if (typeof object === "string" && property === "length") { | ||
| return object.length; | ||
| } | ||
| return object[property]; | ||
| } | ||
| // ============================================================================ | ||
| // INDEX EXPRESSIONS | ||
| // ============================================================================ | ||
| evalIndexExpr(expr, ctx) { | ||
| const object = this.eval(expr.object, ctx); | ||
| const index = this.eval(expr.index, ctx); | ||
| if (object === null || object === void 0) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_NULL_DEREF" /* EVAL_NULL_DEREF */, | ||
| message: `Cannot index into ${object === null ? "null" : "undefined"}`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| if (Array.isArray(object)) { | ||
| const idx = index; | ||
| if (idx < 0 || idx >= object.length) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_OOB_INDEX" /* EVAL_OOB_INDEX */, | ||
| message: `Index ${idx} is out of bounds for array of length ${object.length}`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| return object[idx]; | ||
| } | ||
| if (typeof object === "string") { | ||
| const idx = index; | ||
| if (idx < 0 || idx >= object.length) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_OOB_INDEX" /* EVAL_OOB_INDEX */, | ||
| message: `Index ${idx} is out of bounds for string of length ${object.length}`, | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| return void 0; | ||
| } | ||
| return object[idx]; | ||
| } | ||
| if (typeof object === "object") { | ||
| return object[String(index)]; | ||
| } | ||
| throw new TypeError( | ||
| `Cannot index ${getValueType(object)}`, | ||
| expr.location, | ||
| "array | string | object", | ||
| getValueType(object), | ||
| expr | ||
| ); | ||
| } | ||
| // ============================================================================ | ||
| // QUANTIFIER EXPRESSIONS | ||
| // ============================================================================ | ||
| evalQuantifierExpr(expr, ctx) { | ||
| const collection = this.eval(expr.collection, ctx); | ||
| const variable = expr.variable.name; | ||
| let items; | ||
| if (isEntityProxy(collection)) { | ||
| items = collection.getAll(); | ||
| } else if (Array.isArray(collection)) { | ||
| items = collection; | ||
| } else { | ||
| throw new TypeError( | ||
| `Quantifier requires array or entity, got ${getValueType(collection)}`, | ||
| expr.location, | ||
| "array | entity", | ||
| getValueType(collection), | ||
| expr | ||
| ); | ||
| } | ||
| const evalPredicate = (item) => { | ||
| const newVars = new Map(ctx.variables); | ||
| newVars.set(variable, item); | ||
| const result = this.eval(expr.predicate, { ...ctx, variables: newVars }); | ||
| return Boolean(result); | ||
| }; | ||
| switch (expr.quantifier) { | ||
| case "all": | ||
| return items.every(evalPredicate); | ||
| case "any": | ||
| return items.some(evalPredicate); | ||
| case "none": | ||
| return !items.some(evalPredicate); | ||
| case "count": | ||
| return items.filter(evalPredicate).length; | ||
| case "sum": { | ||
| const evalValue = (item) => { | ||
| const newVars = new Map(ctx.variables); | ||
| newVars.set(variable, item); | ||
| const result = this.eval(expr.predicate, { ...ctx, variables: newVars }); | ||
| if (typeof result !== "number") { | ||
| throw new TypeError( | ||
| `sum quantifier requires numeric predicate result`, | ||
| expr.location, | ||
| "number", | ||
| getValueType(result), | ||
| expr | ||
| ); | ||
| } | ||
| return result; | ||
| }; | ||
| return items.reduce((acc, item) => acc + evalValue(item), 0); | ||
| } | ||
| case "filter": | ||
| return items.filter(evalPredicate); | ||
| default: | ||
| throw new EvaluationError( | ||
| `Unknown quantifier: ${expr.quantifier}`, | ||
| expr.location, | ||
| expr | ||
| ); | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // SPECIAL EXPRESSIONS | ||
| // ============================================================================ | ||
| evalConditionalExpr(expr, ctx) { | ||
| const condition = this.eval(expr.condition, ctx); | ||
| return condition ? this.eval(expr.thenBranch, ctx) : this.eval(expr.elseBranch, ctx); | ||
| } | ||
| evalOldExpr(expr, ctx) { | ||
| if (!ctx.oldState) { | ||
| if (this.strict) { | ||
| throw new DiagnosticError( | ||
| { | ||
| code: "EVAL_MISSING_OLD_STATE" /* EVAL_MISSING_OLD_STATE */, | ||
| message: "old() called without previous state snapshot", | ||
| span: expr.location, | ||
| subExpression: expressionToString(expr) | ||
| }, | ||
| expr | ||
| ); | ||
| } | ||
| throw new RuntimeError( | ||
| "old() called without previous state snapshot", | ||
| expr.location | ||
| ); | ||
| } | ||
| const oldStore = new SnapshotEntityStore(ctx.oldState); | ||
| const oldCtx = { | ||
| ...ctx, | ||
| store: oldStore | ||
| }; | ||
| try { | ||
| return this.eval(expr.expression, oldCtx); | ||
| } catch (error) { | ||
| if (this.strict && error instanceof DiagnosticError) { | ||
| throw DiagnosticError.wrap( | ||
| "EVAL_OLD_NESTED_FAIL" /* EVAL_OLD_NESTED_FAIL */, | ||
| `Nested path resolution failed inside old(): ${error.message}`, | ||
| expr.location, | ||
| expressionToString(expr), | ||
| error, | ||
| expr | ||
| ); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| evalResultExpr(expr, ctx) { | ||
| if (expr.property) { | ||
| if (ctx.result === null || ctx.result === void 0) { | ||
| return void 0; | ||
| } | ||
| return ctx.result[expr.property.name]; | ||
| } | ||
| return ctx.result; | ||
| } | ||
| evalInputExpr(expr, ctx) { | ||
| return ctx.input[expr.property.name]; | ||
| } | ||
| evalLambdaExpr(expr, ctx) { | ||
| const closure = createScope(); | ||
| for (const [name, value] of ctx.variables) { | ||
| closure.define(name, value); | ||
| } | ||
| const lambda = { | ||
| __type__: "lambda", | ||
| params: expr.params.map((p) => p.name), | ||
| body: expr.body, | ||
| closure | ||
| }; | ||
| return lambda; | ||
| } | ||
| evalMapExpr(expr, ctx) { | ||
| const result = {}; | ||
| for (const entry of expr.entries) { | ||
| const key = this.eval(entry.key, ctx); | ||
| const value = this.eval(entry.value, ctx); | ||
| result[String(key)] = value; | ||
| } | ||
| return result; | ||
| } | ||
| evalDuration(expr) { | ||
| const value = expr.value; | ||
| switch (expr.unit) { | ||
| case "ms": | ||
| return value; | ||
| case "seconds": | ||
| return value * 1e3; | ||
| case "minutes": | ||
| return value * 60 * 1e3; | ||
| case "hours": | ||
| return value * 60 * 60 * 1e3; | ||
| case "days": | ||
| return value * 24 * 60 * 60 * 1e3; | ||
| } | ||
| } | ||
| // ============================================================================ | ||
| // UTILITIES | ||
| // ============================================================================ | ||
| assertNumbers(left, right, location, operator) { | ||
| if (typeof left !== "number" || typeof right !== "number") { | ||
| throw new TypeError( | ||
| `Operator '${operator}' requires numbers, got ${getValueType(left)} and ${getValueType(right)}`, | ||
| location, | ||
| "number", | ||
| `${getValueType(left)}, ${getValueType(right)}` | ||
| ); | ||
| } | ||
| } | ||
| deepEqual(a, b) { | ||
| if (a === b) return true; | ||
| if (a === null || b === null) return a === b; | ||
| if (typeof a !== typeof b) return false; | ||
| if (a instanceof Date && b instanceof Date) { | ||
| return a.getTime() === b.getTime(); | ||
| } | ||
| if (Array.isArray(a) && Array.isArray(b)) { | ||
| if (a.length !== b.length) return false; | ||
| return a.every((val, i) => this.deepEqual(val, b[i])); | ||
| } | ||
| if (typeof a === "object" && typeof b === "object") { | ||
| const keysA = Object.keys(a); | ||
| const keysB = Object.keys(b); | ||
| if (keysA.length !== keysB.length) return false; | ||
| return keysA.every( | ||
| (key) => this.deepEqual( | ||
| a[key], | ||
| b[key] | ||
| ) | ||
| ); | ||
| } | ||
| return false; | ||
| } | ||
| }; | ||
| function isEntityProxy(value) { | ||
| return typeof value === "object" && value !== null && "__isProxy__" in value && value.__isProxy__ === true; | ||
| } | ||
| function evaluate(expr, context, options) { | ||
| const evaluator = new Evaluator(options); | ||
| return evaluator.evaluate(expr, context); | ||
| } | ||
| function expressionToString(expr) { | ||
| const e = expr; | ||
| switch (e.kind) { | ||
| case "Identifier": | ||
| return e.name; | ||
| case "QualifiedName": | ||
| return e.parts.map((p) => p.name).join("."); | ||
| case "StringLiteral": | ||
| return JSON.stringify(e.value); | ||
| case "NumberLiteral": | ||
| return String(e.value); | ||
| case "BooleanLiteral": | ||
| return String(e.value); | ||
| case "NullLiteral": | ||
| return "null"; | ||
| case "DurationLiteral": | ||
| return `${e.value}${e.unit}`; | ||
| case "RegexLiteral": | ||
| return `/${e.pattern}/${e.flags}`; | ||
| case "BinaryExpr": | ||
| return `(${expressionToString(e.left)} ${e.operator} ${expressionToString(e.right)})`; | ||
| case "UnaryExpr": | ||
| return `${e.operator}(${expressionToString(e.operand)})`; | ||
| case "CallExpr": | ||
| return `${expressionToString(e.callee)}(${e.arguments.map(expressionToString).join(", ")})`; | ||
| case "MemberExpr": | ||
| return `${expressionToString(e.object)}.${e.property.name}`; | ||
| case "OptionalMemberExpr": | ||
| return `${expressionToString(e.object)}?.${e.property.name}`; | ||
| case "IndexExpr": | ||
| return `${expressionToString(e.object)}[${expressionToString(e.index)}]`; | ||
| case "OldExpr": | ||
| return `old(${expressionToString(e.expression)})`; | ||
| case "ResultExpr": | ||
| return e.property ? `result.${e.property.name}` : "result"; | ||
| case "InputExpr": | ||
| return `input.${e.property.name}`; | ||
| case "QuantifierExpr": | ||
| return `${e.quantifier} ${e.variable.name} in ${expressionToString(e.collection)}: ${expressionToString(e.predicate)}`; | ||
| case "ConditionalExpr": | ||
| return `${expressionToString(e.condition)} ? ${expressionToString(e.thenBranch)} : ${expressionToString(e.elseBranch)}`; | ||
| case "LambdaExpr": | ||
| return `(${e.params.map((p) => p.name).join(", ")}) => ${expressionToString(e.body)}`; | ||
| case "ListExpr": | ||
| return `[${e.elements.map(expressionToString).join(", ")}]`; | ||
| case "MapExpr": | ||
| return `{${e.entries.map((entry) => `${expressionToString(entry.key)}: ${expressionToString(entry.value)}`).join(", ")}}`; | ||
| default: | ||
| return `<${e.kind}>`; | ||
| } | ||
| } | ||
| export { Evaluator, evaluate, expressionToString }; | ||
| //# sourceMappingURL=evaluator.js.map | ||
| //# sourceMappingURL=evaluator.js.map |
Sorry, the diff of this file is too big to display
| /** | ||
| * Source location information for error reporting | ||
| */ | ||
| interface SourceLocation { | ||
| file: string; | ||
| line: number; | ||
| column: number; | ||
| endLine: number; | ||
| endColumn: number; | ||
| } | ||
| /** | ||
| * Base interface for AST nodes (re-exported for standalone use) | ||
| */ | ||
| interface ASTNode { | ||
| kind: string; | ||
| location: SourceLocation; | ||
| } | ||
| /** | ||
| * All possible runtime values in ISL | ||
| */ | ||
| type Value = null | undefined | boolean | number | string | Date | RegExp | unknown[] | Map<string, unknown> | Record<string, unknown> | EntityInstance | LambdaValue; | ||
| /** | ||
| * Represents a lambda/function value | ||
| */ | ||
| interface LambdaValue { | ||
| __type__: 'lambda'; | ||
| params: string[]; | ||
| body: unknown; | ||
| closure: Environment; | ||
| } | ||
| /** | ||
| * Represents an entity instance | ||
| */ | ||
| interface EntityInstance { | ||
| __entity__: string; | ||
| __id__: string; | ||
| [key: string]: unknown; | ||
| } | ||
| /** | ||
| * Variable binding in the environment | ||
| */ | ||
| interface Binding { | ||
| name: string; | ||
| value: Value; | ||
| mutable: boolean; | ||
| } | ||
| /** | ||
| * Environment interface for scope management | ||
| */ | ||
| interface Environment { | ||
| /** Get a variable's value */ | ||
| get(name: string): Value; | ||
| /** Check if a variable exists */ | ||
| has(name: string): boolean; | ||
| /** Set a variable's value */ | ||
| set(name: string, value: Value): void; | ||
| /** Define a new variable */ | ||
| define(name: string, value: Value, mutable?: boolean): void; | ||
| /** Create a child scope */ | ||
| child(): Environment; | ||
| /** Get all bindings */ | ||
| bindings(): Map<string, Binding>; | ||
| } | ||
| /** | ||
| * Entity store for managing entity instances | ||
| */ | ||
| interface EntityStore { | ||
| /** Get all instances of an entity type */ | ||
| getAll(entityName: string): EntityInstance[]; | ||
| /** Check if an entity with given criteria exists */ | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| /** Lookup single entity by criteria */ | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| /** Count entities matching criteria */ | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| /** Create a new entity instance */ | ||
| create(entityName: string, data: Record<string, unknown>): EntityInstance; | ||
| /** Update an entity instance */ | ||
| update(entityName: string, id: string, data: Record<string, unknown>): void; | ||
| /** Delete an entity instance */ | ||
| delete(entityName: string, id: string): void; | ||
| /** Take a snapshot of current state */ | ||
| snapshot(): EntityStoreSnapshot; | ||
| /** Restore from a snapshot */ | ||
| restore(snapshot: EntityStoreSnapshot): void; | ||
| } | ||
| /** | ||
| * Snapshot of entity store state (for old() expressions) | ||
| */ | ||
| interface EntityStoreSnapshot { | ||
| entities: Map<string, Map<string, EntityInstance>>; | ||
| timestamp: number; | ||
| } | ||
| /** | ||
| * Domain definition (simplified for evaluator needs) | ||
| */ | ||
| interface DomainDef { | ||
| name: string; | ||
| entities: EntityDef[]; | ||
| types?: TypeDef[]; | ||
| } | ||
| interface EntityDef { | ||
| name: string; | ||
| fields?: FieldDef[] | unknown[]; | ||
| } | ||
| interface TypeDef { | ||
| name: string; | ||
| definition?: unknown; | ||
| } | ||
| interface FieldDef { | ||
| name: string; | ||
| type?: unknown; | ||
| optional?: boolean; | ||
| } | ||
| /** | ||
| * Context for expression evaluation | ||
| */ | ||
| interface EvaluationContext { | ||
| /** Current input values */ | ||
| input: Record<string, unknown>; | ||
| /** Result of behavior execution (for postconditions) */ | ||
| result?: unknown; | ||
| /** Error if behavior failed */ | ||
| error?: EvaluationErrorInfo; | ||
| /** Entity store for lookups */ | ||
| store: EntityStore; | ||
| /** Snapshot of state before execution (for old() expressions) */ | ||
| oldState?: EntityStoreSnapshot; | ||
| /** Domain definition for type information */ | ||
| domain?: DomainDef; | ||
| /** Current timestamp for now() */ | ||
| now: Date; | ||
| /** Variables in scope */ | ||
| variables: Map<string, unknown>; | ||
| } | ||
| /** | ||
| * Error information during evaluation | ||
| */ | ||
| interface EvaluationErrorInfo { | ||
| code: string; | ||
| message: string; | ||
| retriable: boolean; | ||
| details?: Record<string, unknown>; | ||
| } | ||
| /** | ||
| * Structured evaluation error with source location | ||
| */ | ||
| declare class EvaluationError extends Error { | ||
| readonly location: SourceLocation; | ||
| readonly expression?: unknown | undefined; | ||
| readonly code: string; | ||
| readonly notes: string[]; | ||
| readonly help: string[]; | ||
| constructor(message: string, location: SourceLocation, expression?: unknown | undefined, code?: string); | ||
| /** | ||
| * Get a formatted error message with location | ||
| */ | ||
| formatMessage(): string; | ||
| /** | ||
| * Add a note to the error | ||
| */ | ||
| withNote(note: string): this; | ||
| /** | ||
| * Add a help suggestion to the error | ||
| */ | ||
| withHelp(help: string): this; | ||
| } | ||
| /** | ||
| * Error for type mismatches (E0408) | ||
| */ | ||
| declare class TypeError extends EvaluationError { | ||
| readonly expectedType: string; | ||
| readonly actualType: string; | ||
| constructor(message: string, location: SourceLocation, expectedType: string, actualType: string, expression?: unknown); | ||
| } | ||
| /** | ||
| * Error for undefined variables (E0403) | ||
| */ | ||
| declare class ReferenceError extends EvaluationError { | ||
| readonly identifier: string; | ||
| constructor(message: string, location: SourceLocation, identifier: string, expression?: unknown); | ||
| } | ||
| /** | ||
| * Error for division by zero and similar runtime errors (E0400-E0411) | ||
| */ | ||
| declare class RuntimeError extends EvaluationError { | ||
| constructor(message: string, location: SourceLocation, expression?: unknown, code?: string); | ||
| /** | ||
| * Create a division by zero error | ||
| */ | ||
| static divisionByZero(location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create a null reference error | ||
| */ | ||
| static nullReference(property: string, location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create an index out of bounds error | ||
| */ | ||
| static indexOutOfBounds(index: number, length: number, location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create an entity not found error | ||
| */ | ||
| static entityNotFound(entityName: string, id: string, location: SourceLocation): RuntimeError; | ||
| } | ||
| /** | ||
| * Semantic diagnostic codes for evaluator failures. | ||
| * Every unknown/error path must produce one of these codes. | ||
| */ | ||
| declare enum EvalDiagnosticCode { | ||
| /** Member access on null or undefined value */ | ||
| EVAL_NULL_DEREF = "EVAL_NULL_DEREF", | ||
| /** Property does not exist on target object */ | ||
| EVAL_UNDEFINED_MEMBER = "EVAL_UNDEFINED_MEMBER", | ||
| /** Undefined variable or identifier */ | ||
| EVAL_UNDEFINED_VAR = "EVAL_UNDEFINED_VAR", | ||
| /** old() called without a previous state snapshot */ | ||
| EVAL_MISSING_OLD_STATE = "EVAL_MISSING_OLD_STATE", | ||
| /** Nested path resolution failed inside old() */ | ||
| EVAL_OLD_NESTED_FAIL = "EVAL_OLD_NESTED_FAIL", | ||
| /** Type mismatch in operation */ | ||
| EVAL_TYPE_MISMATCH = "EVAL_TYPE_MISMATCH", | ||
| /** Array/string index out of bounds */ | ||
| EVAL_OOB_INDEX = "EVAL_OOB_INDEX", | ||
| /** Unknown function or method call */ | ||
| EVAL_UNKNOWN_FUNCTION = "EVAL_UNKNOWN_FUNCTION", | ||
| /** Unsupported expression kind */ | ||
| EVAL_UNSUPPORTED_EXPR = "EVAL_UNSUPPORTED_EXPR", | ||
| /** Optional chaining applied to non-object value */ | ||
| EVAL_OPTIONAL_CHAIN_NON_OBJECT = "EVAL_OPTIONAL_CHAIN_NON_OBJECT" | ||
| } | ||
| /** | ||
| * Structured diagnostic payload attached to every evaluator failure. | ||
| */ | ||
| interface DiagnosticPayload { | ||
| /** Diagnostic code identifying the failure class */ | ||
| code: EvalDiagnosticCode; | ||
| /** Human-readable message */ | ||
| message: string; | ||
| /** Source span where the error originated */ | ||
| span: SourceLocation; | ||
| /** String representation of the failing sub-expression */ | ||
| subExpression: string; | ||
| /** Optional upstream cause (e.g. the inner error for old() wrapping) */ | ||
| cause?: DiagnosticPayload; | ||
| } | ||
| /** | ||
| * Structured diagnostic error thrown by the evaluator. | ||
| * Carries a full DiagnosticPayload so callers can inspect | ||
| * the code, span, and sub-expression without parsing strings. | ||
| */ | ||
| declare class DiagnosticError extends EvaluationError { | ||
| readonly diagnostic: DiagnosticPayload; | ||
| constructor(payload: DiagnosticPayload, expression?: unknown); | ||
| /** | ||
| * Wrap an existing DiagnosticError as the cause of a higher-level diagnostic. | ||
| */ | ||
| static wrap(outerCode: EvalDiagnosticCode, outerMessage: string, outerSpan: SourceLocation, outerSubExpr: string, innerError: DiagnosticError, expression?: unknown): DiagnosticError; | ||
| } | ||
| /** | ||
| * Type of verification check | ||
| */ | ||
| type CheckType = 'precondition' | 'postcondition' | 'invariant'; | ||
| /** | ||
| * Result of a single verification check | ||
| */ | ||
| interface CheckResult { | ||
| type: CheckType; | ||
| name: string; | ||
| expression: string; | ||
| passed: boolean; | ||
| expected?: unknown; | ||
| actual?: unknown; | ||
| error?: string; | ||
| location?: SourceLocation; | ||
| duration: number; | ||
| } | ||
| /** | ||
| * A verification failure | ||
| */ | ||
| interface VerificationFailure { | ||
| type: CheckType; | ||
| expression: string; | ||
| message: string; | ||
| expected?: unknown; | ||
| actual?: unknown; | ||
| location: SourceLocation; | ||
| } | ||
| /** | ||
| * Result of spec verification | ||
| */ | ||
| interface VerificationResult { | ||
| passed: boolean; | ||
| failures: VerificationFailure[]; | ||
| preconditions: CheckResult[]; | ||
| postconditions: CheckResult[]; | ||
| invariants: CheckResult[]; | ||
| duration: number; | ||
| } | ||
| /** | ||
| * Builtin function signature | ||
| */ | ||
| type BuiltinFn = (args: Value[], context: EvaluationContext, location: SourceLocation) => Value; | ||
| /** | ||
| * Registry of builtin functions | ||
| */ | ||
| interface BuiltinRegistry { | ||
| get(name: string): BuiltinFn | undefined; | ||
| has(name: string): boolean; | ||
| register(name: string, fn: BuiltinFn): void; | ||
| list(): string[]; | ||
| } | ||
| /** | ||
| * Check if a value is an entity instance | ||
| */ | ||
| declare function isEntityInstance(value: unknown): value is EntityInstance; | ||
| /** | ||
| * Check if a value is a lambda | ||
| */ | ||
| declare function isLambdaValue(value: unknown): value is LambdaValue; | ||
| /** | ||
| * Get the runtime type of a value | ||
| */ | ||
| declare function getValueType(value: unknown): string; | ||
| export { type ASTNode as A, type BuiltinRegistry as B, type CheckType as C, type DomainDef as D, type EntityStoreSnapshot as E, type FieldDef as F, type LambdaValue as L, ReferenceError as R, type SourceLocation as S, type TypeDef as T, type VerificationResult as V, type BuiltinFn as a, type EntityStore as b, type EvaluationContext as c, type CheckResult as d, type Value as e, type Binding as f, DiagnosticError as g, type DiagnosticPayload as h, type EntityDef as i, type EntityInstance as j, type Environment as k, EvalDiagnosticCode as l, EvaluationError as m, type EvaluationErrorInfo as n, RuntimeError as o, TypeError as p, type VerificationFailure as q, getValueType as r, isEntityInstance as s, isLambdaValue as t }; |
| /** | ||
| * Source location information for error reporting | ||
| */ | ||
| interface SourceLocation { | ||
| file: string; | ||
| line: number; | ||
| column: number; | ||
| endLine: number; | ||
| endColumn: number; | ||
| } | ||
| /** | ||
| * Base interface for AST nodes (re-exported for standalone use) | ||
| */ | ||
| interface ASTNode { | ||
| kind: string; | ||
| location: SourceLocation; | ||
| } | ||
| /** | ||
| * All possible runtime values in ISL | ||
| */ | ||
| type Value = null | undefined | boolean | number | string | Date | RegExp | unknown[] | Map<string, unknown> | Record<string, unknown> | EntityInstance | LambdaValue; | ||
| /** | ||
| * Represents a lambda/function value | ||
| */ | ||
| interface LambdaValue { | ||
| __type__: 'lambda'; | ||
| params: string[]; | ||
| body: unknown; | ||
| closure: Environment; | ||
| } | ||
| /** | ||
| * Represents an entity instance | ||
| */ | ||
| interface EntityInstance { | ||
| __entity__: string; | ||
| __id__: string; | ||
| [key: string]: unknown; | ||
| } | ||
| /** | ||
| * Variable binding in the environment | ||
| */ | ||
| interface Binding { | ||
| name: string; | ||
| value: Value; | ||
| mutable: boolean; | ||
| } | ||
| /** | ||
| * Environment interface for scope management | ||
| */ | ||
| interface Environment { | ||
| /** Get a variable's value */ | ||
| get(name: string): Value; | ||
| /** Check if a variable exists */ | ||
| has(name: string): boolean; | ||
| /** Set a variable's value */ | ||
| set(name: string, value: Value): void; | ||
| /** Define a new variable */ | ||
| define(name: string, value: Value, mutable?: boolean): void; | ||
| /** Create a child scope */ | ||
| child(): Environment; | ||
| /** Get all bindings */ | ||
| bindings(): Map<string, Binding>; | ||
| } | ||
| /** | ||
| * Entity store for managing entity instances | ||
| */ | ||
| interface EntityStore { | ||
| /** Get all instances of an entity type */ | ||
| getAll(entityName: string): EntityInstance[]; | ||
| /** Check if an entity with given criteria exists */ | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| /** Lookup single entity by criteria */ | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| /** Count entities matching criteria */ | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| /** Create a new entity instance */ | ||
| create(entityName: string, data: Record<string, unknown>): EntityInstance; | ||
| /** Update an entity instance */ | ||
| update(entityName: string, id: string, data: Record<string, unknown>): void; | ||
| /** Delete an entity instance */ | ||
| delete(entityName: string, id: string): void; | ||
| /** Take a snapshot of current state */ | ||
| snapshot(): EntityStoreSnapshot; | ||
| /** Restore from a snapshot */ | ||
| restore(snapshot: EntityStoreSnapshot): void; | ||
| } | ||
| /** | ||
| * Snapshot of entity store state (for old() expressions) | ||
| */ | ||
| interface EntityStoreSnapshot { | ||
| entities: Map<string, Map<string, EntityInstance>>; | ||
| timestamp: number; | ||
| } | ||
| /** | ||
| * Domain definition (simplified for evaluator needs) | ||
| */ | ||
| interface DomainDef { | ||
| name: string; | ||
| entities: EntityDef[]; | ||
| types?: TypeDef[]; | ||
| } | ||
| interface EntityDef { | ||
| name: string; | ||
| fields?: FieldDef[] | unknown[]; | ||
| } | ||
| interface TypeDef { | ||
| name: string; | ||
| definition?: unknown; | ||
| } | ||
| interface FieldDef { | ||
| name: string; | ||
| type?: unknown; | ||
| optional?: boolean; | ||
| } | ||
| /** | ||
| * Context for expression evaluation | ||
| */ | ||
| interface EvaluationContext { | ||
| /** Current input values */ | ||
| input: Record<string, unknown>; | ||
| /** Result of behavior execution (for postconditions) */ | ||
| result?: unknown; | ||
| /** Error if behavior failed */ | ||
| error?: EvaluationErrorInfo; | ||
| /** Entity store for lookups */ | ||
| store: EntityStore; | ||
| /** Snapshot of state before execution (for old() expressions) */ | ||
| oldState?: EntityStoreSnapshot; | ||
| /** Domain definition for type information */ | ||
| domain?: DomainDef; | ||
| /** Current timestamp for now() */ | ||
| now: Date; | ||
| /** Variables in scope */ | ||
| variables: Map<string, unknown>; | ||
| } | ||
| /** | ||
| * Error information during evaluation | ||
| */ | ||
| interface EvaluationErrorInfo { | ||
| code: string; | ||
| message: string; | ||
| retriable: boolean; | ||
| details?: Record<string, unknown>; | ||
| } | ||
| /** | ||
| * Structured evaluation error with source location | ||
| */ | ||
| declare class EvaluationError extends Error { | ||
| readonly location: SourceLocation; | ||
| readonly expression?: unknown | undefined; | ||
| readonly code: string; | ||
| readonly notes: string[]; | ||
| readonly help: string[]; | ||
| constructor(message: string, location: SourceLocation, expression?: unknown | undefined, code?: string); | ||
| /** | ||
| * Get a formatted error message with location | ||
| */ | ||
| formatMessage(): string; | ||
| /** | ||
| * Add a note to the error | ||
| */ | ||
| withNote(note: string): this; | ||
| /** | ||
| * Add a help suggestion to the error | ||
| */ | ||
| withHelp(help: string): this; | ||
| } | ||
| /** | ||
| * Error for type mismatches (E0408) | ||
| */ | ||
| declare class TypeError extends EvaluationError { | ||
| readonly expectedType: string; | ||
| readonly actualType: string; | ||
| constructor(message: string, location: SourceLocation, expectedType: string, actualType: string, expression?: unknown); | ||
| } | ||
| /** | ||
| * Error for undefined variables (E0403) | ||
| */ | ||
| declare class ReferenceError extends EvaluationError { | ||
| readonly identifier: string; | ||
| constructor(message: string, location: SourceLocation, identifier: string, expression?: unknown); | ||
| } | ||
| /** | ||
| * Error for division by zero and similar runtime errors (E0400-E0411) | ||
| */ | ||
| declare class RuntimeError extends EvaluationError { | ||
| constructor(message: string, location: SourceLocation, expression?: unknown, code?: string); | ||
| /** | ||
| * Create a division by zero error | ||
| */ | ||
| static divisionByZero(location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create a null reference error | ||
| */ | ||
| static nullReference(property: string, location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create an index out of bounds error | ||
| */ | ||
| static indexOutOfBounds(index: number, length: number, location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create an entity not found error | ||
| */ | ||
| static entityNotFound(entityName: string, id: string, location: SourceLocation): RuntimeError; | ||
| } | ||
| /** | ||
| * Semantic diagnostic codes for evaluator failures. | ||
| * Every unknown/error path must produce one of these codes. | ||
| */ | ||
| declare enum EvalDiagnosticCode { | ||
| /** Member access on null or undefined value */ | ||
| EVAL_NULL_DEREF = "EVAL_NULL_DEREF", | ||
| /** Property does not exist on target object */ | ||
| EVAL_UNDEFINED_MEMBER = "EVAL_UNDEFINED_MEMBER", | ||
| /** Undefined variable or identifier */ | ||
| EVAL_UNDEFINED_VAR = "EVAL_UNDEFINED_VAR", | ||
| /** old() called without a previous state snapshot */ | ||
| EVAL_MISSING_OLD_STATE = "EVAL_MISSING_OLD_STATE", | ||
| /** Nested path resolution failed inside old() */ | ||
| EVAL_OLD_NESTED_FAIL = "EVAL_OLD_NESTED_FAIL", | ||
| /** Type mismatch in operation */ | ||
| EVAL_TYPE_MISMATCH = "EVAL_TYPE_MISMATCH", | ||
| /** Array/string index out of bounds */ | ||
| EVAL_OOB_INDEX = "EVAL_OOB_INDEX", | ||
| /** Unknown function or method call */ | ||
| EVAL_UNKNOWN_FUNCTION = "EVAL_UNKNOWN_FUNCTION", | ||
| /** Unsupported expression kind */ | ||
| EVAL_UNSUPPORTED_EXPR = "EVAL_UNSUPPORTED_EXPR", | ||
| /** Optional chaining applied to non-object value */ | ||
| EVAL_OPTIONAL_CHAIN_NON_OBJECT = "EVAL_OPTIONAL_CHAIN_NON_OBJECT" | ||
| } | ||
| /** | ||
| * Structured diagnostic payload attached to every evaluator failure. | ||
| */ | ||
| interface DiagnosticPayload { | ||
| /** Diagnostic code identifying the failure class */ | ||
| code: EvalDiagnosticCode; | ||
| /** Human-readable message */ | ||
| message: string; | ||
| /** Source span where the error originated */ | ||
| span: SourceLocation; | ||
| /** String representation of the failing sub-expression */ | ||
| subExpression: string; | ||
| /** Optional upstream cause (e.g. the inner error for old() wrapping) */ | ||
| cause?: DiagnosticPayload; | ||
| } | ||
| /** | ||
| * Structured diagnostic error thrown by the evaluator. | ||
| * Carries a full DiagnosticPayload so callers can inspect | ||
| * the code, span, and sub-expression without parsing strings. | ||
| */ | ||
| declare class DiagnosticError extends EvaluationError { | ||
| readonly diagnostic: DiagnosticPayload; | ||
| constructor(payload: DiagnosticPayload, expression?: unknown); | ||
| /** | ||
| * Wrap an existing DiagnosticError as the cause of a higher-level diagnostic. | ||
| */ | ||
| static wrap(outerCode: EvalDiagnosticCode, outerMessage: string, outerSpan: SourceLocation, outerSubExpr: string, innerError: DiagnosticError, expression?: unknown): DiagnosticError; | ||
| } | ||
| /** | ||
| * Type of verification check | ||
| */ | ||
| type CheckType = 'precondition' | 'postcondition' | 'invariant'; | ||
| /** | ||
| * Result of a single verification check | ||
| */ | ||
| interface CheckResult { | ||
| type: CheckType; | ||
| name: string; | ||
| expression: string; | ||
| passed: boolean; | ||
| expected?: unknown; | ||
| actual?: unknown; | ||
| error?: string; | ||
| location?: SourceLocation; | ||
| duration: number; | ||
| } | ||
| /** | ||
| * A verification failure | ||
| */ | ||
| interface VerificationFailure { | ||
| type: CheckType; | ||
| expression: string; | ||
| message: string; | ||
| expected?: unknown; | ||
| actual?: unknown; | ||
| location: SourceLocation; | ||
| } | ||
| /** | ||
| * Result of spec verification | ||
| */ | ||
| interface VerificationResult { | ||
| passed: boolean; | ||
| failures: VerificationFailure[]; | ||
| preconditions: CheckResult[]; | ||
| postconditions: CheckResult[]; | ||
| invariants: CheckResult[]; | ||
| duration: number; | ||
| } | ||
| /** | ||
| * Builtin function signature | ||
| */ | ||
| type BuiltinFn = (args: Value[], context: EvaluationContext, location: SourceLocation) => Value; | ||
| /** | ||
| * Registry of builtin functions | ||
| */ | ||
| interface BuiltinRegistry { | ||
| get(name: string): BuiltinFn | undefined; | ||
| has(name: string): boolean; | ||
| register(name: string, fn: BuiltinFn): void; | ||
| list(): string[]; | ||
| } | ||
| /** | ||
| * Check if a value is an entity instance | ||
| */ | ||
| declare function isEntityInstance(value: unknown): value is EntityInstance; | ||
| /** | ||
| * Check if a value is a lambda | ||
| */ | ||
| declare function isLambdaValue(value: unknown): value is LambdaValue; | ||
| /** | ||
| * Get the runtime type of a value | ||
| */ | ||
| declare function getValueType(value: unknown): string; | ||
| export { type ASTNode as A, type BuiltinRegistry as B, type CheckType as C, type DomainDef as D, type EntityStoreSnapshot as E, type FieldDef as F, type LambdaValue as L, ReferenceError as R, type SourceLocation as S, type TypeDef as T, type VerificationResult as V, type BuiltinFn as a, type EntityStore as b, type EvaluationContext as c, type CheckResult as d, type Value as e, type Binding as f, DiagnosticError as g, type DiagnosticPayload as h, type EntityDef as i, type EntityInstance as j, type Environment as k, EvalDiagnosticCode as l, EvaluationError as m, type EvaluationErrorInfo as n, RuntimeError as o, TypeError as p, type VerificationFailure as q, getValueType as r, isEntityInstance as s, isLambdaValue as t }; |
+5
-448
@@ -1,393 +0,7 @@ | ||
| /** | ||
| * Source location information for error reporting | ||
| */ | ||
| interface SourceLocation { | ||
| file: string; | ||
| line: number; | ||
| column: number; | ||
| endLine: number; | ||
| endColumn: number; | ||
| } | ||
| /** | ||
| * Base interface for AST nodes (re-exported for standalone use) | ||
| */ | ||
| interface ASTNode { | ||
| kind: string; | ||
| location: SourceLocation; | ||
| } | ||
| /** | ||
| * All possible runtime values in ISL | ||
| */ | ||
| type Value = null | undefined | boolean | number | string | Date | RegExp | unknown[] | Map<string, unknown> | Record<string, unknown> | EntityInstance | LambdaValue; | ||
| /** | ||
| * Represents a lambda/function value | ||
| */ | ||
| interface LambdaValue { | ||
| __type__: 'lambda'; | ||
| params: string[]; | ||
| body: unknown; | ||
| closure: Environment; | ||
| } | ||
| /** | ||
| * Represents an entity instance | ||
| */ | ||
| interface EntityInstance { | ||
| __entity__: string; | ||
| __id__: string; | ||
| [key: string]: unknown; | ||
| } | ||
| /** | ||
| * Variable binding in the environment | ||
| */ | ||
| interface Binding { | ||
| name: string; | ||
| value: Value; | ||
| mutable: boolean; | ||
| } | ||
| /** | ||
| * Environment interface for scope management | ||
| */ | ||
| interface Environment { | ||
| /** Get a variable's value */ | ||
| get(name: string): Value; | ||
| /** Check if a variable exists */ | ||
| has(name: string): boolean; | ||
| /** Set a variable's value */ | ||
| set(name: string, value: Value): void; | ||
| /** Define a new variable */ | ||
| define(name: string, value: Value, mutable?: boolean): void; | ||
| /** Create a child scope */ | ||
| child(): Environment; | ||
| /** Get all bindings */ | ||
| bindings(): Map<string, Binding>; | ||
| } | ||
| /** | ||
| * Entity store for managing entity instances | ||
| */ | ||
| interface EntityStore { | ||
| /** Get all instances of an entity type */ | ||
| getAll(entityName: string): EntityInstance[]; | ||
| /** Check if an entity with given criteria exists */ | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| /** Lookup single entity by criteria */ | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| /** Count entities matching criteria */ | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| /** Create a new entity instance */ | ||
| create(entityName: string, data: Record<string, unknown>): EntityInstance; | ||
| /** Update an entity instance */ | ||
| update(entityName: string, id: string, data: Record<string, unknown>): void; | ||
| /** Delete an entity instance */ | ||
| delete(entityName: string, id: string): void; | ||
| /** Take a snapshot of current state */ | ||
| snapshot(): EntityStoreSnapshot; | ||
| /** Restore from a snapshot */ | ||
| restore(snapshot: EntityStoreSnapshot): void; | ||
| } | ||
| /** | ||
| * Snapshot of entity store state (for old() expressions) | ||
| */ | ||
| interface EntityStoreSnapshot { | ||
| entities: Map<string, Map<string, EntityInstance>>; | ||
| timestamp: number; | ||
| } | ||
| /** | ||
| * Domain definition (simplified for evaluator needs) | ||
| */ | ||
| interface DomainDef { | ||
| name: string; | ||
| entities: EntityDef[]; | ||
| types?: TypeDef[]; | ||
| } | ||
| interface EntityDef { | ||
| name: string; | ||
| fields?: FieldDef[] | unknown[]; | ||
| } | ||
| interface TypeDef { | ||
| name: string; | ||
| definition?: unknown; | ||
| } | ||
| interface FieldDef { | ||
| name: string; | ||
| type?: unknown; | ||
| optional?: boolean; | ||
| } | ||
| /** | ||
| * Context for expression evaluation | ||
| */ | ||
| interface EvaluationContext { | ||
| /** Current input values */ | ||
| input: Record<string, unknown>; | ||
| /** Result of behavior execution (for postconditions) */ | ||
| result?: unknown; | ||
| /** Error if behavior failed */ | ||
| error?: EvaluationErrorInfo; | ||
| /** Entity store for lookups */ | ||
| store: EntityStore; | ||
| /** Snapshot of state before execution (for old() expressions) */ | ||
| oldState?: EntityStoreSnapshot; | ||
| /** Domain definition for type information */ | ||
| domain?: DomainDef; | ||
| /** Current timestamp for now() */ | ||
| now: Date; | ||
| /** Variables in scope */ | ||
| variables: Map<string, unknown>; | ||
| } | ||
| /** | ||
| * Error information during evaluation | ||
| */ | ||
| interface EvaluationErrorInfo { | ||
| code: string; | ||
| message: string; | ||
| retriable: boolean; | ||
| details?: Record<string, unknown>; | ||
| } | ||
| /** | ||
| * Structured evaluation error with source location | ||
| */ | ||
| declare class EvaluationError extends Error { | ||
| readonly location: SourceLocation; | ||
| readonly expression?: unknown | undefined; | ||
| readonly code: string; | ||
| readonly notes: string[]; | ||
| readonly help: string[]; | ||
| constructor(message: string, location: SourceLocation, expression?: unknown | undefined, code?: string); | ||
| /** | ||
| * Get a formatted error message with location | ||
| */ | ||
| formatMessage(): string; | ||
| /** | ||
| * Add a note to the error | ||
| */ | ||
| withNote(note: string): this; | ||
| /** | ||
| * Add a help suggestion to the error | ||
| */ | ||
| withHelp(help: string): this; | ||
| } | ||
| /** | ||
| * Error for type mismatches (E0408) | ||
| */ | ||
| declare class TypeError extends EvaluationError { | ||
| readonly expectedType: string; | ||
| readonly actualType: string; | ||
| constructor(message: string, location: SourceLocation, expectedType: string, actualType: string, expression?: unknown); | ||
| } | ||
| /** | ||
| * Error for undefined variables (E0403) | ||
| */ | ||
| declare class ReferenceError extends EvaluationError { | ||
| readonly identifier: string; | ||
| constructor(message: string, location: SourceLocation, identifier: string, expression?: unknown); | ||
| } | ||
| /** | ||
| * Error for division by zero and similar runtime errors (E0400-E0411) | ||
| */ | ||
| declare class RuntimeError extends EvaluationError { | ||
| constructor(message: string, location: SourceLocation, expression?: unknown, code?: string); | ||
| /** | ||
| * Create a division by zero error | ||
| */ | ||
| static divisionByZero(location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create a null reference error | ||
| */ | ||
| static nullReference(property: string, location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create an index out of bounds error | ||
| */ | ||
| static indexOutOfBounds(index: number, length: number, location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create an entity not found error | ||
| */ | ||
| static entityNotFound(entityName: string, id: string, location: SourceLocation): RuntimeError; | ||
| } | ||
| /** | ||
| * Type of verification check | ||
| */ | ||
| type CheckType = 'precondition' | 'postcondition' | 'invariant'; | ||
| /** | ||
| * Result of a single verification check | ||
| */ | ||
| interface CheckResult { | ||
| type: CheckType; | ||
| name: string; | ||
| expression: string; | ||
| passed: boolean; | ||
| expected?: unknown; | ||
| actual?: unknown; | ||
| error?: string; | ||
| location?: SourceLocation; | ||
| duration: number; | ||
| } | ||
| /** | ||
| * A verification failure | ||
| */ | ||
| interface VerificationFailure { | ||
| type: CheckType; | ||
| expression: string; | ||
| message: string; | ||
| expected?: unknown; | ||
| actual?: unknown; | ||
| location: SourceLocation; | ||
| } | ||
| /** | ||
| * Result of spec verification | ||
| */ | ||
| interface VerificationResult { | ||
| passed: boolean; | ||
| failures: VerificationFailure[]; | ||
| preconditions: CheckResult[]; | ||
| postconditions: CheckResult[]; | ||
| invariants: CheckResult[]; | ||
| duration: number; | ||
| } | ||
| /** | ||
| * Builtin function signature | ||
| */ | ||
| type BuiltinFn = (args: Value[], context: EvaluationContext, location: SourceLocation) => Value; | ||
| /** | ||
| * Registry of builtin functions | ||
| */ | ||
| interface BuiltinRegistry { | ||
| get(name: string): BuiltinFn | undefined; | ||
| has(name: string): boolean; | ||
| register(name: string, fn: BuiltinFn): void; | ||
| list(): string[]; | ||
| } | ||
| /** | ||
| * Check if a value is an entity instance | ||
| */ | ||
| declare function isEntityInstance(value: unknown): value is EntityInstance; | ||
| /** | ||
| * Check if a value is a lambda | ||
| */ | ||
| declare function isLambdaValue(value: unknown): value is LambdaValue; | ||
| /** | ||
| * Get the runtime type of a value | ||
| */ | ||
| declare function getValueType(value: unknown): string; | ||
| import { B as BuiltinRegistry, a as BuiltinFn, S as SourceLocation, E as EntityStoreSnapshot, b as EntityStore, D as DomainDef, V as VerificationResult, c as EvaluationContext, C as CheckType, d as CheckResult, e as Value } from './types-BP9x1AUL.cjs'; | ||
| export { A as ASTNode, f as Binding, g as DiagnosticError, h as DiagnosticPayload, i as EntityDef, j as EntityInstance, k as Environment, l as EvalDiagnosticCode, m as EvaluationError, n as EvaluationErrorInfo, F as FieldDef, L as LambdaValue, R as ReferenceError, o as RuntimeError, T as TypeDef, p as TypeError, q as VerificationFailure, r as getValueType, s as isEntityInstance, t as isLambdaValue } from './types-BP9x1AUL.cjs'; | ||
| export { InMemoryEntityStore, Scope, SnapshotEntityStore, createEntityStore, createScope, createSnapshotStore } from './environment.cjs'; | ||
| export { Evaluator, EvaluatorOptions, evaluate, expressionToString } from './evaluator.cjs'; | ||
| /** | ||
| * Lexical scope implementation with parent chain lookup | ||
| */ | ||
| declare class Scope implements Environment { | ||
| private readonly parent?; | ||
| private readonly scope; | ||
| constructor(parent?: Scope | undefined); | ||
| /** | ||
| * Get a variable's value, searching up the scope chain | ||
| */ | ||
| get(name: string): Value; | ||
| /** | ||
| * Check if a variable exists in any scope | ||
| */ | ||
| has(name: string): boolean; | ||
| /** | ||
| * Set a variable's value (must already exist) | ||
| */ | ||
| set(name: string, value: Value): void; | ||
| /** | ||
| * Define a new variable in the current scope | ||
| */ | ||
| define(name: string, value: Value, mutable?: boolean): void; | ||
| /** | ||
| * Create a child scope | ||
| */ | ||
| child(): Scope; | ||
| /** | ||
| * Get all bindings from this scope (not including parent) | ||
| */ | ||
| bindings(): Map<string, Binding>; | ||
| /** | ||
| * Find a binding in the scope chain | ||
| */ | ||
| private findBinding; | ||
| } | ||
| /** | ||
| * In-memory entity store implementation for testing and verification | ||
| */ | ||
| declare class InMemoryEntityStore implements EntityStore { | ||
| private entities; | ||
| private idCounters; | ||
| constructor(); | ||
| /** | ||
| * Get all instances of an entity type | ||
| */ | ||
| getAll(entityName: string): EntityInstance[]; | ||
| /** | ||
| * Check if any entity matching criteria exists | ||
| */ | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| /** | ||
| * Lookup a single entity by criteria | ||
| */ | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| /** | ||
| * Count entities matching criteria | ||
| */ | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| /** | ||
| * Create a new entity instance | ||
| */ | ||
| create(entityName: string, data: Record<string, unknown>): EntityInstance; | ||
| /** | ||
| * Update an entity instance | ||
| */ | ||
| update(entityName: string, id: string, data: Record<string, unknown>): void; | ||
| /** | ||
| * Delete an entity instance | ||
| */ | ||
| delete(entityName: string, id: string): void; | ||
| /** | ||
| * Take a snapshot of current state | ||
| */ | ||
| snapshot(): EntityStoreSnapshot; | ||
| /** | ||
| * Restore from a snapshot | ||
| */ | ||
| restore(snapshot: EntityStoreSnapshot): void; | ||
| /** | ||
| * Clear all entities (useful for testing) | ||
| */ | ||
| clear(): void; | ||
| /** | ||
| * Seed with initial data | ||
| */ | ||
| seed(entityName: string, instances: Record<string, unknown>[]): void; | ||
| private matchesCriteria; | ||
| private deepEqual; | ||
| private deepClone; | ||
| private generateId; | ||
| } | ||
| /** | ||
| * Read-only entity store wrapper for old() evaluation | ||
| */ | ||
| declare class SnapshotEntityStore implements EntityStore { | ||
| private readonly _snapshot; | ||
| constructor(snapshot: EntityStoreSnapshot); | ||
| getAll(entityName: string): EntityInstance[]; | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| create(): EntityInstance; | ||
| update(): void; | ||
| delete(): void; | ||
| snapshot(): EntityStoreSnapshot; | ||
| restore(): void; | ||
| } | ||
| /** | ||
| * Create a new scope with optional parent | ||
| */ | ||
| declare function createScope(parent?: Scope): Scope; | ||
| /** | ||
| * Create a new in-memory entity store | ||
| */ | ||
| declare function createEntityStore(): InMemoryEntityStore; | ||
| /** | ||
| * Create a read-only store from a snapshot | ||
| */ | ||
| declare function createSnapshotStore(snapshot: EntityStoreSnapshot): SnapshotEntityStore; | ||
| /** | ||
| * Registry for built-in functions | ||
@@ -413,59 +27,2 @@ */ | ||
| interface EvaluatorOptions { | ||
| /** Custom builtin registry */ | ||
| builtins?: BuiltinRegistry; | ||
| /** Enable strict type checking */ | ||
| strict?: boolean; | ||
| /** Maximum recursion depth */ | ||
| maxDepth?: number; | ||
| /** Timeout in milliseconds */ | ||
| timeout?: number; | ||
| } | ||
| /** | ||
| * Tree-walking interpreter for ISL expressions | ||
| */ | ||
| declare class Evaluator { | ||
| private readonly builtins; | ||
| private readonly maxDepth; | ||
| private currentDepth; | ||
| private startTime; | ||
| private timeout; | ||
| constructor(options?: EvaluatorOptions); | ||
| /** | ||
| * Evaluate an expression in the given context | ||
| */ | ||
| evaluate(expr: unknown, context: EvaluationContext): Value; | ||
| private eval; | ||
| private evalIdentifier; | ||
| private evalQualifiedName; | ||
| private createEntityProxy; | ||
| private evalBinaryExpr; | ||
| private evalUnaryExpr; | ||
| private evalCallExpr; | ||
| private callLambda; | ||
| private handleEntityMethod; | ||
| private handleArrayMethod; | ||
| private handleStringMethod; | ||
| private evalMemberExpr; | ||
| private evalIndexExpr; | ||
| private evalQuantifierExpr; | ||
| private evalConditionalExpr; | ||
| private evalOldExpr; | ||
| private evalResultExpr; | ||
| private evalInputExpr; | ||
| private evalLambdaExpr; | ||
| private evalMapExpr; | ||
| private evalDuration; | ||
| private assertNumbers; | ||
| private deepEqual; | ||
| } | ||
| /** | ||
| * Evaluate an expression (convenience wrapper) | ||
| */ | ||
| declare function evaluate(expr: unknown, context: EvaluationContext, options?: EvaluatorOptions): Value; | ||
| /** | ||
| * Convert expression to string representation | ||
| */ | ||
| declare function expressionToString(expr: unknown): string; | ||
| interface BehaviorSpec { | ||
@@ -547,2 +104,2 @@ name: string; | ||
| export { type ASTNode, type Binding, type BuiltinFn, type BuiltinRegistry, type CheckResult, type CheckType, DefaultBuiltinRegistry, type DomainDef, type EntityDef, type EntityInstance, type EntityStore, type EntityStoreSnapshot, type Environment, type EvaluationContext, EvaluationError, type EvaluationErrorInfo, Evaluator, type EvaluatorOptions, type FieldDef, InMemoryEntityStore, type LambdaValue, ReferenceError, RuntimeError, Scope, SnapshotEntityStore, type SourceLocation, type TypeDef, TypeError, type Value, type VerificationFailure, type VerificationInput, type VerificationResult, Verifier, createBuiltinRegistry, createEntityStore, createScope, createSnapshotStore, createVerifier, evaluate, expressionToString, getDefaultBuiltins, getValueType, isEntityInstance, isLambdaValue, verifyExpression }; | ||
| export { BuiltinFn, BuiltinRegistry, CheckResult, CheckType, DefaultBuiltinRegistry, DomainDef, EntityStore, EntityStoreSnapshot, EvaluationContext, SourceLocation, Value, type VerificationInput, VerificationResult, Verifier, createBuiltinRegistry, createVerifier, getDefaultBuiltins, verifyExpression }; |
+5
-448
@@ -1,393 +0,7 @@ | ||
| /** | ||
| * Source location information for error reporting | ||
| */ | ||
| interface SourceLocation { | ||
| file: string; | ||
| line: number; | ||
| column: number; | ||
| endLine: number; | ||
| endColumn: number; | ||
| } | ||
| /** | ||
| * Base interface for AST nodes (re-exported for standalone use) | ||
| */ | ||
| interface ASTNode { | ||
| kind: string; | ||
| location: SourceLocation; | ||
| } | ||
| /** | ||
| * All possible runtime values in ISL | ||
| */ | ||
| type Value = null | undefined | boolean | number | string | Date | RegExp | unknown[] | Map<string, unknown> | Record<string, unknown> | EntityInstance | LambdaValue; | ||
| /** | ||
| * Represents a lambda/function value | ||
| */ | ||
| interface LambdaValue { | ||
| __type__: 'lambda'; | ||
| params: string[]; | ||
| body: unknown; | ||
| closure: Environment; | ||
| } | ||
| /** | ||
| * Represents an entity instance | ||
| */ | ||
| interface EntityInstance { | ||
| __entity__: string; | ||
| __id__: string; | ||
| [key: string]: unknown; | ||
| } | ||
| /** | ||
| * Variable binding in the environment | ||
| */ | ||
| interface Binding { | ||
| name: string; | ||
| value: Value; | ||
| mutable: boolean; | ||
| } | ||
| /** | ||
| * Environment interface for scope management | ||
| */ | ||
| interface Environment { | ||
| /** Get a variable's value */ | ||
| get(name: string): Value; | ||
| /** Check if a variable exists */ | ||
| has(name: string): boolean; | ||
| /** Set a variable's value */ | ||
| set(name: string, value: Value): void; | ||
| /** Define a new variable */ | ||
| define(name: string, value: Value, mutable?: boolean): void; | ||
| /** Create a child scope */ | ||
| child(): Environment; | ||
| /** Get all bindings */ | ||
| bindings(): Map<string, Binding>; | ||
| } | ||
| /** | ||
| * Entity store for managing entity instances | ||
| */ | ||
| interface EntityStore { | ||
| /** Get all instances of an entity type */ | ||
| getAll(entityName: string): EntityInstance[]; | ||
| /** Check if an entity with given criteria exists */ | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| /** Lookup single entity by criteria */ | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| /** Count entities matching criteria */ | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| /** Create a new entity instance */ | ||
| create(entityName: string, data: Record<string, unknown>): EntityInstance; | ||
| /** Update an entity instance */ | ||
| update(entityName: string, id: string, data: Record<string, unknown>): void; | ||
| /** Delete an entity instance */ | ||
| delete(entityName: string, id: string): void; | ||
| /** Take a snapshot of current state */ | ||
| snapshot(): EntityStoreSnapshot; | ||
| /** Restore from a snapshot */ | ||
| restore(snapshot: EntityStoreSnapshot): void; | ||
| } | ||
| /** | ||
| * Snapshot of entity store state (for old() expressions) | ||
| */ | ||
| interface EntityStoreSnapshot { | ||
| entities: Map<string, Map<string, EntityInstance>>; | ||
| timestamp: number; | ||
| } | ||
| /** | ||
| * Domain definition (simplified for evaluator needs) | ||
| */ | ||
| interface DomainDef { | ||
| name: string; | ||
| entities: EntityDef[]; | ||
| types?: TypeDef[]; | ||
| } | ||
| interface EntityDef { | ||
| name: string; | ||
| fields?: FieldDef[] | unknown[]; | ||
| } | ||
| interface TypeDef { | ||
| name: string; | ||
| definition?: unknown; | ||
| } | ||
| interface FieldDef { | ||
| name: string; | ||
| type?: unknown; | ||
| optional?: boolean; | ||
| } | ||
| /** | ||
| * Context for expression evaluation | ||
| */ | ||
| interface EvaluationContext { | ||
| /** Current input values */ | ||
| input: Record<string, unknown>; | ||
| /** Result of behavior execution (for postconditions) */ | ||
| result?: unknown; | ||
| /** Error if behavior failed */ | ||
| error?: EvaluationErrorInfo; | ||
| /** Entity store for lookups */ | ||
| store: EntityStore; | ||
| /** Snapshot of state before execution (for old() expressions) */ | ||
| oldState?: EntityStoreSnapshot; | ||
| /** Domain definition for type information */ | ||
| domain?: DomainDef; | ||
| /** Current timestamp for now() */ | ||
| now: Date; | ||
| /** Variables in scope */ | ||
| variables: Map<string, unknown>; | ||
| } | ||
| /** | ||
| * Error information during evaluation | ||
| */ | ||
| interface EvaluationErrorInfo { | ||
| code: string; | ||
| message: string; | ||
| retriable: boolean; | ||
| details?: Record<string, unknown>; | ||
| } | ||
| /** | ||
| * Structured evaluation error with source location | ||
| */ | ||
| declare class EvaluationError extends Error { | ||
| readonly location: SourceLocation; | ||
| readonly expression?: unknown | undefined; | ||
| readonly code: string; | ||
| readonly notes: string[]; | ||
| readonly help: string[]; | ||
| constructor(message: string, location: SourceLocation, expression?: unknown | undefined, code?: string); | ||
| /** | ||
| * Get a formatted error message with location | ||
| */ | ||
| formatMessage(): string; | ||
| /** | ||
| * Add a note to the error | ||
| */ | ||
| withNote(note: string): this; | ||
| /** | ||
| * Add a help suggestion to the error | ||
| */ | ||
| withHelp(help: string): this; | ||
| } | ||
| /** | ||
| * Error for type mismatches (E0408) | ||
| */ | ||
| declare class TypeError extends EvaluationError { | ||
| readonly expectedType: string; | ||
| readonly actualType: string; | ||
| constructor(message: string, location: SourceLocation, expectedType: string, actualType: string, expression?: unknown); | ||
| } | ||
| /** | ||
| * Error for undefined variables (E0403) | ||
| */ | ||
| declare class ReferenceError extends EvaluationError { | ||
| readonly identifier: string; | ||
| constructor(message: string, location: SourceLocation, identifier: string, expression?: unknown); | ||
| } | ||
| /** | ||
| * Error for division by zero and similar runtime errors (E0400-E0411) | ||
| */ | ||
| declare class RuntimeError extends EvaluationError { | ||
| constructor(message: string, location: SourceLocation, expression?: unknown, code?: string); | ||
| /** | ||
| * Create a division by zero error | ||
| */ | ||
| static divisionByZero(location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create a null reference error | ||
| */ | ||
| static nullReference(property: string, location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create an index out of bounds error | ||
| */ | ||
| static indexOutOfBounds(index: number, length: number, location: SourceLocation, expression?: unknown): RuntimeError; | ||
| /** | ||
| * Create an entity not found error | ||
| */ | ||
| static entityNotFound(entityName: string, id: string, location: SourceLocation): RuntimeError; | ||
| } | ||
| /** | ||
| * Type of verification check | ||
| */ | ||
| type CheckType = 'precondition' | 'postcondition' | 'invariant'; | ||
| /** | ||
| * Result of a single verification check | ||
| */ | ||
| interface CheckResult { | ||
| type: CheckType; | ||
| name: string; | ||
| expression: string; | ||
| passed: boolean; | ||
| expected?: unknown; | ||
| actual?: unknown; | ||
| error?: string; | ||
| location?: SourceLocation; | ||
| duration: number; | ||
| } | ||
| /** | ||
| * A verification failure | ||
| */ | ||
| interface VerificationFailure { | ||
| type: CheckType; | ||
| expression: string; | ||
| message: string; | ||
| expected?: unknown; | ||
| actual?: unknown; | ||
| location: SourceLocation; | ||
| } | ||
| /** | ||
| * Result of spec verification | ||
| */ | ||
| interface VerificationResult { | ||
| passed: boolean; | ||
| failures: VerificationFailure[]; | ||
| preconditions: CheckResult[]; | ||
| postconditions: CheckResult[]; | ||
| invariants: CheckResult[]; | ||
| duration: number; | ||
| } | ||
| /** | ||
| * Builtin function signature | ||
| */ | ||
| type BuiltinFn = (args: Value[], context: EvaluationContext, location: SourceLocation) => Value; | ||
| /** | ||
| * Registry of builtin functions | ||
| */ | ||
| interface BuiltinRegistry { | ||
| get(name: string): BuiltinFn | undefined; | ||
| has(name: string): boolean; | ||
| register(name: string, fn: BuiltinFn): void; | ||
| list(): string[]; | ||
| } | ||
| /** | ||
| * Check if a value is an entity instance | ||
| */ | ||
| declare function isEntityInstance(value: unknown): value is EntityInstance; | ||
| /** | ||
| * Check if a value is a lambda | ||
| */ | ||
| declare function isLambdaValue(value: unknown): value is LambdaValue; | ||
| /** | ||
| * Get the runtime type of a value | ||
| */ | ||
| declare function getValueType(value: unknown): string; | ||
| import { B as BuiltinRegistry, a as BuiltinFn, S as SourceLocation, E as EntityStoreSnapshot, b as EntityStore, D as DomainDef, V as VerificationResult, c as EvaluationContext, C as CheckType, d as CheckResult, e as Value } from './types-BP9x1AUL.js'; | ||
| export { A as ASTNode, f as Binding, g as DiagnosticError, h as DiagnosticPayload, i as EntityDef, j as EntityInstance, k as Environment, l as EvalDiagnosticCode, m as EvaluationError, n as EvaluationErrorInfo, F as FieldDef, L as LambdaValue, R as ReferenceError, o as RuntimeError, T as TypeDef, p as TypeError, q as VerificationFailure, r as getValueType, s as isEntityInstance, t as isLambdaValue } from './types-BP9x1AUL.js'; | ||
| export { InMemoryEntityStore, Scope, SnapshotEntityStore, createEntityStore, createScope, createSnapshotStore } from './environment.js'; | ||
| export { Evaluator, EvaluatorOptions, evaluate, expressionToString } from './evaluator.js'; | ||
| /** | ||
| * Lexical scope implementation with parent chain lookup | ||
| */ | ||
| declare class Scope implements Environment { | ||
| private readonly parent?; | ||
| private readonly scope; | ||
| constructor(parent?: Scope | undefined); | ||
| /** | ||
| * Get a variable's value, searching up the scope chain | ||
| */ | ||
| get(name: string): Value; | ||
| /** | ||
| * Check if a variable exists in any scope | ||
| */ | ||
| has(name: string): boolean; | ||
| /** | ||
| * Set a variable's value (must already exist) | ||
| */ | ||
| set(name: string, value: Value): void; | ||
| /** | ||
| * Define a new variable in the current scope | ||
| */ | ||
| define(name: string, value: Value, mutable?: boolean): void; | ||
| /** | ||
| * Create a child scope | ||
| */ | ||
| child(): Scope; | ||
| /** | ||
| * Get all bindings from this scope (not including parent) | ||
| */ | ||
| bindings(): Map<string, Binding>; | ||
| /** | ||
| * Find a binding in the scope chain | ||
| */ | ||
| private findBinding; | ||
| } | ||
| /** | ||
| * In-memory entity store implementation for testing and verification | ||
| */ | ||
| declare class InMemoryEntityStore implements EntityStore { | ||
| private entities; | ||
| private idCounters; | ||
| constructor(); | ||
| /** | ||
| * Get all instances of an entity type | ||
| */ | ||
| getAll(entityName: string): EntityInstance[]; | ||
| /** | ||
| * Check if any entity matching criteria exists | ||
| */ | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| /** | ||
| * Lookup a single entity by criteria | ||
| */ | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| /** | ||
| * Count entities matching criteria | ||
| */ | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| /** | ||
| * Create a new entity instance | ||
| */ | ||
| create(entityName: string, data: Record<string, unknown>): EntityInstance; | ||
| /** | ||
| * Update an entity instance | ||
| */ | ||
| update(entityName: string, id: string, data: Record<string, unknown>): void; | ||
| /** | ||
| * Delete an entity instance | ||
| */ | ||
| delete(entityName: string, id: string): void; | ||
| /** | ||
| * Take a snapshot of current state | ||
| */ | ||
| snapshot(): EntityStoreSnapshot; | ||
| /** | ||
| * Restore from a snapshot | ||
| */ | ||
| restore(snapshot: EntityStoreSnapshot): void; | ||
| /** | ||
| * Clear all entities (useful for testing) | ||
| */ | ||
| clear(): void; | ||
| /** | ||
| * Seed with initial data | ||
| */ | ||
| seed(entityName: string, instances: Record<string, unknown>[]): void; | ||
| private matchesCriteria; | ||
| private deepEqual; | ||
| private deepClone; | ||
| private generateId; | ||
| } | ||
| /** | ||
| * Read-only entity store wrapper for old() evaluation | ||
| */ | ||
| declare class SnapshotEntityStore implements EntityStore { | ||
| private readonly _snapshot; | ||
| constructor(snapshot: EntityStoreSnapshot); | ||
| getAll(entityName: string): EntityInstance[]; | ||
| exists(entityName: string, criteria?: Record<string, unknown>): boolean; | ||
| lookup(entityName: string, criteria: Record<string, unknown>): EntityInstance | undefined; | ||
| count(entityName: string, criteria?: Record<string, unknown>): number; | ||
| create(): EntityInstance; | ||
| update(): void; | ||
| delete(): void; | ||
| snapshot(): EntityStoreSnapshot; | ||
| restore(): void; | ||
| } | ||
| /** | ||
| * Create a new scope with optional parent | ||
| */ | ||
| declare function createScope(parent?: Scope): Scope; | ||
| /** | ||
| * Create a new in-memory entity store | ||
| */ | ||
| declare function createEntityStore(): InMemoryEntityStore; | ||
| /** | ||
| * Create a read-only store from a snapshot | ||
| */ | ||
| declare function createSnapshotStore(snapshot: EntityStoreSnapshot): SnapshotEntityStore; | ||
| /** | ||
| * Registry for built-in functions | ||
@@ -413,59 +27,2 @@ */ | ||
| interface EvaluatorOptions { | ||
| /** Custom builtin registry */ | ||
| builtins?: BuiltinRegistry; | ||
| /** Enable strict type checking */ | ||
| strict?: boolean; | ||
| /** Maximum recursion depth */ | ||
| maxDepth?: number; | ||
| /** Timeout in milliseconds */ | ||
| timeout?: number; | ||
| } | ||
| /** | ||
| * Tree-walking interpreter for ISL expressions | ||
| */ | ||
| declare class Evaluator { | ||
| private readonly builtins; | ||
| private readonly maxDepth; | ||
| private currentDepth; | ||
| private startTime; | ||
| private timeout; | ||
| constructor(options?: EvaluatorOptions); | ||
| /** | ||
| * Evaluate an expression in the given context | ||
| */ | ||
| evaluate(expr: unknown, context: EvaluationContext): Value; | ||
| private eval; | ||
| private evalIdentifier; | ||
| private evalQualifiedName; | ||
| private createEntityProxy; | ||
| private evalBinaryExpr; | ||
| private evalUnaryExpr; | ||
| private evalCallExpr; | ||
| private callLambda; | ||
| private handleEntityMethod; | ||
| private handleArrayMethod; | ||
| private handleStringMethod; | ||
| private evalMemberExpr; | ||
| private evalIndexExpr; | ||
| private evalQuantifierExpr; | ||
| private evalConditionalExpr; | ||
| private evalOldExpr; | ||
| private evalResultExpr; | ||
| private evalInputExpr; | ||
| private evalLambdaExpr; | ||
| private evalMapExpr; | ||
| private evalDuration; | ||
| private assertNumbers; | ||
| private deepEqual; | ||
| } | ||
| /** | ||
| * Evaluate an expression (convenience wrapper) | ||
| */ | ||
| declare function evaluate(expr: unknown, context: EvaluationContext, options?: EvaluatorOptions): Value; | ||
| /** | ||
| * Convert expression to string representation | ||
| */ | ||
| declare function expressionToString(expr: unknown): string; | ||
| interface BehaviorSpec { | ||
@@ -547,2 +104,2 @@ name: string; | ||
| export { type ASTNode, type Binding, type BuiltinFn, type BuiltinRegistry, type CheckResult, type CheckType, DefaultBuiltinRegistry, type DomainDef, type EntityDef, type EntityInstance, type EntityStore, type EntityStoreSnapshot, type Environment, type EvaluationContext, EvaluationError, type EvaluationErrorInfo, Evaluator, type EvaluatorOptions, type FieldDef, InMemoryEntityStore, type LambdaValue, ReferenceError, RuntimeError, Scope, SnapshotEntityStore, type SourceLocation, type TypeDef, TypeError, type Value, type VerificationFailure, type VerificationInput, type VerificationResult, Verifier, createBuiltinRegistry, createEntityStore, createScope, createSnapshotStore, createVerifier, evaluate, expressionToString, getDefaultBuiltins, getValueType, isEntityInstance, isLambdaValue, verifyExpression }; | ||
| export { BuiltinFn, BuiltinRegistry, CheckResult, CheckType, DefaultBuiltinRegistry, DomainDef, EntityStore, EntityStoreSnapshot, EvaluationContext, SourceLocation, Value, type VerificationInput, VerificationResult, Verifier, createBuiltinRegistry, createVerifier, getDefaultBuiltins, verifyExpression }; |
+17
-5
| { | ||
| "name": "@isl-lang/evaluator", | ||
| "version": "0.1.0", | ||
| "version": "1.0.0", | ||
| "description": "Expression evaluator for ISL - runtime evaluation and verification of contracts", | ||
@@ -36,2 +36,12 @@ "author": "ISL Team", | ||
| "require": "./dist/index.cjs" | ||
| }, | ||
| "./evaluator": { | ||
| "types": "./dist/evaluator.d.ts", | ||
| "import": "./dist/evaluator.js", | ||
| "require": "./dist/evaluator.cjs" | ||
| }, | ||
| "./environment": { | ||
| "types": "./dist/environment.d.ts", | ||
| "import": "./dist/environment.js", | ||
| "require": "./dist/environment.cjs" | ||
| } | ||
@@ -45,4 +55,4 @@ }, | ||
| "dependencies": { | ||
| "@isl-lang/parser": "0.1.0", | ||
| "@isl-lang/typechecker": "0.1.0" | ||
| "@isl-lang/parser": "1.0.0", | ||
| "@isl-lang/typechecker": "1.0.0" | ||
| }, | ||
@@ -56,6 +66,7 @@ "devDependencies": { | ||
| }, | ||
| "sideEffects": false, | ||
| "scripts": { | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "test": "vitest run", | ||
| "test": "vitest run --passWithNoTests", | ||
| "test:watch": "vitest", | ||
@@ -65,4 +76,5 @@ "test:coverage": "vitest run --coverage", | ||
| "typecheck": "tsc --noEmit", | ||
| "clean": "rimraf dist" | ||
| "clean": "rimraf dist", | ||
| "test:unit": "vitest run --passWithNoTests" | ||
| } | ||
| } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
995564
103.89%23
155.56%9250
99.7%1
-50%140
102.9%+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
Updated
Updated