@rcrsr/rill 0.16.0 → 0.17.0
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.
- package/README.md +37 -21
- package/dist/ext/crypto/index.d.ts +3 -3
- package/dist/ext/crypto/index.js +61 -58
- package/dist/ext/exec/index.d.ts +3 -3
- package/dist/ext/exec/index.js +14 -8
- package/dist/ext/fetch/index.d.ts +3 -3
- package/dist/ext/fetch/index.js +16 -11
- package/dist/ext/fs/index.d.ts +3 -3
- package/dist/ext/fs/index.js +242 -239
- package/dist/ext/kv/index.d.ts +3 -3
- package/dist/ext/kv/index.js +197 -195
- package/dist/ext/kv/store.js +2 -1
- package/dist/ext-parse-bridge.d.ts +10 -0
- package/dist/ext-parse-bridge.js +10 -0
- package/dist/generated/introspection-data.d.ts +1 -1
- package/dist/generated/introspection-data.js +385 -296
- package/dist/generated/version-data.d.ts +1 -1
- package/dist/generated/version-data.js +2 -2
- package/dist/index.d.ts +15 -4
- package/dist/index.js +14 -5
- package/dist/parser/parser-types.js +12 -0
- package/dist/parser/parser-use.js +7 -1
- package/dist/runtime/core/callable.d.ts +20 -8
- package/dist/runtime/core/callable.js +63 -23
- package/dist/runtime/core/context.d.ts +0 -11
- package/dist/runtime/core/context.js +76 -75
- package/dist/runtime/core/eval/index.d.ts +2 -2
- package/dist/runtime/core/eval/index.js +11 -0
- package/dist/runtime/core/eval/mixins/closures.js +15 -15
- package/dist/runtime/core/eval/mixins/conversion.js +51 -110
- package/dist/runtime/core/eval/mixins/core.js +2 -2
- package/dist/runtime/core/eval/mixins/expressions.js +35 -27
- package/dist/runtime/core/eval/mixins/literals.js +3 -3
- package/dist/runtime/core/eval/mixins/types.js +44 -54
- package/dist/runtime/core/eval/mixins/variables.js +10 -8
- package/dist/runtime/core/field-descriptor.d.ts +3 -3
- package/dist/runtime/core/field-descriptor.js +2 -1
- package/dist/runtime/core/introspection.js +6 -6
- package/dist/runtime/core/markers.d.ts +12 -0
- package/dist/runtime/core/markers.js +7 -0
- package/dist/runtime/core/type-registrations.d.ts +136 -0
- package/dist/runtime/core/type-registrations.js +749 -0
- package/dist/runtime/core/type-structures.d.ts +128 -0
- package/dist/runtime/core/type-structures.js +12 -0
- package/dist/runtime/core/types.d.ts +15 -3
- package/dist/runtime/core/values.d.ts +62 -153
- package/dist/runtime/core/values.js +308 -524
- package/dist/runtime/ext/builtins.js +83 -64
- package/dist/runtime/ext/extensions.d.ts +30 -124
- package/dist/runtime/ext/extensions.js +0 -93
- package/dist/runtime/ext/test-context.d.ts +28 -0
- package/dist/runtime/ext/test-context.js +154 -0
- package/dist/runtime/index.d.ts +22 -8
- package/dist/runtime/index.js +18 -4
- package/dist/signature-parser.d.ts +2 -2
- package/dist/signature-parser.js +14 -14
- package/package.json +1 -1
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Version string from package.json
|
|
5
5
|
*/
|
|
6
|
-
export const VERSION = '0.
|
|
6
|
+
export const VERSION = '0.17.0';
|
|
7
7
|
/**
|
|
8
8
|
* Parsed version components
|
|
9
9
|
*/
|
|
10
10
|
export const VERSION_INFO = {
|
|
11
11
|
major: 0,
|
|
12
|
-
minor:
|
|
12
|
+
minor: 17,
|
|
13
13
|
patch: 0,
|
|
14
14
|
prerelease: undefined,
|
|
15
15
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -5,11 +5,22 @@
|
|
|
5
5
|
export { LexerError, tokenize, type TokenizeOptions } from './lexer/index.js';
|
|
6
6
|
export { parse, parseWithRecovery } from './parser/index.js';
|
|
7
7
|
export type { ParseResult, RecoveryErrorNode, ErrorNode } from './types.js';
|
|
8
|
-
export { anyTypeValue, type ApplicationCallable, BreakSignal, callable, type CallableFn, type CallFrame, commonType, type CaptureEvent, type ConfigFieldDescriptor, createRuntimeContext, createStepper, createTuple, createVector, type DocumentationCoverageResult, emitExtensionEvent,
|
|
9
|
-
/** @deprecated Use
|
|
10
|
-
export type {
|
|
8
|
+
export { anyTypeValue, type ApplicationCallable, BreakSignal, buildFieldDescriptor, callable, type CallableFn, type CallFrame, commonType, type CaptureEvent, type ConfigFieldDescriptor, contextResolver, createRuntimeContext, createStepper, createTestContext, createTuple, createVector, type DocumentationCoverageResult, emitExtensionEvent, type ErrorEvent, execute, type ExecutionResult, type ExecutionStepper, ExtensionBindingError, type ExtensionConfigSchema, type ExtensionEvent, type ExtensionFactory, type ExtensionFactoryResult, type ExtensionManifest, extResolver, formatStructure, type FsExtensionContract, type FunctionMetadata, type FunctionReturnEvent, generateManifest, getCallStack, getDocumentationCoverage, getFunctions, getLanguageReference, type HostCallEvent, inferElementType, inferStructure, inferType, invokeCallable, isApplicationCallable, isCallable, isDict, isIterator, isReservedMethod, isRuntimeCallable, isScriptCallable, isTuple, isTypeValue, isVector, type KvExtensionContract, moduleResolver, type NativeArray, type NativePlainObject, type NativeResult, type NativeValue, type ObservabilityCallbacks, type ParamMetadata, paramToFieldDef, popCallFrame, pushCallFrame, RESERVED_DICT_METHODS, type ResolverResult, ReturnSignal, type RillCallable, type RillFieldDef, type RillFunction, type RillIterator, type RillParam, type RillTuple, type RillTypeValue, type RillValue, type RillVector, type RuntimeCallable, type RuntimeCallbacks, type RuntimeContext, type RuntimeOptions, type SchemaEntry, type SchemeResolver, type ScriptCallable, type StepEndEvent, type StepResult, type StepStartEvent, structureEquals, structureMatches, structureToTypeValue, toCallable, toNative, type TypeDefinition, type TypeProtocol, type TypeStructure, VERSION, VERSION_INFO, type VersionInfo, } from './runtime/index.js';
|
|
9
|
+
/** @deprecated Use TypeStructure instead. Will be removed in the next major version. */
|
|
10
|
+
export type { RillType } from './runtime/index.js';
|
|
11
|
+
/** @deprecated Use formatStructure instead. */
|
|
12
|
+
export { formatStructuralType } from './runtime/index.js';
|
|
13
|
+
/** @deprecated Use inferStructure instead. */
|
|
14
|
+
export { inferStructuralType } from './runtime/index.js';
|
|
15
|
+
/** @deprecated Use isIterator instead. */
|
|
16
|
+
export { isRillIterator } from './runtime/index.js';
|
|
17
|
+
/** @deprecated Use structureToTypeValue instead. */
|
|
18
|
+
export { rillTypeToTypeValue } from './runtime/index.js';
|
|
19
|
+
/** @deprecated Use structureEquals instead. */
|
|
20
|
+
export { structuralTypeEquals } from './runtime/index.js';
|
|
21
|
+
/** @deprecated Use structureMatches instead. */
|
|
22
|
+
export { structuralTypeMatches } from './runtime/index.js';
|
|
11
23
|
export { type ErrorCategory, type ErrorDefinition, type ErrorSeverity, ERROR_REGISTRY, renderMessage, getHelpUrl, createError, } from './types.js';
|
|
12
24
|
export { formatRillError, formatRillErrorJson, type FormatErrorOptions, type FormatErrorJsonOptions, type SourceMap, } from './error-formatter.js';
|
|
13
|
-
export { VALID_TYPE_NAMES } from './constants.js';
|
|
14
25
|
export { type HighlightCategory, TOKEN_HIGHLIGHT_MAP, } from './highlight-map.js';
|
|
15
26
|
export * from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,20 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { LexerError, tokenize } from './lexer/index.js';
|
|
6
6
|
export { parse, parseWithRecovery } from './parser/index.js';
|
|
7
|
-
export { anyTypeValue, BreakSignal, callable, commonType, createRuntimeContext, createStepper, createTuple, createVector, emitExtensionEvent,
|
|
7
|
+
export { anyTypeValue, BreakSignal, buildFieldDescriptor, callable, commonType, contextResolver, createRuntimeContext, createStepper, createTestContext, createTuple, createVector, emitExtensionEvent, execute, ExtensionBindingError, extResolver, formatStructure, generateManifest, getCallStack, getDocumentationCoverage, getFunctions, getLanguageReference, inferElementType, inferStructure, inferType, invokeCallable, isApplicationCallable, isCallable, isDict, isIterator, isReservedMethod, isRuntimeCallable, isScriptCallable, isTuple, isTypeValue, isVector, moduleResolver, paramToFieldDef, popCallFrame, pushCallFrame, RESERVED_DICT_METHODS, ReturnSignal, structureEquals, structureMatches, structureToTypeValue, toCallable, toNative, VERSION, VERSION_INFO, } from './runtime/index.js';
|
|
8
|
+
// Deprecated aliases — old names kept for one release
|
|
9
|
+
/** @deprecated Use formatStructure instead. */
|
|
10
|
+
export { formatStructuralType } from './runtime/index.js';
|
|
11
|
+
/** @deprecated Use inferStructure instead. */
|
|
12
|
+
export { inferStructuralType } from './runtime/index.js';
|
|
13
|
+
/** @deprecated Use isIterator instead. */
|
|
14
|
+
export { isRillIterator } from './runtime/index.js';
|
|
15
|
+
/** @deprecated Use structureToTypeValue instead. */
|
|
16
|
+
export { rillTypeToTypeValue } from './runtime/index.js';
|
|
17
|
+
/** @deprecated Use structureEquals instead. */
|
|
18
|
+
export { structuralTypeEquals } from './runtime/index.js';
|
|
19
|
+
/** @deprecated Use structureMatches instead. */
|
|
20
|
+
export { structuralTypeMatches } from './runtime/index.js';
|
|
8
21
|
// ============================================================
|
|
9
22
|
// ERROR TAXONOMY
|
|
10
23
|
// ============================================================
|
|
@@ -14,10 +27,6 @@ export { ERROR_REGISTRY, renderMessage, getHelpUrl, createError, } from './types
|
|
|
14
27
|
// ============================================================
|
|
15
28
|
export { formatRillError, formatRillErrorJson, } from './error-formatter.js';
|
|
16
29
|
// ============================================================
|
|
17
|
-
// CONSTANTS
|
|
18
|
-
// ============================================================
|
|
19
|
-
export { VALID_TYPE_NAMES } from './constants.js';
|
|
20
|
-
// ============================================================
|
|
21
30
|
// SYNTAX HIGHLIGHTING
|
|
22
31
|
// ============================================================
|
|
23
32
|
export { TOKEN_HIGHLIGHT_MAP, } from './highlight-map.js';
|
|
@@ -98,6 +98,18 @@ export function parseTypeRef(state, opts) {
|
|
|
98
98
|
* @internal
|
|
99
99
|
*/
|
|
100
100
|
function parseSingleType(state, opts) {
|
|
101
|
+
// Zero-param closure type: || :returnType or bare ||
|
|
102
|
+
if (check(state, TOKEN_TYPES.OR)) {
|
|
103
|
+
advance(state); // consume || (OR token)
|
|
104
|
+
// Check for :returnType
|
|
105
|
+
if (check(state, TOKEN_TYPES.COLON)) {
|
|
106
|
+
advance(state); // consume :
|
|
107
|
+
const ret = parseSingleType(state, opts);
|
|
108
|
+
return { kind: 'static', typeName: 'closure', args: [{ value: ret }] };
|
|
109
|
+
}
|
|
110
|
+
// Bare || without :returnType — equivalent to 'closure'
|
|
111
|
+
return { kind: 'static', typeName: 'closure' };
|
|
112
|
+
}
|
|
101
113
|
if (check(state, TOKEN_TYPES.DOLLAR)) {
|
|
102
114
|
advance(state); // consume $
|
|
103
115
|
const nameToken = expect(state, TOKEN_TYPES.IDENTIFIER, 'Expected variable name after $');
|
|
@@ -56,7 +56,13 @@ Parser.prototype.parseUseExpr = function () {
|
|
|
56
56
|
let typeRef = null;
|
|
57
57
|
let closureAnnotation = null;
|
|
58
58
|
if (check(this.state, TOKEN_TYPES.COLON)) {
|
|
59
|
-
if (peek(this.state, 1).type === TOKEN_TYPES.
|
|
59
|
+
if (peek(this.state, 1).type === TOKEN_TYPES.OR) {
|
|
60
|
+
// Zero-param closure annotation: :||
|
|
61
|
+
advance(this.state); // consume :
|
|
62
|
+
advance(this.state); // consume || (OR token)
|
|
63
|
+
closureAnnotation = [];
|
|
64
|
+
}
|
|
65
|
+
else if (peek(this.state, 1).type === TOKEN_TYPES.PIPE_BAR) {
|
|
60
66
|
// Closure annotation: :|param: type, ...|
|
|
61
67
|
advance(this.state); // consume :
|
|
62
68
|
advance(this.state); // consume opening |
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* - Kept for API consistency with marshalArgs signature
|
|
21
21
|
*/
|
|
22
22
|
import type { BodyNode, SourceLocation } from '../../types.js';
|
|
23
|
-
import type {
|
|
23
|
+
import type { TypeStructure, RillTypeValue, RillValue } from './values.js';
|
|
24
24
|
interface RuntimeContextLike {
|
|
25
25
|
readonly parent?: RuntimeContextLike | undefined;
|
|
26
26
|
readonly variables: Map<string, RillValue>;
|
|
@@ -42,7 +42,7 @@ export type CallableFn = (args: Record<string, RillValue>, ctx: RuntimeContextLi
|
|
|
42
42
|
*/
|
|
43
43
|
export interface RillParam {
|
|
44
44
|
readonly name: string;
|
|
45
|
-
readonly type:
|
|
45
|
+
readonly type: TypeStructure | undefined;
|
|
46
46
|
readonly defaultValue: RillValue | undefined;
|
|
47
47
|
readonly annotations: Record<string, RillValue>;
|
|
48
48
|
}
|
|
@@ -57,6 +57,8 @@ export interface RillFunction {
|
|
|
57
57
|
readonly fn: CallableFn;
|
|
58
58
|
readonly annotations?: Record<string, RillValue>;
|
|
59
59
|
readonly returnType: RillTypeValue;
|
|
60
|
+
/** When true, RILL-R003 generic receiver validation is skipped for this method. */
|
|
61
|
+
readonly skipReceiverValidation?: boolean;
|
|
60
62
|
}
|
|
61
63
|
/** Common fields for all callable types */
|
|
62
64
|
interface CallableBase {
|
|
@@ -112,6 +114,16 @@ export declare function isApplicationCallable(value: RillValue): value is Applic
|
|
|
112
114
|
* @param isProperty If true, auto-invokes when accessed from dict (property-style)
|
|
113
115
|
*/
|
|
114
116
|
export declare function callable(fn: CallableFn, isProperty?: boolean): ApplicationCallable;
|
|
117
|
+
/**
|
|
118
|
+
* Convert a RillFunction to an ApplicationCallable.
|
|
119
|
+
*
|
|
120
|
+
* Validates the input and produces a callable value accepted by the loader.
|
|
121
|
+
* Pure function with no side effects.
|
|
122
|
+
*
|
|
123
|
+
* @param def - Host function definition to convert
|
|
124
|
+
* @returns ApplicationCallable with __type, kind, isProperty, and preserved annotations
|
|
125
|
+
*/
|
|
126
|
+
export declare function toCallable(def: RillFunction, isProperty?: boolean): ApplicationCallable;
|
|
115
127
|
/** Type guard for dict (plain object, not array, not callable, not tuple) */
|
|
116
128
|
export declare function isDict(value: RillValue): value is Record<string, RillValue>;
|
|
117
129
|
/** Format a callable for display */
|
|
@@ -129,19 +141,19 @@ export declare function formatCallable(callable: RillCallable): string;
|
|
|
129
141
|
*/
|
|
130
142
|
export declare function callableEquals(a: ScriptCallable, b: ScriptCallable, valueEquals?: (a: RillValue, b: RillValue) => boolean): boolean;
|
|
131
143
|
/**
|
|
132
|
-
* Build a
|
|
144
|
+
* Build a TypeStructure closure variant from a closure's parameter list.
|
|
133
145
|
*
|
|
134
146
|
* Called at closure creation time to build the structural type for `$fn.^input`.
|
|
135
147
|
* - Typed params use param.type directly when present
|
|
136
|
-
* - Untyped params (type: undefined) map to {
|
|
137
|
-
* - Return type is always {
|
|
148
|
+
* - Untyped params (type: undefined) map to { kind: 'any' }
|
|
149
|
+
* - Return type is always { kind: 'any' }
|
|
138
150
|
*
|
|
139
151
|
* No validation: parser already validates type names.
|
|
140
152
|
*
|
|
141
153
|
* @param params - Closure parameter definitions (RillParam[])
|
|
142
|
-
* @returns Frozen
|
|
154
|
+
* @returns Frozen TypeStructure with closure variant
|
|
143
155
|
*/
|
|
144
|
-
export declare function paramsToStructuralType(params: readonly RillParam[]):
|
|
156
|
+
export declare function paramsToStructuralType(params: readonly RillParam[]): TypeStructure;
|
|
145
157
|
/**
|
|
146
158
|
* Validate defaultValue type matches declared parameter type.
|
|
147
159
|
*
|
|
@@ -171,7 +183,7 @@ export interface MarshalOptions {
|
|
|
171
183
|
*
|
|
172
184
|
* Pure function: no class context, no evaluator, no side effects.
|
|
173
185
|
*/
|
|
174
|
-
export declare function hydrateFieldDefaults(value: RillValue, type:
|
|
186
|
+
export declare function hydrateFieldDefaults(value: RillValue, type: TypeStructure): RillValue;
|
|
175
187
|
/**
|
|
176
188
|
* Unified marshaling entry point for all 3 invocation paths.
|
|
177
189
|
*
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import { RuntimeError } from '../../types.js';
|
|
23
23
|
import { astEquals } from './equals.js';
|
|
24
|
-
import { formatValue,
|
|
24
|
+
import { formatValue, formatStructure, inferType, isOrdered, createOrdered, copyValue, isTuple, paramToFieldDef, structureEquals, structureMatches, anyTypeValue, hasCollectionFields, emptyForType, } from './values.js';
|
|
25
25
|
/** Type guard for any callable */
|
|
26
26
|
export function isCallable(value) {
|
|
27
27
|
return (typeof value === 'object' &&
|
|
@@ -61,6 +61,35 @@ export function callable(fn, isProperty = false) {
|
|
|
61
61
|
isProperty,
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Convert a RillFunction to an ApplicationCallable.
|
|
66
|
+
*
|
|
67
|
+
* Validates the input and produces a callable value accepted by the loader.
|
|
68
|
+
* Pure function with no side effects.
|
|
69
|
+
*
|
|
70
|
+
* @param def - Host function definition to convert
|
|
71
|
+
* @returns ApplicationCallable with __type, kind, isProperty, and preserved annotations
|
|
72
|
+
*/
|
|
73
|
+
export function toCallable(def, isProperty = false) {
|
|
74
|
+
if (def == null) {
|
|
75
|
+
throw new TypeError('RillFunction cannot be null or undefined');
|
|
76
|
+
}
|
|
77
|
+
if (typeof def.fn !== 'function') {
|
|
78
|
+
throw new TypeError('RillFunction.fn must be a function');
|
|
79
|
+
}
|
|
80
|
+
if (!Array.isArray(def.params)) {
|
|
81
|
+
throw new TypeError('RillFunction.params must be an array');
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
__type: 'callable',
|
|
85
|
+
kind: 'application',
|
|
86
|
+
isProperty,
|
|
87
|
+
fn: def.fn,
|
|
88
|
+
params: def.params,
|
|
89
|
+
returnType: def.returnType,
|
|
90
|
+
annotations: def.annotations ?? {},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
64
93
|
/** Type guard for dict (plain object, not array, not callable, not tuple) */
|
|
65
94
|
export function isDict(value) {
|
|
66
95
|
return (typeof value === 'object' &&
|
|
@@ -116,14 +145,14 @@ export function callableEquals(a, b, valueEquals = (x, y) => formatValue(x) ===
|
|
|
116
145
|
return false;
|
|
117
146
|
if (ap.name !== bp.name)
|
|
118
147
|
return false;
|
|
119
|
-
// Compare type via
|
|
148
|
+
// Compare type via structureEquals; absent type (any-typed) matches absent type
|
|
120
149
|
if (ap.type === undefined && bp.type !== undefined)
|
|
121
150
|
return false;
|
|
122
151
|
if (ap.type !== undefined && bp.type === undefined)
|
|
123
152
|
return false;
|
|
124
153
|
if (ap.type !== undefined &&
|
|
125
154
|
bp.type !== undefined &&
|
|
126
|
-
!
|
|
155
|
+
!structureEquals(ap.type, bp.type))
|
|
127
156
|
return false;
|
|
128
157
|
if (!valueEquals(ap.defaultValue ?? null, bp.defaultValue ?? null)) {
|
|
129
158
|
return false;
|
|
@@ -146,24 +175,24 @@ export function callableEquals(a, b, valueEquals = (x, y) => formatValue(x) ===
|
|
|
146
175
|
return true;
|
|
147
176
|
}
|
|
148
177
|
/**
|
|
149
|
-
* Build a
|
|
178
|
+
* Build a TypeStructure closure variant from a closure's parameter list.
|
|
150
179
|
*
|
|
151
180
|
* Called at closure creation time to build the structural type for `$fn.^input`.
|
|
152
181
|
* - Typed params use param.type directly when present
|
|
153
|
-
* - Untyped params (type: undefined) map to {
|
|
154
|
-
* - Return type is always {
|
|
182
|
+
* - Untyped params (type: undefined) map to { kind: 'any' }
|
|
183
|
+
* - Return type is always { kind: 'any' }
|
|
155
184
|
*
|
|
156
185
|
* No validation: parser already validates type names.
|
|
157
186
|
*
|
|
158
187
|
* @param params - Closure parameter definitions (RillParam[])
|
|
159
|
-
* @returns Frozen
|
|
188
|
+
* @returns Frozen TypeStructure with closure variant
|
|
160
189
|
*/
|
|
161
190
|
export function paramsToStructuralType(params) {
|
|
162
|
-
const closureParams = params.map((param) => paramToFieldDef(param.name, param.type ?? {
|
|
191
|
+
const closureParams = params.map((param) => paramToFieldDef(param.name, param.type ?? { kind: 'any' }, param.defaultValue));
|
|
163
192
|
return Object.freeze({
|
|
164
|
-
|
|
193
|
+
kind: 'closure',
|
|
165
194
|
params: closureParams,
|
|
166
|
-
ret: {
|
|
195
|
+
ret: { kind: 'any' },
|
|
167
196
|
});
|
|
168
197
|
}
|
|
169
198
|
/**
|
|
@@ -182,9 +211,9 @@ export function validateDefaultValueType(param, _functionName) {
|
|
|
182
211
|
// Skip validation when type is undefined (any-typed, all defaults valid)
|
|
183
212
|
if (param.type === undefined)
|
|
184
213
|
return;
|
|
185
|
-
if (!
|
|
214
|
+
if (!structureMatches(param.defaultValue, param.type)) {
|
|
186
215
|
const actualType = inferType(param.defaultValue);
|
|
187
|
-
const expectedType =
|
|
216
|
+
const expectedType = formatStructure(param.type);
|
|
188
217
|
throw new Error(`Invalid defaultValue for parameter '${param.name}': expected ${expectedType}, got ${actualType}`);
|
|
189
218
|
}
|
|
190
219
|
}
|
|
@@ -198,16 +227,17 @@ export function validateDefaultValueType(param, _functionName) {
|
|
|
198
227
|
* Pure function: no class context, no evaluator, no side effects.
|
|
199
228
|
*/
|
|
200
229
|
export function hydrateFieldDefaults(value, type) {
|
|
201
|
-
if (type.
|
|
230
|
+
if (type.kind === 'dict' && type.fields && isDict(value)) {
|
|
231
|
+
const t = type;
|
|
202
232
|
const dictValue = value;
|
|
203
233
|
// Seed with all input entries so extra keys survive (structural match allows extras)
|
|
204
234
|
const result = { ...dictValue };
|
|
205
|
-
for (const [fieldName, fieldDef] of Object.entries(
|
|
235
|
+
for (const [fieldName, fieldDef] of Object.entries(t.fields)) {
|
|
206
236
|
if (fieldName in dictValue) {
|
|
207
237
|
result[fieldName] = hydrateFieldDefaults(dictValue[fieldName], fieldDef.type);
|
|
208
238
|
}
|
|
209
239
|
else if (fieldDef.defaultValue !== undefined) {
|
|
210
|
-
result[fieldName] = hydrateFieldDefaults(
|
|
240
|
+
result[fieldName] = hydrateFieldDefaults(copyValue(fieldDef.defaultValue), fieldDef.type);
|
|
211
241
|
}
|
|
212
242
|
else if (hasCollectionFields(fieldDef.type)) {
|
|
213
243
|
result[fieldName] = hydrateFieldDefaults(emptyForType(fieldDef.type), fieldDef.type);
|
|
@@ -216,11 +246,14 @@ export function hydrateFieldDefaults(value, type) {
|
|
|
216
246
|
}
|
|
217
247
|
return result;
|
|
218
248
|
}
|
|
219
|
-
if (type.
|
|
249
|
+
if (type.kind === 'ordered' &&
|
|
250
|
+
type.fields &&
|
|
251
|
+
isOrdered(value)) {
|
|
252
|
+
const t = type;
|
|
220
253
|
const lookup = new Map(value.entries.map(([k, v]) => [k, v]));
|
|
221
|
-
const fieldNames = new Set(
|
|
254
|
+
const fieldNames = new Set(t.fields.map((f) => f.name ?? ''));
|
|
222
255
|
const resultEntries = [];
|
|
223
|
-
for (const field of
|
|
256
|
+
for (const field of t.fields) {
|
|
224
257
|
const name = field.name ?? '';
|
|
225
258
|
if (lookup.has(name)) {
|
|
226
259
|
resultEntries.push([
|
|
@@ -231,7 +264,7 @@ export function hydrateFieldDefaults(value, type) {
|
|
|
231
264
|
else if (field.defaultValue !== undefined) {
|
|
232
265
|
resultEntries.push([
|
|
233
266
|
name,
|
|
234
|
-
hydrateFieldDefaults(
|
|
267
|
+
hydrateFieldDefaults(copyValue(field.defaultValue), field.type),
|
|
235
268
|
]);
|
|
236
269
|
}
|
|
237
270
|
else if (hasCollectionFields(field.type)) {
|
|
@@ -250,7 +283,9 @@ export function hydrateFieldDefaults(value, type) {
|
|
|
250
283
|
}
|
|
251
284
|
return createOrdered(resultEntries);
|
|
252
285
|
}
|
|
253
|
-
if (type.
|
|
286
|
+
if (type.kind === 'tuple' &&
|
|
287
|
+
type.elements &&
|
|
288
|
+
isTuple(value)) {
|
|
254
289
|
const elements = type.elements;
|
|
255
290
|
const entries = value.entries;
|
|
256
291
|
// All fields present: recurse into nested types for present positions
|
|
@@ -270,7 +305,7 @@ export function hydrateFieldDefaults(value, type) {
|
|
|
270
305
|
resultEntries.push(hydrateFieldDefaults(entries[i], el.type));
|
|
271
306
|
}
|
|
272
307
|
else if (el.defaultValue !== undefined) {
|
|
273
|
-
resultEntries.push(hydrateFieldDefaults(
|
|
308
|
+
resultEntries.push(hydrateFieldDefaults(copyValue(el.defaultValue), el.type));
|
|
274
309
|
}
|
|
275
310
|
else if (hasCollectionFields(el.type)) {
|
|
276
311
|
resultEntries.push(hydrateFieldDefaults(emptyForType(el.type), el.type));
|
|
@@ -327,6 +362,11 @@ export function marshalArgs(args, params, options) {
|
|
|
327
362
|
if (param.defaultValue !== undefined) {
|
|
328
363
|
value = param.defaultValue;
|
|
329
364
|
}
|
|
365
|
+
else if (param.type !== undefined && hasCollectionFields(param.type)) {
|
|
366
|
+
// Collection-typed param with field-level defaults: synthesize empty
|
|
367
|
+
// collection so Stage 2.5 (hydrateFieldDefaults) can fill in defaults
|
|
368
|
+
value = emptyForType(param.type);
|
|
369
|
+
}
|
|
330
370
|
else {
|
|
331
371
|
// Stage 2: Missing required parameter
|
|
332
372
|
throw new RuntimeError('RILL-R044', `Missing argument for parameter '${param.name}'`, location, {
|
|
@@ -341,8 +381,8 @@ export function marshalArgs(args, params, options) {
|
|
|
341
381
|
}
|
|
342
382
|
// Stage 3: Type check when param.type is defined
|
|
343
383
|
if (param.type !== undefined) {
|
|
344
|
-
if (!
|
|
345
|
-
const expectedType =
|
|
384
|
+
if (!structureMatches(value, param.type)) {
|
|
385
|
+
const expectedType = formatStructure(param.type);
|
|
346
386
|
const actualType = inferType(value);
|
|
347
387
|
throw new RuntimeError('RILL-R001', `Parameter type mismatch: ${param.name} expects ${expectedType}, got ${actualType}`, location, {
|
|
348
388
|
functionName,
|
|
@@ -6,18 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { RuntimeContext, RuntimeOptions } from './types.js';
|
|
8
8
|
import { type RillValue } from './values.js';
|
|
9
|
-
import { type RillFunction } from './callable.js';
|
|
10
9
|
export declare const UNVALIDATED_METHOD_PARAMS: Set<string>;
|
|
11
|
-
export declare const UNVALIDATED_METHOD_RECEIVERS: Set<string>;
|
|
12
|
-
/**
|
|
13
|
-
* Build a ReadonlyMap of frozen ApplicationCallable dicts from an array of
|
|
14
|
-
* [typeName, methods] pairs. Accepts pairs (not a plain object) so the same
|
|
15
|
-
* typeName can appear more than once — duplicate method names across entries
|
|
16
|
-
* for the same type trigger an Error (EC-6).
|
|
17
|
-
*
|
|
18
|
-
* Re-exported from the public barrel index for host integration use.
|
|
19
|
-
*/
|
|
20
|
-
export declare function buildTypeMethodDicts(pairs: Array<[string, Record<string, RillFunction>]>): ReadonlyMap<string, Readonly<Record<string, RillValue>>>;
|
|
21
10
|
/**
|
|
22
11
|
* Create a runtime context for script execution.
|
|
23
12
|
* This is the main entry point for configuring the Rill runtime.
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* Public API for host applications.
|
|
6
6
|
*/
|
|
7
7
|
import { RuntimeError } from '../../types.js';
|
|
8
|
-
import { BUILTIN_FUNCTIONS
|
|
8
|
+
import { BUILTIN_FUNCTIONS } from '../ext/builtins.js';
|
|
9
|
+
import { BUILT_IN_TYPES } from './type-registrations.js';
|
|
9
10
|
import { bindDictCallables } from './types.js';
|
|
10
11
|
import { inferType } from './values.js';
|
|
11
12
|
import { callable, validateDefaultValueType, } from './callable.js';
|
|
@@ -17,69 +18,23 @@ const UNTYPED_BUILTINS = new Set(['log', 'chain']);
|
|
|
17
18
|
// messages expected by protected language tests. Generic marshalArgs
|
|
18
19
|
// must not fire before the method body's own check.
|
|
19
20
|
export const UNVALIDATED_METHOD_PARAMS = new Set(['has', 'has_any', 'has_all']);
|
|
20
|
-
// Built-in methods that perform their own receiver type checking with specific
|
|
21
|
-
// error messages. Generic RILL-R003 must not fire before the method body runs.
|
|
22
|
-
// Mirrors the old flat-structure convention of receiverTypes: [].
|
|
23
|
-
export const UNVALIDATED_METHOD_RECEIVERS = new Set([
|
|
24
|
-
'head',
|
|
25
|
-
'tail',
|
|
26
|
-
'first',
|
|
27
|
-
'at',
|
|
28
|
-
'eq',
|
|
29
|
-
'ne',
|
|
30
|
-
'keys',
|
|
31
|
-
'values',
|
|
32
|
-
'entries',
|
|
33
|
-
'has',
|
|
34
|
-
'has_any',
|
|
35
|
-
'has_all',
|
|
36
|
-
'dimensions',
|
|
37
|
-
'model',
|
|
38
|
-
'similarity',
|
|
39
|
-
'dot',
|
|
40
|
-
'distance',
|
|
41
|
-
'norm',
|
|
42
|
-
'normalize',
|
|
43
|
-
]);
|
|
44
21
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* for the same type trigger an Error (EC-6).
|
|
49
|
-
*
|
|
50
|
-
* Re-exported from the public barrel index for host integration use.
|
|
22
|
+
* Derive the set of method names that handle their own receiver type checking.
|
|
23
|
+
* Collects names from methods where skipReceiverValidation is true.
|
|
24
|
+
* Methods without the flag default to standard RILL-R003 receiver validation.
|
|
51
25
|
*/
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const existing = result.get(typeName) ?? {};
|
|
59
|
-
const dict = { ...existing };
|
|
60
|
-
for (const [name, fn] of Object.entries(methods)) {
|
|
61
|
-
if (seen.has(name)) {
|
|
62
|
-
throw new Error(`Duplicate method '${name}' on type '${typeName}'`);
|
|
26
|
+
function deriveUnvalidatedMethodReceivers(registrations) {
|
|
27
|
+
const bypass = new Set();
|
|
28
|
+
for (const reg of registrations) {
|
|
29
|
+
for (const [name, method] of Object.entries(reg.methods)) {
|
|
30
|
+
if (method.skipReceiverValidation) {
|
|
31
|
+
bypass.add(name);
|
|
63
32
|
}
|
|
64
|
-
seen.add(name);
|
|
65
|
-
const appCallable = {
|
|
66
|
-
__type: 'callable',
|
|
67
|
-
kind: 'application',
|
|
68
|
-
params: fn.params,
|
|
69
|
-
returnType: fn.returnType,
|
|
70
|
-
annotations: fn.annotations ?? {},
|
|
71
|
-
isProperty: false,
|
|
72
|
-
fn: fn.fn,
|
|
73
|
-
};
|
|
74
|
-
dict[name] = appCallable;
|
|
75
33
|
}
|
|
76
|
-
result.set(typeName, Object.freeze(dict));
|
|
77
34
|
}
|
|
78
|
-
return
|
|
35
|
+
return Object.freeze(bypass);
|
|
79
36
|
}
|
|
80
37
|
const BUILTIN_FN_CACHE = new Map();
|
|
81
|
-
const BUILTIN_METHOD_PARAMS_CACHE = new Map();
|
|
82
|
-
const BUILTIN_METHOD_RECEIVER_TYPES_CACHE = new Map();
|
|
83
38
|
function initBuiltinCaches() {
|
|
84
39
|
for (const [name, entry] of Object.entries(BUILTIN_FUNCTIONS)) {
|
|
85
40
|
if (UNTYPED_BUILTINS.has(name)) {
|
|
@@ -94,21 +49,6 @@ function initBuiltinCaches() {
|
|
|
94
49
|
};
|
|
95
50
|
BUILTIN_FN_CACHE.set(name, { appCallable: typedCallable });
|
|
96
51
|
}
|
|
97
|
-
for (const [typeName, methods] of Object.entries(BUILTIN_METHODS)) {
|
|
98
|
-
for (const [name, impl] of Object.entries(methods)) {
|
|
99
|
-
// Accumulate receiver types across all type groups for this method name.
|
|
100
|
-
// Skip methods that perform their own receiver type checking.
|
|
101
|
-
if (!UNVALIDATED_METHOD_RECEIVERS.has(name)) {
|
|
102
|
-
const existing = BUILTIN_METHOD_RECEIVER_TYPES_CACHE.get(name);
|
|
103
|
-
BUILTIN_METHOD_RECEIVER_TYPES_CACHE.set(name, existing !== undefined ? [...existing, typeName] : [typeName]);
|
|
104
|
-
}
|
|
105
|
-
if (!UNVALIDATED_METHOD_PARAMS.has(name)) {
|
|
106
|
-
if (impl.params.length > 0) {
|
|
107
|
-
BUILTIN_METHOD_PARAMS_CACHE.set(name, impl.params);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
52
|
}
|
|
113
53
|
// Initialise once at module load.
|
|
114
54
|
initBuiltinCaches();
|
|
@@ -194,15 +134,74 @@ export function createRuntimeContext(options = {}) {
|
|
|
194
134
|
const resolverConfigs = new Map(options.configurations?.resolvers
|
|
195
135
|
? Object.entries(options.configurations.resolvers)
|
|
196
136
|
: []);
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
const
|
|
137
|
+
// EC-1: Validate no duplicate type names in registrations.
|
|
138
|
+
const seenTypeNames = new Set();
|
|
139
|
+
for (const reg of BUILT_IN_TYPES) {
|
|
140
|
+
if (seenTypeNames.has(reg.name)) {
|
|
141
|
+
throw new Error(`Duplicate type registration '${reg.name}'`);
|
|
142
|
+
}
|
|
143
|
+
seenTypeNames.add(reg.name);
|
|
144
|
+
}
|
|
145
|
+
// EC-2: Validate every registration has protocol.format.
|
|
146
|
+
for (const reg of BUILT_IN_TYPES) {
|
|
147
|
+
if (!reg.protocol.format) {
|
|
148
|
+
throw new Error(`Type '${reg.name}' missing required format protocol`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Derive typeNames from registrations (replaces VALID_TYPE_NAMES in context).
|
|
152
|
+
const typeNames = Object.freeze(BUILT_IN_TYPES.map((r) => r.name));
|
|
153
|
+
// Derive leafTypes from registrations where isLeaf === true, plus 'any'
|
|
154
|
+
// which has no registration but rejects type arguments (AC-4).
|
|
155
|
+
const leafTypes = Object.freeze(new Set([
|
|
156
|
+
...BUILT_IN_TYPES.filter((r) => r.isLeaf).map((r) => r.name),
|
|
157
|
+
'any',
|
|
158
|
+
]));
|
|
159
|
+
// Derive method dicts from registration.methods (absorbs buildTypeMethodDicts
|
|
160
|
+
// logic). Validates EC-6: duplicate method on same type.
|
|
161
|
+
const methodRegistry = new Map();
|
|
162
|
+
const typeMethodDicts = new Map();
|
|
163
|
+
for (const reg of BUILT_IN_TYPES) {
|
|
164
|
+
const methods = reg.methods;
|
|
165
|
+
if (!methods || Object.keys(methods).length === 0)
|
|
166
|
+
continue;
|
|
167
|
+
const seen = methodRegistry.get(reg.name) ?? new Set();
|
|
168
|
+
methodRegistry.set(reg.name, seen);
|
|
169
|
+
const existing = typeMethodDicts.get(reg.name) ?? {};
|
|
170
|
+
const dict = { ...existing };
|
|
171
|
+
for (const [name, fn] of Object.entries(methods)) {
|
|
172
|
+
if (seen.has(name)) {
|
|
173
|
+
throw new Error(`Duplicate method '${name}' on type '${reg.name}'`);
|
|
174
|
+
}
|
|
175
|
+
seen.add(name);
|
|
176
|
+
const appCallable = {
|
|
177
|
+
__type: 'callable',
|
|
178
|
+
kind: 'application',
|
|
179
|
+
params: fn.params,
|
|
180
|
+
returnType: fn.returnType,
|
|
181
|
+
annotations: fn.annotations ?? {},
|
|
182
|
+
isProperty: false,
|
|
183
|
+
fn: fn.fn,
|
|
184
|
+
};
|
|
185
|
+
dict[name] = appCallable;
|
|
186
|
+
}
|
|
187
|
+
typeMethodDicts.set(reg.name, Object.freeze(dict));
|
|
188
|
+
}
|
|
189
|
+
// Derive bypass set from registrations: method names that handle their own
|
|
190
|
+
// receiver type checking. Generic RILL-R003 must not fire before the method body.
|
|
191
|
+
const unvalidatedMethodReceivers = deriveUnvalidatedMethodReceivers(BUILT_IN_TYPES);
|
|
192
|
+
// BC-5: Freeze all derived collections after creation.
|
|
193
|
+
Object.freeze(typeNames);
|
|
194
|
+
Object.freeze(typeMethodDicts);
|
|
195
|
+
// Suppress unused-variable warning for typeNames (consumed in later phases).
|
|
196
|
+
void typeNames;
|
|
200
197
|
return {
|
|
201
198
|
parent: undefined,
|
|
202
199
|
variables,
|
|
203
200
|
variableTypes,
|
|
204
201
|
functions,
|
|
205
202
|
typeMethodDicts,
|
|
203
|
+
leafTypes,
|
|
204
|
+
unvalidatedMethodReceivers,
|
|
206
205
|
callbacks: { ...defaultCallbacks, ...options.callbacks },
|
|
207
206
|
observability: options.observability ?? {},
|
|
208
207
|
pipeValue: null,
|
|
@@ -232,6 +231,8 @@ export function createChildContext(parent, overrides) {
|
|
|
232
231
|
variableTypes: new Map(),
|
|
233
232
|
functions: parent.functions,
|
|
234
233
|
typeMethodDicts: parent.typeMethodDicts,
|
|
234
|
+
leafTypes: parent.leafTypes,
|
|
235
|
+
unvalidatedMethodReceivers: parent.unvalidatedMethodReceivers,
|
|
235
236
|
callbacks: parent.callbacks,
|
|
236
237
|
observability: parent.observability,
|
|
237
238
|
pipeValue: parent.pipeValue,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import type { AnnotatedStatementNode, ASTNode, CaptureNode, ExpressionNode, RillTypeName, SourceLocation, StatementNode } from '../../../types.js';
|
|
10
10
|
import type { RillCallable } from '../callable.js';
|
|
11
11
|
import type { RuntimeContext } from '../types.js';
|
|
12
|
-
import type { RillValue,
|
|
12
|
+
import type { RillValue, TypeStructure } from '../values.js';
|
|
13
13
|
/**
|
|
14
14
|
* Capture information returned by handleCapture.
|
|
15
15
|
*/
|
|
@@ -39,7 +39,7 @@ export declare function handleCapture(capture: CaptureNode | null, value: RillVa
|
|
|
39
39
|
* Assert that a value is of the expected type.
|
|
40
40
|
* Returns the value unchanged if assertion passes, throws on mismatch.
|
|
41
41
|
*/
|
|
42
|
-
export declare function assertType(value: RillValue, expected: RillTypeName |
|
|
42
|
+
export declare function assertType(value: RillValue, expected: RillTypeName | TypeStructure, location?: SourceLocation): RillValue;
|
|
43
43
|
/**
|
|
44
44
|
* Evaluate an expression and return its value.
|
|
45
45
|
* Main entry point for expression evaluation.
|