slow.monster

STUDIO HAZE · topaz

Topaz source

Open by house policy. Topaz is our own language.

Topaz 5.20 · 56 files

compiler/crates/topaz_self_frontend/topaz/parser/declarations_modules.tpz

Topaz · 36793 B · Original file

1// Declaration, statement, block, import, export, and program grammar.
2// Expression and type-pattern parsers are called through their forward service
3// records; the public parse result is assembled by parser.tpz.
5import types { PreviewToken, SyntaxNode }
6import parser.core {
7 Parser,
8 ParserService,
9 addDiagnostic,
10 at,
11 attach,
12 boolAttribute,
13 boxValue,
14 bump,
15 current,
16 eat,
17 expect,
18 expectLeftBrace,
19 expectRightBrace,
20 fail,
21 identNode,
22 identifier,
23 itemBoundary,
24 lambdaAllowed,
25 node,
26 recordUpdateAllowed,
27 rejectReservedBinding,
28 setLambdaAllowed,
29 setRecordUpdateAllowed,
30 skipSeparators,
31 stringAttribute,
32 synchronize,
33 text,
34 tokenAt,
36import parser.types_patterns {
37 bindingPattern,
38 expectCloseAngle,
39 namedType,
40 parsePattern,
41 parseType,
43import parser.expressions {
44 blockExpression,
45 labelNode,
46 parseExpression,
47 parseExpressionBeforeBlock,
50// The high component is the type-parameter index and the low component is its bound ordinal.
51const TYPE_BOUND_INDEX_STRIDE = 4294967296
53function rejectedStatement(message: string) -> Result<SyntaxNode, string> {
54 Err(message)
57function skipBalancedBraces(parser: Parser) -> () {
58 if !at(parser, "left-brace") {
59 return ()
60 }
61 let mut depth = 0
62 while !at(parser, "eof") {
63 let kind = current(parser).kind
64 if kind == "left-brace" {
65 depth += 1
66 } else if kind == "right-brace" {
67 depth -= 1
68 }
69 bump(parser)
70 if depth == 0 {
71 break
72 }
73 }
74 ()
77function parseTypeParameters(
78 parser: Parser,
79 field: string,
80) -> Result<Array<SyntaxNode>, string> {
81 let mut parameters: Array<SyntaxNode> = []
82 if !eat(parser, "lt") {
83 return Ok(parameters)
84 }
85 let mut index = 0
86 while true {
87 let name = identifier(parser, "a type parameter")?
88 parameters.push(identNode(name, field, index))
89 index += 1
90 if !eat(parser, "comma") {
91 break
92 }
93 }
94 expectCloseAngle(parser)?
95 Ok(parameters)
98function parseFunctionTypeParameters(parser: Parser) -> Result<Array<SyntaxNode>, string> {
99 let mut parameters: Array<SyntaxNode> = []
100 let mut bounds: Array<SyntaxNode> = []
101 if !eat(parser, "lt") {
102 return Ok(parameters)
103 }
104 let mut parameterIndex = 0
105 while true {
106 let name = identifier(parser, "a type parameter")?
107 parameters.push(identNode(name, "typeParameters", parameterIndex))
108 if eat(parser, "colon") {
109 let mut boundIndex = 0
110 while true {
111 let bound = identifier(parser, "a protocol bound")?
112 bounds.push(identNode(
113 bound,
114 "typeParameterBounds",
115 parameterIndex * TYPE_BOUND_INDEX_STRIDE + boundIndex,
116 ))
117 boundIndex += 1
118 if !eat(parser, "plus") {
119 break
120 }
121 }
122 }
123 parameterIndex += 1
124 if !eat(parser, "comma") {
125 break
126 }
127 }
128 expectCloseAngle(parser)?
129 for bound in bounds {
130 parameters.push(bound)
131 }
132 Ok(parameters)
135function parseFunction(service: ParserService,
136parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
137 let keyword = expect(parser, "keyword/function", "`function`")?
138 let name = identifier(parser, "a function name")?
139 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
140 for parameter in parseFunctionTypeParameters(parser)? {
141 children.push(parameter)
142 }
143 expect(parser, "left-paren", "`(`")?
144 let mut parameterIndex = 0
145 while !at(parser, "right-paren") && !at(parser, "eof") {
146 let parameterLo = current(parser).lo
147 let variadic = eat(parser, "ellipsis")
148 let parameterName = identifier(parser, "a parameter name")?
149 rejectReservedBinding(parser, parameterName)
150 let parameterType = if parameterIndex == 0 && !variadic &&
151 text(parser, parameterName.lo, parameterName.hi) == "self" &&
152 !at(parser, "colon") {
153 namedType(parameterName, "type", 0)
154 } else {
155 expect(parser, "colon", "`:`")?
156 parseType(service, parser, "type", 0)?
157 }
158 let mut parameterChildren: Array<SyntaxNode> = [
159 identNode(parameterName, "name", 0),
160 parameterType,
161 ]
162 if eat(parser, "eq") {
163 parameterChildren.push(parseExpression(service, parser, "default", 0)?)
164 }
165 children.push(node(
166 "parameter",
167 parameterLo,
168 boxValue(parser.lastHi),
169 "parameters",
170 parameterIndex,
171 [boolAttribute("variadic", variadic)],
172 parameterChildren,
173 ))
174 parameterIndex += 1
175 if !eat(parser, "comma") {
176 break
177 }
178 }
179 expect(parser, "right-paren", "`)`")?
180 if eat(parser, "thin-arrow") {
181 children.push(parseType(service, parser, "returnType", 0)?)
182 }
183 let body = parseBlock(service, parser, "body", 0)?
184 let hi = body.hi
185 children.push(body)
186 let declaration = node(
187 "function-declaration",
188 name.lo,
189 hi,
190 "declaration",
191 0,
192 [],
193 children,
194 )
195 Ok(node(
196 "statement/function",
197 keyword.lo,
198 hi,
199 field,
200 index,
201 [],
202 [declaration],
203 ))
206function parseTypeAlias(service: ParserService,
207parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
208 let keyword = expect(parser, "keyword/type", "`type`")?
209 let name = identifier(parser, "a type name")?
210 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
211 for parameter in parseTypeParameters(parser, "typeParameters")? {
212 children.push(parameter)
213 }
214 expect(parser, "eq", "`=`")?
215 let typeNode = parseType(service, parser, "type", 0)?
216 let hi = typeNode.hi
217 children.push(typeNode)
218 Ok(node(
219 "statement/type-alias",
220 keyword.lo,
221 hi,
222 field,
223 index,
224 [],
225 children,
226 ))
229function parseDerives(parser: Parser) -> Result<Array<SyntaxNode>, string> {
230 let mut derives: Array<SyntaxNode> = []
231 if !at(parser, "identifier") || text(parser, current(parser).lo, current(parser).hi) != "derives" {
232 return Ok(derives)
233 }
234 bump(parser)
235 let mut index = 0
236 while true {
237 derives.push(identNode(identifier(parser, "a protocol name to derive")?, "derives", index))
238 index += 1
239 if !eat(parser, "comma") {
240 break
241 }
242 }
243 Ok(derives)
246function contextualHeadAt(parser: Parser, offset: int, word: string) -> bool {
247 let head = tokenAt(parser, offset)
248 head.kind == "identifier" && text(parser, head.lo, head.hi) == word &&
249 tokenAt(parser, offset + 1).kind == "identifier"
252function contextualHead(parser: Parser, word: string) -> bool {
253 contextualHeadAt(parser, 0, word)
256function contextualHeadWithFollowAt(
257 parser: Parser,
258 offset: int,
259 word: string,
260 firstFollow: string,
261 secondFollow: string,
262) -> bool {
263 contextualHeadAt(parser, offset, word) &&
264 (tokenAt(parser, offset + 2).kind == firstFollow ||
265 tokenAt(parser, offset + 2).kind == secondFollow)
268function contextualHeadWithFollow(
269 parser: Parser,
270 word: string,
271 firstFollow: string,
272 secondFollow: string,
273) -> bool {
274 contextualHeadWithFollowAt(parser, 0, word, firstFollow, secondFollow)
277function derivableDeclarationHeadAt(parser: Parser, offset: int, word: string) -> bool {
278 if !contextualHeadAt(parser, offset, word) {
279 return false
280 }
281 let follow = tokenAt(parser, offset + 2)
282 follow.kind == "left-brace" || follow.kind == "lt" ||
283 (follow.kind == "identifier" && text(parser, follow.lo, follow.hi) == "derives")
286function derivableDeclarationHead(parser: Parser, word: string) -> bool {
287 derivableDeclarationHeadAt(parser, 0, word)
290function parseEnum(service: ParserService,
291parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
292 let head = identifier(parser, "`enum`")?
293 let name = identifier(parser, "an enum name")?
294 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
295 for parameter in parseTypeParameters(parser, "typeParameters")? {
296 children.push(parameter)
297 }
298 let derives = parseDerives(parser)?
299 expectLeftBrace(parser)?
300 let mut variantIndex = 0
301 while !at(parser, "right-brace") && !at(parser, "eof") {
302 let variant = identifier(parser, "a variant name")?
303 let mut variantChildren: Array<SyntaxNode> = [identNode(variant, "name", 0)]
304 if eat(parser, "left-paren") {
305 let mut payloadIndex = 0
306 while true {
307 variantChildren.push(parseType(
308 service,
310 parser,
311 "payload",
312 payloadIndex,
313 )?)
314 payloadIndex += 1
315 if !eat(parser, "comma") {
316 break
317 }
318 }
319 expect(parser, "right-paren", "`)`")?
320 }
321 children.push(node(
322 "enum-variant",
323 variant.lo,
324 variant.hi,
325 "variants",
326 variantIndex,
327 [],
328 variantChildren,
329 ))
330 variantIndex += 1
331 if !eat(parser, "comma") {
332 break
333 }
334 }
335 let close = expectRightBrace(parser)?
336 for derived in derives {
337 children.push(derived)
338 }
339 Ok(node(
340 "statement/enum",
341 head.lo,
342 close.hi,
343 field,
344 index,
345 [],
346 children,
347 ))
350function parseRecord(service: ParserService,
351parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
352 let head = identifier(parser, "`record`")?
353 let name = identifier(parser, "a record name")?
354 let recordName = text(parser, name.lo, name.hi)
355 if recordName == "map" || recordName == "set" {
356 addDiagnostic(
357 parser,
358 "TPZ2012",
359 "`{recordName}` is reserved for the `{recordName} \{ … \}` collection literal (§6) and cannot be a record name",
360 name.lo,
361 name.hi,
362 )
363 }
364 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
365 for parameter in parseTypeParameters(parser, "typeParameters")? {
366 children.push(parameter)
367 }
368 let derives = parseDerives(parser)?
369 expectLeftBrace(parser)?
370 let mut fieldIndex = 0
371 while !at(parser, "right-brace") && !at(parser, "eof") {
372 let fieldLo = current(parser).lo
373 let fieldNameToken = identifier(parser, "a field name")?
374 expect(parser, "colon", "`:`")?
375 let typeNode = parseType(service, parser, "type", 0)?
376 let mut fieldChildren: Array<SyntaxNode> = [
377 identNode(fieldNameToken, "name", 0),
378 typeNode,
379 ]
380 if eat(parser, "eq") {
381 fieldChildren.push(parseExpression(service, parser, "default", 0)?)
382 }
383 children.push(node(
384 "record-field-declaration",
385 fieldLo,
386 boxValue(parser.lastHi),
387 "fields",
388 fieldIndex,
389 [],
390 fieldChildren,
391 ))
392 fieldIndex += 1
393 if !eat(parser, "comma") {
394 break
395 }
396 }
397 let close = expectRightBrace(parser)?
398 for derived in derives {
399 children.push(derived)
400 }
401 Ok(node(
402 "statement/record",
403 head.lo,
404 close.hi,
405 field,
406 index,
407 [],
408 children,
409 ))
412function parseNewtype(service: ParserService,
413parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
414 let head = identifier(parser, "`newtype`")?
415 let name = identifier(parser, "a newtype name")?
416 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
417 for parameter in parseTypeParameters(parser, "typeParameters")? {
418 children.push(parameter)
419 }
420 expect(parser, "eq", "`=`")?
421 let base = parseType(service, parser, "base", 0)?
422 let hi = base.hi
423 children.push(base)
424 Ok(node(
425 "statement/newtype",
426 head.lo,
427 hi,
428 field,
429 index,
430 [],
431 children,
432 ))
435function parseImpl(service: ParserService,
436parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
437 let head = identifier(parser, "`impl`")?
438 let name = identifier(parser, "a type name")?
439 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
440 if eat(parser, "lt") {
441 children.push(identNode(identifier(parser, "a conforming type name")?, "target", 0))
442 expectCloseAngle(parser)?
443 }
444 expectLeftBrace(parser)?
445 skipSeparators(parser)
446 let mut methodIndex = 0
447 while !at(parser, "right-brace") && !at(parser, "eof") {
448 let methodLo = current(parser).lo
449 let exported = at(parser, "identifier") &&
450 text(parser, current(parser).lo, current(parser).hi) == "export"
451 if exported {
452 bump(parser)
453 }
454 if !at(parser, "keyword/function") {
455 fail(parser, "an impl body contains only `function` methods")?
456 }
457 let statement = parseFunction(service, parser, "unused", 0)?
458 let declaration = match statement.children.get(0) {
459 case Some(value) => attach(value, "declaration", 0)
460 case None => return Err("function declaration projection is missing")
461 }
462 children.push(node(
463 "impl-method",
464 methodLo,
465 statement.hi,
466 "methods",
467 methodIndex,
468 [boolAttribute("exported", exported)],
469 [declaration],
470 ))
471 methodIndex += 1
472 skipSeparators(parser)
473 }
474 let close = expectRightBrace(parser)?
475 Ok(node(
476 "statement/impl",
477 head.lo,
478 close.hi,
479 field,
480 index,
481 [],
482 children,
483 ))
486function parseProtocolMethod(service: ParserService,
487parser: Parser, index: int) -> Result<SyntaxNode, string> {
488 expect(parser, "keyword/function", "`function`")?
489 let name = identifier(parser, "a function name")?
490 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
491 for parameter in parseFunctionTypeParameters(parser)? {
492 children.push(parameter)
493 }
494 expect(parser, "left-paren", "`(`")?
495 let mut parameterIndex = 0
496 while !at(parser, "right-paren") && !at(parser, "eof") {
497 let parameterLo = current(parser).lo
498 let variadic = eat(parser, "ellipsis")
499 let parameterName = identifier(parser, "a parameter name")?
500 rejectReservedBinding(parser, parameterName)
501 expect(parser, "colon", "`:`")?
502 let parameterType = parseType(service, parser, "type", 0)?
503 let mut parameterChildren: Array<SyntaxNode> = [
504 identNode(parameterName, "name", 0),
505 parameterType,
506 ]
507 if eat(parser, "eq") {
508 parameterChildren.push(parseExpression(service, parser, "default", 0)?)
509 }
510 children.push(node(
511 "parameter",
512 parameterLo,
513 boxValue(parser.lastHi),
514 "parameters",
515 parameterIndex,
516 [boolAttribute("variadic", variadic)],
517 parameterChildren,
518 ))
519 parameterIndex += 1
520 if !eat(parser, "comma") {
521 break
522 }
523 }
524 expect(parser, "right-paren", "`)`")?
525 if eat(parser, "thin-arrow") {
526 children.push(parseType(service, parser, "returnType", 0)?)
527 }
528 let bodyToken = current(parser)
529 children.push(node(
530 "block",
531 bodyToken.lo,
532 bodyToken.hi,
533 "body",
534 0,
535 [],
536 [],
537 ))
538 Ok(node(
539 "function-declaration",
540 name.lo,
541 bodyToken.hi,
542 "methods",
543 index,
544 [],
545 children,
546 ))
549function parseProtocol(service: ParserService,
550parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
551 let head = identifier(parser, "`protocol`")?
552 let name = identifier(parser, "a protocol name")?
553 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
554 for parameter in parseTypeParameters(parser, "typeParameters")? {
555 children.push(parameter)
556 }
557 expectLeftBrace(parser)?
558 skipSeparators(parser)
559 let mut methodIndex = 0
560 while !at(parser, "right-brace") && !at(parser, "eof") {
561 if !at(parser, "keyword/function") {
562 fail(parser, "a protocol body contains only `function` signatures")?
563 }
564 children.push(parseProtocolMethod(service, parser, methodIndex)?)
565 methodIndex += 1
566 skipSeparators(parser)
567 }
568 let close = expectRightBrace(parser)?
569 Ok(node(
570 "statement/protocol",
571 head.lo,
572 close.hi,
573 field,
574 index,
575 [],
576 children,
577 ))
580function parseUsing(service: ParserService,
581parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
582 let head = identifier(parser, "`using`")?
583 let name = identifier(parser, "a resource binding name")?
584 rejectReservedBinding(parser, name)
585 expect(parser, "eq", "`=`")?
586 let value = parseExpressionBeforeBlock(service, parser, "value", 0)?
587 let body = parseBlock(service, parser, "body", 0)?
588 Ok(node(
589 "statement/using",
590 head.lo,
591 body.hi,
592 field,
593 index,
594 [],
595 [identNode(name, "name", 0), value, body],
596 ))
599function parseLet(service: ParserService,
600parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
601 let keyword = expect(parser, "keyword/let", "`let`")?
602 let mutable = eat(parser, "keyword/mut")
603 let pattern = if mutable {
604 let name = identifier(parser, "a binding name")?
605 rejectReservedBinding(parser, name)
606 bindingPattern(name, "pattern", 0)
607 } else {
608 parsePattern(service, parser, "pattern", 0)?
609 }
610 let mut children: Array<SyntaxNode> = [pattern]
611 if eat(parser, "colon") {
612 children.push(parseType(service, parser, "type", 0)?)
613 }
614 if !mutable && at(parser, "keyword/mut") {
615 fail(parser, "`mut` comes right after `let` — write `let mut <name> = …`")?
616 }
617 expect(parser, "eq", "`=`")?
618 children.push(parseExpression(service, parser, "value", 0)?)
619 Ok(node(
620 "statement/let",
621 keyword.lo,
622 boxValue(parser.lastHi),
623 field,
624 index,
625 [boolAttribute("mutable", mutable)],
626 children,
627 ))
630function parseConst(service: ParserService,
631parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
632 let keyword = expect(parser, "keyword/const", "`const`")?
633 let name = identifier(parser, "a constant name")?
634 rejectReservedBinding(parser, name)
635 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
636 if eat(parser, "colon") {
637 children.push(parseType(service, parser, "type", 0)?)
638 }
639 expect(parser, "eq", "`=`")?
640 children.push(parseExpression(service, parser, "value", 0)?)
641 Ok(node(
642 "statement/const",
643 keyword.lo,
644 boxValue(parser.lastHi),
645 field,
646 index,
647 [],
648 children,
649 ))
652function parseReturnStatement(
653 service: ParserService,
654 parser: Parser,
655 field: string,
656 index: int,
657) -> Result<SyntaxNode, string> {
658 let keyword = bump(parser)
659 let mut children: Array<SyntaxNode> = []
660 if !at(parser, "separator") && !at(parser, "right-brace") &&
661 !at(parser, "eof") {
662 children.push(parseExpression(service, parser, "value", 0)?)
663 }
664 Ok(node(
665 "statement/return",
666 keyword.lo,
667 boxValue(parser.lastHi),
668 field,
669 index,
670 [],
671 children,
672 ))
675function parseLoopExitStatement(
676 service: ParserService,
677 parser: Parser,
678 field: string,
679 index: int,
680) -> Result<SyntaxNode, string> {
681 let kind = current(parser).kind
682 let keyword = bump(parser)
683 let mut children: Array<SyntaxNode> = []
684 if at(parser, "label") {
685 children.push(labelNode(bump(parser), "label", 0))
686 }
687 if kind == "keyword/break" && !at(parser, "separator") &&
688 !at(parser, "right-brace") && !at(parser, "eof") {
689 children.push(parseExpression(service, parser, "value", 0)?)
690 }
691 Ok(node(
692 if kind == "keyword/break" {
693 "statement/break"
694 } else {
695 "statement/continue"
696 },
697 keyword.lo,
698 boxValue(parser.lastHi),
699 field,
700 index,
701 [],
702 children,
703 ))
706function whileLetNode(
707 keyword: PreviewToken,
708 pattern: SyntaxNode,
709 scrutinee: SyntaxNode,
710 sourceBody: SyntaxNode,
711 field: string,
712 index: int,
713) -> SyntaxNode {
714 let hi = sourceBody.hi
715 let lo = keyword.lo
716 let bodyExpression = blockExpression(sourceBody, "body", 0)
717 let firstCase = node(
718 "match-case",
719 lo,
720 hi,
721 "cases",
722 0,
723 [],
724 [pattern, bodyExpression],
725 )
726 let wildcard = node("pattern/wildcard", lo, hi, "pattern", 0, [], [])
727 let syntheticBreak = node(
728 "statement/break",
729 lo,
730 hi,
731 "statements",
732 0,
733 [],
734 [],
735 )
736 let syntheticBlock = node(
737 "block",
738 lo,
739 hi,
740 "block",
741 0,
742 [],
743 [syntheticBreak],
744 )
745 let breakExpression = node(
746 "expression/block",
747 lo,
748 hi,
749 "body",
750 0,
751 [],
752 [syntheticBlock],
753 )
754 let secondCase = node(
755 "match-case",
756 lo,
757 hi,
758 "cases",
759 1,
760 [],
761 [wildcard, breakExpression],
762 )
763 let matchExpression = node(
764 "expression/match",
765 lo,
766 hi,
767 "tail",
768 0,
769 [],
770 [scrutinee, firstCase, secondCase],
771 )
772 let body = node("block", lo, hi, "body", 0, [], [matchExpression])
773 let condition = node(
774 "expression/boolean",
775 lo,
776 hi,
777 "condition",
778 0,
779 [boolAttribute("value", true)],
780 [],
781 )
782 node("statement/while", lo, hi, field, index, [], [condition, body])
785function parseWhileStatement(
786 service: ParserService,
787 parser: Parser,
788 field: string,
789 index: int,
790) -> Result<SyntaxNode, string> {
791 let keyword = bump(parser)
792 if eat(parser, "keyword/let") {
793 let pattern = parsePattern(service, parser, "pattern", 0)?
794 expect(parser, "eq", "`=`")?
795 let scrutinee = parseExpressionBeforeBlock(service, parser, "scrutinee", 0)?
796 let body = parseBlock(service, parser, "block", 0)?
797 return Ok(whileLetNode(keyword, pattern, scrutinee, body, field, index))
798 }
799 let condition = parseExpressionBeforeBlock(service, parser, "condition", 0)?
800 let body = parseBlock(service, parser, "body", 0)?
801 Ok(node(
802 "statement/while",
803 keyword.lo,
804 body.hi,
805 field,
806 index,
807 [],
808 [condition, body],
809 ))
812function parseDeferStatement(
813 service: ParserService,
814 parser: Parser,
815 field: string,
816 index: int,
817) -> Result<SyntaxNode, string> {
818 let keyword = bump(parser)
819 let value = parseExpression(service, parser, "value", 0)?
820 if value.kind != "expression/block" && value.kind != "expression/call" {
821 addDiagnostic(
822 parser,
823 "TPZ2004",
824 "`defer` takes a block or a call",
825 value.lo,
826 value.hi,
827 )
828 }
829 Ok(node(
830 "statement/defer",
831 keyword.lo,
832 value.hi,
833 field,
834 index,
835 [],
836 [value],
837 ))
840function assignmentOperator(kind: string) -> string {
841 match kind {
842 case "eq" => "assign"
843 case "plus-eq" => "add"
844 case "minus-eq" => "subtract"
845 case "star-eq" => "multiply"
846 case "slash-eq" => "divide"
847 case "percent-eq" => "remainder"
848 case _ => "coalesce"
849 }
852function parseExpressionStatement(
853 service: ParserService,
854 parser: Parser,
855 field: string,
856 index: int,
857) -> Result<SyntaxNode, string> {
858 let expression = parseExpression(service, parser, "value", 0)?
859 let assignmentKind = current(parser).kind
860 if assignmentKind != "eq" && assignmentKind != "plus-eq" &&
861 assignmentKind != "minus-eq" && assignmentKind != "star-eq" &&
862 assignmentKind != "slash-eq" && assignmentKind != "percent-eq" &&
863 assignmentKind != "question-question-eq" {
864 return Ok(node(
865 "statement/expression",
866 expression.lo,
867 expression.hi,
868 field,
869 index,
870 [],
871 [expression],
872 ))
873 }
874 if expression.kind != "expression/identifier" &&
875 expression.kind != "expression/member" &&
876 expression.kind != "expression/index" {
877 addDiagnostic(
878 parser,
879 "TPZ2003",
880 "assignment target must be an identifier, member access, or index access",
881 expression.lo,
882 expression.hi,
883 )
884 }
885 bump(parser)
886 let value = parseExpression(service, parser, "value", 0)?
887 Ok(node(
888 "statement/assign",
889 expression.lo,
890 value.hi,
891 field,
892 index,
893 [stringAttribute("operator", assignmentOperator(assignmentKind))],
894 [attach(expression, "target", 0), value],
895 ))
898function parseStatement(service: ParserService,
899parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
900 let kind = current(parser).kind
901 if kind == "keyword/function" { return parseFunction(service, parser, field, index) }
902 if kind == "keyword/let" { return parseLet(service, parser, field, index) }
903 if kind == "keyword/mut" {
904 fail(parser, "`mut` comes right after `let` — write `let mut <name> = …`")?
905 }
906 if kind == "keyword/type" { return parseTypeAlias(service, parser, field, index) }
907 if derivableDeclarationHead(parser, "enum") { return parseEnum(service, parser, field, index) }
908 if derivableDeclarationHead(parser, "record") { return parseRecord(service, parser, field, index) }
909 if contextualHeadWithFollow(parser, "newtype", "eq", "lt") {
910 return parseNewtype(service, parser, field, index)
911 }
912 if contextualHeadWithFollow(parser, "impl", "left-brace", "lt") {
913 return parseImpl(service, parser, field, index)
914 }
915 if contextualHeadWithFollow(parser, "protocol", "left-brace", "lt") {
916 return parseProtocol(service, parser, field, index)
917 }
918 if contextualHead(parser, "using") && tokenAt(parser, 2).kind == "eq" {
919 return parseUsing(service, parser, field, index)
920 }
921 if kind == "keyword/const" { return parseConst(service, parser, field, index) }
922 if kind == "keyword/return" {
923 return parseReturnStatement(service, parser, field, index)
924 }
925 if kind == "keyword/break" || kind == "keyword/continue" {
926 return parseLoopExitStatement(service, parser, field, index)
927 }
928 if kind == "keyword/while" {
929 return parseWhileStatement(service, parser, field, index)
930 }
931 if kind == "keyword/defer" {
932 return parseDeferStatement(service, parser, field, index)
933 }
934 parseExpressionStatement(service, parser, field, index)
937function parseBlockBody(
938 service: ParserService,
939 parser: Parser,
940 open: PreviewToken,
941 field: string,
942 index: int,
943) -> Result<SyntaxNode, string> {
944 let mut statements: Array<SyntaxNode> = []
945 let mut tail: Option<SyntaxNode> = None
946 let mut statementIndex = 0
947 skipSeparators(parser)
948 while !at(parser, "right-brace") && !at(parser, "eof") {
949 let before = boxValue(parser.position)
950 match parseStatement(service, parser, "statements", statementIndex) {
951 case Ok(statement) => {
952 if at(parser, "right-brace") && statement.kind == "statement/expression" {
953 tail = statement.children.get(0)
954 break
955 }
956 statements.push(statement)
957 statementIndex += 1
958 itemBoundary(parser)
959 }
960 case Err(_) => synchronize(parser)
961 }
962 if boxValue(parser.position) == before &&
963 !at(parser, "right-brace") && !at(parser, "eof") {
964 addDiagnostic(
965 parser,
966 "TPZ2001",
967 "expected a statement",
968 current(parser).lo,
969 current(parser).hi,
970 )
971 bump(parser)
972 }
973 skipSeparators(parser)
974 }
975 let close = expectRightBrace(parser)?
976 let mut children = statements
977 match tail {
978 case Some(value) => children.push(attach(value, "tail", 0))
979 case None => ()
980 }
981 Ok(node("block", open.lo, close.hi, field, index, [], children))
984export function parseBlock(
985 service: ParserService,
986 parser: Parser,
987 field: string,
988 index: int,
989) -> Result<SyntaxNode, string> {
990 let open = expectLeftBrace(parser)?
991 let previousLambda = lambdaAllowed(parser)
992 let previousRecordUpdate = recordUpdateAllowed(parser)
993 setLambdaAllowed(parser, true)
994 setRecordUpdateAllowed(parser, true)
995 let result = parseBlockBody(service, parser, open, field, index)
996 setLambdaAllowed(parser, previousLambda)
997 setRecordUpdateAllowed(parser, previousRecordUpdate)
998 result
1001function isContextualWord(parser: Parser, word: string) -> bool {
1002 at(parser, "identifier") && text(parser, current(parser).lo, current(parser).hi) == word
1005record ParsedImportSpec {
1006 node: SyntaxNode,
1007 sourceName: string,
1008 sourceToken: PreviewToken,
1009 boundName: string,
1010 boundToken: PreviewToken,
1013function parseModulePath(parser: Parser) -> Result<SyntaxNode, string> {
1014 let first = identifier(parser, "a module path segment")?
1015 let mut pathChildren: Array<SyntaxNode> = [identNode(first, "segments", 0)]
1016 let mut pathIndex = 1
1017 let mut pathHi = first.hi
1018 while eat(parser, "dot") {
1019 let segment = identifier(parser, "a module path segment")?
1020 pathChildren.push(identNode(segment, "segments", pathIndex))
1021 pathIndex += 1
1022 pathHi = segment.hi
1024 Ok(node(
1025 "module-path",
1026 first.lo,
1027 pathHi,
1028 "path",
1029 0,
1030 [],
1031 pathChildren,
1032 ))
1035function parseImportSpec(
1036 parser: Parser,
1037 index: int,
1038) -> Result<ParsedImportSpec, string> {
1039 if current(parser).kind.startsWith("keyword/") {
1040 let token = current(parser)
1041 addDiagnostic(
1042 parser,
1043 "TPZ2011",
1044 "an import name is an identifier; keywords cannot be selected",
1045 token.lo,
1046 token.hi,
1048 return Err("an import name is an identifier")
1050 let name = identifier(parser, "an import name")?
1051 let mut children: Array<SyntaxNode> = [identNode(name, "name", 0)]
1052 let mut hi = name.hi
1053 let sourceName = text(parser, name.lo, name.hi)
1054 let mut boundName = sourceName
1055 let mut boundToken = name
1056 if isContextualWord(parser, "as") {
1057 bump(parser)
1058 let alias = identifier(parser, "an import alias")?
1059 hi = alias.hi
1060 boundName = text(parser, alias.lo, alias.hi)
1061 boundToken = alias
1062 children.push(identNode(alias, "alias", 0))
1064 Ok(ParsedImportSpec {
1065 node: node("import-spec", name.lo, hi, "specs", index, [], children),
1066 sourceName: sourceName,
1067 sourceToken: name,
1068 boundName: boundName,
1069 boundToken: boundToken,
1070 })
1073function diagnoseDuplicateImportSpecs(
1074 parser: Parser,
1075 specs: Array<ParsedImportSpec>,
1076) -> () {
1077 // Diagnose each later offending spec once in source order, with
1078 // source-name precedence when both duplicate axes apply.
1079 let mut sourceNames: Set<string> = set {}
1080 let mut boundNames: Set<string> = set {}
1081 for spec in specs {
1082 let sourceDuplicate = sourceNames.contains(spec.sourceName)
1083 let boundDuplicate = boundNames.contains(spec.boundName)
1084 sourceNames.add(spec.sourceName)
1085 boundNames.add(spec.boundName)
1086 if sourceDuplicate {
1087 addDiagnostic(
1088 parser,
1089 "TPZ2011",
1090 "this exported name is already selected in this list",
1091 spec.sourceToken.lo,
1092 spec.sourceToken.hi,
1094 } else if boundDuplicate {
1095 addDiagnostic(
1096 parser,
1097 "TPZ2011",
1098 "this local name is already bound by this list",
1099 spec.boundToken.lo,
1100 spec.boundToken.hi,
1104 ()
1107function parseImportSelection(parser: Parser) -> Result<Array<SyntaxNode>, string> {
1108 let open = expectLeftBrace(parser)?
1109 let mut parsedSpecs: Array<ParsedImportSpec> = []
1110 while !at(parser, "right-brace") && !at(parser, "eof") {
1111 parsedSpecs.push(parseImportSpec(parser, parsedSpecs.length)?)
1112 if !eat(parser, "comma") {
1113 break
1116 let close = expectRightBrace(parser)?
1117 if parsedSpecs.length == 0 {
1118 addDiagnostic(
1119 parser,
1120 "TPZ2011",
1121 "a selection list selects at least one exported name",
1122 open.lo,
1123 close.hi,
1126 diagnoseDuplicateImportSpecs(parser, parsedSpecs)
1127 let mut specs: Array<SyntaxNode> = []
1128 for spec in parsedSpecs {
1129 specs.push(spec.node)
1131 Ok(specs)
1134function parseImportAlias(parser: Parser) -> Result<SyntaxNode, string> {
1135 bump(parser)
1136 let alias = identNode(identifier(parser, "an import alias")?, "alias", 0)
1137 if at(parser, "left-brace") {
1138 let brace = current(parser)
1139 addDiagnostic(
1140 parser,
1141 "TPZ2009",
1142 "a namespace alias and a selection list do not compose (`import m as ns \{ x \}` is invalid syntax)",
1143 brace.lo,
1144 brace.hi,
1146 skipBalancedBraces(parser)
1148 Ok(alias)
1151function parseImport(parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
1152 let head = identifier(parser, "`import`")?
1153 let path = parseModulePath(parser)?
1154 let mut importChildren: Array<SyntaxNode> = [path]
1155 if at(parser, "left-brace") {
1156 for spec in parseImportSelection(parser)? {
1157 importChildren.push(spec)
1159 } else if isContextualWord(parser, "as") {
1160 importChildren.push(parseImportAlias(parser)?)
1162 let hi = boxValue(parser.lastHi)
1163 let importItem = node(
1164 "import-item",
1165 head.lo,
1166 hi,
1167 "import",
1168 0,
1169 [],
1170 importChildren,
1172 Ok(node(
1173 "statement/import",
1174 head.lo,
1175 hi,
1176 field,
1177 index,
1178 [],
1179 [importItem],
1180 ))
1183function parseImportAtProgram(
1184 parser: Parser,
1185 field: string,
1186 index: int,
1187 prologueDone: bool,
1188) -> Result<SyntaxNode, string> {
1189 let statement = parseImport(parser, field, index)?
1190 if prologueDone {
1191 addDiagnostic(
1192 parser,
1193 "TPZ2010",
1194 "imports form a prologue: every `import` precedes all other top-level items",
1195 statement.lo,
1196 statement.hi,
1199 Ok(statement)
1202function parseExport(service: ParserService,
1203parser: Parser, field: string, index: int) -> Result<SyntaxNode, string> {
1204 let head = identifier(parser, "`export`")?
1205 let inner = parseStatement(service, parser, "item", 0)?
1206 if inner.kind == "statement/let" {
1207 match inner.children.get(0) {
1208 case Some(pattern) => {
1209 if pattern.kind != "pattern/binding" && pattern.kind != "pattern/typed" {
1210 addDiagnostic(
1211 parser,
1212 "TPZ2007",
1213 "an exported `let` binds exactly one identifier; destructure privately, then export the identifier",
1214 pattern.lo,
1215 pattern.hi,
1219 case None => ()
1222 Ok(node(
1223 "statement/export",
1224 head.lo,
1225 inner.hi,
1226 field,
1227 index,
1228 [],
1229 [inner],
1230 ))
1233function exportDeclarationHead(parser: Parser) -> bool {
1234 if !isContextualWord(parser, "export") {
1235 return false
1237 let follow = tokenAt(parser, 1)
1238 if follow.kind == "keyword/function" ||
1239 follow.kind == "keyword/type" ||
1240 follow.kind == "keyword/let" ||
1241 follow.kind == "keyword/const" {
1242 return true
1244 if follow.kind != "identifier" {
1245 return false
1247 let word = text(parser, follow.lo, follow.hi)
1248 if word == "enum" || word == "record" {
1249 return derivableDeclarationHeadAt(parser, 1, word)
1251 word == "newtype" && contextualHeadWithFollowAt(parser, 1, word, "eq", "lt")
1254function rejectStringModulePath(parser: Parser) -> Result<SyntaxNode, string> {
1255 let token = current(parser)
1256 addDiagnostic(
1257 parser,
1258 "TPZ2008",
1259 "string and template module paths are reserved and unused; module paths are dotted identifiers",
1260 token.lo,
1261 token.hi,
1263 rejectedStatement("reserved module path")
1266function rejectUseItem(parser: Parser) -> Result<SyntaxNode, string> {
1267 let token = current(parser)
1268 addDiagnostic(
1269 parser,
1270 "TPZ2008",
1271 "`use` is reserved and unused; did you mean `import`?",
1272 token.lo,
1273 token.hi,
1275 rejectedStatement("reserved use item")
1278function rejectExportList(parser: Parser) -> Result<SyntaxNode, string> {
1279 let token = current(parser)
1280 addDiagnostic(
1281 parser,
1282 "TPZ2009",
1283 "export lists are invalid syntax; put `export` on each public declaration",
1284 token.lo,
1285 token.hi,
1287 bump(parser)
1288 skipBalancedBraces(parser)
1289 rejectedStatement("rejected export list")
1292function rejectReexport(parser: Parser) -> Result<SyntaxNode, string> {
1293 let token = current(parser)
1294 addDiagnostic(
1295 parser,
1296 "TPZ2009",
1297 "re-export syntax does not exist (`export import ...` is rejected)",
1298 token.lo,
1299 token.hi,
1301 rejectedStatement("re-export is rejected")
1304function parseProgramItem(
1305 service: ParserService,
1306 parser: Parser,
1307 index: int,
1308 prologueDone: bool,
1309) -> Result<SyntaxNode, string> {
1310 if isContextualWord(parser, "import") && tokenAt(parser, 1).kind == "identifier" {
1311 return parseImportAtProgram(parser, "items", index, prologueDone)
1313 if isContextualWord(parser, "import") &&
1314 tokenAt(parser, 1).kind.startsWith("string-start/") {
1315 return rejectStringModulePath(parser)
1317 if isContextualWord(parser, "use") && tokenAt(parser, 1).kind == "identifier" {
1318 return rejectUseItem(parser)
1320 if isContextualWord(parser, "export") && tokenAt(parser, 1).kind == "left-brace" {
1321 return rejectExportList(parser)
1323 if isContextualWord(parser, "export") &&
1324 tokenAt(parser, 1).kind == "identifier" &&
1325 text(parser, tokenAt(parser, 1).lo, tokenAt(parser, 1).hi) == "import" {
1326 return rejectReexport(parser)
1328 if exportDeclarationHead(parser) {
1329 parseExport(service, parser, "items", index)
1330 } else {
1331 parseStatement(service, parser, "items", index)
1335export function parseProgram(service: ParserService,
1336parser: Parser, sourceLength: int) -> SyntaxNode {
1337 let mut items: Array<SyntaxNode> = []
1338 let mut index = 0
1339 let mut prologueDone = false
1340 skipSeparators(parser)
1341 while !at(parser, "eof") {
1342 let before = boxValue(parser.position)
1343 match parseProgramItem(service, parser, index, prologueDone) {
1344 case Ok(statement) => {
1345 if statement.kind != "statement/import" {
1346 prologueDone = true
1348 items.push(statement)
1349 index += 1
1350 itemBoundary(parser)
1352 case Err(_) => synchronize(parser)
1354 if boxValue(parser.position) == before && !at(parser, "eof") {
1355 addDiagnostic(
1356 parser,
1357 "TPZ2001",
1358 "expected a statement",
1359 current(parser).lo,
1360 current(parser).hi,
1362 bump(parser)
1364 skipSeparators(parser)
1366 node("program", 0, sourceLength, "root", 0, [], items)

SHA256 4368280c4461c3d81a2d0b734372dd054ce75ef243ba87b61a9c8200d4246887