@rcrsr/rill 0.16.0 → 0.18.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/ast-nodes.d.ts +14 -4
- package/dist/ast-unions.d.ts +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -0
- package/dist/error-registry.js +228 -0
- package/dist/ext/crypto/index.d.ts +3 -3
- package/dist/ext/crypto/index.js +62 -59
- package/dist/ext/exec/index.d.ts +3 -3
- package/dist/ext/exec/index.js +15 -9
- package/dist/ext/fetch/index.d.ts +3 -3
- package/dist/ext/fetch/index.js +17 -12
- package/dist/ext/fetch/request.js +1 -1
- package/dist/ext/fs/index.d.ts +3 -3
- package/dist/ext/fs/index.js +256 -266
- package/dist/ext/fs/sandbox.d.ts +18 -0
- package/dist/ext/fs/sandbox.js +33 -0
- package/dist/ext/kv/index.d.ts +3 -3
- package/dist/ext/kv/index.js +198 -196
- package/dist/ext/kv/store.d.ts +1 -1
- 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/highlight-map.js +1 -0
- package/dist/index.d.ts +1 -4
- package/dist/index.js +1 -5
- package/dist/lexer/operators.js +1 -0
- package/dist/parser/helpers.js +1 -0
- package/dist/parser/parser-expr.js +44 -5
- package/dist/parser/parser-literals.js +111 -4
- package/dist/parser/parser-shape.js +2 -2
- package/dist/parser/parser-types.js +12 -0
- package/dist/parser/parser-use.js +26 -3
- package/dist/parser/parser.d.ts +2 -0
- package/dist/parser/parser.js +2 -0
- package/dist/runtime/core/callable.d.ts +24 -13
- package/dist/runtime/core/callable.js +71 -38
- package/dist/runtime/core/context.d.ts +2 -13
- package/dist/runtime/core/context.js +80 -79
- package/dist/runtime/core/eval/base.d.ts +2 -2
- package/dist/runtime/core/eval/base.js +2 -0
- package/dist/runtime/core/eval/evaluator.d.ts +1 -1
- package/dist/runtime/core/eval/index.d.ts +3 -3
- package/dist/runtime/core/eval/index.js +11 -0
- package/dist/runtime/core/eval/mixins/closures.js +381 -41
- package/dist/runtime/core/eval/mixins/collections.js +81 -6
- package/dist/runtime/core/eval/mixins/control-flow.js +1 -1
- package/dist/runtime/core/eval/mixins/conversion.js +61 -115
- package/dist/runtime/core/eval/mixins/core.js +17 -4
- package/dist/runtime/core/eval/mixins/expressions.js +36 -27
- package/dist/runtime/core/eval/mixins/extraction.js +2 -3
- package/dist/runtime/core/eval/mixins/list-dispatch.js +1 -1
- package/dist/runtime/core/eval/mixins/literals.js +17 -6
- package/dist/runtime/core/eval/mixins/types.js +73 -54
- package/dist/runtime/core/eval/mixins/variables.js +12 -8
- package/dist/runtime/core/execute.d.ts +1 -1
- package/dist/runtime/core/field-descriptor.d.ts +3 -3
- package/dist/runtime/core/field-descriptor.js +2 -1
- package/dist/runtime/core/introspection.d.ts +2 -2
- package/dist/runtime/core/introspection.js +7 -6
- package/dist/runtime/core/resolvers.d.ts +1 -1
- package/dist/runtime/core/signals.d.ts +6 -1
- package/dist/runtime/core/signals.js +9 -0
- package/dist/runtime/core/types/constructors.d.ts +54 -0
- package/dist/runtime/core/types/constructors.js +201 -0
- package/dist/runtime/core/types/guards.d.ts +42 -0
- package/dist/runtime/core/types/guards.js +88 -0
- package/dist/runtime/core/types/index.d.ts +18 -0
- package/dist/runtime/core/types/index.js +19 -0
- package/dist/runtime/core/types/markers.d.ts +12 -0
- package/dist/runtime/core/types/markers.js +7 -0
- package/dist/runtime/core/types/operations.d.ts +98 -0
- package/dist/runtime/core/types/operations.js +804 -0
- package/dist/runtime/core/types/registrations.d.ts +126 -0
- package/dist/runtime/core/types/registrations.js +751 -0
- package/dist/runtime/core/{types.d.ts → types/runtime.d.ts} +22 -10
- package/dist/runtime/core/types/structures.d.ts +146 -0
- package/dist/runtime/core/types/structures.js +12 -0
- package/dist/runtime/core/values.d.ts +29 -209
- package/dist/runtime/core/values.js +56 -968
- package/dist/runtime/ext/builtins.js +88 -68
- package/dist/runtime/ext/extensions.d.ts +31 -125
- package/dist/runtime/ext/extensions.js +2 -94
- package/dist/runtime/ext/test-context.d.ts +28 -0
- package/dist/runtime/ext/test-context.js +155 -0
- package/dist/runtime/index.d.ts +12 -12
- package/dist/runtime/index.js +13 -5
- package/dist/signature-parser.d.ts +2 -2
- package/dist/signature-parser.js +14 -14
- package/dist/token-types.d.ts +1 -0
- package/dist/token-types.js +1 -0
- package/package.json +1 -1
- /package/dist/runtime/core/{types.js → types/runtime.js} +0 -0
|
@@ -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.18.0';
|
|
7
7
|
/**
|
|
8
8
|
* Parsed version components
|
|
9
9
|
*/
|
|
10
10
|
export const VERSION_INFO = {
|
|
11
11
|
major: 0,
|
|
12
|
-
minor:
|
|
12
|
+
minor: 18,
|
|
13
13
|
patch: 0,
|
|
14
14
|
prerelease: undefined,
|
|
15
15
|
};
|
package/dist/highlight-map.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -5,11 +5,8 @@
|
|
|
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 RillType instead. Will be removed in the next major version. */
|
|
10
|
-
export type { RillStructuralType } from './runtime/index.js';
|
|
8
|
+
export { anyTypeValue, type ApplicationCallable, BreakSignal, BUILT_IN_TYPES, BUILTIN_METHODS, buildFieldDescriptor, callable, type CallableFn, type CallFrame, commonType, compareStructuredFields, type CaptureEvent, type ConfigFieldDescriptor, contextResolver, copyValue, createOrdered, createRillStream, createRuntimeContext, createStepper, createTestContext, createTuple, createVector, deepEquals, deserializeValue, type DocumentationCoverageResult, emitExtensionEvent, type ErrorEvent, execute, type ExecutionResult, type ExecutionStepper, ExtensionBindingError, type ExtensionConfigSchema, type ExtensionEvent, type ExtensionFactory, type ExtensionFactoryResult, type ExtensionManifest, extResolver, type FieldComparisonCallbacks, formatRillLiteral, formatStructure, formatValue, type FsExtensionContract, type FunctionMetadata, type FunctionReturnEvent, generateManifest, getCallStack, getDocumentationCoverage, getFunctions, getLanguageReference, type HostCallEvent, hydrateFieldDefaults, inferElementType, inferStructure, inferType, invokeCallable, isApplicationCallable, isCallable, isDict, isEmpty, isIterator, isReservedMethod, isRillStream, isRuntimeCallable, isScriptCallable, isStream, isTruthy, isTuple, isTypeValue, isVector, type KvExtensionContract, marshalArgs, type MarshalOptions, moduleResolver, type NativeArray, type NativePlainObject, type NativeResult, type NativeValue, type ObservabilityCallbacks, type ParamMetadata, paramToFieldDef, popCallFrame, pushCallFrame, RESERVED_DICT_METHODS, type ResolverResult, ReturnSignal, YieldSignal, type RillCallable, type RillFieldDef, type RillFunction, type RillIterator, type RillParam, type RillStream, type RillTuple, type RillTypeValue, type RillValue, type RillVector, type RuntimeCallable, type RuntimeCallbacks, type RuntimeContext, type RuntimeOptions, type SchemaEntry, type SchemeResolver, type ScriptCallable, serializeValue, 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';
|
|
11
9
|
export { type ErrorCategory, type ErrorDefinition, type ErrorSeverity, ERROR_REGISTRY, renderMessage, getHelpUrl, createError, } from './types.js';
|
|
12
10
|
export { formatRillError, formatRillErrorJson, type FormatErrorOptions, type FormatErrorJsonOptions, type SourceMap, } from './error-formatter.js';
|
|
13
|
-
export { VALID_TYPE_NAMES } from './constants.js';
|
|
14
11
|
export { type HighlightCategory, TOKEN_HIGHLIGHT_MAP, } from './highlight-map.js';
|
|
15
12
|
export * from './types.js';
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
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, BUILT_IN_TYPES, BUILTIN_METHODS, buildFieldDescriptor, callable, commonType, compareStructuredFields, contextResolver, copyValue, createOrdered, createRillStream, createRuntimeContext, createStepper, createTestContext, createTuple, createVector, deepEquals, deserializeValue, emitExtensionEvent, execute, ExtensionBindingError, extResolver, formatRillLiteral, formatStructure, formatValue, generateManifest, getCallStack, getDocumentationCoverage, getFunctions, getLanguageReference, hydrateFieldDefaults, inferElementType, inferStructure, inferType, invokeCallable, isApplicationCallable, isCallable, isDict, isEmpty, isIterator, isReservedMethod, isRillStream, isRuntimeCallable, isScriptCallable, isStream, isTruthy, isTuple, isTypeValue, isVector, marshalArgs, moduleResolver, paramToFieldDef, popCallFrame, pushCallFrame, RESERVED_DICT_METHODS, ReturnSignal, YieldSignal, serializeValue, structureEquals, structureMatches, structureToTypeValue, toCallable, toNative, VERSION, VERSION_INFO, } from './runtime/index.js';
|
|
8
8
|
// ============================================================
|
|
9
9
|
// ERROR TAXONOMY
|
|
10
10
|
// ============================================================
|
|
@@ -14,10 +14,6 @@ export { ERROR_REGISTRY, renderMessage, getHelpUrl, createError, } from './types
|
|
|
14
14
|
// ============================================================
|
|
15
15
|
export { formatRillError, formatRillErrorJson, } from './error-formatter.js';
|
|
16
16
|
// ============================================================
|
|
17
|
-
// CONSTANTS
|
|
18
|
-
// ============================================================
|
|
19
|
-
export { VALID_TYPE_NAMES } from './constants.js';
|
|
20
|
-
// ============================================================
|
|
21
17
|
// SYNTAX HIGHLIGHTING
|
|
22
18
|
// ============================================================
|
|
23
19
|
export { TOKEN_HIGHLIGHT_MAP, } from './highlight-map.js';
|
package/dist/lexer/operators.js
CHANGED
package/dist/parser/helpers.js
CHANGED
|
@@ -25,6 +25,7 @@ export function isIdentifierOrKeyword(token) {
|
|
|
25
25
|
token.type === TOKEN_TYPES.FALSE ||
|
|
26
26
|
token.type === TOKEN_TYPES.BREAK ||
|
|
27
27
|
token.type === TOKEN_TYPES.RETURN ||
|
|
28
|
+
token.type === TOKEN_TYPES.YIELD ||
|
|
28
29
|
token.type === TOKEN_TYPES.ASSERT ||
|
|
29
30
|
token.type === TOKEN_TYPES.ERROR ||
|
|
30
31
|
token.type === TOKEN_TYPES.EACH ||
|
|
@@ -139,6 +139,20 @@ Parser.prototype.parsePipeChain = function () {
|
|
|
139
139
|
span: token.span,
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
|
+
// Handle bare yield: "yield" ≡ "$ -> yield"
|
|
143
|
+
if (check(this.state, TOKEN_TYPES.YIELD)) {
|
|
144
|
+
if (this.closureDepth === 0) {
|
|
145
|
+
throw new ParseError('RILL-P006', "'yield' is only valid inside a stream closure", current(this.state).span.start);
|
|
146
|
+
}
|
|
147
|
+
const token = advance(this.state);
|
|
148
|
+
return {
|
|
149
|
+
type: 'PipeChain',
|
|
150
|
+
head: this.implicitPipeVar(token.span),
|
|
151
|
+
pipes: [],
|
|
152
|
+
terminator: { type: 'Yield', span: token.span },
|
|
153
|
+
span: token.span,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
142
156
|
// Parse expression head with full precedence chain
|
|
143
157
|
let head = this.parseLogicalOr();
|
|
144
158
|
// Check for loop: expr @ body
|
|
@@ -214,6 +228,15 @@ Parser.prototype.parsePipeChain = function () {
|
|
|
214
228
|
terminator = { type: 'Return', span: token.span };
|
|
215
229
|
break;
|
|
216
230
|
}
|
|
231
|
+
// Check for yield terminator: -> yield
|
|
232
|
+
if (check(this.state, TOKEN_TYPES.YIELD)) {
|
|
233
|
+
if (this.closureDepth === 0) {
|
|
234
|
+
throw new ParseError('RILL-P006', "'yield' is only valid inside a stream closure", current(this.state).span.start);
|
|
235
|
+
}
|
|
236
|
+
const token = advance(this.state);
|
|
237
|
+
terminator = { type: 'Yield', span: token.span };
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
217
240
|
// Guard against removed -> export syntax
|
|
218
241
|
if (check(this.state, TOKEN_TYPES.IDENTIFIER) &&
|
|
219
242
|
current(this.state).value === 'export') {
|
|
@@ -576,8 +599,14 @@ Parser.prototype.parsePrimary = function () {
|
|
|
576
599
|
if (isMethodCall(this.state)) {
|
|
577
600
|
return this.parseMethodCall(null);
|
|
578
601
|
}
|
|
579
|
-
// Type constructor: list(...), dict(...), tuple(...), ordered(...)
|
|
580
|
-
const TYPE_CONSTRUCTORS = [
|
|
602
|
+
// Type constructor: list(...), dict(...), tuple(...), ordered(...), stream(...)
|
|
603
|
+
const TYPE_CONSTRUCTORS = [
|
|
604
|
+
'list',
|
|
605
|
+
'dict',
|
|
606
|
+
'tuple',
|
|
607
|
+
'ordered',
|
|
608
|
+
'stream',
|
|
609
|
+
];
|
|
581
610
|
if (check(this.state, TOKEN_TYPES.IDENTIFIER) &&
|
|
582
611
|
TYPE_CONSTRUCTORS.includes(current(this.state).value) &&
|
|
583
612
|
this.state.tokens[this.state.pos + 1]?.type === TOKEN_TYPES.LPAREN) {
|
|
@@ -615,6 +644,10 @@ Parser.prototype.parsePrimary = function () {
|
|
|
615
644
|
const common = this.parseCommonConstruct();
|
|
616
645
|
if (common)
|
|
617
646
|
return common;
|
|
647
|
+
// Yield keyword in expression position (not valid as identifier)
|
|
648
|
+
if (check(this.state, TOKEN_TYPES.YIELD)) {
|
|
649
|
+
throw new ParseError('RILL-P001', "Unexpected keyword 'yield'", current(this.state).span.start);
|
|
650
|
+
}
|
|
618
651
|
// Detect heredoc syntax (removed feature)
|
|
619
652
|
const token = current(this.state);
|
|
620
653
|
if (token.type === TOKEN_TYPES.LT &&
|
|
@@ -1063,10 +1096,16 @@ Parser.prototype.parseConvert = function () {
|
|
|
1063
1096
|
const start = current(this.state).span.start;
|
|
1064
1097
|
expect(this.state, TOKEN_TYPES.COLON, 'Expected :');
|
|
1065
1098
|
expect(this.state, TOKEN_TYPES.GT, 'Expected >');
|
|
1066
|
-
// Structural convert: :>ordered(field: type, ...)
|
|
1067
|
-
const
|
|
1099
|
+
// Structural convert: :>ordered(field: type, ...), :>stream(T), etc.
|
|
1100
|
+
const TYPE_CONSTRUCTORS_CONVERT = [
|
|
1101
|
+
'list',
|
|
1102
|
+
'dict',
|
|
1103
|
+
'tuple',
|
|
1104
|
+
'ordered',
|
|
1105
|
+
'stream',
|
|
1106
|
+
];
|
|
1068
1107
|
if (check(this.state, TOKEN_TYPES.IDENTIFIER) &&
|
|
1069
|
-
|
|
1108
|
+
TYPE_CONSTRUCTORS_CONVERT.includes(current(this.state).value) &&
|
|
1070
1109
|
this.state.tokens[this.state.pos + 1]?.type === TOKEN_TYPES.LPAREN) {
|
|
1071
1110
|
const constructorName = current(this.state).value;
|
|
1072
1111
|
const typeRef = this.parseTypeConstructor(constructorName);
|
|
@@ -7,7 +7,7 @@ import { ParseError, TOKEN_TYPES } from '../types.js';
|
|
|
7
7
|
import { tokenize } from '../lexer/index.js';
|
|
8
8
|
import { check, advance, expect, current, peek, skipNewlines, makeSpan, } from './state.js';
|
|
9
9
|
import { isDictStart, isNegativeNumber, VALID_TYPE_NAMES } from './helpers.js';
|
|
10
|
-
import { parseTypeRef } from './parser-types.js';
|
|
10
|
+
import { parseTypeRef, parseFieldArgList } from './parser-types.js';
|
|
11
11
|
// ============================================================
|
|
12
12
|
// LITERAL PARSING
|
|
13
13
|
// ============================================================
|
|
@@ -384,14 +384,106 @@ Parser.prototype.parseDictEntry = function () {
|
|
|
384
384
|
// ============================================================
|
|
385
385
|
// CLOSURE PARSING
|
|
386
386
|
// ============================================================
|
|
387
|
+
/**
|
|
388
|
+
* Parse a stream type constructor: stream(T):R
|
|
389
|
+
*
|
|
390
|
+
* Grammar: "stream" "(" [type-ref] ")" [":" type-ref]
|
|
391
|
+
*
|
|
392
|
+
* Chunk type goes in args[0], resolution type in args[1].
|
|
393
|
+
* stream() → 0 args, stream(T) → 1 arg, stream(T):R → 2 args.
|
|
394
|
+
*
|
|
395
|
+
* @internal
|
|
396
|
+
*/
|
|
397
|
+
function parseStreamTypeConstructor(parser) {
|
|
398
|
+
const start = current(parser.state).span.start;
|
|
399
|
+
advance(parser.state); // consume 'stream'
|
|
400
|
+
if (!check(parser.state, TOKEN_TYPES.LPAREN)) {
|
|
401
|
+
throw new ParseError('RILL-P006', 'Expected type name in stream constructor', current(parser.state).span.start);
|
|
402
|
+
}
|
|
403
|
+
advance(parser.state); // consume '('
|
|
404
|
+
const args = parseFieldArgList(parser.state);
|
|
405
|
+
const rparen = expect(parser.state, TOKEN_TYPES.RPAREN, 'Expected )', 'RILL-P005');
|
|
406
|
+
// Check for resolution type: stream(T):R
|
|
407
|
+
if (check(parser.state, TOKEN_TYPES.COLON)) {
|
|
408
|
+
advance(parser.state); // consume ':'
|
|
409
|
+
skipNewlines(parser.state);
|
|
410
|
+
// Guard: resolution type must start with a valid type name
|
|
411
|
+
if (!check(parser.state, TOKEN_TYPES.IDENTIFIER)) {
|
|
412
|
+
throw new ParseError('RILL-P006', "Expected type name after ':' in stream type", current(parser.state).span.start);
|
|
413
|
+
}
|
|
414
|
+
// Parse the resolution type reference
|
|
415
|
+
const resolutionType = parseTypeRef(parser.state);
|
|
416
|
+
// Ensure positional alignment: args[0] = chunk, args[1] = ret.
|
|
417
|
+
// When parens are empty (no chunk type), insert an 'any' placeholder
|
|
418
|
+
// so the runtime correctly maps arg positions.
|
|
419
|
+
if (args.length === 0) {
|
|
420
|
+
args.push({ value: { kind: 'static', typeName: 'any' } });
|
|
421
|
+
}
|
|
422
|
+
args.push({ value: resolutionType });
|
|
423
|
+
return {
|
|
424
|
+
type: 'TypeConstructor',
|
|
425
|
+
constructorName: 'stream',
|
|
426
|
+
args,
|
|
427
|
+
span: makeSpan(start, current(parser.state).span.end),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
return {
|
|
431
|
+
type: 'TypeConstructor',
|
|
432
|
+
constructorName: 'stream',
|
|
433
|
+
args,
|
|
434
|
+
span: makeSpan(start, rparen.span.end),
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Check whether a closure body contains any yield terminators at the
|
|
439
|
+
* immediate level (not inside nested closures). Returns true if at
|
|
440
|
+
* least one yield is found.
|
|
441
|
+
* @internal
|
|
442
|
+
*/
|
|
443
|
+
function bodyContainsYield(body) {
|
|
444
|
+
if (body.type === 'PipeChain') {
|
|
445
|
+
if (body.terminator?.type === 'Yield')
|
|
446
|
+
return true;
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
if (body.type === 'Block') {
|
|
450
|
+
for (const stmt of body.statements) {
|
|
451
|
+
const expr = stmt.type === 'AnnotatedStatement'
|
|
452
|
+
? stmt.statement.expression
|
|
453
|
+
: stmt.expression;
|
|
454
|
+
if (expr.terminator?.type === 'Yield')
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Validate that yield nodes in a closure body are only present when
|
|
463
|
+
* the closure has a stream return type. Throws RILL-P006 if yield
|
|
464
|
+
* appears without :stream(T):R annotation.
|
|
465
|
+
* @internal
|
|
466
|
+
*/
|
|
467
|
+
function validateYieldInClosure(body, returnTypeTarget, closureStart) {
|
|
468
|
+
if (!bodyContainsYield(body))
|
|
469
|
+
return;
|
|
470
|
+
const isStream = returnTypeTarget !== undefined &&
|
|
471
|
+
'type' in returnTypeTarget &&
|
|
472
|
+
returnTypeTarget.type === 'TypeConstructor' &&
|
|
473
|
+
returnTypeTarget.constructorName === 'stream';
|
|
474
|
+
if (!isStream) {
|
|
475
|
+
throw new ParseError('RILL-P006', "'yield' is only valid inside a stream closure", closureStart);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
387
478
|
/**
|
|
388
479
|
* Parse the optional postfix `:type-target` after a closure body.
|
|
389
480
|
*
|
|
390
481
|
* Grammar: [ ":" , type-target ]
|
|
391
|
-
* type-target =
|
|
482
|
+
* type-target = "stream" "(" [type-ref] ")" [":" type-ref] | type-ref
|
|
392
483
|
*
|
|
393
|
-
* Returns the parsed TypeRef
|
|
484
|
+
* Returns the parsed TypeRef, TypeConstructorNode, or undefined if absent.
|
|
394
485
|
* Follows the same disambiguation logic as parsePostfixTypeOperation.
|
|
486
|
+
* Extended for stream(T):R return type pattern.
|
|
395
487
|
*/
|
|
396
488
|
function parseClosureReturnTypeTarget(parser) {
|
|
397
489
|
skipNewlines(parser.state);
|
|
@@ -400,6 +492,11 @@ function parseClosureReturnTypeTarget(parser) {
|
|
|
400
492
|
}
|
|
401
493
|
advance(parser.state); // consume ':'
|
|
402
494
|
skipNewlines(parser.state);
|
|
495
|
+
// Stream type constructor: stream(T):R
|
|
496
|
+
if (check(parser.state, TOKEN_TYPES.IDENTIFIER) &&
|
|
497
|
+
current(parser.state).value === 'stream') {
|
|
498
|
+
return parseStreamTypeConstructor(parser);
|
|
499
|
+
}
|
|
403
500
|
// Default: plain type name or dynamic type reference
|
|
404
501
|
return parseTypeRef(parser.state);
|
|
405
502
|
}
|
|
@@ -408,8 +505,11 @@ Parser.prototype.parseClosure = function () {
|
|
|
408
505
|
if (check(this.state, TOKEN_TYPES.OR)) {
|
|
409
506
|
advance(this.state);
|
|
410
507
|
skipNewlines(this.state);
|
|
508
|
+
this.closureDepth++;
|
|
411
509
|
const body = this.parseBody(true);
|
|
510
|
+
this.closureDepth--;
|
|
412
511
|
const returnTypeTarget = parseClosureReturnTypeTarget(this);
|
|
512
|
+
validateYieldInClosure(body, returnTypeTarget, start);
|
|
413
513
|
return {
|
|
414
514
|
type: 'Closure',
|
|
415
515
|
params: [],
|
|
@@ -454,8 +554,11 @@ Parser.prototype.parseClosure = function () {
|
|
|
454
554
|
const typeRef = parseTypeRef(this.state, { allowTrailingPipe: true });
|
|
455
555
|
expect(this.state, TOKEN_TYPES.PIPE_BAR, 'Expected |', 'RILL-P005');
|
|
456
556
|
skipNewlines(this.state);
|
|
557
|
+
this.closureDepth++;
|
|
457
558
|
const body = this.parseBody(true);
|
|
559
|
+
this.closureDepth--;
|
|
458
560
|
const returnTypeTarget = parseClosureReturnTypeTarget(this);
|
|
561
|
+
validateYieldInClosure(body, returnTypeTarget, start);
|
|
459
562
|
const param = {
|
|
460
563
|
type: 'ClosureParam',
|
|
461
564
|
name: '$',
|
|
@@ -482,8 +585,11 @@ Parser.prototype.parseClosure = function () {
|
|
|
482
585
|
}
|
|
483
586
|
expect(this.state, TOKEN_TYPES.PIPE_BAR, 'Expected |', 'RILL-P005');
|
|
484
587
|
skipNewlines(this.state);
|
|
588
|
+
this.closureDepth++;
|
|
485
589
|
const body = this.parseBody(true);
|
|
590
|
+
this.closureDepth--;
|
|
486
591
|
const returnTypeTarget = parseClosureReturnTypeTarget(this);
|
|
592
|
+
validateYieldInClosure(body, returnTypeTarget, start);
|
|
487
593
|
return {
|
|
488
594
|
type: 'Closure',
|
|
489
595
|
params,
|
|
@@ -500,7 +606,8 @@ Parser.prototype.parseBody = function (allowEmptyBlock) {
|
|
|
500
606
|
return this.parseGrouped();
|
|
501
607
|
}
|
|
502
608
|
if (check(this.state, TOKEN_TYPES.BREAK) ||
|
|
503
|
-
check(this.state, TOKEN_TYPES.RETURN)
|
|
609
|
+
check(this.state, TOKEN_TYPES.RETURN) ||
|
|
610
|
+
check(this.state, TOKEN_TYPES.YIELD)) {
|
|
504
611
|
return this.parsePipeChain();
|
|
505
612
|
}
|
|
506
613
|
return this.parsePostfixExpr();
|
|
@@ -18,9 +18,9 @@ import { parseFieldArgList } from './parser-types.js';
|
|
|
18
18
|
* Produces TypeConstructorNode.
|
|
19
19
|
*/
|
|
20
20
|
Parser.prototype.parseTypeConstructor = function (constructorName) {
|
|
21
|
-
const validNames = ['list', 'dict', 'tuple', 'ordered'];
|
|
21
|
+
const validNames = ['list', 'dict', 'tuple', 'ordered', 'stream'];
|
|
22
22
|
if (!validNames.includes(constructorName)) {
|
|
23
|
-
throw new ParseError('RILL-P001', `Expected type constructor name (list, dict, tuple, ordered), got: ${constructorName}`, current(this.state).span.start);
|
|
23
|
+
throw new ParseError('RILL-P001', `Expected type constructor name (list, dict, tuple, ordered, stream), got: ${constructorName}`, current(this.state).span.start);
|
|
24
24
|
}
|
|
25
25
|
const start = current(this.state).span.start;
|
|
26
26
|
// Consume the constructor name identifier token
|
|
@@ -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 $');
|
|
@@ -55,8 +55,20 @@ Parser.prototype.parseUseExpr = function () {
|
|
|
55
55
|
expect(this.state, TOKEN_TYPES.GT, "Expected '>' to close use<>", 'RILL-P022');
|
|
56
56
|
let typeRef = null;
|
|
57
57
|
let closureAnnotation = null;
|
|
58
|
+
const parseLiteral = () => this.parseLiteral();
|
|
58
59
|
if (check(this.state, TOKEN_TYPES.COLON)) {
|
|
59
|
-
if (peek(this.state, 1).type === TOKEN_TYPES.
|
|
60
|
+
if (peek(this.state, 1).type === TOKEN_TYPES.OR) {
|
|
61
|
+
// Zero-param closure annotation: :||
|
|
62
|
+
advance(this.state); // consume :
|
|
63
|
+
advance(this.state); // consume || (OR token)
|
|
64
|
+
closureAnnotation = [];
|
|
65
|
+
// Optional return type after :||
|
|
66
|
+
if (check(this.state, TOKEN_TYPES.COLON)) {
|
|
67
|
+
advance(this.state); // consume :
|
|
68
|
+
typeRef = parseTypeRef(this.state, { parseLiteral });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (peek(this.state, 1).type === TOKEN_TYPES.PIPE_BAR) {
|
|
60
72
|
// Closure annotation: :|param: type, ...|
|
|
61
73
|
advance(this.state); // consume :
|
|
62
74
|
advance(this.state); // consume opening |
|
|
@@ -66,11 +78,17 @@ Parser.prototype.parseUseExpr = function () {
|
|
|
66
78
|
expect(this.state, TOKEN_TYPES.COLON, 'Expected : after parameter name in closure annotation');
|
|
67
79
|
const paramTypeRef = parseTypeRef(this.state, {
|
|
68
80
|
allowTrailingPipe: true,
|
|
81
|
+
parseLiteral,
|
|
69
82
|
});
|
|
70
|
-
|
|
83
|
+
const entry = {
|
|
71
84
|
name: nameToken.value,
|
|
72
85
|
typeRef: paramTypeRef,
|
|
73
|
-
}
|
|
86
|
+
};
|
|
87
|
+
if (check(this.state, TOKEN_TYPES.ASSIGN)) {
|
|
88
|
+
advance(this.state); // consume =
|
|
89
|
+
entry.defaultValue = parseLiteral();
|
|
90
|
+
}
|
|
91
|
+
closureAnnotation.push(entry);
|
|
74
92
|
if (check(this.state, TOKEN_TYPES.COMMA)) {
|
|
75
93
|
advance(this.state); // consume ,
|
|
76
94
|
}
|
|
@@ -79,6 +97,11 @@ Parser.prototype.parseUseExpr = function () {
|
|
|
79
97
|
}
|
|
80
98
|
}
|
|
81
99
|
advance(this.state); // consume closing |
|
|
100
|
+
// Optional return type after :|params|
|
|
101
|
+
if (check(this.state, TOKEN_TYPES.COLON)) {
|
|
102
|
+
advance(this.state); // consume :
|
|
103
|
+
typeRef = parseTypeRef(this.state, { parseLiteral });
|
|
104
|
+
}
|
|
82
105
|
}
|
|
83
106
|
else {
|
|
84
107
|
advance(this.state); // consume :
|
package/dist/parser/parser.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ import { type ParserState } from './state.js';
|
|
|
33
33
|
export declare class Parser {
|
|
34
34
|
/** Parser state including tokens, position, and error collection */
|
|
35
35
|
state: ParserState;
|
|
36
|
+
/** Tracks closure nesting depth for yield validation */
|
|
37
|
+
closureDepth: number;
|
|
36
38
|
constructor(tokens: Token[], options?: {
|
|
37
39
|
recoveryMode?: boolean;
|
|
38
40
|
source?: string;
|
package/dist/parser/parser.js
CHANGED
|
@@ -32,6 +32,8 @@ import { createParserState } from './state.js';
|
|
|
32
32
|
export class Parser {
|
|
33
33
|
/** Parser state including tokens, position, and error collection */
|
|
34
34
|
state;
|
|
35
|
+
/** Tracks closure nesting depth for yield validation */
|
|
36
|
+
closureDepth = 0;
|
|
35
37
|
constructor(tokens, options) {
|
|
36
38
|
this.state = createParserState(tokens, {
|
|
37
39
|
recoveryMode: options?.recoveryMode ?? false,
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
* - Kept for API consistency with marshalArgs signature
|
|
21
21
|
*/
|
|
22
22
|
import type { BodyNode, SourceLocation } from '../../types.js';
|
|
23
|
-
import
|
|
23
|
+
import { isDict } from './types/guards.js';
|
|
24
|
+
import type { TypeStructure, RillTypeValue, RillValue } from './types/structures.js';
|
|
24
25
|
interface RuntimeContextLike {
|
|
25
26
|
readonly parent?: RuntimeContextLike | undefined;
|
|
26
27
|
readonly variables: Map<string, RillValue>;
|
|
@@ -42,7 +43,7 @@ export type CallableFn = (args: Record<string, RillValue>, ctx: RuntimeContextLi
|
|
|
42
43
|
*/
|
|
43
44
|
export interface RillParam {
|
|
44
45
|
readonly name: string;
|
|
45
|
-
readonly type:
|
|
46
|
+
readonly type: TypeStructure | undefined;
|
|
46
47
|
readonly defaultValue: RillValue | undefined;
|
|
47
48
|
readonly annotations: Record<string, RillValue>;
|
|
48
49
|
}
|
|
@@ -57,6 +58,8 @@ export interface RillFunction {
|
|
|
57
58
|
readonly fn: CallableFn;
|
|
58
59
|
readonly annotations?: Record<string, RillValue>;
|
|
59
60
|
readonly returnType: RillTypeValue;
|
|
61
|
+
/** When true, RILL-R003 generic receiver validation is skipped for this method. */
|
|
62
|
+
readonly skipReceiverValidation?: boolean;
|
|
60
63
|
}
|
|
61
64
|
/** Common fields for all callable types */
|
|
62
65
|
interface CallableBase {
|
|
@@ -97,8 +100,8 @@ export interface ApplicationCallable extends CallableBase {
|
|
|
97
100
|
}
|
|
98
101
|
/** Union of all callable types */
|
|
99
102
|
export type RillCallable = ScriptCallable | RuntimeCallable | ApplicationCallable;
|
|
100
|
-
/** Type guard for any callable */
|
|
101
|
-
export declare
|
|
103
|
+
/** Type guard for any callable (delegates to types/guards.ts) */
|
|
104
|
+
export declare const isCallable: (value: RillValue) => value is RillCallable;
|
|
102
105
|
/** Type guard for script callable */
|
|
103
106
|
export declare function isScriptCallable(value: RillValue): value is ScriptCallable;
|
|
104
107
|
/** Type guard for runtime callable */
|
|
@@ -112,8 +115,17 @@ export declare function isApplicationCallable(value: RillValue): value is Applic
|
|
|
112
115
|
* @param isProperty If true, auto-invokes when accessed from dict (property-style)
|
|
113
116
|
*/
|
|
114
117
|
export declare function callable(fn: CallableFn, isProperty?: boolean): ApplicationCallable;
|
|
115
|
-
/**
|
|
116
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Convert a RillFunction to an ApplicationCallable.
|
|
120
|
+
*
|
|
121
|
+
* Validates the input and produces a callable value accepted by the loader.
|
|
122
|
+
* Pure function with no side effects.
|
|
123
|
+
*
|
|
124
|
+
* @param def - Host function definition to convert
|
|
125
|
+
* @returns ApplicationCallable with __type, kind, isProperty, and preserved annotations
|
|
126
|
+
*/
|
|
127
|
+
export declare function toCallable(def: RillFunction, isProperty?: boolean): ApplicationCallable;
|
|
128
|
+
export { isDict };
|
|
117
129
|
/** Format a callable for display */
|
|
118
130
|
export declare function formatCallable(callable: RillCallable): string;
|
|
119
131
|
/**
|
|
@@ -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
|
*
|
|
@@ -196,4 +208,3 @@ export declare function hydrateFieldDefaults(value: RillValue, type: RillType):
|
|
|
196
208
|
* @returns Named argument map keyed by param name
|
|
197
209
|
*/
|
|
198
210
|
export declare function marshalArgs(args: RillValue[], params: readonly RillParam[], options?: MarshalOptions): Record<string, RillValue>;
|
|
199
|
-
export {};
|