@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.
Files changed (97) hide show
  1. package/README.md +37 -21
  2. package/dist/ast-nodes.d.ts +14 -4
  3. package/dist/ast-unions.d.ts +1 -1
  4. package/dist/constants.d.ts +1 -1
  5. package/dist/constants.js +1 -0
  6. package/dist/error-registry.js +228 -0
  7. package/dist/ext/crypto/index.d.ts +3 -3
  8. package/dist/ext/crypto/index.js +62 -59
  9. package/dist/ext/exec/index.d.ts +3 -3
  10. package/dist/ext/exec/index.js +15 -9
  11. package/dist/ext/fetch/index.d.ts +3 -3
  12. package/dist/ext/fetch/index.js +17 -12
  13. package/dist/ext/fetch/request.js +1 -1
  14. package/dist/ext/fs/index.d.ts +3 -3
  15. package/dist/ext/fs/index.js +256 -266
  16. package/dist/ext/fs/sandbox.d.ts +18 -0
  17. package/dist/ext/fs/sandbox.js +33 -0
  18. package/dist/ext/kv/index.d.ts +3 -3
  19. package/dist/ext/kv/index.js +198 -196
  20. package/dist/ext/kv/store.d.ts +1 -1
  21. package/dist/ext/kv/store.js +2 -1
  22. package/dist/ext-parse-bridge.d.ts +10 -0
  23. package/dist/ext-parse-bridge.js +10 -0
  24. package/dist/generated/introspection-data.d.ts +1 -1
  25. package/dist/generated/introspection-data.js +385 -296
  26. package/dist/generated/version-data.d.ts +1 -1
  27. package/dist/generated/version-data.js +2 -2
  28. package/dist/highlight-map.js +1 -0
  29. package/dist/index.d.ts +1 -4
  30. package/dist/index.js +1 -5
  31. package/dist/lexer/operators.js +1 -0
  32. package/dist/parser/helpers.js +1 -0
  33. package/dist/parser/parser-expr.js +44 -5
  34. package/dist/parser/parser-literals.js +111 -4
  35. package/dist/parser/parser-shape.js +2 -2
  36. package/dist/parser/parser-types.js +12 -0
  37. package/dist/parser/parser-use.js +26 -3
  38. package/dist/parser/parser.d.ts +2 -0
  39. package/dist/parser/parser.js +2 -0
  40. package/dist/runtime/core/callable.d.ts +24 -13
  41. package/dist/runtime/core/callable.js +71 -38
  42. package/dist/runtime/core/context.d.ts +2 -13
  43. package/dist/runtime/core/context.js +80 -79
  44. package/dist/runtime/core/eval/base.d.ts +2 -2
  45. package/dist/runtime/core/eval/base.js +2 -0
  46. package/dist/runtime/core/eval/evaluator.d.ts +1 -1
  47. package/dist/runtime/core/eval/index.d.ts +3 -3
  48. package/dist/runtime/core/eval/index.js +11 -0
  49. package/dist/runtime/core/eval/mixins/closures.js +381 -41
  50. package/dist/runtime/core/eval/mixins/collections.js +81 -6
  51. package/dist/runtime/core/eval/mixins/control-flow.js +1 -1
  52. package/dist/runtime/core/eval/mixins/conversion.js +61 -115
  53. package/dist/runtime/core/eval/mixins/core.js +17 -4
  54. package/dist/runtime/core/eval/mixins/expressions.js +36 -27
  55. package/dist/runtime/core/eval/mixins/extraction.js +2 -3
  56. package/dist/runtime/core/eval/mixins/list-dispatch.js +1 -1
  57. package/dist/runtime/core/eval/mixins/literals.js +17 -6
  58. package/dist/runtime/core/eval/mixins/types.js +73 -54
  59. package/dist/runtime/core/eval/mixins/variables.js +12 -8
  60. package/dist/runtime/core/execute.d.ts +1 -1
  61. package/dist/runtime/core/field-descriptor.d.ts +3 -3
  62. package/dist/runtime/core/field-descriptor.js +2 -1
  63. package/dist/runtime/core/introspection.d.ts +2 -2
  64. package/dist/runtime/core/introspection.js +7 -6
  65. package/dist/runtime/core/resolvers.d.ts +1 -1
  66. package/dist/runtime/core/signals.d.ts +6 -1
  67. package/dist/runtime/core/signals.js +9 -0
  68. package/dist/runtime/core/types/constructors.d.ts +54 -0
  69. package/dist/runtime/core/types/constructors.js +201 -0
  70. package/dist/runtime/core/types/guards.d.ts +42 -0
  71. package/dist/runtime/core/types/guards.js +88 -0
  72. package/dist/runtime/core/types/index.d.ts +18 -0
  73. package/dist/runtime/core/types/index.js +19 -0
  74. package/dist/runtime/core/types/markers.d.ts +12 -0
  75. package/dist/runtime/core/types/markers.js +7 -0
  76. package/dist/runtime/core/types/operations.d.ts +98 -0
  77. package/dist/runtime/core/types/operations.js +804 -0
  78. package/dist/runtime/core/types/registrations.d.ts +126 -0
  79. package/dist/runtime/core/types/registrations.js +751 -0
  80. package/dist/runtime/core/{types.d.ts → types/runtime.d.ts} +22 -10
  81. package/dist/runtime/core/types/structures.d.ts +146 -0
  82. package/dist/runtime/core/types/structures.js +12 -0
  83. package/dist/runtime/core/values.d.ts +29 -209
  84. package/dist/runtime/core/values.js +56 -968
  85. package/dist/runtime/ext/builtins.js +88 -68
  86. package/dist/runtime/ext/extensions.d.ts +31 -125
  87. package/dist/runtime/ext/extensions.js +2 -94
  88. package/dist/runtime/ext/test-context.d.ts +28 -0
  89. package/dist/runtime/ext/test-context.js +155 -0
  90. package/dist/runtime/index.d.ts +12 -12
  91. package/dist/runtime/index.js +13 -5
  92. package/dist/signature-parser.d.ts +2 -2
  93. package/dist/signature-parser.js +14 -14
  94. package/dist/token-types.d.ts +1 -0
  95. package/dist/token-types.js +1 -0
  96. package/package.json +1 -1
  97. /package/dist/runtime/core/{types.js → types/runtime.js} +0 -0
