stringent 0.0.1 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +96 -0
  2. package/dist/context.d.ts +45 -0
  3. package/dist/context.d.ts.map +1 -0
  4. package/dist/context.js +14 -0
  5. package/dist/context.js.map +1 -0
  6. package/dist/createParser.d.ts +159 -0
  7. package/dist/createParser.d.ts.map +1 -0
  8. package/dist/createParser.js +118 -0
  9. package/dist/createParser.js.map +1 -0
  10. package/dist/errors.d.ts +121 -0
  11. package/dist/errors.d.ts.map +1 -0
  12. package/dist/errors.js +186 -0
  13. package/dist/errors.js.map +1 -0
  14. package/dist/grammar/index.d.ts +48 -0
  15. package/dist/grammar/index.d.ts.map +1 -0
  16. package/dist/grammar/index.js +13 -0
  17. package/dist/grammar/index.js.map +1 -0
  18. package/dist/index.d.ts +27 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +31 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/parse/index.d.ts +211 -0
  23. package/dist/parse/index.d.ts.map +1 -0
  24. package/dist/parse/index.js +16 -0
  25. package/dist/parse/index.js.map +1 -0
  26. package/dist/performance.bench.d.ts +10 -0
  27. package/dist/performance.bench.d.ts.map +1 -0
  28. package/dist/performance.bench.js +379 -0
  29. package/dist/performance.bench.js.map +1 -0
  30. package/dist/primitive/index.d.ts +96 -0
  31. package/dist/primitive/index.d.ts.map +1 -0
  32. package/dist/primitive/index.js +102 -0
  33. package/dist/primitive/index.js.map +1 -0
  34. package/dist/runtime/eval.d.ts +157 -0
  35. package/dist/runtime/eval.d.ts.map +1 -0
  36. package/dist/runtime/eval.js +206 -0
  37. package/dist/runtime/eval.js.map +1 -0
  38. package/dist/runtime/infer.d.ts +27 -0
  39. package/dist/runtime/infer.d.ts.map +1 -0
  40. package/dist/runtime/infer.js +35 -0
  41. package/dist/runtime/infer.js.map +1 -0
  42. package/dist/runtime/parser.d.ts +115 -0
  43. package/dist/runtime/parser.d.ts.map +1 -0
  44. package/dist/runtime/parser.js +746 -0
  45. package/dist/runtime/parser.js.map +1 -0
  46. package/dist/schema/index.d.ts +476 -0
  47. package/dist/schema/index.d.ts.map +1 -0
  48. package/dist/schema/index.js +137 -0
  49. package/dist/schema/index.js.map +1 -0
  50. package/dist/static/infer.d.ts +27 -0
  51. package/dist/static/infer.d.ts.map +1 -0
  52. package/dist/static/infer.js +10 -0
  53. package/dist/static/infer.js.map +1 -0
  54. package/package.json +62 -8
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Runtime Expression Evaluation
3
+ *
4
+ * Evaluates parsed AST nodes to produce runtime values.
5
+ * Uses the eval functions defined in NodeSchema to compute results.
6
+ *
7
+ * The evaluator:
8
+ * 1. Recursively evaluates child nodes first
9
+ * 2. Passes evaluated values to the node's eval function
10
+ * 3. Returns the computed result
11
+ * 4. Validates values against arktype constraints at runtime
12
+ */
13
+ import type { NodeSchema, SchemaToType } from '../schema/index.js';
14
+ /**
15
+ * Extract the outputSchema from an AST node type.
16
+ * Returns the literal schema string if present, otherwise 'unknown'.
17
+ */
18
+ type ExtractOutputSchema<T> = T extends {
19
+ outputSchema: infer S extends string;
20
+ } ? S : 'unknown';
21
+ /**
22
+ * A type that represents any AST node with an outputSchema field.
23
+ * This is used as a constraint for the evaluate() function.
24
+ */
25
+ export type ASTNodeWithSchema<TSchema extends string = string> = {
26
+ readonly node: string;
27
+ readonly outputSchema: TSchema;
28
+ };
29
+ /**
30
+ * Recursively extract all identifier nodes from an AST.
31
+ * Returns a union of { name: string, outputSchema: string } tuples.
32
+ *
33
+ * This is used to determine what variables are used in an expression
34
+ * and what types they expect.
35
+ */
36
+ type ExtractIdentifiers<T> = T extends {
37
+ node: 'identifier';
38
+ name: infer N;
39
+ outputSchema: infer S;
40
+ } ? {
41
+ name: N;
42
+ outputSchema: S;
43
+ } : T extends object ? {
44
+ [K in keyof T]: ExtractIdentifiers<T[K]>;
45
+ }[keyof T] : never;
46
+ /**
47
+ * Convert a union of identifier tuples to a data object type.
48
+ *
49
+ * @example
50
+ * type Ids = { name: 'x'; outputSchema: 'number' } | { name: 'y'; outputSchema: 'string' };
51
+ * type Data = IdentifiersToData<Ids>;
52
+ * // { x: number; y: string }
53
+ */
54
+ type IdentifiersToData<T> = T extends {
55
+ name: infer N extends string;
56
+ outputSchema: infer S;
57
+ } ? {
58
+ [K in N]: SchemaToType<S>;
59
+ } : never;
60
+ /**
61
+ * Merge a union of single-key objects into a single object type.
62
+ *
63
+ * @example
64
+ * type Union = { x: number } | { y: string };
65
+ * type Merged = UnionToIntersection<Union>;
66
+ * // { x: number } & { y: string }
67
+ */
68
+ type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
69
+ /**
70
+ * Extract required data types from an AST based on its identifier nodes.
71
+ * Returns Record<string, never> if no identifiers are found (empty object is allowed).
72
+ *
73
+ * @example
74
+ * type AST = { node: 'add'; left: { node: 'identifier'; name: 'x'; outputSchema: 'number' }; ... };
75
+ * type Data = ExtractRequiredData<AST>;
76
+ * // { x: number }
77
+ */
78
+ export type ExtractRequiredData<T> = ExtractIdentifiers<T> extends never ? Record<string, never> : UnionToIntersection<IdentifiersToData<ExtractIdentifiers<T>>>;
79
+ /**
80
+ * Evaluation context that includes both the parse context and node schemas.
81
+ * When AST type is provided, the data is type-checked against the AST's variables.
82
+ */
83
+ export interface EvalContext<TData = Record<string, unknown>> {
84
+ /** The data context (variable name → value mapping) */
85
+ data: TData;
86
+ /** The node schemas (for looking up eval functions) */
87
+ nodes: readonly NodeSchema[];
88
+ }
89
+ /**
90
+ * Evaluate an AST node to produce a runtime value.
91
+ *
92
+ * The return type is inferred from the AST node's `outputSchema` field:
93
+ * - `outputSchema: "number"` → returns `number`
94
+ * - `outputSchema: "string"` → returns `string`
95
+ * - `outputSchema: "boolean"` → returns `boolean`
96
+ * - `outputSchema: "null"` → returns `null`
97
+ * - `outputSchema: "undefined"` → returns `undefined`
98
+ * - Other/unknown → returns `unknown`
99
+ *
100
+ * @param ast - The parsed AST node to evaluate
101
+ * @param ctx - The evaluation context containing variable values and node schemas
102
+ * @returns The evaluated value with the type derived from the AST's outputSchema
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * import { createParser, defineNode, lhs, rhs, constVal } from "stringent";
107
+ * import { evaluate } from "stringent/runtime/eval";
108
+ *
109
+ * const add = defineNode({
110
+ * name: "add",
111
+ * pattern: [lhs("number").as("left"), constVal("+"), rhs("number").as("right")],
112
+ * precedence: 1,
113
+ * resultType: "number",
114
+ * eval: ({ left, right }) => left + right,
115
+ * });
116
+ *
117
+ * const parser = createParser([add] as const);
118
+ * const result = parser.parse("1+2", {});
119
+ *
120
+ * if (result.length === 2) {
121
+ * const value = evaluate(result[0], { data: {}, nodes: [add] });
122
+ * // value has type: number (not unknown!)
123
+ * // value === 3
124
+ * }
125
+ * ```
126
+ */
127
+ export declare function evaluate<T, TData extends ExtractRequiredData<T>>(ast: T, ctx: EvalContext<TData>): SchemaToType<ExtractOutputSchema<T>>;
128
+ /**
129
+ * Create a bound evaluator function for a specific set of node schemas.
130
+ *
131
+ * This is a convenience function that pre-binds the node schemas,
132
+ * so you only need to pass the AST and variable values when evaluating.
133
+ *
134
+ * The returned evaluator function preserves type inference:
135
+ * - The return type is derived from the AST's `outputSchema` field
136
+ * - `outputSchema: "number"` → returns `number`
137
+ * - `outputSchema: "string"` → returns `string`
138
+ * - etc.
139
+ *
140
+ * @param nodes - The node schemas with eval functions
141
+ * @returns An evaluator function with type inference
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * const evaluator = createEvaluator([add, mul]);
146
+ *
147
+ * const result = parser.parse("1+2*3", {});
148
+ * if (result.length === 2) {
149
+ * const value = evaluator(result[0], {});
150
+ * // value has type: number (inferred from AST's outputSchema)
151
+ * // value === 7
152
+ * }
153
+ * ```
154
+ */
155
+ export declare function createEvaluator(nodes: readonly NodeSchema[]): <T, TData extends ExtractRequiredData<T>>(ast: T, data: TData) => SchemaToType<ExtractOutputSchema<T>>;
156
+ export {};
157
+ //# sourceMappingURL=eval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../src/runtime/eval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMnE;;;GAGG;AACH,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,YAAY,EAAE,MAAM,CAAC,SAAS,MAAM,CAAA;CAAE,GAAG,CAAC,GAAG,SAAS,CAAC;AAEjG;;;GAGG;AACH,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,IAAI;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC,CAAC;AAMF;;;;;;GAMG;AACH,KAAK,kBAAkB,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC,CAAA;CAAE,GAC/F;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,YAAY,EAAE,CAAC,CAAA;CAAE,GAC5B,CAAC,SAAS,MAAM,GACd;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAAC,MAAM,CAAC,CAAC,GACrD,KAAK,CAAC;AAEZ;;;;;;;GAOG;AACH,KAAK,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS;IACpC,IAAI,EAAE,MAAM,CAAC,SAAS,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC,CAAC;CACvB,GACG;KAAG,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;CAAE,GAC7B,KAAK,CAAC;AAEV;;;;;;;GAOG;AACH,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,SAAS,CACjF,CAAC,EAAE,MAAM,CAAC,KACP,IAAI,GACL,CAAC,GACD,KAAK,CAAC;AAEV;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAC/B,kBAAkB,CAAC,CAAC,CAAC,SAAS,KAAK,GAC/B,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACrB,mBAAmB,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpE;;;GAGG;AACH,MAAM,WAAW,WAAW,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1D,uDAAuD;IACvD,IAAI,EAAE,KAAK,CAAC;IACZ,uDAAuD;IACvD,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;CAC9B;AA0DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,SAAS,mBAAmB,CAAC,CAAC,CAAC,EAC9D,GAAG,EAAE,CAAC,EACN,GAAG,EAAE,WAAW,CAAC,KAAK,CAAC,GACtB,YAAY,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAgGtC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,IAChC,CAAC,EAAE,KAAK,SAAS,mBAAmB,CAAC,CAAC,CAAC,EAC/D,KAAK,CAAC,EACN,MAAM,KAAK,KACV,YAAY,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAGxC"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Runtime Expression Evaluation
3
+ *
4
+ * Evaluates parsed AST nodes to produce runtime values.
5
+ * Uses the eval functions defined in NodeSchema to compute results.
6
+ *
7
+ * The evaluator:
8
+ * 1. Recursively evaluates child nodes first
9
+ * 2. Passes evaluated values to the node's eval function
10
+ * 3. Returns the computed result
11
+ * 4. Validates values against arktype constraints at runtime
12
+ */
13
+ import { type } from 'arktype';
14
+ // =============================================================================
15
+ // Runtime ArkType Validation
16
+ // =============================================================================
17
+ /**
18
+ * Cache for arktype validators to avoid re-creating them for each evaluation.
19
+ * Maps schema strings to their compiled validators.
20
+ */
21
+ const validatorCache = new Map();
22
+ /**
23
+ * Get or create an arktype validator for a given schema string.
24
+ * Uses a cache to avoid re-creating validators for frequently used schemas.
25
+ *
26
+ * @param schema - The arktype schema string (e.g., 'number >= 0', 'string.email')
27
+ * @returns The compiled arktype validator
28
+ */
29
+ function getValidator(schema) {
30
+ let validator = validatorCache.get(schema);
31
+ if (!validator) {
32
+ // Create and cache the validator
33
+ // Note: Invalid schemas will cause arktype to throw at compile time
34
+ // At runtime, we trust the schema was validated at parse time
35
+ validator = type(schema);
36
+ validatorCache.set(schema, validator);
37
+ }
38
+ return validator;
39
+ }
40
+ /**
41
+ * Validate a value against an arktype schema at runtime.
42
+ * Throws an error if the value doesn't match the schema constraints.
43
+ *
44
+ * @param value - The value to validate
45
+ * @param schema - The arktype schema string (e.g., 'number >= 0', 'string.email')
46
+ * @param variableName - The name of the variable (for error messages)
47
+ * @throws Error if the value doesn't match the schema constraints
48
+ */
49
+ function validateValue(value, schema, variableName) {
50
+ // Skip validation for generic schemas that don't have runtime constraints
51
+ // These basic types are handled by TypeScript's compile-time checking
52
+ if (schema === 'unknown' || schema === 'never') {
53
+ return;
54
+ }
55
+ const validator = getValidator(schema);
56
+ const result = validator(value);
57
+ // arktype returns the value if valid, or an ArkErrors object if invalid
58
+ if (result instanceof type.errors) {
59
+ throw new Error(`Variable '${variableName}' failed validation for schema '${schema}': ${result.summary}`);
60
+ }
61
+ }
62
+ /**
63
+ * Evaluate an AST node to produce a runtime value.
64
+ *
65
+ * The return type is inferred from the AST node's `outputSchema` field:
66
+ * - `outputSchema: "number"` → returns `number`
67
+ * - `outputSchema: "string"` → returns `string`
68
+ * - `outputSchema: "boolean"` → returns `boolean`
69
+ * - `outputSchema: "null"` → returns `null`
70
+ * - `outputSchema: "undefined"` → returns `undefined`
71
+ * - Other/unknown → returns `unknown`
72
+ *
73
+ * @param ast - The parsed AST node to evaluate
74
+ * @param ctx - The evaluation context containing variable values and node schemas
75
+ * @returns The evaluated value with the type derived from the AST's outputSchema
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * import { createParser, defineNode, lhs, rhs, constVal } from "stringent";
80
+ * import { evaluate } from "stringent/runtime/eval";
81
+ *
82
+ * const add = defineNode({
83
+ * name: "add",
84
+ * pattern: [lhs("number").as("left"), constVal("+"), rhs("number").as("right")],
85
+ * precedence: 1,
86
+ * resultType: "number",
87
+ * eval: ({ left, right }) => left + right,
88
+ * });
89
+ *
90
+ * const parser = createParser([add] as const);
91
+ * const result = parser.parse("1+2", {});
92
+ *
93
+ * if (result.length === 2) {
94
+ * const value = evaluate(result[0], { data: {}, nodes: [add] });
95
+ * // value has type: number (not unknown!)
96
+ * // value === 3
97
+ * }
98
+ * ```
99
+ */
100
+ export function evaluate(ast, ctx) {
101
+ if (typeof ast !== 'object' || ast === null) {
102
+ throw new Error(`Invalid AST node: expected object, got ${typeof ast}`);
103
+ }
104
+ const node = ast;
105
+ // Check for the 'node' property that indicates the node type
106
+ if (!('node' in node) || typeof node.node !== 'string') {
107
+ throw new Error(`Invalid AST node: missing 'node' property`);
108
+ }
109
+ const nodeType = node.node;
110
+ // Handle literal nodes (number, string, boolean, null, undefined)
111
+ if (nodeType === 'literal') {
112
+ if ('value' in node) {
113
+ return node.value;
114
+ }
115
+ throw new Error(`Literal node missing 'value' property`);
116
+ }
117
+ // Internal eval context for recursive calls (typed at runtime level)
118
+ const internalCtx = ctx;
119
+ // Handle identifier nodes - look up value in context and validate against schema
120
+ if (nodeType === 'identifier') {
121
+ if (!('name' in node) || typeof node.name !== 'string') {
122
+ throw new Error(`Identifier node missing 'name' property`);
123
+ }
124
+ const name = node.name;
125
+ if (!(name in internalCtx.data)) {
126
+ throw new Error(`Undefined variable: ${name}`);
127
+ }
128
+ const value = internalCtx.data[name];
129
+ // Validate value against arktype schema at runtime
130
+ if ('outputSchema' in node && typeof node.outputSchema === 'string') {
131
+ validateValue(value, node.outputSchema, name);
132
+ }
133
+ return value;
134
+ }
135
+ // Handle const nodes (operators, keywords) - these shouldn't be evaluated directly
136
+ if (nodeType === 'const') {
137
+ throw new Error(`Cannot evaluate const node directly`);
138
+ }
139
+ // Handle parentheses - just evaluate the inner expression
140
+ if (nodeType === 'parentheses') {
141
+ if (!('inner' in node)) {
142
+ throw new Error(`Parentheses node missing 'inner' property`);
143
+ }
144
+ // Use type assertion for recursive call (data constraint already validated at entry)
145
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
146
+ return evaluate(node.inner, internalCtx);
147
+ }
148
+ // Look up the node schema for this node type
149
+ const nodeSchema = internalCtx.nodes.find((n) => n.name === nodeType);
150
+ if (!nodeSchema) {
151
+ throw new Error(`Unknown node type: ${nodeType}. Make sure to pass all node schemas to evaluate().`);
152
+ }
153
+ if (!nodeSchema.eval) {
154
+ throw new Error(`Node type '${nodeType}' has no eval function defined`);
155
+ }
156
+ // Extract and evaluate all named bindings from the node
157
+ const evaluatedBindings = {};
158
+ // Get the pattern to determine which fields are named bindings
159
+ for (const element of nodeSchema.pattern) {
160
+ // Check if this is a named schema (has __named and name)
161
+ if ('__named' in element && element.__named === true && 'name' in element) {
162
+ const bindingName = element.name;
163
+ if (bindingName in node) {
164
+ // Recursively evaluate the child node
165
+ // Use type assertion for recursive call (data constraint already validated at entry)
166
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
167
+ evaluatedBindings[bindingName] = evaluate(node[bindingName], internalCtx);
168
+ }
169
+ }
170
+ }
171
+ // Call the eval function with evaluated bindings
172
+ return nodeSchema.eval(evaluatedBindings, internalCtx.data);
173
+ }
174
+ /**
175
+ * Create a bound evaluator function for a specific set of node schemas.
176
+ *
177
+ * This is a convenience function that pre-binds the node schemas,
178
+ * so you only need to pass the AST and variable values when evaluating.
179
+ *
180
+ * The returned evaluator function preserves type inference:
181
+ * - The return type is derived from the AST's `outputSchema` field
182
+ * - `outputSchema: "number"` → returns `number`
183
+ * - `outputSchema: "string"` → returns `string`
184
+ * - etc.
185
+ *
186
+ * @param nodes - The node schemas with eval functions
187
+ * @returns An evaluator function with type inference
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * const evaluator = createEvaluator([add, mul]);
192
+ *
193
+ * const result = parser.parse("1+2*3", {});
194
+ * if (result.length === 2) {
195
+ * const value = evaluator(result[0], {});
196
+ * // value has type: number (inferred from AST's outputSchema)
197
+ * // value === 7
198
+ * }
199
+ * ```
200
+ */
201
+ export function createEvaluator(nodes) {
202
+ return function evaluator(ast, data) {
203
+ return evaluate(ast, { data, nodes });
204
+ };
205
+ }
206
+ //# sourceMappingURL=eval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval.js","sourceRoot":"","sources":["../../src/runtime/eval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Runtime Type Inference
3
+ *
4
+ * Infers the result type of a parsed AST at runtime.
5
+ *
6
+ * With the new architecture, nodes carry their outputSchema directly,
7
+ * so inference is simpler - just extract the outputSchema field.
8
+ */
9
+ import type { Context } from '../context.js';
10
+ export type InferredType = string;
11
+ /**
12
+ * Runtime inference - extracts outputSchema from parsed AST nodes.
13
+ *
14
+ * @param ast - The parsed AST node
15
+ * @param context - Parse context (unused, kept for API compatibility)
16
+ * @returns The result type of the AST node
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const result = parser.parse("1+2", {});
21
+ * if (result.length === 2) {
22
+ * const type = infer(result[0], {}); // "number"
23
+ * }
24
+ * ```
25
+ */
26
+ export declare function infer(ast: unknown, _context: Context): InferredType;
27
+ //# sourceMappingURL=infer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infer.d.ts","sourceRoot":"","sources":["../../src/runtime/infer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,YAAY,CAanE"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Runtime Type Inference
3
+ *
4
+ * Infers the result type of a parsed AST at runtime.
5
+ *
6
+ * With the new architecture, nodes carry their outputSchema directly,
7
+ * so inference is simpler - just extract the outputSchema field.
8
+ */
9
+ /**
10
+ * Runtime inference - extracts outputSchema from parsed AST nodes.
11
+ *
12
+ * @param ast - The parsed AST node
13
+ * @param context - Parse context (unused, kept for API compatibility)
14
+ * @returns The result type of the AST node
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const result = parser.parse("1+2", {});
19
+ * if (result.length === 2) {
20
+ * const type = infer(result[0], {}); // "number"
21
+ * }
22
+ * ```
23
+ */
24
+ export function infer(ast, _context) {
25
+ if (typeof ast !== 'object' || ast === null) {
26
+ throw new Error(`Invalid AST node: ${ast}`);
27
+ }
28
+ const node = ast;
29
+ // Nodes with outputSchema (new architecture)
30
+ if ('outputSchema' in node && typeof node.outputSchema === 'string') {
31
+ return node.outputSchema;
32
+ }
33
+ throw new Error(`AST node has no outputSchema: ${JSON.stringify(ast)}`);
34
+ }
35
+ //# sourceMappingURL=infer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"infer.js","sourceRoot":"","sources":["../../src/runtime/infer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,KAAK,CAAC,GAAY,EAAE,QAAiB;IACnD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,GAAG,GAA8B,CAAC;IAE5C,6CAA6C;IAC7C,IAAI,cAAc,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QACpE,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Runtime Parser
3
+ *
4
+ * Mirrors the type-level Parse<Grammar, Input, Context> at runtime.
5
+ * Uses the same precedence-based parsing strategy:
6
+ * 1. Try operators at current level (lowest precedence first)
7
+ * 2. Fall back to next level (higher precedence)
8
+ * 3. Base case: try atoms (last level)
9
+ */
10
+ import type { Context } from '../context.js';
11
+ import type { ComputeGrammar, Grammar } from '../grammar/index.js';
12
+ import type { Parse } from '../parse/index.js';
13
+ import type { NodeSchema, StringSchema, ConstSchema, ExprSchema } from '../schema/index.js';
14
+ import { ASTNode } from '../primitive/index.js';
15
+ /** All built-in atoms, used as the last level of the grammar */
16
+ export declare const BUILT_IN_ATOMS: readonly [NodeSchema<"numberLiteral", readonly [import("../schema/index.js").NumberSchema & {
17
+ as<TName extends string>(name: TName): import("../schema/index.js").NamedSchema<import("../schema/index.js").NumberSchema, TName>;
18
+ }], 0, "number">, NodeSchema<"stringLiteral", readonly [StringSchema<readonly ["\"", "'"]> & {
19
+ as<TName extends string>(name: TName): import("../schema/index.js").NamedSchema<StringSchema<readonly ["\"", "'"]>, TName>;
20
+ }], 0, "string">, NodeSchema<"nullLiteral", readonly [import("../schema/index.js").NullSchema & {
21
+ as<TName extends string>(name: TName): import("../schema/index.js").NamedSchema<import("../schema/index.js").NullSchema, TName>;
22
+ }], 0, "null">, NodeSchema<"booleanLiteral", readonly [import("../schema/index.js").BooleanSchema & {
23
+ as<TName extends string>(name: TName): import("../schema/index.js").NamedSchema<import("../schema/index.js").BooleanSchema, TName>;
24
+ }], 0, "boolean">, NodeSchema<"undefinedLiteral", readonly [import("../schema/index.js").UndefinedSchema & {
25
+ as<TName extends string>(name: TName): import("../schema/index.js").NamedSchema<import("../schema/index.js").UndefinedSchema, TName>;
26
+ }], 0, "undefined">, NodeSchema<"identifier", readonly [import("../schema/index.js").IdentSchema & {
27
+ as<TName extends string>(name: TName): import("../schema/index.js").NamedSchema<import("../schema/index.js").IdentSchema, TName>;
28
+ }], 0, "unknown">, NodeSchema<"parentheses", readonly [ConstSchema<"("> & {
29
+ as<TName extends string>(name: TName): import("../schema/index.js").NamedSchema<ConstSchema<"(">, TName>;
30
+ }, import("../schema/index.js").NamedSchema<ExprSchema<string, "expr">, "inner">, ConstSchema<")"> & {
31
+ as<TName extends string>(name: TName): import("../schema/index.js").NamedSchema<ConstSchema<")">, TName>;
32
+ }], 0, "unknown">];
33
+ /** Parse result: empty = no match, [node, rest] = matched */
34
+ export type ParseResult<T extends ASTNode<string, unknown> = ASTNode<string, unknown>> = [] | [T & {}, string];
35
+ /**
36
+ * Process escape sequences in a string.
37
+ * Supports: \n, \t, \r, \\, \", \', \0, \b, \f, \v, \xHH, \uHHHH
38
+ *
39
+ * @param str - The raw string with escape sequences
40
+ * @returns The processed string with escape sequences converted
41
+ */
42
+ export declare function processEscapeSequences(str: string): string;
43
+ /**
44
+ * Build runtime grammar from operator schemas.
45
+ *
46
+ * Returns a flat tuple of levels:
47
+ * [[ops@prec1], [ops@prec2], ..., [builtInAtoms]]
48
+ *
49
+ * Operators are sorted by precedence ascending (lowest first).
50
+ * Built-in atoms are always appended as the last level.
51
+ */
52
+ export declare function buildGrammar(operators: readonly NodeSchema[]): Grammar;
53
+ /**
54
+ * Parse input string using node schemas.
55
+ *
56
+ * The return type is computed from the input types using the type-level
57
+ * Parse<Grammar, Input, Context> type, ensuring runtime and type-level
58
+ * parsing stay in sync.
59
+ */
60
+ export declare function parse<const TNodes extends readonly NodeSchema[], const TInput extends string, const TContext extends Context>(nodes: TNodes, input: TInput, context: TContext): Parse<ComputeGrammar<TNodes>, TInput, TContext>;
61
+ import { type RichParseError, type ParseResultWithErrors } from '../errors.js';
62
+ export type { RichParseError, ParseResultWithErrors };
63
+ /**
64
+ * Result from parseWithErrors - includes rich error information on failure.
65
+ */
66
+ export interface ParseWithErrorsResult<T extends ASTNode<string, unknown> = ASTNode<string, unknown>> {
67
+ /** Whether parsing was successful */
68
+ readonly success: boolean;
69
+ /** The parsed AST node (only present if success is true) */
70
+ readonly ast?: T;
71
+ /** Remaining unparsed input (only present if success is true) */
72
+ readonly remaining?: string;
73
+ /** Parse error information (only present if success is false) */
74
+ readonly error?: RichParseError;
75
+ /** Original input string */
76
+ readonly input: string;
77
+ }
78
+ /**
79
+ * Parse input with rich error information.
80
+ *
81
+ * Unlike `parse()` which returns an empty array on failure, this function
82
+ * returns detailed error information including:
83
+ * - Position (line, column, offset)
84
+ * - Error message
85
+ * - Source snippet showing where the error occurred
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * const result = parseWithErrors([add], "1 + ", context);
90
+ * if (!result.success) {
91
+ * console.log(result.error.message);
92
+ * // "No grammar rule matched at position 1:5: """
93
+ * console.log(result.error.snippet);
94
+ * // "1 + →"
95
+ * }
96
+ * ```
97
+ */
98
+ export declare function parseWithErrors<const TNodes extends readonly NodeSchema[], const TInput extends string, const TContext extends Context>(nodes: TNodes, input: TInput, context: TContext): ParseWithErrorsResult;
99
+ /**
100
+ * Format a parse error for display.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const result = parseWithErrors([add], "1 + ", context);
105
+ * if (!result.success) {
106
+ * console.log(formatParseError(result.error));
107
+ * // Error at line 1, column 5:
108
+ * // No grammar rule matched at position 1:5: ""
109
+ * //
110
+ * // 1 + →
111
+ * }
112
+ * ```
113
+ */
114
+ export declare function formatParseError(error: RichParseError): string;
115
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/runtime/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EACV,UAAU,EAEV,YAAY,EACZ,WAAW,EACX,UAAU,EAEX,MAAM,oBAAoB,CAAC;AAa5B,OAAO,EACL,OAAO,EAOR,MAAM,uBAAuB,CAAC;AA2E/B,gEAAgE;AAGhE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;kBAQjB,CAAC;AAEX,6DAA6D;AAC7D,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,IACjF,EAAE,GACF,CAAC,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;AAoBrB;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA+F1D;AA6KD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAuBtE;AA4TD;;;;;;GAMG;AACH,wBAAgB,KAAK,CACnB,KAAK,CAAC,MAAM,SAAS,SAAS,UAAU,EAAE,EAC1C,KAAK,CAAC,MAAM,SAAS,MAAM,EAC3B,KAAK,CAAC,QAAQ,SAAS,OAAO,EAE9B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,QAAQ,GAChB,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAOjD;AAMD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAG3B,MAAM,cAAc,CAAC;AAEtB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,qBAAqB,CACpC,CAAC,SAAS,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;IAE7D,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,4DAA4D;IAC5D,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACjB,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAC7B,KAAK,CAAC,MAAM,SAAS,SAAS,UAAU,EAAE,EAC1C,KAAK,CAAC,MAAM,SAAS,MAAM,EAC3B,KAAK,CAAC,QAAQ,SAAS,OAAO,EAC9B,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,GAAG,qBAAqB,CA+BxE;AAsCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAmB9D"}