@cavelang/parser 0.31.0 → 0.32.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 CHANGED
@@ -32,13 +32,15 @@ parse('a USES b') // strict variant: throws on any diagnostic
32
32
  (`Token.splitComment`).
33
33
  3. **Tokenize** into words / `"text"` literals / `` `code` `` literals
34
34
  (`token.ts`, `@prelude/parser` combinators).
35
- 4. **Classify** the line per §8's three-kind table: qualifier (starts with
35
+ 4. **Expand incomplete prefixes** (§8.5): prepend every incomplete ancestor's
36
+ tokens recursively; blank and comment lines are transparent.
37
+ 5. **Classify** the completed logical line per §8's three-kind table: qualifier (starts with
36
38
  `WHEN`/`UNLESS`/`VIA`/`BECAUSE`), continuation (starts with a bare
37
39
  relational verb), or full claim.
38
- 5. **Parse the token stream** (`line.ts`): subject, verb, `NOT`, payload,
40
+ 6. **Parse the token stream** (`line.ts`): subject, verb, `NOT`, payload,
39
41
  then metadata items.
40
- 6. **Resolve parents**: each structural line links to the nearest
41
- less-indented structural line above.
42
+ 7. **Resolve parents**: each completed line links to the nearest
43
+ less-indented materialized claim above; prefix headers do not become claims.
42
44
 
43
45
  ## Payload classification
44
46
 
@@ -100,6 +102,14 @@ examples and are tried in order:
100
102
  with last-wins retention (§3.2 allows repetition only for contexts and
101
103
  tags); a glued attribute colon (`expiry:3600s`) splits into the attribute
102
104
  form with a diagnostic, since payload `:` is reserved (§4.3).
105
+ - **Prefix compatibility boundary.** A physical line becomes a §8.5 prefix
106
+ only when its accumulated tokens are incomplete and it has indented
107
+ content. Complete lines retain the established qualifier, continuation,
108
+ and grouped-claim semantics. Prefixes compose recursively; blank and
109
+ full-line comments are transparent. A prefix's trailing comment is
110
+ documentary and not inherited, while a leaf comment remains persisted.
111
+ `raw` preserves the physical leaf and `expanded` carries the self-contained
112
+ logical line used as stored `raw_line`.
103
113
 
104
114
  ## Tests
105
115
 