@@ -10,7 +10,7 @@ export interface VersionInfo {
10
10
  /**
11
11
  * Version string from package.json
12
12
  */
13
- export declare const VERSION = "0.16.0";
13
+ export declare const VERSION = "0.18.0";
14
14
  /**
15
15
  * Parsed version components
16
16
  */
@@ -3,13 +3,13 @@
3
3
  /**
4
4
  * Version string from package.json
5
5
  */
6
- export const VERSION = '0.16.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: 16,
12
+ minor: 18,
13
13
  patch: 0,
14
14
  prerelease: undefined,
15
15
  };
@@ -24,6 +24,7 @@ export const TOKEN_HIGHLIGHT_MAP = new Map([
24
24
  ['FILTER', 'keyword'],
25
25
  ['BREAK', 'keyword'],
26
26
  ['RETURN', 'keyword'],
27
+ ['YIELD', 'keyword'],
27
28
  ['PASS', 'keyword'],
28
29
  ['ASSERT', 'keyword'],
29
30
  ['ERROR', 'keyword'],
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, contextResolver, extResolver, type ErrorEvent, execute, type ExecutionResult, type ExecutionStepper, type ExtensionConfigSchema, type ExtensionEvent, type ExtensionFactory, type ExtensionManifest, type ExtensionResult, type FsExtensionContract, type FunctionMetadata, hoistExtension, type HoistedExtension, type HostCallEvent, type FunctionReturnEvent, getCallStack, generateManifest, getDocumentationCoverage, getFunctions, getLanguageReference, buildFieldDescriptor, buildTypeMethodDicts, formatStructuralType, inferElementType, inferStructuralType, inferType, invokeCallable, isApplicationCallable, moduleResolver, isTuple, isCallable, isDict, isReservedMethod, isRillIterator, isRuntimeCallable, isScriptCallable, isTypeValue, isVector, type KvExtensionContract, type NativeArray, type NativePlainObject, type NativeResult, type NativeValue, type LlmExtensionContract, type SchemaEntry, type ObservabilityCallbacks, type ParamMetadata, paramToFieldDef, popCallFrame, prefixFunctions, pushCallFrame, RESERVED_DICT_METHODS, rillTypeToTypeValue, ReturnSignal, type RillCallable, type RillFieldDef, type RillFunction, type RillParam, type RillIterator, type RillTuple, type RillType, type RillTypeValue, type RillValue, type RillVector, type RuntimeCallable, type ResolverResult, type RuntimeCallbacks, type RuntimeContext, type RuntimeOptions, type SchemeResolver, type ScriptCallable, type StepEndEvent, type StepResult, type StepStartEvent, type VectorExtensionContract, structuralTypeEquals, structuralTypeMatches, toNative, VERSION, VERSION_INFO, type VersionInfo, } from './runtime/index.js';
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, contextResolver, extResolver, execute, hoistExtension, getCallStack, generateManifest, getDocumentationCoverage, getFunctions, getLanguageReference, buildFieldDescriptor, buildTypeMethodDicts, formatStructuralType, inferElementType, inferStructuralType, inferType, invokeCallable, isApplicationCallable, moduleResolver, isTuple, isCallable, isDict, isReservedMethod, isRillIterator, isRuntimeCallable, isScriptCallable, isTypeValue, isVector, paramToFieldDef, popCallFrame, prefixFunctions, pushCallFrame, RESERVED_DICT_METHODS, rillTypeToTypeValue, ReturnSignal, structuralTypeEquals, structuralTypeMatches, toNative, VERSION, VERSION_INFO, } from './runtime/index.js';
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';
@@ -48,6 +48,7 @@ export const KEYWORDS = {
48
48
  false: TOKEN_TYPES.FALSE,
49
49
  break: TOKEN_TYPES.BREAK,
50
50
  return: TOKEN_TYPES.RETURN,
51
+ yield: TOKEN_TYPES.YIELD,
51
52
  pass: TOKEN_TYPES.PASS,
52
53
  assert: TOKEN_TYPES.ASSERT,
53
54
  error: TOKEN_TYPES.ERROR,
@@ -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 = ['list', 'dict', 'tuple', 'ordered'];
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 TYPE_CONSTRUCTORS = ['list', 'dict', 'tuple', 'ordered'];
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
- TYPE_CONSTRUCTORS.includes(current(this.state).value) &&
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 = shape(...) | type-ref
482
+ * type-target = "stream" "(" [type-ref] ")" [":" type-ref] | type-ref
392
483
  *
393
- * Returns the parsed TypeRef or ShapeLiteralNode, or undefined if absent.
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.PIPE_BAR) {
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
- closureAnnotation.push({
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 :
@@ -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;
@@ -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 type { RillType, RillTypeValue, RillValue } from './values.js';
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: RillType | undefined;
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 function isCallable(value: RillValue): value is RillCallable;
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
- /** Type guard for dict (plain object, not array, not callable, not tuple) */
116
- export declare function isDict(value: RillValue): value is Record<string, RillValue>;
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 RillType closure variant from a closure's parameter list.
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 { type: 'any' }
137
- * - Return type is always { type: 'any' }
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 RillType with closure variant
154
+ * @returns Frozen TypeStructure with closure variant
143
155
  */
144
- export declare function paramsToStructuralType(params: readonly RillParam[]): RillType;
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: RillType): RillValue;
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 {};