package/dist/src/ast.d.ts CHANGED
@@ -68,7 +68,9 @@ export type QualifierPayload = {
68
68
  /**
69
69
  * A parsed line. `depth` is the indentation width in characters; `parent` is
70
70
  * the index (into the document's `lines`) of the nearest less-indented
71
- * structural line above (spec §8). `raw` is the line exactly as written.
71
+ * materialized claim above (spec §8). `raw` is the physical line exactly as
72
+ * written. A shorthand leaf also carries `expanded`, the self-contained
73
+ * logical line assembled from its incomplete prefix ancestors (§8.5).
72
74
  */
73
75
  export type Line = {
74
76
  readonly kind: 'blank';
@@ -79,10 +81,19 @@ export type Line = {
79
81
  readonly line: number;
80
82
  readonly raw: string;
81
83
  readonly text: string;
84
+ } | {
85
+ readonly kind: 'prefix';
86
+ readonly line: number;
87
+ readonly raw: string;
88
+ readonly depth: number;
89
+ readonly parent?: number;
90
+ readonly expanded: string;
91
+ readonly comment?: string;
82
92
  } | {
83
93
  readonly kind: 'claim';
84
94
  readonly line: number;
85
95
  readonly raw: string;
96
+ readonly expanded?: string;
86
97
  readonly depth: number;
87
98
  readonly parent?: number;
88
99
  readonly claim: Full;
@@ -90,6 +101,7 @@ export type Line = {
90
101
  readonly kind: 'continuation';
91
102
  readonly line: number;
92
103
  readonly raw: string;
104
+ readonly expanded?: string;
93
105
  readonly depth: number;
94
106
  readonly parent?: number;
95
107
  readonly body: Body;
@@ -97,6 +109,7 @@ export type Line = {
97
109
  readonly kind: 'qualifier';
98
110
  readonly line: number;
99
111
  readonly raw: string;
112
+ readonly expanded?: string;
100
113
  readonly depth: number;
101
114
  readonly parent?: number;
102
115
  readonly qualifier: Verb.Qualifier;
@@ -1 +1 @@
1
- {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/ast.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/ast.ts"],"names":[],"mappings":"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"}
@@ -2,9 +2,9 @@
2
2
  * Document parser (spec §8, §16).
3
3
  *
4
4
  * Splits input into physical lines, measures indentation, classifies each
5
- * line (blank / comment / claim / continuation / qualifier), and resolves
6
- * each indented line's parent — the nearest less-indented structural line
7
- * above (spec §8).
5
+ * line (blank / comment / prefix / claim / continuation / qualifier), and
6
+ * resolves each materialized line's parent — the nearest less-indented
7
+ * materialized claim above (spec §8).
8
8
  *
9
9
  * Classification of an indented line follows spec §8's table, decided by
10
10
  * what the line starts with:
@@ -13,6 +13,11 @@
13
13
  * - bare relational verb → continuation
14
14
  * - full triple → grouped claim
15
15
  *
16
+ * An incomplete line with indented content is a shorthand prefix (§8.5).
17
+ * Its tokens are prepended to every child; nested incomplete prefixes
18
+ * compose recursively. Complete lines never become prefixes, preserving the
19
+ * three existing indentation meanings above.
20
+ *
16
21
  * One ambiguity needs a tiebreak: `API NEEDS auth` starts with a token that
17
22
  * is lexically verb-shaped. A two-token `VERB VERB` line is a continuation:
18
23
  * it has a verb and object but no third token for a full claim's payload.
@@ -1 +1 @@
1
- {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/document.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAA;AAkDpC;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,GAAG,CAAC,QAgGjD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,SAAS,GAAG,CAAC,IAAI,EAStD,CAAA"}
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/document.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAGH,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAA;AA2EpC;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,GAAG,CAAC,QAmJjD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,SAAS,GAAG,CAAC,IAAI,EAStD,CAAA"}
@@ -2,9 +2,9 @@
2
2
  * Document parser (spec §8, §16).
3
3
  *
4
4
  * Splits input into physical lines, measures indentation, classifies each
5
- * line (blank / comment / claim / continuation / qualifier), and resolves
6
- * each indented line's parent — the nearest less-indented structural line
7
- * above (spec §8).
5
+ * line (blank / comment / prefix / claim / continuation / qualifier), and
6
+ * resolves each materialized line's parent — the nearest less-indented
7
+ * materialized claim above (spec §8).
8
8
  *
9
9
  * Classification of an indented line follows spec §8's table, decided by
10
10
  * what the line starts with:
@@ -13,6 +13,11 @@
13
13
  * - bare relational verb → continuation
14
14
  * - full triple → grouped claim
15
15
  *
16
+ * An incomplete line with indented content is a shorthand prefix (§8.5).
17
+ * Its tokens are prepended to every child; nested incomplete prefixes
18
+ * compose recursively. Complete lines never become prefixes, preserving the
19
+ * three existing indentation meanings above.
20
+ *
16
21
  * One ambiguity needs a tiebreak: `API NEEDS auth` starts with a token that
17
22
  * is lexically verb-shaped. A two-token `VERB VERB` line is a continuation:
18
23
  * it has a verb and object but no third token for a full claim's payload.
@@ -65,6 +70,17 @@ const classify = (tokens, depth) => {
65
70
  }
66
71
  return 'claim';
67
72
  };
73
+ const hasIndentedContent = (rawLines, at, depth) => {
74
+ for (let next = at + 1; next < rawLines.length; next += 1) {
75
+ const info = indentOf(rawLines[next]);
76
+ if (info.rest === '' || info.rest.startsWith(';')) {
77
+ continue;
78
+ }
79
+ return info.depth > depth;
80
+ }
81
+ return false;
82
+ };
83
+ const logicalRaw = (head, comment) => comment === undefined ? head : `${head} ; ${comment}`;
68
84
  /**
69
85
  * Parses a CAVE document. Never throws; problems surface as diagnostics and
70
86
  * `invalid` lines.
@@ -91,26 +107,55 @@ export const parseDocument = (input) => {
91
107
  lines.push({ kind: 'comment', line: lineNo, raw, text: rest.slice(1).trim() });
92
108
  return;
93
109
  }
94
- const { head, comment } = Token.splitComment(rest);
95
- const tokens = Token.tokenize(head);
96
- if (tokens.length === 0) {
97
- lines.push({ kind: 'comment', line: lineNo, raw, text: comment ?? '' });
98
- return;
99
- }
100
- const kind = classify(tokens, depth);
101
- if (typeof kind === 'object') {
102
- problem(lineNo, raw, kind.error);
103
- lines.push({ kind: 'invalid', line: lineNo, raw, message: kind.error });
110
+ const split = Token.splitComment(rest);
111
+ const ownHead = split.head.trim();
112
+ const ownTokens = Token.tokenize(ownHead);
113
+ if (ownTokens.length === 0) {
114
+ lines.push({ kind: 'comment', line: lineNo, raw, text: split.comment ?? '' });
104
115
  return;
105
116
  }
106
117
  while (stack.length > 0 && stack[stack.length - 1].depth >= depth) {
107
118
  stack.pop();
108
119
  }
109
- const parent = stack[stack.length - 1]?.index;
120
+ const frame = stack[stack.length - 1];
121
+ const inherited = frame?.prefix;
122
+ const tokens = inherited === undefined ?
123
+ ownTokens :
124
+ [...inherited.tokens, ...ownTokens];
125
+ const head = inherited === undefined ?
126
+ ownHead :
127
+ `${inherited.head} ${ownHead}`;
128
+ const semanticDepth = inherited?.semanticDepth ?? depth;
129
+ const parent = inherited === undefined ? frame?.index : inherited.parent;
130
+ const expanded = inherited === undefined ? undefined : logicalRaw(head, split.comment);
131
+ const asPrefix = (message) => {
132
+ if (!hasIndentedContent(rawLines, at, depth)) {
133
+ problem(lineNo, raw, message);
134
+ lines.push({ kind: 'invalid', line: lineNo, raw, message });
135
+ return false;
136
+ }
137
+ const index = lines.length;
138
+ const prefix = { tokens, head, semanticDepth, ...parent === undefined ? {} : { parent } };
139
+ lines.push({
140
+ kind: 'prefix',
141
+ line: lineNo,
142
+ raw,
143
+ depth,
144
+ expanded: head,
145
+ ...parent === undefined ? {} : { parent },
146
+ ...split.comment === undefined ? {} : { comment: split.comment }
147
+ });
148
+ stack.push({ index, depth, prefix });
149
+ return true;
150
+ };
151
+ const kind = classify(tokens, semanticDepth);
152
+ if (typeof kind === 'object') {
153
+ asPrefix(kind.error);
154
+ return;
155
+ }
110
156
  if (parent === undefined && kind !== 'claim') {
111
157
  const message = `${kind} line has no parent claim above (spec §8)`;
112
- problem(lineNo, raw, message);
113
- lines.push({ kind: 'invalid', line: lineNo, raw, message });
158
+ asPrefix(message);
114
159
  return;
115
160
  }
116
161
  const index = lines.length;
@@ -123,34 +168,56 @@ export const parseDocument = (input) => {
123
168
  };
124
169
  switch (kind) {
125
170
  case 'claim': {
126
- const result = Line.parseClaim(tokens, comment);
171
+ const result = Line.parseClaim(tokens, split.comment);
127
172
  if (!result.ok) {
128
- problem(lineNo, raw, result.message);
129
- lines.push({ kind: 'invalid', line: lineNo, raw, message: result.message });
173
+ asPrefix(result.message);
130
174
  return;
131
175
  }
132
- push({ kind: 'claim', line: lineNo, raw, depth, ...parent !== undefined ? { parent } : {}, claim: result.value }, result.problems);
176
+ push({
177
+ kind: 'claim',
178
+ line: lineNo,
179
+ raw,
180
+ depth,
181
+ ...expanded === undefined ? {} : { expanded },
182
+ ...parent !== undefined ? { parent } : {},
183
+ claim: result.value
184
+ }, result.problems);
133
185
  return;
134
186
  }
135
187
  case 'continuation': {
136
- const result = Line.parseBody(tokens, comment);
188
+ const result = Line.parseBody(tokens, split.comment);
137
189
  if (!result.ok) {
138
- problem(lineNo, raw, result.message);
139
- lines.push({ kind: 'invalid', line: lineNo, raw, message: result.message });
190
+ asPrefix(result.message);
140
191
  return;
141
192
  }
142
- push({ kind: 'continuation', line: lineNo, raw, depth, parent: parent, body: result.value }, result.problems);
193
+ push({
194
+ kind: 'continuation',
195
+ line: lineNo,
196
+ raw,
197
+ depth,
198
+ parent: parent,
199
+ ...expanded === undefined ? {} : { expanded },
200
+ body: result.value
201
+ }, result.problems);
143
202
  return;
144
203
  }
145
204
  case 'qualifier': {
146
205
  const qualifier = tokens[0].text;
147
- const result = Line.parseQualifierPayload(tokens.slice(1), comment);
206
+ const result = Line.parseQualifierPayload(tokens.slice(1), split.comment);
148
207
  if (!result.ok) {
149
- problem(lineNo, raw, result.message);
150
- lines.push({ kind: 'invalid', line: lineNo, raw, message: result.message });
208
+ asPrefix(result.message);
151
209
  return;
152
210
  }
153
- push({ kind: 'qualifier', line: lineNo, raw, depth, parent: parent, qualifier, payload: result.value }, result.problems);
211
+ push({
212
+ kind: 'qualifier',
213
+ line: lineNo,
214
+ raw,
215
+ depth,
216
+ parent: parent,
217
+ ...expanded === undefined ? {} : { expanded },
218
+ qualifier,
219
+ payload: result.value
220
+ }, result.problems);
154
221
  return;
155
222
  }
156
223
  }
@@ -1 +1 @@
1
- {"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/document.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/document.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cavelang/parser",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "type": "module",
5
5
  "description": "CAVE text to AST parser built on @prelude/parser combinators.",
6
6
  "keywords": [
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@prelude/parser": "^7.1.0",
47
- "@cavelang/core": "0.31.0"
47
+ "@cavelang/core": "0.32.0"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "tsc -b",
package/src/ast.ts CHANGED
@@ -66,14 +66,17 @@ export type QualifierPayload =
66
66
  /**
67
67
  * A parsed line. `depth` is the indentation width in characters; `parent` is
68
68
  * the index (into the document's `lines`) of the nearest less-indented
69
- * structural line above (spec §8). `raw` is the line exactly as written.
69
+ * materialized claim above (spec §8). `raw` is the physical line exactly as
70
+ * written. A shorthand leaf also carries `expanded`, the self-contained
71
+ * logical line assembled from its incomplete prefix ancestors (§8.5).
70
72
  */
71
73
  export type Line =
72
74
  | { readonly kind: 'blank', readonly line: number, readonly raw: string }
73
75
  | { readonly kind: 'comment', readonly line: number, readonly raw: string, readonly text: string }
74
- | { readonly kind: 'claim', readonly line: number, readonly raw: string, readonly depth: number, readonly parent?: number, readonly claim: Full }
75
- | { readonly kind: 'continuation', readonly line: number, readonly raw: string, readonly depth: number, readonly parent?: number, readonly body: Body }
76
- | { readonly kind: 'qualifier', readonly line: number, readonly raw: string, readonly depth: number, readonly parent?: number, readonly qualifier: Verb.Qualifier, readonly payload: QualifierPayload }
76
+ | { readonly kind: 'prefix', readonly line: number, readonly raw: string, readonly depth: number, readonly parent?: number, readonly expanded: string, readonly comment?: string }
77
+ | { readonly kind: 'claim', readonly line: number, readonly raw: string, readonly expanded?: string, readonly depth: number, readonly parent?: number, readonly claim: Full }
78
+ | { readonly kind: 'continuation', readonly line: number, readonly raw: string, readonly expanded?: string, readonly depth: number, readonly parent?: number, readonly body: Body }
79
+ | { readonly kind: 'qualifier', readonly line: number, readonly raw: string, readonly expanded?: string, readonly depth: number, readonly parent?: number, readonly qualifier: Verb.Qualifier, readonly payload: QualifierPayload }
77
80
  | { readonly kind: 'invalid', readonly line: number, readonly raw: string, readonly message: string }
78
81
 
79
82
  export type t = Line
package/src/document.ts CHANGED
@@ -2,9 +2,9 @@
2
2
  * Document parser (spec §8, §16).
3
3
  *
4
4
  * Splits input into physical lines, measures indentation, classifies each
5
- * line (blank / comment / claim / continuation / qualifier), and resolves
6
- * each indented line's parent — the nearest less-indented structural line
7
- * above (spec §8).
5
+ * line (blank / comment / prefix / claim / continuation / qualifier), and
6
+ * resolves each materialized line's parent — the nearest less-indented
7
+ * materialized claim above (spec §8).
8
8
  *
9
9
  * Classification of an indented line follows spec §8's table, decided by
10
10
  * what the line starts with:
@@ -13,6 +13,11 @@
13
13
  * - bare relational verb → continuation
14
14
  * - full triple → grouped claim
15
15
  *
16
+ * An incomplete line with indented content is a shorthand prefix (§8.5).
17
+ * Its tokens are prepended to every child; nested incomplete prefixes
18
+ * compose recursively. Complete lines never become prefixes, preserving the
19
+ * three existing indentation meanings above.
20
+ *
16
21
  * One ambiguity needs a tiebreak: `API NEEDS auth` starts with a token that
17
22
  * is lexically verb-shaped. A two-token `VERB VERB` line is a continuation:
18
23
  * it has a verb and object but no third token for a full claim's payload.
@@ -72,7 +77,32 @@ const classify = (tokens: readonly Token.t[], depth: number): Classified | { err
72
77
  return 'claim'
73
78
  }
74
79
 
75
- type Frame = { index: number, depth: number }
80
+ type Prefix = {
81
+ readonly tokens: readonly Token.t[]
82
+ readonly head: string
83
+ readonly semanticDepth: number
84
+ readonly parent?: number
85
+ }
86
+
87
+ type Frame = {
88
+ readonly index: number
89
+ readonly depth: number
90
+ readonly prefix?: Prefix
91
+ }
92
+
93
+ const hasIndentedContent = (rawLines: readonly string[], at: number, depth: number): boolean => {
94
+ for (let next = at + 1; next < rawLines.length; next += 1) {
95
+ const info = indentOf(rawLines[next]!)
96
+ if (info.rest === '' || info.rest.startsWith(';')) {
97
+ continue
98
+ }
99
+ return info.depth > depth
100
+ }
101
+ return false
102
+ }
103
+
104
+ const logicalRaw = (head: string, comment?: string): string =>
105
+ comment === undefined ? head : `${head} ; ${comment}`
76
106
 
77
107
  /**
78
108
  * Parses a CAVE document. Never throws; problems surface as diagnostics and
@@ -100,26 +130,55 @@ export const parseDocument = (input: string): Ast.Document => {
100
130
  lines.push({ kind: 'comment', line: lineNo, raw, text: rest.slice(1).trim() })
101
131
  return
102
132
  }
103
- const { head, comment } = Token.splitComment(rest)
104
- const tokens = Token.tokenize(head)
105
- if (tokens.length === 0) {
106
- lines.push({ kind: 'comment', line: lineNo, raw, text: comment ?? '' })
107
- return
108
- }
109
- const kind = classify(tokens, depth)
110
- if (typeof kind === 'object') {
111
- problem(lineNo, raw, kind.error)
112
- lines.push({ kind: 'invalid', line: lineNo, raw, message: kind.error })
133
+ const split = Token.splitComment(rest)
134
+ const ownHead = split.head.trim()
135
+ const ownTokens = Token.tokenize(ownHead)
136
+ if (ownTokens.length === 0) {
137
+ lines.push({ kind: 'comment', line: lineNo, raw, text: split.comment ?? '' })
113
138
  return
114
139
  }
115
140
  while (stack.length > 0 && stack[stack.length - 1]!.depth >= depth) {
116
141
  stack.pop()
117
142
  }
118
- const parent = stack[stack.length - 1]?.index
143
+ const frame = stack[stack.length - 1]
144
+ const inherited = frame?.prefix
145
+ const tokens = inherited === undefined ?
146
+ ownTokens :
147
+ [...inherited.tokens, ...ownTokens]
148
+ const head = inherited === undefined ?
149
+ ownHead :
150
+ `${inherited.head} ${ownHead}`
151
+ const semanticDepth = inherited?.semanticDepth ?? depth
152
+ const parent = inherited === undefined ? frame?.index : inherited.parent
153
+ const expanded = inherited === undefined ? undefined : logicalRaw(head, split.comment)
154
+ const asPrefix = (message: string): boolean => {
155
+ if (!hasIndentedContent(rawLines, at, depth)) {
156
+ problem(lineNo, raw, message)
157
+ lines.push({ kind: 'invalid', line: lineNo, raw, message })
158
+ return false
159
+ }
160
+ const index = lines.length
161
+ const prefix: Prefix = { tokens, head, semanticDepth, ...parent === undefined ? {} : { parent } }
162
+ lines.push({
163
+ kind: 'prefix',
164
+ line: lineNo,
165
+ raw,
166
+ depth,
167
+ expanded: head,
168
+ ...parent === undefined ? {} : { parent },
169
+ ...split.comment === undefined ? {} : { comment: split.comment }
170
+ })
171
+ stack.push({ index, depth, prefix })
172
+ return true
173
+ }
174
+ const kind = classify(tokens, semanticDepth)
175
+ if (typeof kind === 'object') {
176
+ asPrefix(kind.error)
177
+ return
178
+ }
119
179
  if (parent === undefined && kind !== 'claim') {
120
180
  const message = `${kind} line has no parent claim above (spec §8)`
121
- problem(lineNo, raw, message)
122
- lines.push({ kind: 'invalid', line: lineNo, raw, message })
181
+ asPrefix(message)
123
182
  return
124
183
  }
125
184
  const index = lines.length
@@ -132,41 +191,63 @@ export const parseDocument = (input: string): Ast.Document => {
132
191
  }
133
192
  switch (kind) {
134
193
  case 'claim': {
135
- const result = Line.parseClaim(tokens, comment)
194
+ const result = Line.parseClaim(tokens, split.comment)
136
195
  if (!result.ok) {
137
- problem(lineNo, raw, result.message)
138
- lines.push({ kind: 'invalid', line: lineNo, raw, message: result.message })
196
+ asPrefix(result.message)
139
197
  return
140
198
  }
141
199
  push(
142
- { kind: 'claim', line: lineNo, raw, depth, ...parent !== undefined ? { parent } : {}, claim: result.value },
200
+ {
201
+ kind: 'claim',
202
+ line: lineNo,
203
+ raw,
204
+ depth,
205
+ ...expanded === undefined ? {} : { expanded },
206
+ ...parent !== undefined ? { parent } : {},
207
+ claim: result.value
208
+ },
143
209
  result.problems
144
210
  )
145
211
  return
146
212
  }
147
213
  case 'continuation': {
148
- const result = Line.parseBody(tokens, comment)
214
+ const result = Line.parseBody(tokens, split.comment)
149
215
  if (!result.ok) {
150
- problem(lineNo, raw, result.message)
151
- lines.push({ kind: 'invalid', line: lineNo, raw, message: result.message })
216
+ asPrefix(result.message)
152
217
  return
153
218
  }
154
219
  push(
155
- { kind: 'continuation', line: lineNo, raw, depth, parent: parent!, body: result.value },
220
+ {
221
+ kind: 'continuation',
222
+ line: lineNo,
223
+ raw,
224
+ depth,
225
+ parent: parent!,
226
+ ...expanded === undefined ? {} : { expanded },
227
+ body: result.value
228
+ },
156
229
  result.problems
157
230
  )
158
231
  return
159
232
  }
160
233
  case 'qualifier': {
161
234
  const qualifier = (tokens[0] as { text: string }).text as Verb.Qualifier
162
- const result = Line.parseQualifierPayload(tokens.slice(1), comment)
235
+ const result = Line.parseQualifierPayload(tokens.slice(1), split.comment)
163
236
  if (!result.ok) {
164
- problem(lineNo, raw, result.message)
165
- lines.push({ kind: 'invalid', line: lineNo, raw, message: result.message })
237
+ asPrefix(result.message)
166
238
  return
167
239
  }
168
240
  push(
169
- { kind: 'qualifier', line: lineNo, raw, depth, parent: parent!, qualifier, payload: result.value },
241
+ {
242
+ kind: 'qualifier',
243
+ line: lineNo,
244
+ raw,
245
+ depth,
246
+ parent: parent!,
247
+ ...expanded === undefined ? {} : { expanded },
248
+ qualifier,
249
+ payload: result.value
250
+ },
170
251
  result.problems
171
252
  )
172
253
  return