@@ -26,7 +26,9 @@
2626:: likely reading and are listed, with the doc's words, for the doc's
2727:: author to settle. The golden corpus's "expect:" lines give each
2828:: error's position. The layout pass's errors sit there, except where
29−:: the parser finds an earlier error first, as in `++ 2nd 5` (2.0, 2.8).
29+:: the parser finds an earlier error first, as in `++ 2nd 5`, or moves
30+:: one back to the start of its text, as in `++ x @sd` (2.0, 2.8, and
31+:: section 3, Errors).
3032::
3133:: ===================================================================
3234:: 1. Positions
@@ -52,7 +54,12 @@
5254:: only, and milestone 1's errors use starts only, so ends are first
5355:: used by milestone 2's excerpts. Until then +check-spans tests the two
5456:: rules above on every tree +golden prints, and a tree that breaks one
55−:: ends with a line "SPAN ERROR: (<kind> <start> to <end>) <why>".
57+:: ends with a line "SPAN ERROR: (<kind> <start> to <end>) <why>". It
58+:: finds each node's end from the tokens alone, matching each opener
59+:: with its closer on the line, so a node that stops at a child where
60+:: its closer follows fails it, and +check-spans-test plants such
61+:: wrong ends to show that it does (tools/hoon check-spans-test prints
62+:: the empty list, <<>>, when it passes).
5663::
5764:: ===================================================================
5865:: 2. The layout pass (+layout)
@@ -62,17 +69,22 @@
6269:: crosses a line break, and only layout tokens join lines.
6370::
6471:: 2.0 Errors. +layout never fails. Where the text breaks a rule of this
65−:: section, it emits one error token, [%error msg], at the first
66−:: character that breaks it, and stops reading. The parser accepts no
67−:: error token, so it reports whichever comes first, its own error or
68−:: this one (section 3, Errors). Every error, from either stage, points
69−:: at the first character where the text stops being the start of any
70−:: valid module: everything before it could still be right. Hoon's
71−:: parser reports errors the same way, and the golden corpus's expect
72−:: lines assume it. It also puts `++ x ]` on line 1 before a bad string
73−:: on line 9, which a lexer that failed first would report instead. The
74−:: positions below follow from it. Messages quote code in backticks, as
75−:: the parser's do (section 3, Errors).
72+:: section, it emits one error token, [%error msg from c], at the first
73+:: character that breaks it, and stops reading. from is where the text
74+:: it was reading began, c is that text's first character, and the
75+:: token is tight when that text follows the previous token with no
76+:: space. The parser accepts no error token, so it reports whichever
77+:: comes first, its own error or this one (section 3, Errors). Every
78+:: error, from either stage, points at the first character where the
79+:: text stops being the start of any valid module: everything before
80+:: it could still be right. Hoon's parser reports errors the same way,
81+:: and the golden corpus's expect lines assume it. It also puts `++ x
82+:: ]` on line 1 before a bad string on line 9, which a lexer that
83+:: failed first would report instead. The positions below follow from
84+:: it, for text that could begin a token where it stands; where the
85+:: parser's place can't begin with c at all, the parser moves the
86+:: error back to from, as `++ x @sd` at the @ (section 3, Errors).
87+:: Messages quote code in backticks, as the parser's do.
7688::
7789:: 2.1 Lines. The text is split at every \0a. A final \0a ends the last
7890:: line rather than starting an empty one. Lines are numbered from 1.
@@ -164,7 +176,8 @@
164176:: $?( $? $-( glyphs; $- followed by anything but ( is an error
165177:: at 3rd, "`$-` has only the wide form `$-(sample
166178:: product)`"
167−:: ^- ?- !! ? glyphs (? alone is the loobean mold)
179+:: ^- ?- !! ? glyphs (? alone is the loobean mold; ? then a
180+:: character of Hoon's other ? runes is left out, below)
168181:: @ aura: @, then [a-z]*, then at most one [A-Z]; the
169182:: token holds the text after @. An aura starting @s or
170183:: @r is an error at 2nd: "signed and floating-point
@@ -186,8 +199,8 @@
186199:: an error at 2nd, "`|` begins `|=`, `|=(` or `|$`",
187200:: "`$` begins `$?`, `$?(` or `$-(`", "`^` begins `^-`"
188201:: : followed by anything but :, an error at 2nd: the
189−:: table's :~ :* and a:b, else "a comment starts with
190−:: `::`"
202+:: table's :~ :* :- :+ :^ :_ and a:b, else "a comment
203+:: starts with `::`"
191204:: anything else an error at it, naming it: "unexpected `,`", with a
192205:: hint where one helps (+unexpected): for , . - and <,
193206:: what Jibb writes instead
@@ -195,32 +208,46 @@
195208:: Hoon forms the doc leaves out are errors with the doc's reason, as
196209:: "`|%` is left out: modules are records". Each points where the text
197210:: stops being Jibb: at its second character when its first can begin
198−:: Jibb there, else at its first.
211+:: some Jibb token, else at its first. Where the parser's place can't
212+:: begin with that first character, the parser moves the error to it
213+:: (2.0): `|%` at the top of a file fails at the |, `++ x |%` at the %.
214+:: The doc's list says "such as" of the tall forms and the wide ones,
215+:: so Hoon's runes of the same kinds get the same reason (doc
216+:: question):
199217::
200218:: |% |_ |* 2nd modules are records
201219:: |- 2nd gates recurse by name
202−:: $( 1st gates recurse by name; no expression starts $
220+:: $( 2nd gates recurse by name (at the $ where an
221+:: expression goes, as no expression starts $)
203222:: $% 2nd $? covers unions
204−:: ?+ ?: 2nd ?- is the branch (?:: is ? and a comment)
223+:: ?: ?+ 2nd ?- is the branch, and so for Hoon's other ?
224+:: runes, ?~ ?= ?. ?@ ?^ ?& ?| ?< ?> (?:: is ?
225+:: and a comment)
205226:: ?! 2nd eq and not are gates
206227:: .= 1st eq and not are gates
207228:: !x 2nd not is a gate: ! then anything but ! or >
208229:: !> /+ 2nd code also runs in the browser
209−:: =< => .* 1st names never shadow, and . reads imports too
230+:: =< => 2nd names never shadow, and . reads imports too
231+:: .* 1st the same
210232:: a:b 2nd of the :, right after a name: names never
211233:: shadow, and . reads imports too; write a.b
212234:: :~ :* 2nd indentation covers them; write ~[…] or […]
213−:: %: %= 2nd indentation covers them
214−:: == -- 1st the closers are left out: indentation covers
215−:: them
235+:: :- :+ :^ :_ 2nd indentation covers them; write a cell as [a b]
236+:: %: %- %+ 2nd indentation covers them; a call is (f a b)
237+:: %^ %~
238+:: %= 2nd indentation covers it; write a change, m(a=b)
239+:: == 2nd the closers are left out: indentation covers
240+:: -- 1st them
216241:: ~| 2nd ~& covers debugging
242+:: ;: 1st nest the calls, as (add a (add b c))
217243:: ; 1st Sail's ; runes are left out: layout is Jibb's
218244:: elements
219245:: ' 1st there is no '…' form: strings are "…"
220246::
221247:: The parser finds the doc's other left-out forms (section 3, Errors):
222−:: =(a b), =/, *mold, ^-(…) and ?-(…). The lexer can't, since =( =/ and *
223−:: begin valid Jibb too: open=(not open.s), scry=/todos, a * mold.
248+:: =(a b), =/, *mold, ^-(…), ?-(…) and ~&(…), and Hoon's =+ =? and =.
249+:: The lexer can't, since = and * begin valid Jibb too: open=(not
250+:: open.s), scry=/todos, a * mold.
224251::
225252:: 2.7 Paths. Right after a / or %/ glyph, a run of knot characters
226253:: [a-z0-9._~-] is one knot token, tight. So /posts/~zod is / knot / knot;
@@ -241,17 +268,38 @@
241268::
242269:: 2.8 Literals. The lexer takes a literal's run (2.6), then reads it
243270:: with Hoon's own parser, (nuck:so [[line col] run]), whose edge says
244−:: how much it read and how far it looked (p.edge):
271+:: how much it read and how far it looked (p.edge). Some runs never
272+:: reach it, since they begin an aura Jibb doesn't write, whatever
273+:: follows, or text Hoon's parser crashes on:
274+:: - 0b, 0c, 0i and 0w: an error at 2nd, "Jibb writes no @uw
275+:: literals" and so on. Hoon's parser would read 0b, or a 0c1 whose
276+:: checksum fails, as the number 0 and an error past the run.
277+:: - ~- (a @c), "Jibb writes no @c literals", and ~~ (a cord), "Jibb
278+:: writes no @t literals; strings are "…"", at 2nd. Hoon's reader of
279+:: @c crashes on a control character, as in ~-~1.
280+:: - ~0 and a base-32 digit, at 3rd: Hoon's parser reads a blob there
281+:: and cues it, which can run out of memory, past what mule catches.
282+:: No Jibb literal goes on so, since a year has no leading 0: after
283+:: a letter it is "Jibb writes no blob literals", after a digit the
284+:: date's message (+literal-msg). ~0.1.1 is a date (below).
285+:: - A year BC of 0 or past 292.277.024.401, as in ~0-.1.1, at the -
286+:: that makes it BC: Hoon's +year crashes on it (+year-bc).
287+:: - A fifth sub-second group, after a duration's .. or a date's
288+:: second .., at the dot that begins it: "a date or duration takes
289+:: at most four sub-second groups", as Hoon's do, since its +yule
290+:: crashes on a fifth (+fifth-group).
291+:: A date or duration is also read under mule, so that any other crash
292+:: is an error at the run's start, "Jibb can't read this literal"; other
293+:: runs aren't, since mule costs about a millisecond a call. Then:
245294:: - It read the whole run, as an aura Jibb takes: the token. Numbers
246295:: take %ud, %ux and %uv: 1.000, 0x1f, 0v5.fdf99 (Hoon reads 0x1F
247296:: too). ~ runs take %p, %da, %dr and %ta: ~zod, ~sampel-palnet,
248−:: ~2026.10.23..14.30.00, ~h1.m30, ~.my-post.
249−:: - It read the run or part of it as an aura Jibb doesn't take: 0w1,
250−:: 0i1, ~~a (a cord), ~-a (a @c). An error at 2nd, "Jibb writes no
251−:: @uw literals". A run starting 0b, 0c, 0i or 0w gets that error
252−:: before nuck:so reads it, since no Jibb literal goes on that way:
253−:: Hoon's parser would read 0b, or a 0c1 whose checksum fails, as
254−:: the number 0 and an error past the run.
297+:: ~2026.10.23..14.30.00, ~h1.m30, ~.my-post. Its value is Hoon's:
298+:: ~0.1.1 is 1 BC and prints as ~1-.1.1, and ~2026.2.31 is
299+:: ~2026.3.3 (doc question).
300+:: - It read the run or part of it as another aura Jibb doesn't take:
301+:: an error at 2nd that names the aura, as "Jibb writes no @if
302+:: literals".
255303:: - It read only part of the run, as an aura Jibb takes: that part is
256304:: a token, then an error token at p.edge, the furthest character
257305:: Hoon's parser looked at, where Hoon reports it too. 1000 is the
@@ -267,13 +315,12 @@
267315:: d h m or s, if that is later: Hoon's parser reads a syllable's
268316:: three letters before it looks them up, so it looks past that
269317:: letter. `++ x ~x` fails at the x, 1:7, as no syllable starts with
270−:: x, and ~sampel-palnez at the z.
271−:: A run that starts as a date BC does, ~ and a year then -, fails at the
272−:: - if the year is 0 or past 292.277.024.401, before nuck:so sees it:
273−:: Hoon's +year crashes on those years, as in ~0-.1.1 (+year-bc).
274−:: The token is [%lit [form aura val]]: form names the literal rule that
275−:: matched, aura and val are the dime Hoon's parser gives. Terms,
276−:: loobeans and the bare ~ are read by hand (2.6).
318+:: x, and ~sampel-palnez at the z. The error token's from is the
319+:: run's start, since the whole run is what fails (2.0).
320+:: The token is [%lit [form aura val txt]]: form names the literal rule
321+:: that matched, aura and val are the dime Hoon's parser gives, and txt
322+:: is the literal as written. Terms, loobeans and the bare ~ are read by
323+:: hand (2.6).
277324::
278325:: 2.9 Strings. A " starts a string, which ends on the same line. Up to
279326:: the closing ":
@@ -342,14 +389,15 @@
342389:: descent is shorter, and each error names what its construct expected.
343390:: An operand that isn't where an expression starts (a call's argument,
344391:: an item, a pair's or unit's operand, the wide gate's body) can't be a
345−:: rune, so there |= is a constructor and needs its term at once:
346−:: (state.cart |= %got) is an error at the space after |=, 1:20. A loop
347−:: over many items (definitions, arms, lines, items) is a trap whose
348−:: every step, through +then, is a tail call, so a long module grows no
349−:: stack. Nesting does, by a few frames a level: 100.000 nested
350−:: parentheses parse, and so does a 20.000-line module. +golden's tree
351−:: is another matter: its indent grows with depth, so 7.000 nested
352−:: parentheses print as 49 MB and 10.000 run out of memory.
392+:: rune, so there |= is a constructor and needs its term at once, or
393+:: the ( of the wide gate: in ++ x (state.cart |= %got) the space after
394+:: |= is an error, 1:20. A loop over many items (definitions, arms,
395+:: lines, items) is a trap whose every step, through +then, is a tail
396+:: call, so a long module grows no stack. Nesting does, by a few frames
397+:: a level: 100.000 nested parentheses parse, and so does a 20.000-line
398+:: module. +golden's tree stops indenting past 64 levels (4.2), so its
399+:: size grows with the text's, not with its square: tools/golden takes
400+:: 8 s on 10.000 nested parentheses, 5.5 s of it building the library.
353401::
354402:: The EBNF and its nodes (see the types below):
355403:: module { import NEWLINE } { definition NEWLINE }, then the end
@@ -357,7 +405,9 @@
357405:: "expected a definition, found `/-`; imports come first"
358406:: import /- name -> %sur; /% term -> %mark; /= name pathlit ->
359407:: %jibb. /% takes % and a name only: no mark is called %0,
360−:: %& or %| (doc question)
408+:: %& or %| (doc question). /='s path has a segment, as it
409+:: names a module's file: /= card / is an error just past
410+:: the / (doc question)
361411:: definition +$ name mold, or the mold alone on a deeper line ->
362412:: %mold (both layouts give one node); ++ name expr or body
363413:: -> %value (a body becomes a %body expr)
@@ -404,13 +454,15 @@
404454:: - Spaces, comments and blank lines: the layout pass, and Spacing
405455:: below.
406456:: - pathlit as an operand (above), with / alone the empty path.
407−:: - knot may be empty: only / alone uses that, as the empty path; //
408−:: and a trailing / are errors (doc question).
457+:: - knot may be empty: only / alone uses that, as the empty path in
458+:: an expression or a mold, not in an import; // and a trailing /
459+:: are errors (doc question).
409460:: - Open brackets in molds: mold has no open form, so a mold's [ or (
410461:: closes on its line, and only $? takes lines below (doc question).
411462:: - Two brackets left open on one line, as (column ~[: the last one
412463:: takes the deeper lines, and the other is then unclosed, an error
413−:: (doc question).
464+:: at the end of that line, where nothing can close it any more
465+:: (doc question; Errors below).
414466:: - Local definitions: the EBNF takes them in every body (of ++, |=,
415467:: ^-, ~& and arms), the Runes prose says "inside a gate"; the parser
416468:: takes them in every body and leaves the rest to the checker (doc
@@ -428,12 +480,13 @@
428480:: right before a closer ) ] or } (the theme example writes `[ space=`),
429481:: the ( and ) of an application path's segment included; inside
430482:: them the expression is spaced as anywhere else, as %/x/(f a)
431−:: A missing space is an error at the tight token, and so is a space
432−:: inside a tight form, at the space (Errors). A rune with children, and
433−:: an import glyph, is followed by a space (or, for $? with its cases
434−:: below, the end of the line). Items are separated by one or more
435−:: spaces; how many isn't checked. This is how the parser makes "one
436−:: space between items; more for alignment" precise (doc question).
483+:: A missing space is an error at the tight token, and a space inside
484+:: a tight form, or the end of the line there, is one where it starts
485+:: (Errors). A rune with children, and an import glyph, is followed by
486+:: a space (or, for $? with its cases below, the end of the line).
487+:: Items are separated by one or more spaces; how many isn't checked.
488+:: This is how the parser makes "one space between items; more for
489+:: alignment" precise (doc question).
437490::
438491:: Errors. The parser stops at the first token it can't accept and
439492:: reports "expected <what>, found <token>", with an optional "; <hint>",
@@ -444,30 +497,78 @@
444497:: the same depth" (NEWLINE), "a shallower line" (DEDENT), or "the end of
445498:: the file" (an empty span, 2.5). Each error points at the first
446499:: character that can't begin a valid module (2.0):
447−:: - At the token's start; for a layout token, at the start of the
448−:: line it begins, or just past the last token at the end of the
449−:: file (+where). So `++ view` above `++ main view` is an error at
450−:: 2:1, the line that isn't deeper.
500+:: - At a token the place can't take: just past the part of it that
501+:: could still begin what the place takes (+fail-in, +prefix). That
502+:: is none when the place can't begin with its first character, so
503+:: `++ 2nd 5` fails at the 2, 1:4; a wing's first name where a name
504+:: goes, so `++ a.b 1` fails at the dot, 1:5; else one character,
505+:: as the % of %.y where a term goes, the ~ of ~zod where a mold
506+:: goes (~ alone is one), or a + or ? alone. A layout token is at
507+:: the start of the line it begins, or just past the last token at
508+:: the end of the file (+where). So `++ view` above `++ main view`
509+:: is an error at 2:1, the line that isn't deeper.
451510:: - Where a tight form needs its next token at once (after name+, `,
452−:: |= in an operand, name=, the = of a pun, a path's / and %/, a
453−:: typed segment's parts) and finds a space: at the end of the
454−:: previous token, where the space starts, "expected a term right
455−:: after `|=`, found a space" (+fail-space). A wing and a ( after a
456−:: space are no error: that is a call.
457−:: - At an error token: the lexer's position and message, unchanged.
458−:: - Three pattern errors point inside their token, where it stops
459−:: being a pattern: a date, duration or knot at its second character
460−:: (~ alone is null, and no ship goes on so), ~[ at its [, and a
461−:: string with {…} at its {.
511+:: |= in an operand, name=, the = of a pun, a / after a path
512+:: segment, a typed segment's parts) and finds a space or the end
513+:: of the line: at the end of the previous token, where the space or
514+:: the line's end starts, as "expected an operand right after `+`,
515+:: found the end of the line" (+fail-space). No later line can give
516+:: a tight form its next token. A wing and a ( after a space are no
517+:: error: that is a call; nor is / or %/ alone, a whole path.
518+:: - At an error token: the lexer's position and message, unless the
519+:: text it was reading begins with a character the place can't
520+:: begin with. Then at that character, the lexer's message after
521+:: the parser's (+moved): `++ x @sd` is "expected an expression,
522+:: found `@`; signed and floating-point auras are left out of Jibb"
523+:: at the @, while `+$ x @sd` fails at the s. The place includes
524+:: what could still go on before it: after a call's operand and a
525+:: space, another operand, so `++ x a ?:` fails at the ? and `++ x
526+:: a |%` at the % (+read-operands); after a mold, an import or !!
527+:: that ends a line, nothing, so `+$ x @ |%` fails at the |
528+:: (+bad-end-in); tight after an item, a closer, or after a name
529+:: the ( . + or = of a change, wing, pair or face (+tight-error,
530+:: which doesn't look at what the item was, though it takes no =
531+:: after a call's operand). A : stays where the lexer put it, since
532+:: it could begin a comment. An error token after a space or on a
533+:: later line, where a tight form needed its next token, comes after
534+:: the tight form's error (+fail-space).
535+:: - At layout tokens followed by an error token whose text begins
536+:: the line, both errors are at the line's start, and the lexer's
537+:: message, about that text, says more: a line `==` that closes a
538+:: ?- is "the closer `==` is left out: indentation covers it", not
539+:: "expected the end of the body" (+lexer-error).
540+:: - Where a line's last open bracket or rune took the deeper lines
541+:: while something opened before it on the line still needs a
542+:: closer there or deeper lines of its own: at the end of that
543+:: line, since no later line can supply them (+doomed). `++ x
544+:: (column ~[` above deeper lines is "expected `)` to close the `(`
545+:: at 1:6, found the end of the line; the deeper lines go to the
546+:: last bracket or rune left open on this line", at 1:16.
547+:: - Pattern errors point inside their token, where it stops being a
548+:: pattern: a date or knot at its second character (~ alone is
549+:: null, and no ship goes on so), a duration just past its unit
550+:: letter (~d begins ships, as ~dur), ~[ at its [, and a string
551+:: with {…} at its {.
462552:: In a bracket, a closer that doesn't match is "expected `]` to close
463553:: the `~[` at 1:6, found `)`", checked before spacing; after an item, a
464554:: tight token that isn't a closer is "expected a space between items,
465−:: found `M`". Hints name the left-out forms the lexer can't see (2.6):
466−:: where an expression starts, = followed tight by ( is "=(a b) is left
467−:: out: eq is a gate", = followed tight by / is "=/ is left out: ++
468−:: defines values", and * is "*mold is left out: no defaults"; ^- or ?-
469−:: followed tight by ( is "the wide form ^-(…) is left out: indentation
470−:: covers it". The messages quote that code in backticks (2.0), as in
555+:: found `M`". A ) or ] that closes no bracket opened before it on its
556+:: line adds "this `)` closes no bracket" (+stray), and a closer on a
557+:: line of an open bracket "a bracket open at the end of its line takes
558+:: no closer: its items end at the first line that isn't deeper". Hints
559+:: name the left-out forms the lexer can't see (2.6): where an
560+:: expression starts, = followed tight by ( is "=(a b) is left out: eq
561+:: is a gate"; = followed tight by / is "=/ is left out: ++ defines
562+:: values", and so for Hoon's =+ =? and =.; * is "*mold is left out: no
563+:: defaults"; ^-, ?- or ~& followed tight by ( is "the wide form ^-(…)
564+:: is left out: indentation covers it". Others name likely slips: |=
565+:: and a space where an operand goes, "a gate in an operand is |=(a
566+:: body)", or before a term "a case's constructor takes its term with
567+:: no space, as |=%got"; name= in a pattern, "patterns take no
568+:: `name=`: a bare name binds, as [a b]"; a capital or a wing where a
569+:: name goes, "a name starts with a lowercase letter" and "a name has
570+:: no `.`"; a lone + where a definition goes, "`+` begins `++` or
571+:: `+$`". The messages quote that code in backticks (2.0), as in
471572:: "`=(a b)` is left out: eq is a gate". Examples:
472573:: expected `]` or an item on a deeper line, found a line at the same
473574:: depth
@@ -524,7 +625,10 @@
524625:: (a string's quoted text, an application path's knots). A node whose
525626:: kids are all leaves prints on one line; otherwise each kid goes on its
526627:: own line, indented two more spaces, and the closing parens end the
527−:: last kid's line. (module …) always breaks. Bare fields and samples
628+:: last kid's line. (module …) always breaks. Past 64 levels the indent
629+:: stops growing: a deeper line starts with 128 spaces and its depth
630+:: between bars, as `|65| (group 1:69`, so the printed tree's size is
631+:: linear in the text's however deep it nests. Bare fields and samples
528632:: print as their mold, and a cell sample as (cell …) of its samples, a
529633:: bare name there as (bind …); unnamed items print as their expr;
530634:: strings print text pieces quoted, between their interpolated exprs;
@@ -627,7 +731,7 @@
627731 [%knot p=@ta] :: path segment
628732 [%aura p=@ta] :: @ud as 'ud', @ as ''
629733 [%tvar p=@t] :: M
630− [%error p=tape] :: 2.0: what broke
734+ [%error p=tape from=loc c=@] :: 2.0: what broke
631735 ==
632736::
633737:: +glyph: a token that is its text, and the layout tokens
@@ -646,8 +750,10 @@
646750::
647751:: +lit: a literal other than a string, as Hoon's parsers read it
648752::
649−:: form is the literal rule that matched; aura and val are the dime
650−:: nuck:so gives, or for terms and loobeans:
753+:: form is the literal rule that matched; txt is the literal as
754+:: written, which the printers show, since Hoon's own printing of
755+:: some auras (@da) differs between Hoon versions; aura and val are
756+:: the dime nuck:so gives, or for terms and loobeans:
651757:: %number 1.000 0x1f 0v5.fdf99 %ud %ux %uv
652758:: %ship ~zod %p
653759:: %date ~2026.10.23 %da
@@ -657,7 +763,7 @@
657763:: %loobean %.y %.n %f 0, %f 1
658764:: %null ~ %n 0
659765::
660−+$ lit [form=lit-form aura=@ta val=@]
766++$ lit [form=lit-form aura=@ta val=@ txt=@t]
661767+$ lit-form
662768 ?(%number %ship %date %duration %knot %term %loobean %null)
663769::
@@ -794,8 +900,8 @@
794900::
795901:: +layout: source to tokens (design: section 2)
796902::
797−:: Never fails: an error it finds is its last token, [%error msg], at
798−:: the error's position (2.0). +lexer does the work.
903+:: Never fails: an error it finds is its last token, [%error msg from
904+:: c], at the error's position (2.0). +lexer does the work.
799905::
800906++ layout
801907 |= [file=path src=@t]
@@ -827,7 +933,7 @@
827933++ parse-tokens
828934 |= [file=path toks=(list token)]
829935 ^- (each module error)
830− (~(read-module parser file) toks)
936+ (~(read-module parser file toks) toks)
831937::
832938:: +golden: both stages printed, or the rendered error
833939::
@@ -962,10 +1068,23 @@
9621068 ::
9631069 :: +err: the error token, at column c of this line (2.0)
9641070 ::
1071+ :: It also records where the text it was reading began, from, and
1072+ :: that text's first character: the parser moves the error there
1073+ :: when the place it is in can't begin with that character (section
1074+ :: 3, Errors). Like any token, it is tight when that text follows the
1075+ :: last token with no space.
1076+ ::
9651077 ++ err
9661078 |= [c=@ud msg=tape]
9671079 ^+ cor
968− cor(out [[[[lin c] [lin c]] | [%error msg]] out])
1080+ (err-from c msg [lin col] ?~(cs 0 i.cs))
1081+ ::
1082+ :: +err-from: +err, where the text began at from with first
1083+ ::
1084+ ++ err-from
1085+ |= [c=@ud msg=tape from=loc first=@]
1086+ ^+ cor
1087+ cor(out [[[[lin c] [lin c]] =(from pend) [%error msg from first]] out])
9691088 ::
9701089 :: +put: a token from beg to end on this line, with rest the text
9711090 :: after it, which starts at end
@@ -1023,10 +1142,10 @@
10231142 ?: =('%' a) (percent b c)
10241143 ?: =('=' a)
10251144 ?: |(=('<' b) =('>' b))
1026− %+ err col
1145+ %+ err +(col)
10271146 "`={[b ~]}` is left out: names never shadow, and `.` reads imports too"
10281147 ?: =('=' b)
1029− (err col "the closer `==` is left out: indentation covers it")
1148+ (err +(col) "the closer `==` is left out: indentation covers it")
10301149 (emit 1 %'=')
10311150 ?: =('`' a) (emit 1 %'`')
10321151 ?: =('*' a) (emit 1 %'*')
@@ -1035,7 +1154,7 @@
10351154 ?: =('&' b) (emit 2 %'~&')
10361155 ?: =('|' b) (err +(col) "`~|` is left out: `~&` covers debugging")
10371156 =/ n=@ud (run-len t.cs knot-mask)
1038− ?: =(0 n) (emit 1 [%lit %null %n 0])
1157+ ?: =(0 n) (emit 1 [%lit %null %n 0 '~'])
10391158 (literal +(n))
10401159 ?: =('/' a)
10411160 ?: &(=(1 col) |(=('-' b) =('%' b) =('=' b)))
@@ -1061,7 +1180,7 @@
10611180 ?: &(=('-' b) =('(' c)) (emit 3 %'$-(')
10621181 ?: =('-' b)
10631182 (err (add 2 col) "`$-` has only the wide form `$-(sample product)`")
1064− ?: =('(' b) (err col "`$(…)` is left out: gates recurse by name")
1183+ ?: =('(' b) (err +(col) "`$(…)` is left out: gates recurse by name")
10651184 ?: =('%' b) (err +(col) "`$%` is left out: `$?` covers unions")
10661185 (err +(col) "`$` begins `$?`, `$?(` or `$-(`")
10671186 ?: =('^' a)
@@ -1069,10 +1188,12 @@
10691188 (err +(col) "`^` begins `^-`")
10701189 ?: =('?' a)
10711190 ?: =('-' b) (emit 2 %'?-')
1072− ?: =('+' b) (err +(col) "`?+` is left out: `?-` is the branch")
10731191 ?: &(=(':' b) !=(':' c))
10741192 (err +(col) "`?:` is left out: `?-` is the branch")
10751193 ?: =('!' b) (err +(col) "`?!` is left out: eq and not are gates")
1194+ :: Hoon's other ? runes; nothing in Jibb goes tight after a ? mold
1195+ ?: (in b wut-mask)
1196+ (err +(col) "`?{[b ~]}` is left out: `?-` is the branch")
10761197 (emit 1 %'?')
10771198 ?: =('!' a)
10781199 ?: =('!' b) (emit 2 %'!!')
@@ -1098,6 +1219,9 @@
10981219 (err +(col) "`:~` is left out: indentation covers it; write ~[…]")
10991220 ?: =('*' b)
11001221 (err +(col) "`:*` is left out: indentation covers it; write […]")
1222+ ?: |(=('-' b) =('+' b) =('^' b) =('_' b))
1223+ %+ err +(col)
1224+ "`:{[b ~]}` is left out: indentation covers it; write a cell as [a b]"
11011225 ?: &(=(pend [lin col]) ?=([[* * ?([%name *] [%wing *])] *] out))
11021226 %+ err +(col)
11031227 %+ weld "`a:b` is left out: names never shadow, "
@@ -1114,6 +1238,8 @@
11141238 (err col "the closer `--` is left out: indentation covers it")
11151239 (err col (unexpected a))
11161240 ?: =(';' a)
1241+ ?: =(':' b)
1242+ (err col "`;:` is left out: nest the calls, as (add a (add b c))")
11171243 (err col "Sail's `;` runes are left out: layout is Jibb's elements")
11181244 ?: =('\'' a) (err col "there is no '…' form: strings are \"…\"")
11191245 ?: =('{' a)
@@ -1146,24 +1272,28 @@
11461272 ^+ cor
11471273 ?: =('/' b) segment:(emit 2 %'%/')
11481274 ?: =('.' b)
1149− ?: =('y' c) (emit 3 [%lit %loobean %f 0])
1150− ?: =('n' c) (emit 3 [%lit %loobean %f 1])
1275+ ?: =('y' c) (emit 3 [%lit %loobean %f 0 '%.y'])
1276+ ?: =('n' c) (emit 3 [%lit %loobean %f 1 '%.n'])
11511277 (err (add 2 col) "the loobeans are `%.y` and `%.n`")
1152− ?: =('&' b) (emit 2 [%lit %term %f 0])
1153− ?: =('|' b) (emit 2 [%lit %term %f 1])
1154− ?: =(':' b) (err +(col) "`%:` is left out: indentation covers it")
1278+ ?: =('&' b) (emit 2 [%lit %term %f 0 '%&'])
1279+ ?: =('|' b) (emit 2 [%lit %term %f 1 '%|'])
1280+ ?: |(=(':' b) =('-' b) =('+' b) =('^' b) =('~' b))
1281+ %+ err +(col)
1282+ "`%{[b ~]}` is left out: indentation covers it; a call is (f a b)"
11551283 ?: =('=' b)
11561284 %+ err +(col)
11571285 "`%=` is left out: indentation covers it; write a change, as m(a=b)"
11581286 =/ rest=tape ?~(cs ~ t.cs)
11591287 ?: (is-lower b)
11601288 =/ n=@ud (run-len rest name-mask)
1161− => (emit +(n) [%lit %term %tas (crip (scag n rest))])
1289+ =/ nam=tape (scag n rest)
1290+ => (emit +(n) [%lit %term %tas (crip nam) (crip ['%' nam])])
11621291 ?. &(?=(^ cs) |((is-upper i.cs) =('_' i.cs))) cor
11631292 (err col "names are lowercase letters, digits and -")
11641293 ?: (is-digit b)
11651294 =/ n=@ud (run-len rest digit-mask)
1166− => (emit +(n) [%lit %term %ud (decimal (scag n rest))])
1295+ =/ dig=tape (scag n rest)
1296+ => (emit +(n) [%lit %term %ud (decimal dig) (crip ['%' dig])])
11671297 ?. &(?=(^ cs) (in i.cs term-tail-mask)) cor
11681298 %+ err col
11691299 "unexpected `{[i.cs ~]}`: a numeric term is `%` and digits only, as %1000"
@@ -1217,9 +1347,20 @@
12171347 =/ run=tape (scag n cs)
12181348 =/ a=@ ?~(run 0 i.run)
12191349 =/ b=@ ?~(run 0 ?~(t.run 0 i.t.run))
1220− :: 0b 0c 0i 0w begin auras Jibb doesn't write, whatever follows
1350+ :: 0b 0c 0i 0w, ~- and ~~ begin auras Jibb doesn't write, whatever
1351+ :: follows; Hoon's reader of ~- (@c) crashes on a control character
12211352 ?: &(=('0' a) |(=('b' b) =('c' b) =('i' b) =('w' b)))
12221353 (err +(col) "Jibb writes no @u{[b ~]} literals")
1354+ ?: &(=('~' a) =('-' b)) (err +(col) "Jibb writes no @c literals")
1355+ ?: &(=('~' a) =('~' b))
1356+ (err +(col) "Jibb writes no @t literals; strings are \"…\"")
1357+ :: ~0 and a base-32 digit begin a blob, which Hoon's reader cues, and
1358+ :: cue can run out of memory, which nothing catches; no Jibb literal
1359+ :: goes on so (a date's year has no leading 0)
1360+ =/ c=@ ?~(run 0 ?~(t.run 0 ?~(t.t.run 0 i.t.t.run)))
1361+ ?: &(=('~' a) =('0' b) (in c b32-mask))
1362+ ?: (is-digit c) (err (add 2 col) (literal-msg run %da))
1363+ (err (add 2 col) "Jibb writes no blob literals")
12231364 :: a year BC that Hoon's dates can't hold, which its date code
12241365 :: crashes on: an error at the - that makes it BC
12251366 =/ bc=(unit [at=@ud y=@ud]) (year-bc col run)
@@ -1227,7 +1368,18 @@
12271368 (err at.u.bc "there is no year 0 BC: 1 BC is ~1-, as ~1-.1.1")
12281369 ?: &(?=(^ bc) (gth y.u.bc 292.277.024.401))
12291370 (err at.u.bc "Hoon's dates begin in 292.277.024.401 BC")
1230− =/ ed (nuck:so [[lin col] run])
1371+ :: a fifth sub-second group, which Hoon's +yule crashes on
1372+ =/ five=(unit @ud) (fifth-group run)
1373+ ?^ five
1374+ %+ err (add col u.five)
1375+ "a date or duration takes at most four sub-second groups"
1376+ :: Hoon's date code reads dates and durations, and has crashed on
1377+ :: forms the checks above now stop; it runs under mule, in case
1378+ =/ try=(each (like coin) tang)
1379+ ?. (is-time run) [%& (nuck:so [[lin col] run])]
1380+ (mule |.((nuck:so [[lin col] run])))
1381+ ?: ?=(%| -.try) (err col "Jibb can't read this literal")
1382+ =/ ed=(like coin) p.try
12311383 ?~ q.ed (err q.p.ed (literal-msg run %$))
12321384 =/ used=@ud (sub n (lent q.q.u.q.ed))
12331385 =/ con=coin p.u.q.ed
@@ -1238,7 +1390,7 @@
12381390 %+ err +(col)
12391391 %+ weld "Jibb writes no @{(trip p.p.con)} literals"
12401392 ?:(=(%t p.p.con) "; strings are \"…\"" "")
1241− =/ lex=lexeme [%lit u.form p.p.con q.p.con]
1393+ =/ lex=lexeme [%lit u.form p.p.con q.p.con (crip (scag used run))]
12421394 ?: =(used n)
12431395 ?. =(%ta p.p.con) (emit n lex)
12441396 :: a ~. knot is followed as a path segment is (2.7)
@@ -1255,7 +1407,9 @@
12551407 =? at &(=('~' a) (is-lower b) ?=(?(%n %p) p.p.con))
12561408 =/ dur=@ud ?:(|(=('d' b) =('h' b) =('m' b) =('s' b)) 2 1)
12571409 (min at (add col (max dur (ship-stop run))))
1258− (err:(emit used lex) at (literal-msg run p.p.con))
1410+ :: the text that fails is the whole run, from its start, though its
1411+ :: first part is a token
1412+ (err-from:(emit used lex) at (literal-msg run p.p.con) [lin col] a)
12591413 ::
12601414 :: +text: a string's text, from its opening " or the } that closes
12611415 :: an interpolation, through the " or { that ends it (2.9). mid: it
@@ -1336,6 +1490,31 @@
13361490++ seg-bad-mask 0x1800.0001.57ff.ffff.f800.1cfe.0000.0000
13371491:: after a numeric term: a-z A-Z _ - .
13381492++ term-tail-mask 0x7ff.fffe.87ff.fffe.0000.6000.0000.0000
1493+:: after a ? glyph, Hoon's ? runes but ?- ?: and ?! (2.6): + ~ = . @ ^ & | < >
1494+++ wut-mask 0x5000.0000.4000.0001.7000.4840.0000.0000
1495+:: base-32 digits: 0-9 a-v
1496+++ b32-mask 0x7f.fffe.0000.0000.03ff.0000.0000.0000
1497+::
1498+:: What may begin each place the parser reads (section 3, Errors):
1499+:: an expression a-z 0-9 " ( [ ~ % / ` | ^ ? !
1500+:: an operand a-z 0-9 " ( [ ~ % / ` |
1501+:: a mold a-z A-Z @ * ! ? ~ % / ( [ $ |
1502+:: a pattern a-z 0-9 " ~ % * [
1503+:: and what may go tight after an operand: . ( + = after a name, a
1504+:: closer ) ] }, or the : of a comment
1505+::
1506+++ expr-mask 0x57ff.ffff.4800.0000.83ff.8126.0000.0000
1507+++ operand-mask 0x57ff.ffff.0800.0000.03ff.8124.0000.0000
1508+++ mold-mask 0x57ff.fffe.0fff.ffff.8000.8532.0000.0000
1509+++ pattern-mask 0x47ff.fffe.0800.0000.03ff.0424.0000.0000
1510+++ after-mask 0x2000.0000.2000.0000.2400.4b00.0000.0000
1511+++ plus-mask 0x800.0000.0000 :: +
1512+++ cen-mask 0x20.0000.0000 :: %
1513+++ fas-mask 0x8000.0000.0000 :: /
1514+++ tis-mask 0x2000.0000.0000.0000 :: =
1515+++ pat-mask 0x1.0000.0000.0000.0000 :: @
1516+++ sel-mask 0x800.0000.0000.0000.0000.0000 :: [
1517+++ ser-mask 0x2000.0000.0000.0000.0000.0000 :: ]
13391518::
13401519:: +cont-mask: UTF-8 continuation bytes, 10xx.xxxx, which start no
13411520:: column (1)
@@ -1437,6 +1616,62 @@
14371616 ?. ?=([%'-' *] rest) ~
14381617 `[(add col +((lent ds))) (decimal ds)]
14391618::
1619+:: +fifth-group: where in a ~ literal's run, counting from its ~, the
1620+:: dot that begins a fifth sub-second group is, if the first four are
1621+:: well formed
1622+::
1623+:: Sub-seconds follow a duration's first .. or a date's second, as in
1624+:: ~s1..0000 and ~2026.10.23..14.30.00..0000: groups of four
1625+:: lowercase hex digits joined by dots. Hoon's reader takes any
1626+:: number, and its +yule crashes on a fifth (2.8).
1627+::
1628+++ fifth-group
1629+ |= run=tape
1630+ ^- (unit @ud)
1631+ =/ b=@ ?.(?=([%'~' @ *] run) 0 i.t.run)
1632+ =/ k=@ud
1633+ ?: (is-digit b) 2
1634+ ?:(|(=('d' b) =('h' b) =('m' b) =('s' b)) 1 0)
1635+ ?: =(0 k) ~
1636+ =/ past=(unit [i=@ud cs=tape]) (past-dots k 0 run)
1637+ ?~ past ~
1638+ =/ i=@ud i.u.past
1639+ =/ cs=tape cs.u.past
1640+ =/ g=@ud 1
1641+ |- ^- (unit @ud)
1642+ =/ quad=tape (scag 4 cs)
1643+ ?. &(=(4 (lent quad)) (levy quad is-hex)) ~
1644+ =. cs (slag 4 cs)
1645+ =. i (add 4 i)
1646+ ?. ?=([%'.' *] cs) ~
1647+ ?: =(4 g) `i
1648+ $(g +(g), i +(i), cs t.cs)
1649+::
1650+:: +past-dots: where the text past the k-th .. of cs starts, counting
1651+:: from i, and that text
1652+::
1653+++ past-dots
1654+ |= [k=@ud i=@ud cs=tape]
1655+ ^- (unit [i=@ud cs=tape])
1656+ ?~ cs ~
1657+ ?. &(=('.' i.cs) ?=(^ t.cs) =('.' i.t.cs))
1658+ $(i +(i), cs t.cs)
1659+ ?: =(1 k) `[(add 2 i) t.t.cs]
1660+ $(k (dec k), i (add 2 i), cs t.t.cs)
1661+::
1662+:: +is-time: whether a ~ literal's run starts as a date or a duration
1663+:: does, which Hoon's date code reads (2.8)
1664+::
1665+++ is-time
1666+ |= run=tape
1667+ ^- ?
1668+ ?. ?=([%'~' @ *] run) |
1669+ ?: (is-digit i.t.run) &
1670+ ?& |(=('d' i.t.run) =('h' i.t.run) =('m' i.t.run) =('s' i.t.run))
1671+ ?=([@ @ @ *] run)
1672+ (is-digit i.t.t.run)
1673+ ==
1674+::
14401675:: +ship-stop: how many characters of a ~ literal's run, from its ~,
14411676:: could still begin a ship (2.8)
14421677::
@@ -1554,11 +1789,8 @@
15541789 ^- @t
15551790 =/ kids=(list sexp)
15561791 (weld (turn imports.mod sexp-import) (turn defs.mod sexp-def))
1557− =/ lines=wall
1558− ?~ kids ~["(module)"]
1559− :- "(module"
1560− (close (zing (turn kids |=(k=sexp (render 2 k)))))
1561− (of-wain:format (turn lines crip))
1792+ ?~ kids '(module)'
1793+ (of-wain:format (turn (render kids) crip))
15621794::
15631795:: +show-error: "<file>:<line>:<col>: <message>", the line, a caret
15641796::
@@ -1654,17 +1886,15 @@
16541886 ?~ t.ns (trip i.ns)
16551887 "{(trip i.ns)}.{$(ns t.ns)}"
16561888::
1657−:: +show-lit: a literal as Hoon prints it
1889+:: +show-lit: a literal as written for atoms read by nuck:so, whose
1890+:: printing differs between Hoon versions (@da); terms, loobeans and ~
1891+:: in their one form
16581892::
16591893++ show-lit
16601894 |= l=lit
16611895 ^- tape
16621896 ?- form.l
1663− %number (scow aura.l val.l)
1664− %ship (scow %p val.l)
1665− %date (scow %da val.l)
1666− %duration (scow %dr val.l)
1667− %knot (scow %ta val.l)
1897+ ?(%number %ship %date %duration %knot) (trip txt.l)
16681898 %loobean ?:(=(0 val.l) "%.y" "%.n")
16691899 %null "~"
16701900 %term
@@ -1726,20 +1956,57 @@
17261956 [%node head=tape kids=(list sexp)]
17271957 ==
17281958::
1729−:: +render: a node as lines, at an indent
1959+:: +render: a module's kids as the tree's lines (4.2)
17301960::
1731−:: On one line when every kid is a leaf: an atom, or a node whose kids
1732−:: are all atoms (a string's text, a path's knots). Else each kid on
1733−:: its own lines, two spaces deeper.
1961+:: A node whose kids are all leaves goes on one line; else its head,
1962+:: then each kid a level deeper, and its ) at the end of its last
1963+:: kid's last line; (module …) always breaks. Each line is built once,
1964+:: from its depth: a line deeper than 64 levels keeps 64 levels'
1965+:: indent and says its depth, as |65| (group 3:1 …), so printing is
1966+:: linear in the tree's size however deep it nests.
17341967::
17351968++ render
1736− |= [ind=@ud s=sexp]
1969+ |= kids=(list sexp)
17371970 ^- wall
1738− =/ pad=tape (reap ind ' ')
1739− ?: ?=(%atom -.s) ~[(weld pad p.s)]
1740− ?: (levy kids.s is-leaf) ~[(weld pad (flat s))]
1741− :- "{pad}({head.s}"
1742− (close (zing (turn kids.s |=(k=sexp (render (add ind 2) k)))))
1971+ =/ acc=(list pline) ~[[0 "(module" 0]]
1972+ =. acc
1973+ |- ^- (list pline)
1974+ ?~ kids acc
1975+ $(kids t.kids, acc (put-sexp 1 i.kids acc))
1976+ (flop (turn (shut-last acc) show-pline))
1977+::
1978+:: +pline: a printed line: its depth, its text, and how many )s end it
1979+::
1980++$ pline [dep=@ud txt=tape shut=@ud]
1981+::
1982+:: +put-sexp: a node's lines at depth dep, last first, onto acc
1983+::
1984+++ put-sexp
1985+ |= [dep=@ud s=sexp acc=(list pline)]
1986+ ^- (list pline)
1987+ ?: ?=(%atom -.s) [[dep p.s 0] acc]
1988+ ?: (levy kids.s is-leaf) [[dep (flat s) 0] acc]
1989+ =/ ks=(list sexp) kids.s
1990+ =. acc [[dep "({head.s}" 0] acc]
1991+ |- ^- (list pline)
1992+ ?~ ks (shut-last acc)
1993+ $(ks t.ks, acc (put-sexp +(dep) i.ks acc))
1994+::
1995+:: +shut-last: one more ) at the end of the last line
1996+::
1997+++ shut-last
1998+ |= acc=(list pline)
1999+ ^- (list pline)
2000+ ?~ acc ~
2001+ [i.acc(shut +(shut.i.acc)) t.acc]
2002+::
2003+++ show-pline
2004+ |= l=pline
2005+ ^- tape
2006+ =/ pad=tape
2007+ ?: (lte dep.l 64) (reap (mul 2 dep.l) ' ')
2008+ "{(reap 128 ' ')}|{(a-co:co dep.l)}| "
2009+ :(weld pad txt.l (reap shut.l ')'))
17432010::
17442011++ is-leaf
17452012 |= s=sexp
@@ -1753,15 +2020,6 @@
17532020 ?: ?=(%atom -.s) p.s
17542021 "({head.s}{(zing (turn kids.s |=(k=sexp (weld " " (flat k)))))})"
17552022::
1756−:: +close: end the last line with )
1757−::
1758−++ close
1759− |= w=wall
1760− ^- wall
1761− ?~ w ~
1762− ?~ t.w ~[(weld i.w ")")]
1763− [i.w $(w t.w)]
1764−::
17652023:: +nod: a node's sexp: "kind line:col extra" and its kids
17662024::
17672025++ nod
@@ -1927,49 +2185,195 @@
19272185::
19282186:: +fail: the error "expected <want>, found <the next token>"
19292187::
1930−:: At an error token, the layout pass's error instead (2.0). The token
1931−:: list always ends with NEWLINE or an error token (2.5), and the
1932−:: parser stops at either, so it never runs out; if it did, the error
1933−:: would sit at 1:1.
2188+:: At the layout pass's error instead (+lexer-error). The token list
2189+:: always ends with NEWLINE or an error token (2.5), and the parser
2190+:: stops at either, so it never runs out; if it did, the error would
2191+:: sit at 1:1.
19342192::
19352193++ fail
19362194 |= [file=path toks=(list token) want=tape]
19372195 ^- [%| p=error]
19382196 ?~ toks [%| file 1 1 "expected {want}, found the end of the tokens"]
1939− ?: ?=([%error *] lex.i.toks)
1940− [%| file line.beg.at.i.toks col.beg.at.i.toks p.lex.i.toks]
2197+ =/ lex=(unit error) (lexer-error file toks)
2198+ ?^ lex [%| u.lex]
19412199 =/ l=loc (where i.toks)
19422200 [%| file line.l col.l "expected {want}, found {(show-found i.toks)}"]
19432201::
1944−:: +fail-space: a tight form found a space before its next token
2202+:: +lexer-error: the layout pass's error, where the parser fails at it
19452203::
1946−:: The error sits where the space starts, just past prev, the token
1947−:: that needs its next one at once (section 3, Errors). If the next
1948−:: token is a layout or error token, it is +fail's error instead.
2204+:: At an error token, its error. At layout tokens followed by an error
2205+:: token whose text begins the line, both errors point at the line's
2206+:: start (+where), and the layout pass's message, about that text,
2207+:: says more: a line `==` closing a ?- is "the closer `==` is left
2208+:: out", not "expected the end of the body".
2209+::
2210+++ lexer-error
2211+ |= [file=path toks=(list token)]
2212+ ^- (unit error)
2213+ ?~ toks ~
2214+ ?: ?=([%error *] lex.i.toks)
2215+ `[file line.beg.at.i.toks col.beg.at.i.toks p.lex.i.toks]
2216+ ?. (is-layout i.toks) ~
2217+ =/ l=loc (where i.toks)
2218+ =/ rest=(list token) t.toks
2219+ |- ^- (unit error)
2220+ ?~ rest ~
2221+ ?: (is-layout i.rest) $(rest t.rest)
2222+ ?. ?=([%error *] lex.i.rest) ~
2223+ ?. =(l from.lex.i.rest) ~
2224+ `[file line.l col.l p.lex.i.rest]
2225+::
2226+:: +fail-in: +fail where the next token begins a place, such as an
2227+:: expression or a mold, whose first character is one of the mask can
2228+::
2229+:: The error points at the first character where the text stops being
2230+:: the start of any valid module (2.0), so at a token the place can't
2231+:: take, just past the part of it the place could: none if the place
2232+:: can't begin with its first character; a wing's first name, as in
2233+:: `++ a.b`, where a name goes; else that first character, as the ~ of
2234+:: ~zod where a mold goes (~ alone is one). At an error token whose
2235+:: text begins with a character the place can't, the error moves to
2236+:: that character, with the layout pass's message: `++ x @sd` fails
2237+:: at the @, since no expression begins with @, while `+$ x @sd`
2238+:: fails at the s.
2239+::
2240+++ fail-in
2241+ |= [file=path toks=(list token) want=tape can=@]
2242+ ^- [%| p=error]
2243+ ?~ toks (fail file toks want)
2244+ =* t i.toks
2245+ ?: ?=([%error *] lex.t)
2246+ :: a : could begin a comment anywhere, which this leaves out
2247+ ?: |(=(':' c.lex.t) (in c.lex.t can)) (fail file toks want)
2248+ [%| (moved file want t)]
2249+ ?: (is-layout t) (fail file toks want)
2250+ =/ n=@ud (prefix t can)
2251+ =/ e=[%| p=error] (fail file toks want)
2252+ e(col.p (add n col.p.e))
2253+::
2254+:: +prefix: how many of the first characters of a token that a place
2255+:: can't take could still begin it, the place beginning with a
2256+:: character of the mask can (+fail-in)
2257+::
2258+++ prefix
2259+ |= [t=token can=@]
2260+ ^- @ud
2261+ ?. (in (first-char t) can) 0
2262+ ?. ?=([%wing *] lex.t) 1
2263+ ?~(p.lex.t 1 (met 3 i.p.lex.t))
2264+::
2265+:: +first-char: a token's first character, or one like it: a number
2266+:: begins with a digit, ~zod with ~ and %add with %
2267+::
2268+++ first-char
2269+ |= t=token
2270+ ^- @
2271+ =/ x=lexeme lex.t
2272+ ?@ x ?:(?=(?(%indent %dedent %newline) x) 0 (end 3 x))
2273+ ?- -.x
2274+ %name (end 3 p.x)
2275+ %wing ?~(p.x 0 (end 3 i.p.x))
2276+ %str '"'
2277+ %str-head '"'
2278+ %str-mid '}'
2279+ %str-tail '}'
2280+ %knot (end 3 p.x)
2281+ %aura '@'
2282+ %tvar (end 3 p.x)
2283+ %error c.x
2284+ ::
2285+ %lit
2286+ ?- form.p.x
2287+ %number '0'
2288+ ?(%term %loobean) '%'
2289+ ?(%ship %date %duration %knot %null) '~'
2290+ ==
2291+ ==
2292+::
2293+:: +fail-space: a tight form found no next token right after prev
2294+::
2295+:: The error sits just past prev, the token that needs its next one
2296+:: at once, where the space or the end of the line starts (section 3,
2297+:: Errors): no deeper line can supply a tight form's next token. So
2298+:: does an error token past a space or on a later line, whose error
2299+:: comes after. A tight error token's text begins right after prev,
2300+:: and its error is +fail's. why is a hint, if not empty.
19492301::
19502302++ fail-space
1951− |= [file=path prev=token toks=(list token) want=tape]
2303+ |= [file=path prev=token toks=(list token) want=tape why=tape]
19522304 ^- [%| p=error]
1953− ?: ?| ?=(~ toks)
1954− ?=(?(%indent %dedent %newline) lex.i.toks)
1955− ?=([%error *] lex.i.toks)
1956− ==
2305+ =/ at=loc end.at.prev
2306+ ?: &(?=(^ toks) ?=([%error *] lex.i.toks) =(at from.lex.i.toks))
19572307 (fail file toks want)
1958− :+ %| file
1959− :+ line.end.at.prev col.end.at.prev
1960− "expected {want} right after {(show-found prev)}, found a space"
2308+ =/ found=tape
2309+ ?~ toks "the end of the file"
2310+ =* t i.toks
2311+ ?: (is-layout t)
2312+ ?:(=(beg.at.t end.at.t) "the end of the file" "the end of the line")
2313+ ?: &(?=([%error *] lex.t) !=(line.at line.from.lex.t))
2314+ "the end of the line"
2315+ "a space"
2316+ =/ msg=tape
2317+ "expected {want} right after {(show-found prev)}, found {found}"
2318+ [%| file line.at col.at ?~(why msg "{msg}; {why}")]
19612319::
19622320:: +fail-why: +fail with a hint after its message, "; <why>"
19632321::
1964−:: The layout pass's error, at an error token, stays as it is (2.0).
2322+:: The layout pass's error (+lexer-error) stays as it is (2.0).
19652323::
19662324++ fail-why
19672325 |= [file=path toks=(list token) want=tape why=tape]
19682326 ^- [%| p=error]
19692327 =/ e=[%| p=error] (fail file toks want)
2328+ ?^ (lexer-error file toks) e
2329+ e(msg.p (weld msg.p.e "; {why}"))
2330+::
2331+:: +fail-in-why: +fail-in with a hint, as +fail-why
2332+::
2333+++ fail-in-why
2334+ |= [file=path toks=(list token) want=tape can=@ why=tape]
2335+ ^- [%| p=error]
2336+ =/ e=[%| p=error] (fail-in file toks want can)
19702337 ?: &(?=(^ toks) ?=([%error *] lex.i.toks)) e
2338+ ?^ (lexer-error file toks) e
19712339 e(msg.p (weld msg.p.e "; {why}"))
19722340::
2341+:: +tight-error: the error at an error token tight after an operand or
2342+:: an item, if its text's first character can't go there: the layout
2343+:: pass's message, at that character (+fail-in)
2344+::
2345+:: What may go tight after an item is a closer, a comment's :, or,
2346+:: after a name, the ( . + or = of a change, a wing, a pair or a face
2347+:: (after-mask, which doesn't look at what the item was).
2348+::
2349+++ tight-error
2350+ |= [file=path toks=(list token)]
2351+ ^- (unit error)
2352+ (tight-error-in file toks after-mask)
2353+::
2354+:: +tight-error-in: +tight-error where what may go tight is can, as no
2355+:: = goes tight after a call's operand, which takes no face
2356+::
2357+++ tight-error-in
2358+ |= [file=path toks=(list token) can=@]
2359+ ^- (unit error)
2360+ ?. ?=([[* %& [%error *]] *] toks) ~
2361+ ?: (in c.lex.i.toks can) ~
2362+ `(moved file "a space between items" i.toks)
2363+::
2364+:: +moved: an error token's error, moved to the first character of the
2365+:: text it was reading, which can't go where it is (+fail-in): "expected
2366+:: <want>, found <that character>; <the layout pass's message>"
2367+::
2368+++ moved
2369+ |= [file=path want=tape t=token]
2370+ ^- error
2371+ ?. ?=([%error *] lex.t) [file line.beg.at.t col.beg.at.t "expected {want}"]
2372+ =* x lex.t
2373+ ?: =(from.x beg.at.t) [file line.from.x col.from.x p.x]
2374+ =/ what=tape ?:(=('"' c.x) "a string" "`{[c.x ~]}`")
2375+ [file line.from.x col.from.x "expected {want}, found {what}; {p.x}"]
2376+::
19732377:: Token tests for the parser
19742378::
19752379:: +is-layout: INDENT, DEDENT or NEWLINE
@@ -2001,6 +2405,28 @@
20012405 ?=([%error *] lex.t)
20022406 ==
20032407::
2408+:: +tail-can: what may begin text that goes on, on its line, after an
2409+:: expression: more operands after a call, nothing after !! (+bad-end-in)
2410+::
2411+++ tail-can
2412+ |= e=expr
2413+ ^- @
2414+ ?+ -.e operand-mask
2415+ %crash 0
2416+ %cast $(e val.e)
2417+ %gate $(e body.e)
2418+ ==
2419+::
2420+:: +def-can: +tail-can after a definition: nothing after a mold
2421+::
2422+++ def-can
2423+ |= d=def
2424+ ^- @
2425+ ?- -.d
2426+ %mold 0
2427+ %value (tail-can val.d)
2428+ ==
2429+::
20042430:: +is-operand-start: a token an operand starts with; where an operand
20052431:: goes, |= is the constructor's (section 3)
20062432::
@@ -2093,10 +2519,11 @@
20932519:: (section 3), so it never backtracks. A loop over items is a trap
20942520:: whose every step, through +then, is a tail call, so a long module
20952521:: grows no stack; only nesting does, and a line's nesting is bounded
2096−:: by its length.
2522+:: by its length. all is the whole token list, which only errors
2523+:: read (+stray).
20972524::
20982525++ parser
2099− |_ file=path
2526+ |_ [file=path all=(list token)]
21002527 ::
21012528 :: +bad: "expected <want>, found <the next token>" (+fail)
21022529 ::
@@ -2112,82 +2539,161 @@
21122539 ^- [%| p=error]
21132540 (fail-why file ts want why)
21142541 ::
2115− :: +bad-space: a tight form that found a space after prev
2542+ :: +bad-in: +bad where a place begins whose first characters are the
2543+ :: mask can (+fail-in)
2544+ ::
2545+ ++ bad-in
2546+ |= [ts=(list token) want=tape can=@]
2547+ ^- [%| p=error]
2548+ (fail-in file ts want can)
2549+ ::
2550+ :: +bad-in-why: +bad-in with a hint (+fail-in-why)
2551+ ::
2552+ ++ bad-in-why
2553+ |= [ts=(list token) want=tape can=@ why=tape]
2554+ ^- [%| p=error]
2555+ (fail-in-why file ts want can why)
2556+ ::
2557+ :: +bad-space: a tight form that found no next token right after prev
21162558 :: (+fail-space)
21172559 ::
21182560 ++ bad-space
21192561 |= [prev=token ts=(list token) want=tape]
21202562 ^- [%| p=error]
2121− (fail-space file prev ts want)
2563+ (fail-space file prev ts want "")
21222564 ::
2123− :: +bad-at: an error inside a token (section 3, Errors)
2565+ :: +bad-at: an error inside a token, or at the end of a line
21242566 ::
21252567 ++ bad-at
21262568 |= [at=loc msg=tape]
21272569 ^- [%| p=error]
21282570 [%| file line.at col.at msg]
21292571 ::
2130− :: +bad-end: a line that should end and goes on
2572+ :: +closing: what a bracket op still needs, its closer close
2573+ ::
2574+ ++ closing
2575+ |= [op=token close=tape]
2576+ ^- tape
2577+ "`{close}` to close the {(show-found op)} at {(show-loc beg.at.op)}"
2578+ ::
2579+ :: +bad-end: a line that should end and goes on, after a call
21312580 ::
21322581 ++ bad-end
21332582 |= ts=(list token)
21342583 ^- [%| p=error]
2135− ?. ?=([[* * %indent] *] ts) (bad ts "the end of the line")
2136− %^ bad-why ts "the end of the line"
2137− %+ weld "only a bracket open at the end of a line, "
2138− "or a rune's body, takes deeper lines"
2584+ (bad-end-in ts operand-mask)
2585+ ::
2586+ :: +bad-end-in: +bad-end after a construct that text beginning with
2587+ :: a character of the mask can could still go on, as more operands go
2588+ :: on a call; at an error token whose text can't, at that text's
2589+ :: start (+fail-in): +$ x @ ?: fails at the ?
2590+ ::
2591+ ++ bad-end-in
2592+ |= [ts=(list token) can=@]
2593+ ^- [%| p=error]
2594+ =/ want=tape "the end of the line"
2595+ ?: ?=([[* * %indent] *] ts)
2596+ %^ bad-why ts want
2597+ %+ weld "only a bracket open at the end of a line, "
2598+ "or a rune's body, takes deeper lines"
2599+ ?: &(?=(^ ts) (stray i.ts))
2600+ (bad-why ts want "this {(show-found i.ts)} closes no bracket")
2601+ ?. ?=([[* * [%error *]] *] ts) (bad ts want)
2602+ =/ ok=@ ?:(tight.i.ts after-mask can)
2603+ ?: |(=(':' c.lex.i.ts) (in c.lex.i.ts ok)) (bad ts want)
2604+ [%| (moved file want i.ts)]
2605+ ::
2606+ :: +no-gap: a token tight where a space goes, after a rune, a name, a
2607+ :: sample or a pattern; at an error token, whose text can't go tight
2608+ :: there unless it is a comment's :, at that text's start (+fail-in)
2609+ ::
2610+ ++ no-gap
2611+ |= [ts=(list token) want=tape]
2612+ ^- [%| p=error]
2613+ ?. &(?=([[* * [%error *]] *] ts) !=(':' c.lex.i.ts)) (bad ts want)
2614+ [%| (moved file want i.ts)]
21392615 ::
21402616 :: +no-space: a token tight after an item, where a space goes
21412617 ::
21422618 ++ no-space
21432619 |= ts=(list token)
21442620 ^- [%| p=error]
2621+ =/ te=(unit error) (tight-error file ts)
2622+ ?^ te [%| u.te]
21452623 ?. ?=([[* * %'='] *] ts) (bad ts "a space between items")
21462624 %^ bad-why ts "a space between items"
21472625 "`name=value` goes in a cell, as [a=1], or a change, as m(a=1)"
21482626 ::
2149− :: +no-operand: a token where an operand goes that starts none, with
2150− :: a hint for the left-out forms the lexer can't see (2.6)
2627+ :: +no-space-pattern: +no-space in a cell pattern
21512628 ::
2152− ++ no-operand
2629+ ++ no-space-pattern
21532630 |= ts=(list token)
21542631 ^- [%| p=error]
2632+ ?. ?=([[* * %'='] *] ts) (no-space ts)
2633+ %^ bad-why ts "a space between items"
2634+ "patterns take no `name=`: a bare name binds, as [a b]"
2635+ ::
2636+ :: +no-operand: a token where an expression or an operand goes that
2637+ :: starts none (can: what may start one), with a hint for the left-out
2638+ :: forms the lexer can't see (2.6) and other likely slips
2639+ ::
2640+ ++ no-operand
2641+ |= [ts=(list token) can=@]
2642+ ^- [%| p=error]
21552643 =/ want=tape "an expression"
21562644 ?: ?=([[* * %'='] [* %& %'('] *] ts)
21572645 (bad-why ts want "`=(a b)` is left out: eq is a gate")
21582646 ?: ?=([[* * %'='] [* %& %'/'] *] ts)
21592647 (bad-why ts want "`=/` is left out: `++` defines values")
2648+ ?: ?=([[* * %'='] [* %& %'+'] *] ts)
2649+ (bad-why ts want "`=+` is left out: `++` defines values")
2650+ ?: ?=([[* * %'='] [* %& %'?'] *] ts)
2651+ (bad-why ts want "`=?` is left out: `++` defines values")
2652+ ?: ?& ?=([[* * %'='] [* %& [%error *]] *] ts)
2653+ =('.' c.lex.i.t.ts)
2654+ ==
2655+ (bad-why ts want "`=.` is left out: `++` defines values")
21602656 ?: ?=([[* * %'*'] *] ts)
21612657 (bad-why ts want "`*mold` is left out: no defaults")
21622658 ?: ?=([[* * %'+'] *] ts)
21632659 (bad-why ts want "a pair takes no spaces, as gap+%s2")
2660+ ?: ?=([[* * %'?'] *] ts)
2661+ %: bad-in-why ts want can
2662+ "`?` alone is the loobean mold, and `?-` the branch"
2663+ ==
21642664 ?: &(?=(^ ts) (is-rune i.ts))
2165− (bad-why ts want "a rune here goes in parentheses")
2166− (bad ts want)
2665+ (bad-in-why ts want can "a rune here goes in parentheses")
2666+ ?: &(?=(^ ts) (stray i.ts))
2667+ (bad-why ts want "this {(show-found i.ts)} closes no bracket")
2668+ (bad-in ts want can)
2669+ ::
2670+ :: +no-name: a token where a name goes that isn't one
2671+ ::
2672+ ++ no-name
2673+ |= ts=(list token)
2674+ ^- [%| p=error]
2675+ ?: ?=([[* * [%tvar *]] *] ts)
2676+ (bad-why ts "a name" "a name starts with a lowercase letter")
2677+ ?: ?=([[* * [%wing *]] *] ts)
2678+ (bad-in-why ts "a name" lower-mask "a name has no `.`")
2679+ (bad-in ts "a name" lower-mask)
21672680 ::
21682681 :: +unclosed: where the closer of the bracket op opened should be
21692682 ::
21702683 ++ unclosed
21712684 |= [op=token close=tape ts=(list token)]
21722685 ^- [%| p=error]
2173− =/ want=tape
2174− "`{close}` to close the {(show-found op)} at {(show-loc beg.at.op)}"
2686+ =/ want=tape (closing op close)
21752687 ?. ?=([[* * %indent] *] ts) (bad ts want)
21762688 (bad-why ts want "this bracket closes on its line")
21772689 ::
21782690 :: +unclosed-open: a bracket that may be left open, whose line ends
2179− :: with neither its closer nor deeper lines; last is its last item's
2180− :: span, and noun names its items
2691+ :: with neither its closer nor deeper lines; noun names its items
21812692 ::
21822693 ++ unclosed-open
2183− |= [op=token close=tape noun=tape last=(unit span) ts=(list token)]
2694+ |= [op=token close=tape noun=tape ts=(list token)]
21842695 ^- [%| p=error]
21852696 ?. ?=([[* * ?(%newline %dedent)] *] ts) (unclosed op close ts)
2186− :: its last item ends on a later line: an item left open took them
2187− ?: &(?=(^ last) (gth line.end.u.last line.beg.at.op))
2188− %^ bad-why ts
2189− "`{close}` to close the {(show-found op)} at {(show-loc beg.at.op)}"
2190− "only the last bracket open at the end of a line takes the deeper lines"
21912697 (bad ts "`{close}` or {noun} on a deeper line")
21922698 ::
21932699 :: +wide-rune: a rune followed tight; txt( is a left-out wide form
@@ -2196,7 +2702,7 @@
21962702 |= [txt=tape ts=(list token)]
21972703 ^- [%| p=error]
21982704 =/ want=tape "a space after `{txt}`"
2199− ?. ?=([[* * %'('] *] ts) (bad ts want)
2705+ ?. ?=([[* * %'('] *] ts) (no-gap ts want)
22002706 %^ bad-why ts want
22012707 "the wide form `{txt}(…)` is left out: indentation covers it"
22022708 ::
@@ -2208,6 +2714,62 @@
22082714 %^ bad-why ts "a named item"
22092715 "a change's items are named, as in m(done=%.y)"
22102716 ::
2717+ :: +doomed: where a part of a line, read from ts up to after, took
2718+ :: the deeper lines while what holds it needs more: a closer on the
2719+ :: line, or deeper lines of its own. No later line can give it that,
2720+ :: so the error is at the end of the line that took them (section 3,
2721+ :: Errors). want is what it needs. Only an error path calls this, and
2722+ :: it looks only when after begins with NEWLINE or DEDENT, so it
2723+ :: costs nothing on the way to a tree.
2724+ ::
2725+ ++ doomed
2726+ |= [ts=(list token) after=(list token) want=tape]
2727+ ^- (unit [%| p=error])
2728+ ?. ?=([[* * ?(%newline %dedent)] *] after) ~
2729+ =/ ind=(unit token) (took ts after)
2730+ ?~ ind ~
2731+ :- ~
2732+ %+ bad-at beg.at.u.ind
2733+ ;: weld
2734+ "expected {want}, found the end of the line; the deeper lines "
2735+ "go to the last bracket or rune left open on this line"
2736+ ==
2737+ ::
2738+ :: +took: the INDENT among the tokens from ts up to after, if any
2739+ ::
2740+ ++ took
2741+ |= [ts=(list token) after=(list token)]
2742+ ^- (unit token)
2743+ ?~ after ~
2744+ =/ stop=loc beg.at.i.after
2745+ |- ^- (unit token)
2746+ ?~ ts ~
2747+ ?. (loc-lth beg.at.i.ts stop) ~
2748+ ?: ?=(%indent lex.i.ts) `i.ts
2749+ $(ts t.ts)
2750+ ::
2751+ :: +stray: whether a ) or ] closes no bracket opened before it on its
2752+ :: line, or none inside the interpolation it is in
2753+ ::
2754+ ++ stray
2755+ |= t=token
2756+ ^- ?
2757+ ?. ?=(?(%')' %']') lex.t) |
2758+ =| open=(list ?)
2759+ =/ ts=(list token) all
2760+ |- ^- ?
2761+ ?~ ts |
2762+ =* u i.ts
2763+ ?: =(at.u at.t) |(?=(~ open) !i.open)
2764+ ?: (is-layout u) $(ts t.ts, open ~)
2765+ ?: ?=(?(%'(' %'[' %'~[' %'|=(' %'$?(' %'$-(') lex.u)
2766+ $(ts t.ts, open [& open])
2767+ ?: ?=([%str-head *] lex.u) $(ts t.ts, open [| open])
2768+ ?: ?=([%str-mid *] lex.u) $(ts t.ts, open [| ?~(open ~ t.open)])
2769+ ?: |(?=(?(%')' %']') lex.u) ?=([%str-tail *] lex.u))
2770+ $(ts t.ts, open ?~(open ~ t.open))
2771+ $(ts t.ts)
2772+ ::
22112773 :: +read-module: { import NEWLINE } { definition NEWLINE }, then the
22122774 :: end of the tokens
22132775 ::
@@ -2218,15 +2780,17 @@
22182780 |- ^- (each module error)
22192781 ?: ?=([[* * ?(%'/-' %'/%' %'/=')] *] ts)
22202782 ;< [im=import after=(list token)] then (read-import ts)
2221− ?. ?=([[* * %newline] *] after) (bad-end after)
2783+ ?. ?=([[* * %newline] *] after) (bad-end-in after 0)
22222784 $(ims [im ims], ts t.after)
22232785 =| defs=(list def)
22242786 |- ^- (each module error)
22252787 ?~ ts [%& (flop ims) (flop defs)]
22262788 ?: ?=([[* * ?(%'/-' %'/%' %'/=')] *] ts)
22272789 (bad-why ts "a definition" "imports come first")
2228− ;< [d=def after=(list token)] then (read-def ts)
2229− ?. ?=([[* * %newline] *] after) (bad-end after)
2790+ :: what may begin the line: a definition, or before any, an import
2791+ =/ can=@ ?~(defs (con plus-mask fas-mask) plus-mask)
2792+ ;< [d=def after=(list token)] then (read-def ts can)
2793+ ?. ?=([[* * %newline] *] after) (bad-end-in after (def-can d))
22302794 $(defs [d defs], ts t.after)
22312795 ::
22322796 :: +read-import: /- name, /% term, or /= name pathlit
@@ -2238,34 +2802,36 @@
22382802 =* g i.ts
22392803 =/ rest=(list token) t.ts
22402804 ?: &(?=(^ rest) tight.i.rest)
2241− (bad rest "a space after {(show-found g)}")
2805+ (no-gap rest "a space after {(show-found g)}")
22422806 ?: =(%'/%' lex.g)
22432807 ?: ?=([[* * [%lit %term %tas *]] *] rest)
22442808 [%& [%mark [beg.at.g end.at.i.rest] val.p.lex.i.rest] t.rest]
22452809 =/ want=tape "a mark's term, as `%todo-action`"
2246− ?. ?=([[* * [%name *]] *] rest) (bad rest want)
2810+ ?. ?=([[* * [%name *]] *] rest) (bad-in rest want cen-mask)
22472811 (bad-why rest want "`/%` takes no face: it names the type after its mark")
2248− ?. ?=([[* * [%name *]] *] rest) (bad rest "a name")
2812+ ?. ?=([[* * [%name *]] *] rest) (no-name rest)
22492813 =* nam i.rest
22502814 ?. =(%'/=' lex.g)
22512815 [%& [%sur [beg.at.g end.at.nam] p.lex.nam] t.rest]
22522816 =/ more=(list token) t.rest
2253− ?: &(?=(^ more) tight.i.more) (bad more "a space after the name")
2817+ ?: &(?=(^ more) tight.i.more) (no-gap more "a space after the name")
22542818 ?. ?=([[* * %'/'] *] more)
2255− (bad more "a module's path, as /ui/components/card")
2819+ (bad-in more "a module's path, as /ui/components/card" fas-mask)
22562820 ;< [[sp=span segs=(list @ta)] after=(list token)] then
2257− (read-pathlit i.more t.more)
2821+ (read-pathlit i.more t.more |)
22582822 [%& [%jibb [beg.at.g end.sp] p.lex.nam segs] after]
22592823 ::
22602824 :: +read-pathlit: after a path's /, its knots, each after a tight /
2261− :: and tight itself; / alone is the empty path
2825+ :: and tight itself; / alone is the empty path where empty allows it,
2826+ :: in an expression but not an import (doc question)
22622827 ::
22632828 ++ read-pathlit
2264− |= [sl=token ts=(list token)]
2829+ |= [sl=token ts=(list token) empty=?]
22652830 ^- (pare [span (list @ta)])
22662831 ?. ?=([[* %& [%knot *]] *] ts)
22672832 ?: &(?=(^ ts) tight.i.ts !(is-closer i.ts))
22682833 (bad ts "a path segment")
2834+ ?. empty (bad-space sl ts "a path segment")
22692835 [%& [at.sl ~] ts]
22702836 =/ segs=(list @ta) ~[p.lex.i.ts]
22712837 =/ fin=loc end.at.i.ts
@@ -2280,10 +2846,11 @@
22802846 (bad-space i.rest nex "a path segment")
22812847 ::
22822848 :: +read-def: ++ name, then an expression or a body; +$ name, then a
2283− :: mold on its line or alone on a deeper one
2849+ :: mold on its line or alone on a deeper one. can is what may begin
2850+ :: a line where a definition goes (+fail-in).
22842851 ::
22852852 ++ read-def
2286− |= ts=(list token)
2853+ |= [ts=(list token) can=@]
22872854 ^- (pare def)
22882855 ?~ ts (bad ts "a definition")
22892856 =* rune i.ts
@@ -2295,18 +2862,23 @@
22952862 ?: (is-closer rune)
22962863 %^ bad-why ts "a definition"
22972864 "this closes no bracket, as one open at the end of its line needs none"
2298− ?. =(%'+$' lex.rune) (bad ts "a definition")
2865+ =/ want=tape
2866+ ?.((in '/' can) "a definition" "an import or a definition")
2867+ ?: =(%'+' lex.rune)
2868+ (bad-in-why ts want can "`+` begins `++` or `+$`")
2869+ ?. =(%'+$' lex.rune) (bad-in ts want can)
22992870 ;< [nam=term after=(list token)] then (read-def-name rune t.ts)
23002871 ?: ?=([[* * %indent] *] after)
23012872 ;< [s=shape more=(list token)] then (read-mold t.after)
23022873 ?: ?=([[* * %dedent] *] more)
23032874 [%& [%mold [beg.at.rune end:(span-of s)] nam s] t.more]
2304− ?. ?=([[* * %newline] *] more) (bad-end more)
2875+ ?. ?=([[* * %newline] *] more) (bad-end-in more 0)
23052876 %^ bad-why more "the end of the mold"
23062877 "a `+$` takes one mold; a union is `$?` with its cases below"
23072878 ?: ?=([[* * ?(%newline %dedent)] *] after)
23082879 (bad after "a mold, on its line or a deeper one")
2309− ?: &(?=(^ after) tight.i.after) (bad after "a space after the name")
2880+ ?: &(?=(^ after) tight.i.after)
2881+ (no-gap after "a space after the name")
23102882 ;< [s=shape more=(list token)] then (read-mold after)
23112883 [%& [%mold [beg.at.rune end:(span-of s)] nam s] more]
23122884 ::
@@ -2316,8 +2888,8 @@
23162888 |= [rune=token ts=(list token)]
23172889 ^- (pare term)
23182890 ?: &(?=(^ ts) tight.i.ts)
2319− (bad ts "a space after {(show-found rune)}")
2320− ?. ?=([[* * [%name *]] *] ts) (bad ts "a name")
2891+ (no-gap ts "a space after {(show-found rune)}")
2892+ ?. ?=([[* * [%name *]] *] ts) (no-name ts)
23212893 [%& p.lex.i.ts t.ts]
23222894 ::
23232895 :: +read-expr-or-body: a space and an expression on the line, or a
@@ -2329,7 +2901,7 @@
23292901 ?: ?=([[* * %indent] *] ts) (read-body t.ts)
23302902 ?: ?=([[* * ?(%newline %dedent)] *] ts)
23312903 (bad ts "an expression, or a body on deeper lines")
2332− ?: &(?=(^ ts) tight.i.ts) (bad ts "a space after {what}")
2904+ ?: &(?=(^ ts) tight.i.ts) (no-gap ts "a space after {what}")
23332905 (read-expr ts)
23342906 ::
23352907 :: +read-body: after its INDENT, { definition NEWLINE } expr DEDENT
@@ -2340,16 +2912,20 @@
23402912 =| defs=(list def)
23412913 |- ^- (pare expr)
23422914 ?: ?=([[* * ?(%'++' %'+$')] *] ts)
2343− ;< [d=def after=(list token)] then (read-def ts)
2915+ ;< [d=def after=(list token)] then (read-def ts plus-mask)
23442916 ?: ?=([[* * %newline] *] after) $(defs [d defs], ts t.after)
2345− ?. ?=([[* * %dedent] *] after) (bad-end after)
2917+ ?. ?=([[* * %dedent] *] after) (bad-end-in after (def-can d))
23462918 (bad after "the body's final expression, after its definitions")
2919+ ?: ?=([[* * %'+'] *] ts)
2920+ %: bad-in-why ts "a definition or an expression" plus-mask
2921+ "`+` begins `++` or `+$`"
2922+ ==
23472923 ;< [e=expr after=(list token)] then (read-expr ts)
23482924 ?: ?=([[* * %dedent] *] after)
23492925 =/ ds=(list def) (flop defs)
23502926 =/ beg=loc ?~(ds beg:(span-of e) beg:(span-of i.ds))
23512927 [%& [%body [beg end:(span-of e)] ds e] t.after]
2352− ?. ?=([[* * %newline] *] after) (bad-end after)
2928+ ?. ?=([[* * %newline] *] after) (bad-end-in after (tail-can e))
23532929 %^ bad-why after "the end of the body"
23542930 "a body's final expression is its last line"
23552931 ::
@@ -2374,7 +2950,7 @@
23742950 |= ts=(list token)
23752951 ^- (pare expr)
23762952 ;< [els=(list expr) after=(list token)] then (read-operands ts)
2377− ?~ els (no-operand ts)
2953+ ?~ els (no-operand ts expr-mask)
23782954 [%& (call-of els) after]
23792955 ::
23802956 :: +read-operands: a call's operands, or those on a group's first
@@ -2387,15 +2963,27 @@
23872963 |- ^- (pare (list expr))
23882964 ?~ ts [%& (flop els) ts]
23892965 =* t i.ts
2390− ?: (ends-call t) [%& (flop els) ts]
2966+ ?: (ends-call t)
2967+ :: an error token whose text can't go tight after an operand
2968+ =/ te=(unit error)
2969+ :: after-mask without its =
2970+ ?~(els ~ (tight-error-in file ts (mix after-mask tis-mask)))
2971+ ?^ te [%| u.te]
2972+ :: or, past a space, can't begin one (+fail-in)
2973+ ?: ?& ?=(^ els) ?=([%error *] lex.t) !tight.t
2974+ !=(':' c.lex.t) !(in c.lex.t operand-mask)
2975+ ==
2976+ [%| (moved file "an expression" t)]
2977+ [%& (flop els) ts]
23912978 ?: &(tight.t ?=(^ els)) (no-space ts)
23922979 ?: (is-operand-start t)
23932980 ;< [e=expr more=(list token)] then (read-operand ts)
23942981 $(els [e els], ts more)
23952982 ?: &(?=(^ els) (is-rune t))
2396− %^ bad-why ts "an expression"
2397− "inside a call, a rune goes in parentheses"
2398− (no-operand ts)
2983+ %: bad-in-why ts "an expression" operand-mask
2984+ "inside a call, a rune goes in parentheses"
2985+ ==
2986+ (no-operand ts ?~(els expr-mask operand-mask))
23992987 ::
24002988 :: +read-operand: one operand, told by its first token and, after a
24012989 :: name or a wing, by a tight ( or +
@@ -2405,7 +2993,7 @@
24052993 ^- (pare expr)
24062994 ?~ ts (bad ts "an expression")
24072995 =* t i.ts
2408− ?+ lex.t (no-operand ts)
2996+ ?+ lex.t (no-operand ts operand-mask)
24092997 [%lit *] [%& [%lit at.t p.lex.t] t.ts]
24102998 [%str *] [%& [%str at.t (text-piece p.lex.t)] t.ts]
24112999 [%str-head *] (read-string t t.ts)
@@ -2454,11 +3042,19 @@
24543042 ::
24553043 :: +read-ctor: |= and a term, with no space: a case's constructor
24563044 ::
3045+ :: Where an operand goes, |= can only be a constructor or begin |=(,
3046+ :: so a tall gate there fails at the space after |=.
3047+ ::
24573048 ++ read-ctor
24583049 |= [bar=token ts=(list token)]
24593050 ^- (pare expr)
2460− ?: |(?=(~ ts) !tight.i.ts) (bad-space bar ts "a term")
2461− ?. ?=([[* * [%lit %term *]] *] ts) (bad ts "a term")
3051+ ?: |(?=(~ ts) !tight.i.ts)
3052+ %: fail-space file bar ts "`(` or a term"
3053+ ?: ?=([[* * [%lit %term *]] *] ts)
3054+ "a case's constructor takes its term with no space, as |=%got"
3055+ "a gate in an operand is |=(a body)"
3056+ ==
3057+ ?. ?=([[* * [%lit %term *]] *] ts) (bad-in ts "a term" cen-mask)
24623058 [%& [%ctor [beg.at.bar end.at.i.ts] p.lex.i.ts] t.ts]
24633059 ::
24643060 :: +read-path: a path literal, as /posts/~zod (doc question)
@@ -2467,7 +3063,7 @@
24673063 |= [sl=token ts=(list token)]
24683064 ^- (pare expr)
24693065 ;< [[sp=span segs=(list @ta)] after=(list token)] then
2470− (read-pathlit sl ts)
3066+ (read-pathlit sl ts &)
24713067 [%& [%path sp segs] after]
24723068 ::
24733069 :: +read-qath: %/, then its segments, knots or (expr), each after a
@@ -2502,7 +3098,10 @@
25023098 ?. ?=([[* * %'('] *] ts) (bad ts "a path segment")
25033099 =* par i.ts
25043100 ;< [e=expr after=(list token)] then (read-expr t.ts)
2505− ?. ?=([[* * %')'] *] after) (unclosed par ")" after)
3101+ ?. ?=([[* * %')'] *] after)
3102+ =/ dm (doomed t.ts after (closing par ")"))
3103+ ?^ dm u.dm
3104+ (unclosed par ")" after)
25063105 [%& [[%expr e] end.at.i.after] t.after]
25073106 ::
25083107 :: +read-string: after its str-head, a string's interpolations and
@@ -2521,7 +3120,10 @@
25213120 $(ps (weld (text-piece p.lex.i.after) ps), op i.after, ts t.after)
25223121 ?. ?=([[* * [%str-tail *]] *] after)
25233122 =/ brace=loc [line.end.at.op (dec (max 2 col.end.at.op))]
2524− (bad after "`}` to close the `\{` at {(show-loc brace)}")
3123+ =/ want=tape "`}` to close the `\{` at {(show-loc brace)}"
3124+ =/ dm (doomed ts after want)
3125+ ?^ dm u.dm
3126+ (bad after want)
25253127 =. ps (weld (text-piece p.lex.i.after) ps)
25263128 [%& [%str [beg.at.head end.at.i.after] (flop ps)] t.after]
25273129 ::
@@ -2537,15 +3139,19 @@
25373139 ^- (pare expr)
25383140 ?: (is-rune-start ts)
25393141 ;< [e=expr after=(list token)] then (read-expr ts)
2540− ?. ?=([[* * %')'] *] after) (unclosed par ")" after)
3142+ ?. ?=([[* * %')'] *] after)
3143+ =/ dm (doomed ts after (closing par ")"))
3144+ ?^ dm u.dm
3145+ (unclosed par ")" after)
25413146 [%& [%group [beg.at.par end.at.i.after] e] t.after]
25423147 ;< [els=(list expr) after=(list token)] then (read-operands ts)
25433148 ?: ?=([[* * %')'] *] after)
25443149 ?~ els (bad after "an expression")
25453150 [%& [%group [beg.at.par end.at.i.after] (call-of els)] t.after]
25463151 ?. ?=([[* * %indent] *] after)
2547− =/ last=(unit span) ?~(els ~ `(span-of (rear els)))
2548− (unclosed-open par ")" "an argument" last after)
3152+ =/ dm (doomed ts after (closing par ")"))
3153+ ?^ dm u.dm
3154+ (unclosed-open par ")" "an argument" after)
25493155 ;< [ls=(list item) more=(list token)] then
25503156 (read-lines %group t.after)
25513157 =/ inner=expr (call-of (weld els (turn ls |=(i=item val.i))))
@@ -2554,6 +3160,8 @@
25543160 :: +read-bracket: a tuple's, list's or change's items, to its closer
25553161 :: on the line, or to the end of its lines below when left open
25563162 ::
3163+ :: pre is the tokens from the last item on, for +doomed.
3164+ ::
25573165 ++ read-bracket
25583166 |= $: kind=?(%tuple %list %change)
25593167 op=token
@@ -2563,6 +3171,7 @@
25633171 ^- (pare expr)
25643172 =/ close=?(%')' %']') ?:(?=(%change kind) %')' %']')
25653173 =| its=(list item)
3174+ =| pre=(list token)
25663175 |- ^- (pare expr)
25673176 ?~ ts (bad ts "an item")
25683177 =* t i.ts
@@ -2571,15 +3180,16 @@
25713180 ?: (is-closer t) (unclosed op (trip close) ts)
25723181 ?: ?=(%indent lex.t)
25733182 ;< [ls=(list item) more=(list token)] then (read-lines kind t.ts)
2574− =/ all=(list item) (weld (flop its) ls)
2575− =/ fin=loc ?~(all end.at.op end.at:(rear all))
2576− [%& (bracket-node kind op target all fin) more]
3183+ =/ every=(list item) (weld (flop its) ls)
3184+ =/ fin=loc ?~(every end.at.op end.at:(rear every))
3185+ [%& (bracket-node kind op target every fin) more]
25773186 ?: ?=(?(%newline %dedent) lex.t)
2578− =/ last=(unit span) ?~(its ~ `at.i.its)
2579− (unclosed-open op (trip close) "an item" last ts)
3187+ =/ dm (doomed pre ts (closing op (trip close)))
3188+ ?^ dm u.dm
3189+ (unclosed-open op (trip close) "an item" ts)
25803190 ?: &(tight.t ?=(^ its)) (no-space ts)
25813191 ;< [i=item more=(list token)] then (read-item kind ts)
2582− $(its [i its], ts more)
3192+ $(its [i its], ts more, pre ts)
25833193 ::
25843194 :: +read-item: [ name= ] operand; a tuple's item may be named, a
25853195 :: change's must be, a list's is not
@@ -2595,8 +3205,9 @@
25953205 [%& [[beg.at.nam end:(span-of v)] `p.lex.nam v] after]
25963206 ?: ?=(%change kind) (unnamed ts)
25973207 ?: &(?=(^ ts) (is-rune i.ts))
2598− %^ bad-why ts "an expression"
2599− "inside brackets, a rune goes in parentheses"
3208+ %: bad-in-why ts "an expression" operand-mask
3209+ "inside brackets, a rune goes in parentheses"
3210+ ==
26003211 ;< [v=expr after=(list token)] then (read-operand ts)
26013212 [%& [(span-of v) ~ v] after]
26023213 ::
@@ -2611,7 +3222,7 @@
26113222 ;< [l=item after=(list token)] then (read-line kind ts)
26123223 ?: ?=([[* * %newline] *] after) $(ls [l ls], ts t.after)
26133224 ?: ?=([[* * %dedent] *] after) [%& (flop [l ls]) t.after]
2614− ?. ?=([[* * ?(%')' %']')] *] after) (bad-end after)
3225+ ?. ?=([[* * ?(%')' %']')] *] after) (bad-end-in after (tail-can val.l))
26153226 %^ bad-why after "the end of the line"
26163227 "a bracket open at the end of its line takes no closer"
26173228 ::
@@ -2622,6 +3233,10 @@
26223233 ++ read-line
26233234 |= [kind=?(%tuple %list %change %group) ts=(list token)]
26243235 ^- (pare item)
3236+ ?: ?=([[* * ?(%')' %']')] *] ts)
3237+ %^ bad-why ts "an item"
3238+ %+ weld "a bracket open at the end of its line takes no closer: "
3239+ "its items end at the first line that isn't deeper"
26253240 ?: ?& ?=(?(%tuple %change) kind)
26263241 ?=([[* * [%name *]] [* %& %'='] *] ts)
26273242 ==
@@ -2641,17 +3256,22 @@
26413256 ^- (pare expr)
26423257 ;< [s=sample after=(list token)] then (read-sample ts)
26433258 ?: ?=([[* * %')'] *] after) (bad after "the gate's body")
2644− ?: &(?=(^ after) tight.i.after) (bad after "a space after the sample")
3259+ ?: &(?=(^ after) tight.i.after)
3260+ (no-gap after "a space after the sample")
3261+ =/ dm (doomed ts after "the gate's body")
3262+ ?^ dm u.dm
26453263 ?: &(?=(^ after) (is-rune i.after))
2646− %^ bad-why after "an expression"
2647− "the wide gate's body is an operand, so a rune goes in parentheses"
3264+ %: bad-in-why after "an expression" operand-mask
3265+ "the wide gate's body is an operand, so a rune goes in parentheses"
3266+ ==
26483267 ;< [b=expr more=(list token)] then (read-operand after)
26493268 ?: ?=([[* * %')'] *] more)
26503269 [%& [%gate-wide [beg.at.op end.at.i.more] s b] t.more]
3270+ =/ dn (doomed after more (closing op ")"))
3271+ ?^ dn u.dn
26513272 ?. &(?=(^ more) !tight.i.more (is-operand-start i.more))
26523273 (unclosed op ")" more)
2653− %^ bad-why more
2654− "`)` to close the `|=(` at {(show-loc beg.at.op)}"
3274+ %^ bad-why more (closing op ")")
26553275 "the wide gate's body is one operand, so a call goes in parentheses"
26563276 ::
26573277 :: +read-gate: |= sample, then an expression or a body
@@ -2659,8 +3279,13 @@
26593279 ++ read-gate
26603280 |= [bar=token ts=(list token)]
26613281 ^- (pare expr)
2662− ?: &(?=(^ ts) tight.i.ts) (bad ts "a space after `|=`")
3282+ ?: &(?=(^ ts) tight.i.ts)
3283+ :: a % could begin a constructor's term, as |=%got
3284+ ?: =('%' (first-char i.ts)) (bad-in ts "a term" cen-mask)
3285+ (no-gap ts "a space after `|=`")
26633286 ;< [s=sample after=(list token)] then (read-sample ts)
3287+ =/ dm (doomed ts after "an expression, or a body on deeper lines")
3288+ ?^ dm u.dm
26643289 ;< [e=expr more=(list token)] then
26653290 (read-expr-or-body "the sample" after)
26663291 [%& [%gate [beg.at.bar end:(span-of e)] s e] more]
@@ -2672,6 +3297,8 @@
26723297 ^- (pare expr)
26733298 ?: &(?=(^ ts) tight.i.ts) (wide-rune "^-" ts)
26743299 ;< [s=shape after=(list token)] then (read-mold ts)
3300+ =/ dm (doomed ts after "an expression, or a body on deeper lines")
3301+ ?^ dm u.dm
26753302 ;< [e=expr more=(list token)] then
26763303 (read-expr-or-body "the mold" after)
26773304 [%& [%cast [beg.at.ket end:(span-of e)] s e] more]
@@ -2681,9 +3308,11 @@
26813308 ++ read-trace
26823309 |= [sig=token ts=(list token)]
26833310 ^- (pare expr)
2684− ?: &(?=(^ ts) tight.i.ts) (bad ts "a space after `~&`")
3311+ ?: &(?=(^ ts) tight.i.ts) (wide-rune "~&" ts)
26853312 ;< [v=expr after=(list token)] then (read-expr ts)
26863313 ?. ?=([[* * %indent] *] after)
3314+ =/ dm (doomed ts after "`~&`'s body on deeper lines")
3315+ ?^ dm u.dm
26873316 (bad after "`~&`'s body on deeper lines")
26883317 ;< [b=expr more=(list token)] then (read-body t.after)
26893318 [%& [%trace [beg.at.sig end:(span-of b)] v b] more]
@@ -2696,13 +3325,15 @@
26963325 ?: &(?=(^ ts) tight.i.ts) (wide-rune "?-" ts)
26973326 ;< [s=expr after=(list token)] then (read-expr ts)
26983327 ?. ?=([[* * %indent] *] after)
3328+ =/ dm (doomed ts after "`?-`'s arms on deeper lines")
3329+ ?^ dm u.dm
26993330 (bad after "`?-`'s arms on deeper lines")
27003331 =| arms=(list arm)
27013332 =/ rest=(list token) t.after
27023333 |- ^- (pare expr)
27033334 ;< [a=arm more=(list token)] then (read-arm rest)
27043335 ?: ?=([[* * %newline] *] more) $(arms [a arms], rest t.more)
2705− ?. ?=([[* * %dedent] *] more) (bad-end more)
3336+ ?. ?=([[* * %dedent] *] more) (bad-end-in more (tail-can val.a))
27063337 [%& [%branch [beg.at.wut end.at.a] s (flop [a arms])] t.more]
27073338 ::
27083339 :: +read-arm: a pattern, then an expression or a body
@@ -2714,6 +3345,9 @@
27143345 ?: ?=([[* %& %'+'] *] after)
27153346 %^ bad-why after "a space after the pattern"
27163347 "patterns take no pairs: write a cell, as [%gap %s2]"
3348+ ?: ?=([[* %& %'='] *] after)
3349+ %^ bad-why after "a space after the pattern"
3350+ "patterns take no `name=`: a bare name binds, as [a b]"
27173351 ;< [e=expr more=(list token)] then
27183352 (read-expr-or-body "the pattern" after)
27193353 [%& [[beg:(span-of p) end:(span-of e)] p e] more]
@@ -2721,17 +3355,18 @@
27213355 :: +read-pattern: a term, number, string, ship, loobean, ~, * or name,
27223356 :: or a cell of patterns
27233357 ::
2724− :: A date, duration or knot fails at its second character, since ~
2725− :: alone is null and no ship goes on so; ~[ at its [; and a string
2726− :: with {…} at its { (section 3, Errors).
3358+ :: Where a pattern can't take a token, the error points where the
3359+ :: token stops being a pattern's start (+fail-in): a date or knot
3360+ :: at its second character, since ~ alone is null; a duration at its
3361+ :: third, as ~s could begin the ship ~sev; ~[ at its [; a string
3362+ :: with {…} at its {; a wing at its first dot.
27273363 ::
27283364 ++ read-pattern
27293365 |= ts=(list token)
27303366 ^- (pare pattern)
27313367 ?~ ts (bad ts "a pattern")
27323368 =* t i.ts
2733− =/ next=loc [line.beg.at.t +(col.beg.at.t)]
2734− ?+ lex.t (bad ts "a pattern")
3369+ ?+ lex.t (bad-in ts "a pattern" pattern-mask)
27353370 [%lit *]
27363371 =* l p.lex.t
27373372 ?: ?=(?(%number %ship %term %loobean %null) form.l)
@@ -2742,7 +3377,8 @@
27423377 %duration "durations"
27433378 %knot "knots"
27443379 ==
2745− %+ bad-at next
3380+ =/ n=@ud ?:(?=(%duration form.l) 2 1)
3381+ %+ bad-at [line.beg.at.t (add n col.beg.at.t)]
27463382 ;: weld
27473383 "expected a pattern, found {(show-found t)}; patterns take no "
27483384 what
@@ -2754,6 +3390,11 @@
27543390 [%name *] [%& [%bind at.t p.lex.t] t.ts]
27553391 %'[' (read-cell-pattern t t.ts)
27563392 %'`' (bad-why ts "a pattern" "patterns take no units: write [~ x]")
3393+ ::
3394+ [%wing *]
3395+ %: bad-in-why ts "a pattern" pattern-mask
3396+ "a name in a pattern binds anew, so it has no `.`"
3397+ ==
27573398 ::
27583399 [%str-head *]
27593400 %+ bad-at [line.end.at.t (dec (max 2 col.end.at.t))]
@@ -2761,7 +3402,7 @@
27613402 "patterns take strings without `\{…}`"
27623403 ::
27633404 %'~['
2764− %+ bad-at next
3405+ %+ bad-at [line.beg.at.t +(col.beg.at.t)]
27653406 "expected a pattern, found `~[`; patterns take no lists"
27663407 ==
27673408 ::
@@ -2777,7 +3418,7 @@
27773418 [%& [%cell [beg.at.op end.at.i.ts] (flop ps)] t.ts]
27783419 ?: &(?=(^ ts) |((is-closer i.ts) (is-layout i.ts)))
27793420 (unclosed op "]" ts)
2780− ?: &(?=(^ ps) ?=(^ ts) tight.i.ts) (no-space ts)
3421+ ?: &(?=(^ ps) ?=(^ ts) tight.i.ts) (no-space-pattern ts)
27813422 ;< [p=pattern after=(list token)] then (read-pattern ts)
27823423 $(ps [p ps], ts after)
27833424 ::
@@ -2791,21 +3432,26 @@
27913432 ?: ?=([[* * [%name *]] *] ts) [%& [%bind at.i.ts p.lex.i.ts] t.ts]
27923433 ?: ?=([[* * %'='] *] ts) (read-pun i.ts t.ts)
27933434 ?: &(?=(^ ts) (is-layout i.ts)) (bad ts "a sample")
3435+ ?: ?=([[* * [%error *]] *] ts)
3436+ (bad-in ts "a mold" (con mold-mask tis-mask))
27943437 ?. ?=([[* * %'['] *] ts)
27953438 ;< [s=shape after=(list token)] then (read-mold ts)
27963439 [%& [%bare (span-of s) s] after]
27973440 =* op i.ts
27983441 =| ss=(list sample)
3442+ =| pre=(list token)
27993443 =/ rest=(list token) t.ts
28003444 |- ^- (pare sample)
28013445 ?: ?=([[* * %']'] *] rest)
28023446 ?~ ss (bad rest "a sample")
28033447 [%& [%cell [beg.at.op end.at.i.rest] (flop ss)] t.rest]
28043448 ?: &(?=(^ rest) |((is-closer i.rest) (is-layout i.rest)))
3449+ =/ dm (doomed pre rest (closing op "]"))
3450+ ?^ dm u.dm
28053451 (unclosed op "]" rest)
28063452 ?: &(?=(^ ss) ?=(^ rest) tight.i.rest) (no-space rest)
28073453 ;< [s=sample after=(list token)] then (read-sample rest)
2808− $(ss [s ss], rest after)
3454+ $(ss [s ss], rest after, pre rest)
28093455 ::
28103456 :: +read-field: a cell mold's field: name=mold, =name, or a mold
28113457 ::
@@ -2814,6 +3460,9 @@
28143460 ^- (pare field)
28153461 ?: ?=([[* * [%name *]] [* %& %'='] *] ts) (read-face ts)
28163462 ?: ?=([[* * %'='] *] ts) (read-pun i.ts t.ts)
3463+ :: = begins a pun here, as a mold's first characters begin a mold
3464+ ?: ?=([[* * [%error *]] *] ts)
3465+ (bad-in ts "a mold" (con mold-mask tis-mask))
28173466 ;< [s=shape after=(list token)] then (read-mold ts)
28183467 [%& [%bare (span-of s) s] after]
28193468 ::
@@ -2835,7 +3484,7 @@
28353484 |= [tis=token ts=(list token)]
28363485 ^- (pare field)
28373486 ?: |(?=(~ ts) !tight.i.ts) (bad-space tis ts "a name")
2838− ?. ?=([[* * [%name *]] *] ts) (bad ts "a name")
3487+ ?. ?=([[* * [%name *]] *] ts) (no-name ts)
28393488 [%& [%pun [beg.at.tis end.at.i.ts] p.lex.i.ts] t.ts]
28403489 ::
28413490 :: +read-mold: one mold
@@ -2845,7 +3494,7 @@
28453494 ^- (pare shape)
28463495 ?~ ts (bad ts "a mold")
28473496 =* t i.ts
2848− ?+ lex.t (bad ts "a mold")
3497+ ?+ lex.t (bad-in ts "a mold" mold-mask)
28493498 [%aura *] [%& [%aura at.t p.lex.t] t.ts]
28503499 %'*' [%& [%noun at.t ~] t.ts]
28513500 %'!!' [%& [%void at.t ~] t.ts]
@@ -2860,9 +3509,15 @@
28603509 %'$?(' (read-union-wide t t.ts)
28613510 %'$-(' (read-fn t t.ts)
28623511 %'|$' (read-generic t t.ts)
3512+ ::
3513+ ?(%'|=' %'|=(')
3514+ %: bad-in-why ts "a mold" mold-mask
3515+ "a gate's mold is $-(sample product)"
3516+ ==
28633517 ::
28643518 [%lit *]
2865− ?. ?=(?(%null %term %loobean) form.p.lex.t) (bad ts "a mold")
3519+ ?. ?=(?(%null %term %loobean) form.p.lex.t)
3520+ (bad-in ts "a mold" mold-mask)
28663521 [%& [%const at.t p.lex.t] t.ts]
28673522 ==
28683523 ::
@@ -2873,15 +3528,18 @@
28733528 |= [op=token spaced=? ts=(list token)]
28743529 ^- (pare [(list shape) loc])
28753530 =| ms=(list shape)
3531+ =| pre=(list token)
28763532 |- ^- (pare [(list shape) loc])
28773533 ?: ?=([[* * %')'] *] ts)
28783534 ?~ ms (bad ts "a mold")
28793535 [%& [(flop ms) end.at.i.ts] t.ts]
28803536 ?: &(?=(^ ts) |((is-closer i.ts) (is-layout i.ts)))
3537+ =/ dm (doomed pre ts (closing op ")"))
3538+ ?^ dm u.dm
28813539 (unclosed op ")" ts)
28823540 ?: &(?=(^ ts) tight.i.ts |(spaced ?=(^ ms))) (no-space ts)
28833541 ;< [m=shape after=(list token)] then (read-mold ts)
2884− $(ms [m ms], ts after)
3542+ $(ms [m ms], ts after, pre ts)
28853543 ::
28863544 :: +read-apply: ( ref mold { mold } )
28873545 ::
@@ -2889,7 +3547,7 @@
28893547 |= [op=token ts=(list token)]
28903548 ^- (pare shape)
28913549 ?. ?=([[* * ?([%name *] [%wing *])] *] ts)
2892− (bad ts "a mold's name, as in (list @t)")
3550+ (bad-in ts "a mold's name, as in (list @t)" lower-mask)
28933551 ;< [[ms=(list shape) fin=loc] after=(list token)] then
28943552 (read-molds op & t.ts)
28953553 [%& [%apply [beg.at.op fin] (names-of lex.i.ts) ms] after]
@@ -2911,10 +3569,15 @@
29113569 ;< [a=shape after=(list token)] then (read-mold ts)
29123570 ?: ?=([[* * %')'] *] after) (bad after "a mold, the product")
29133571 ?: &(?=(^ after) |((is-closer i.after) (is-layout i.after)))
3572+ =/ dm (doomed ts after (closing op ")"))
3573+ ?^ dm u.dm
29143574 (unclosed op ")" after)
29153575 ?: &(?=(^ after) tight.i.after) (no-space after)
29163576 ;< [b=shape more=(list token)] then (read-mold after)
2917− ?. ?=([[* * %')'] *] more) (unclosed op ")" more)
3577+ ?. ?=([[* * %')'] *] more)
3578+ =/ dn (doomed after more (closing op ")"))
3579+ ?^ dn u.dn
3580+ (unclosed op ")" more)
29183581 [%& [%fn [beg.at.op end.at.i.more] a b] t.more]
29193582 ::
29203583 :: +read-cell-mold: [ field { field } ]
@@ -2923,15 +3586,18 @@
29233586 |= [op=token ts=(list token)]
29243587 ^- (pare shape)
29253588 =| fs=(list field)
3589+ =| pre=(list token)
29263590 |- ^- (pare shape)
29273591 ?: ?=([[* * %']'] *] ts)
29283592 ?~ fs (bad ts "a mold")
29293593 [%& [%cell [beg.at.op end.at.i.ts] (flop fs)] t.ts]
29303594 ?: &(?=(^ ts) |((is-closer i.ts) (is-layout i.ts)))
3595+ =/ dm (doomed pre ts (closing op "]"))
3596+ ?^ dm u.dm
29313597 (unclosed op "]" ts)
29323598 ?: &(?=(^ fs) ?=(^ ts) tight.i.ts) (no-space ts)
29333599 ;< [f=field after=(list token)] then (read-field ts)
2934− $(fs [f fs], ts after)
3600+ $(fs [f fs], ts after, pre ts)
29353601 ::
29363602 :: +read-union: $?, then its cases below, one mold per line
29373603 ::
@@ -2951,6 +3617,7 @@
29513617 ?: ?=([[* * %dedent] *] after)
29523618 [%& [%union [beg.at.buc end:(span-of c)] (flop [c cs])] t.after]
29533619 ?: ?=([[* * %indent] *] after) (bad-end after)
3620+ ?: &(?=(^ after) (stray i.after)) (bad-end after)
29543621 (bad-why after "the end of the line" "a union takes one case per line")
29553622 ::
29563623 :: +read-generic: |$ [ typevar { typevar } ] mold
@@ -2958,9 +3625,9 @@
29583625 ++ read-generic
29593626 |= [bar=token ts=(list token)]
29603627 ^- (pare shape)
2961− ?: &(?=(^ ts) tight.i.ts) (bad ts "a space after `|$`")
3628+ ?: &(?=(^ ts) tight.i.ts) (wide-rune "|$" ts)
29623629 ?. ?=([[* * %'['] *] ts)
2963− (bad ts "`[` and its type variables, as in |$ [M]")
3630+ (bad-in ts "`[` and its type variables, as in |$ [M]" sel-mask)
29643631 =* op i.ts
29653632 =| vs=(list @t)
29663633 =/ rest=(list token) t.ts
@@ -2968,13 +3635,14 @@
29683635 ?: ?=([[* * %']'] *] rest)
29693636 ?~ vs (bad rest "a type variable")
29703637 =/ more=(list token) t.rest
2971− ?: &(?=(^ more) tight.i.more) (bad more "a space after `]`")
3638+ ?: &(?=(^ more) tight.i.more) (no-gap more "a space after `]`")
29723639 ;< [b=shape after=(list token)] then (read-mold more)
29733640 [%& [%generic [beg.at.bar end:(span-of b)] (flop vs) b] after]
29743641 ?: &(?=(^ rest) |((is-closer i.rest) (is-layout i.rest)))
29753642 (unclosed op "]" rest)
29763643 ?: &(?=(^ vs) ?=(^ rest) tight.i.rest) (no-space rest)
2977− ?. ?=([[* * [%tvar *]] *] rest) (bad rest "a type variable")
3644+ ?. ?=([[* * [%tvar *]] *] rest)
3645+ (bad-in rest "a type variable" upper-mask)
29783646 $(vs [p.lex.i.rest vs], rest t.rest)
29793647 ::
29803648 :: +read-pathmold: / [ segment { / segment } ], each / and segment
@@ -3010,16 +3678,16 @@
30103678 =* op i.ts
30113679 =/ r1=(list token) t.ts
30123680 ?: |(?=(~ r1) !tight.i.r1) (bad-space op r1 "a name")
3013− ?. ?=([[* * [%name *]] *] r1) (bad r1 "a name")
3681+ ?. ?=([[* * [%name *]] *] r1) (no-name r1)
30143682 =/ r2=(list token) t.r1
30153683 ?: |(?=(~ r2) !tight.i.r2) (bad-space i.r1 r2 "`=`")
3016− ?. ?=([[* * %'='] *] r2) (bad r2 "`=`")
3684+ ?. ?=([[* * %'='] *] r2) (bad-in r2 "`=`" tis-mask)
30173685 =/ r3=(list token) t.r2
30183686 ?: |(?=(~ r3) !tight.i.r3) (bad-space i.r2 r3 "an aura")
3019− ?. ?=([[* * [%aura *]] *] r3) (bad r3 "an aura")
3687+ ?. ?=([[* * [%aura *]] *] r3) (bad-in r3 "an aura" pat-mask)
30203688 =/ r4=(list token) t.r3
30213689 ?: |(?=(~ r4) !tight.i.r4) (bad-space i.r3 r4 "`]`")
3022− ?. ?=([[* * %']'] *] r4) (bad r4 "`]`")
3690+ ?. ?=([[* * %']'] *] r4) (bad-in r4 "`]`" ser-mask)
30233691 =/ at=span [beg.at.op end.at.i.r4]
30243692 [%& [[%typed at p.lex.i.r1 p.lex.i.r3] end.at.i.r4] t.r4]
30253693 --
@@ -3029,38 +3697,97 @@
30293697:: +outline: a node as +check-spans sees it
30303698::
30313699:: lead lists the kinds (+kind-of) of token the node may start with,
3032−:: or is ~ when it starts with its first child; last likewise for its
3033−:: end, and open lets a bracket that may be left open end with its
3034−:: last child instead.
3700+:: or is ~ when it starts with its first child; stop says where it
3701+:: ends (+stop).
30353702::
30363703+$ outline
3037− $~ [%$ *span ~ ~ | ~]
3704+ $~ [%$ *span ~ %kid ~]
30383705 $: kind=@tas
30393706 at=span
30403707 lead=(list @)
3041− last=(list @)
3042− open=?
3708+ =stop
30433709 kids=(list outline)
30443710 ==
30453711::
3712+:: +stop: where a node ends, by the tokens of its text alone
3713+::
3714+:: %kid with its last child
3715+:: %one where its first token ends: a name, a literal
3716+:: %two where the token after its first ends: |=%got, =msg, /- todo
3717+:: %shut at the closer of its first token, an opener closed on its
3718+:: line; or with its last child, if that opener is left open
3719+:: or is a rune, as $? with its cases below
3720+:: %shut2 likewise from the token after its first, a change's (
3721+:: %run at the end of the path it starts: then each tight / and
3722+:: knot, and each tight [ or ( to its closer
3723+:: %run3 likewise from its third token, an import's path
3724+:: %string at the str-tail that ends its string, past each str-mid
3725+::
3726++$ stop ?(%kid %one %two %shut %shut2 %run %run3 %string)
3727+::
3728+:: +tinfo: a token as +check-spans sees it: its kind, its end, and the
3729+:: next token's start and whether that is tight, unless it is a layout
3730+:: token
3731+::
3732++$ tinfo [kind=@ end=loc nex=(unit [beg=loc tight=?])]
3733+::
30463734:: +check-spans: whether a module's spans follow section 1's rules
30473735::
30483736:: A node starts at its first token and ends where its last token
30493737:: ends, never at a layout token: at its own token where it has one
3050−:: there (a rune, a name, an opener or a closer), else where its
3051−:: first or last child does. Its children's spans lie inside its own
3052−:: in source order, and so do the module's imports and definitions.
3053−:: Gives the first node that breaks a rule, and how, or ~.
3738+:: there (a rune, a name, an opener), else where its first child does;
3739+:: and at the token +stop names, which it finds from the tokens alone,
3740+:: matching each opener with its closer on the line. Its children's
3741+:: spans lie inside its own in source order, and so do the module's
3742+:: imports and definitions. Gives the first node that breaks a rule,
3743+:: and how, or ~. +check-spans-test checks that it catches spans a
3744+:: parser bug could give.
30543745::
30553746++ check-spans
30563747 |= [mod=module toks=(list token)]
30573748 ^- (unit tape)
3058− =/ real=(list token) (skip toks is-layout)
3059− =/ begs=(map loc @) (malt (turn real |=(t=token [beg.at.t (kind-of t)])))
3060− =/ ends=(map loc @) (malt (turn real |=(t=token [end.at.t (kind-of t)])))
3061− %^ check-kids [begs ends] ~
3749+ %+ check-outlines toks
30623750 (weld (turn imports.mod outline-import) (turn defs.mod outline-def))
30633751::
3752+:: +check-outlines: +check-spans over the outlines of a module's nodes
3753+::
3754+++ check-outlines
3755+ |= [toks=(list token) os=(list outline)]
3756+ ^- (unit tape)
3757+ (check-kids (index-tokens toks) ~ os)
3758+::
3759+:: +index-tokens: each token that isn't a layout token, by its start,
3760+:: and each opener's closer on its line, by their starts
3761+::
3762+:: A str-head opens an interpolation that a str-mid or str-tail
3763+:: closes, and a str-mid opens the next. Openers still open at the end
3764+:: of a line have no closer.
3765+::
3766+++ index-tokens
3767+ |= toks=(list token)
3768+ ^- [info=(map loc tinfo) mat=(map loc loc)]
3769+ =| info=(map loc tinfo)
3770+ =| mat=(map loc loc)
3771+ =| open=(list loc)
3772+ |- ^- [info=(map loc tinfo) mat=(map loc loc)]
3773+ ?~ toks [info mat]
3774+ =* t i.toks
3775+ ?: (is-layout t) $(toks t.toks, open ~)
3776+ =/ k=@ (kind-of t)
3777+ =/ nex=(unit [beg=loc tight=?])
3778+ ?: |(?=(~ t.toks) (is-layout i.t.toks)) ~
3779+ `[beg.at.i.t.toks tight.i.t.toks]
3780+ =. info (~(put by info) beg.at.t [k end.at.t nex])
3781+ ?: ?=(?(%'(' %'[' %'~[' %'|=(' %'$?(' %'$-(' %str-head) k)
3782+ $(toks t.toks, open [beg.at.t open])
3783+ ?. ?=(?(%')' %']' %str-mid %str-tail) k) $(toks t.toks)
3784+ ?~ open $(toks t.toks)
3785+ %= $
3786+ toks t.toks
3787+ mat (~(put by mat) i.open beg.at.t)
3788+ open ?:(?=(%str-mid k) [beg.at.t t.open] t.open)
3789+ ==
3790+::
30643791:: +kind-of: a token's kind: a glyph, or its lexeme's tag
30653792::
30663793++ kind-of
@@ -3071,7 +3798,10 @@
30713798:: +check-kids: nodes in source order, inside the span in, each checked
30723799::
30733800++ check-kids
3074− |= [maps=[begs=(map loc @) ends=(map loc @)] in=(unit span) os=(list outline)]
3801+ |= $: idx=[info=(map loc tinfo) mat=(map loc loc)]
3802+ in=(unit span)
3803+ os=(list outline)
3804+ ==
30753805 ^- (unit tape)
30763806 =| prev=(unit span)
30773807 |- ^- (unit tape)
@@ -3083,14 +3813,14 @@
30833813 `(span-bad o "ends after its parent")
30843814 ?: &(?=(^ prev) (loc-lth beg.at.o end.u.prev))
30853815 `(span-bad o "starts before the node before it ends")
3086− =/ bad=(unit tape) (check-outline maps o)
3816+ =/ bad=(unit tape) (check-outline idx o)
30873817 ?^ bad bad
30883818 $(prev `at.o, os t.os)
30893819::
30903820:: +check-outline: one node's start and end, then its children
30913821::
30923822++ check-outline
3093− |= [maps=[begs=(map loc @) ends=(map loc @)] o=outline]
3823+ |= [idx=[info=(map loc tinfo) mat=(map loc loc)] o=outline]
30943824 ^- (unit tape)
30953825 =* ks kids.o
30963826 =/ head=(unit span) ?~(ks ~ `at.i.ks)
@@ -3102,29 +3832,95 @@
31023832 ?~ head `"has no token or child to start with"
31033833 ?: =(beg.at.o beg.u.head) ~
31043834 `"should start where its first child does, at {(show-loc beg.u.head)}"
3105− =/ k=(unit @) (~(get by begs.maps) beg.at.o)
3106− ?~ k `"starts where no token does"
3107− ?. (lien `(list @)`lead.o |=(a=@ =(a u.k)))
3835+ =/ t=(unit tinfo) (~(get by info.idx) beg.at.o)
3836+ ?~ t `"starts where no token does"
3837+ ?. (lien `(list @)`lead.o |=(a=@ =(a kind.u.t)))
31083838 `"starts at a token of a kind it can't start with"
31093839 ?: &(?=(^ head) !(loc-lth beg.at.o beg.u.head))
31103840 `"should start with its own token, before its first child"
31113841 ~
31123842 ?^ start `(span-bad o u.start)
3113− :: the end: its own token, or its last child's
3114− =/ stop=(unit tape)
3115− ?: &(|(?=(~ last.o) open.o) ?=(^ tail) =(end.at.o end.u.tail)) ~
3116− ?~ last.o
3117− ?~ tail `"has no token or child to end with"
3118− `"should end where its last child does, at {(show-loc end.u.tail)}"
3119− =/ k=(unit @) (~(get by ends.maps) end.at.o)
3120− ?~ k `"ends where no token does"
3121− ?. (lien `(list @)`last.o |=(a=@ =(a u.k)))
3122− `"ends at a token of a kind it can't end with"
3123− ?: &(?=(^ tail) !(loc-lth end.u.tail end.at.o))
3124− `"should end with its own token, after its last child"
3125− ~
3126− ?^ stop `(span-bad o u.stop)
3127− (check-kids maps `at.o ks)
3843+ :: the end: where +stop says
3844+ =/ want=(unit loc) (stop-of idx o tail)
3845+ ?~ want `(span-bad o "has no end that its tokens give")
3846+ ?. =(u.want end.at.o)
3847+ `(span-bad o "should end at {(show-loc u.want)}")
3848+ (check-kids idx `at.o ks)
3849+::
3850+:: +stop-of: where a node should end, from its stop, the tokens, and
3851+:: its last child's span, tail
3852+::
3853+++ stop-of
3854+ |= $: idx=[info=(map loc tinfo) mat=(map loc loc)]
3855+ o=outline
3856+ tail=(unit span)
3857+ ==
3858+ ^- (unit loc)
3859+ =* info info.idx
3860+ =/ first=(unit tinfo) (~(get by info) beg.at.o)
3861+ :: the token after the one at beg, if it is on the same line
3862+ =/ after
3863+ |= beg=loc
3864+ ^- (unit loc)
3865+ =/ t=(unit tinfo) (~(get by info) beg)
3866+ ?~ t ~
3867+ ?~ nex.u.t ~
3868+ `beg.u.nex.u.t
3869+ :: the end of the token at beg
3870+ =/ end-at
3871+ |= beg=loc
3872+ ^- (unit loc)
3873+ =/ t=(unit tinfo) (~(get by info) beg)
3874+ ?~(t ~ `end.u.t)
3875+ :: the closer of the opener at beg, else the last child
3876+ =/ shut
3877+ |= beg=loc
3878+ ^- (unit loc)
3879+ =/ c=(unit loc) (~(get by mat.idx) beg)
3880+ ?^ c (end-at u.c)
3881+ ?~(tail ~ `end.u.tail)
3882+ :: a path from the token at beg: each tight / and knot after it, and
3883+ :: each tight [ or ( to its closer
3884+ =/ run
3885+ |= beg=loc
3886+ ^- (unit loc)
3887+ |- ^- (unit loc)
3888+ =/ t=(unit tinfo) (~(get by info) beg)
3889+ ?~ t ~
3890+ =/ n nex.u.t
3891+ ?. &(?=(^ n) tight.u.n) `end.u.t
3892+ =/ nk=(unit tinfo) (~(get by info) beg.u.n)
3893+ ?~ nk `end.u.t
3894+ ?: ?=(?(%'/' %knot) kind.u.nk) $(beg beg.u.n)
3895+ ?. ?=(?(%'[' %'(') kind.u.nk) `end.u.t
3896+ =/ c=(unit loc) (~(get by mat.idx) beg.u.n)
3897+ ?~ c `end.u.t
3898+ $(beg u.c)
3899+ ?- stop.o
3900+ %kid ?~(tail ~ `end.u.tail)
3901+ %one (end-at beg.at.o)
3902+ %shut (shut beg.at.o)
3903+ %run (run beg.at.o)
3904+ %two =/(n (after beg.at.o) ?~(n ~ (end-at u.n)))
3905+ %shut2 =/(n (after beg.at.o) ?~(n ~ (shut u.n)))
3906+ ::
3907+ %run3
3908+ =/ n (after beg.at.o)
3909+ ?~ n ~
3910+ =/ m (after u.n)
3911+ ?~ m ~
3912+ (run u.m)
3913+ ::
3914+ %string
3915+ =/ beg=loc beg.at.o
3916+ |- ^- (unit loc)
3917+ =/ c=(unit loc) (~(get by mat.idx) beg)
3918+ ?~ c ~
3919+ =/ t=(unit tinfo) (~(get by info) u.c)
3920+ ?~ t ~
3921+ ?: ?=(%str-tail kind.u.t) `end.u.t
3922+ $(beg u.c)
3923+ ==
31283924::
31293925:: +span-bad: a span check's error, naming the node by kind and span
31303926::
@@ -3146,75 +3942,75 @@
31463942 |= i=import
31473943 ^- outline
31483944 ?- -.i
3149− %sur [%sur at.i ~[%'/-'] ~[%name] | ~]
3150− %mark [%mark at.i ~[%'/%'] ~[%lit] | ~]
3151− %jibb [%jibb at.i ~[%'/='] ~[%'/' %knot] | ~]
3945+ %sur [%sur at.i ~[%'/-'] %two ~]
3946+ %mark [%mark at.i ~[%'/%'] %two ~]
3947+ %jibb [%jibb at.i ~[%'/='] %run3 ~]
31523948 ==
31533949::
31543950++ outline-def
31553951 |= d=def
31563952 ^- outline
31573953 ?- -.d
3158− %mold [%mold at.d ~[%'+$'] ~ | ~[(outline-shape shape.d)]]
3159− %value [%value at.d ~[%'++'] ~ | ~[(outline-expr val.d)]]
3954+ %mold [%mold at.d ~[%'+$'] %kid ~[(outline-shape shape.d)]]
3955+ %value [%value at.d ~[%'++'] %kid ~[(outline-expr val.d)]]
31603956 ==
31613957::
31623958++ outline-expr
31633959 |= e=expr
31643960 ^- outline
31653961 ?- -.e
3166− %lit [%lit at.e ~[%lit] ~[%lit] | ~]
3962+ %lit [%lit at.e ~[%lit] %one ~]
31673963 %str (outline-str at.e pieces.e)
3168− %path [%path at.e ~[%'/'] ~[%'/' %knot] | ~]
3169− %wing [%wing at.e ~[%name %wing] ~[%name %wing] | ~]
3170− %pair [%pair at.e ~[%name] ~ | ~[(outline-expr val.e)]]
3171− %unit [%unit at.e ~[%'`'] ~ | ~[(outline-expr val.e)]]
3172− %group [%group at.e ~[%'('] ~[%')'] & ~[(outline-expr inner.e)]]
3173− %list [%list at.e ~[%'~['] ~[%']'] & (turn items.e outline-expr)]
3174− %tuple [%tuple at.e ~[%'['] ~[%']'] & (turn items.e outline-item)]
3175− %ctor [%ctor at.e ~[%'|='] ~[%lit] | ~]
3176− %crash [%crash at.e ~[%'!!'] ~[%'!!'] | ~]
3964+ %path [%path at.e ~[%'/'] %run ~]
3965+ %wing [%wing at.e ~[%name %wing] %one ~]
3966+ %pair [%pair at.e ~[%name] %kid ~[(outline-expr val.e)]]
3967+ %unit [%unit at.e ~[%'`'] %kid ~[(outline-expr val.e)]]
3968+ %group [%group at.e ~[%'('] %shut ~[(outline-expr inner.e)]]
3969+ %list [%list at.e ~[%'~['] %shut (turn items.e outline-expr)]
3970+ %tuple [%tuple at.e ~[%'['] %shut (turn items.e outline-item)]
3971+ %ctor [%ctor at.e ~[%'|='] %two ~]
3972+ %crash [%crash at.e ~[%'!!'] %one ~]
31773973 ::
31783974 %qath
31793975 =/ ks=(list outline)
31803976 %+ murn segs.e
31813977 |=(s=qseg ?.(?=(%expr -.s) ~ `(outline-expr p.s)))
3182− [%qath at.e ~[%'%/'] ~[%'%/' %knot %')'] | ks]
3978+ [%qath at.e ~[%'%/'] %run ks]
31833979 ::
31843980 %change
31853981 =/ ks=(list outline) (turn edits.e outline-edit)
3186− [%change at.e ~[%name %wing] ~[%')'] & ks]
3982+ [%change at.e ~[%name %wing] %shut2 ks]
31873983 ::
31883984 %gate-wide
31893985 =/ ks=(list outline)
31903986 ~[(outline-sample sample.e) (outline-expr body.e)]
3191− [%gate-wide at.e ~[%'|=('] ~[%')'] | ks]
3987+ [%gate-wide at.e ~[%'|=('] %shut ks]
31923988 ::
31933989 %call
3194− [%call at.e ~ ~ | [(outline-expr head.e) (turn args.e outline-expr)]]
3990+ [%call at.e ~ %kid [(outline-expr head.e) (turn args.e outline-expr)]]
31953991 ::
31963992 %gate
31973993 =/ ks=(list outline)
31983994 ~[(outline-sample sample.e) (outline-expr body.e)]
3199− [%gate at.e ~[%'|='] ~ | ks]
3995+ [%gate at.e ~[%'|='] %kid ks]
32003996 ::
32013997 %cast
32023998 =/ ks=(list outline) ~[(outline-shape shape.e) (outline-expr val.e)]
3203− [%cast at.e ~[%'^-'] ~ | ks]
3999+ [%cast at.e ~[%'^-'] %kid ks]
32044000 ::
32054001 %trace
32064002 =/ ks=(list outline) ~[(outline-expr val.e) (outline-expr then.e)]
3207− [%trace at.e ~[%'~&'] ~ | ks]
4003+ [%trace at.e ~[%'~&'] %kid ks]
32084004 ::
32094005 %branch
32104006 =/ ks=(list outline)
32114007 [(outline-expr subject.e) (turn arms.e outline-arm)]
3212− [%branch at.e ~[%'?-'] ~ | ks]
4008+ [%branch at.e ~[%'?-'] %kid ks]
32134009 ::
32144010 %body
32154011 =/ ks=(list outline)
32164012 (snoc (turn defs.e outline-def) (outline-expr final.e))
3217− [%body at.e ~ ~ | ks]
4013+ [%body at.e ~ %kid ks]
32184014 ==
32194015::
32204016++ outline-str
@@ -3222,60 +4018,60 @@
32224018 ^- outline
32234019 =/ ks=(list outline)
32244020 (murn ps |=(p=piece ?.(?=(%expr -.p) ~ `(outline-expr p.p))))
3225− ?~ ks [%str at ~[%str] ~[%str] | ~]
3226− [%str at ~[%str-head] ~[%str-tail] | ks]
4021+ ?~ ks [%str at ~[%str] %one ~]
4022+ [%str at ~[%str-head] %string ks]
32274023::
32284024++ outline-item
32294025 |= i=item
32304026 ^- outline
3231− ?~ face.i [%item at.i ~ ~ | ~[(outline-expr val.i)]]
3232− [%face at.i ~[%name] ~ | ~[(outline-expr val.i)]]
4027+ ?~ face.i [%item at.i ~ %kid ~[(outline-expr val.i)]]
4028+ [%face at.i ~[%name] %kid ~[(outline-expr val.i)]]
32334029::
32344030++ outline-edit
32354031 |= e=edit
32364032 ^- outline
3237− [%edit at.e ~[%name] ~ | ~[(outline-expr val.e)]]
4033+ [%edit at.e ~[%name] %kid ~[(outline-expr val.e)]]
32384034::
32394035++ outline-arm
32404036 |= a=arm
32414037 ^- outline
3242− [%arm at.a ~ ~ | ~[(outline-pattern pat.a) (outline-expr val.a)]]
4038+ [%arm at.a ~ %kid ~[(outline-pattern pat.a) (outline-expr val.a)]]
32434039::
32444040++ outline-sample
32454041 |= s=sample
32464042 ^- outline
32474043 ?- -.s
3248− %bind [%bind at.s ~[%name] ~[%name] | ~]
3249− %face [%face at.s ~[%name] ~ | ~[(outline-shape shape.s)]]
3250− %pun [%pun at.s ~[%'='] ~[%name] | ~]
3251− %cell [%cell at.s ~[%'['] ~[%']'] | (turn items.s outline-sample)]
3252− %bare [%bare at.s ~ ~ | ~[(outline-shape shape.s)]]
4044+ %bind [%bind at.s ~[%name] %one ~]
4045+ %face [%face at.s ~[%name] %kid ~[(outline-shape shape.s)]]
4046+ %pun [%pun at.s ~[%'='] %two ~]
4047+ %cell [%cell at.s ~[%'['] %shut (turn items.s outline-sample)]
4048+ %bare [%bare at.s ~ %kid ~[(outline-shape shape.s)]]
32534049 ==
32544050::
32554051++ outline-pattern
32564052 |= p=pattern
32574053 ^- outline
32584054 ?- -.p
3259− %lit [%lit at.p ~[%lit] ~[%lit] | ~]
3260− %str [%str at.p ~[%str] ~[%str] | ~]
3261− %any [%any at.p ~[%'*'] ~[%'*'] | ~]
3262− %bind [%bind at.p ~[%name] ~[%name] | ~]
3263− %cell [%cell at.p ~[%'['] ~[%']'] | (turn items.p outline-pattern)]
4055+ %lit [%lit at.p ~[%lit] %one ~]
4056+ %str [%str at.p ~[%str] %one ~]
4057+ %any [%any at.p ~[%'*'] %one ~]
4058+ %bind [%bind at.p ~[%name] %one ~]
4059+ %cell [%cell at.p ~[%'['] %shut (turn items.p outline-pattern)]
32644060 ==
32654061::
32664062++ outline-shape
32674063 |= s=shape
32684064 ^- outline
32694065 ?- -.s
3270− %aura [%aura at.s ~[%aura] ~[%aura] | ~]
3271− %noun [%noun at.s ~[%'*'] ~[%'*'] | ~]
3272− %void [%void at.s ~[%'!!'] ~[%'!!'] | ~]
3273− %flag [%flag at.s ~[%'?'] ~[%'?'] | ~]
3274− %const [%const at.s ~[%lit] ~[%lit] | ~]
3275− %ref [%ref at.s ~[%name %wing] ~[%name %wing] | ~]
3276− %tvar [%tvar at.s ~[%tvar] ~[%tvar] | ~]
3277− %apply [%apply at.s ~[%'('] ~[%')'] | (turn args.s outline-shape)]
3278− %cell [%cell at.s ~[%'['] ~[%']'] | (turn fields.s outline-sample)]
4066+ %aura [%aura at.s ~[%aura] %one ~]
4067+ %noun [%noun at.s ~[%'*'] %one ~]
4068+ %void [%void at.s ~[%'!!'] %one ~]
4069+ %flag [%flag at.s ~[%'?'] %one ~]
4070+ %const [%const at.s ~[%lit] %one ~]
4071+ %ref [%ref at.s ~[%name %wing] %one ~]
4072+ %tvar [%tvar at.s ~[%tvar] %one ~]
4073+ %apply [%apply at.s ~[%'('] %shut (turn args.s outline-shape)]
4074+ %cell [%cell at.s ~[%'['] %shut (turn fields.s outline-sample)]
32794075 ::
32804076 %path
32814077 =/ ks=(list outline)
@@ -3283,19 +4079,100 @@
32834079 |= g=pseg
32844080 ^- (unit outline)
32854081 ?. ?=(%typed -.g) ~
3286− `[%typed at.g ~[%'['] ~[%']'] | ~]
3287− [%path at.s ~[%'/'] ~[%'/' %knot %']'] & ks]
4082+ `[%typed at.g ~[%'['] %shut ~]
4083+ [%path at.s ~[%'/'] %run ks]
32884084 ::
32894085 %union
32904086 =/ ks=(list outline) (turn cases.s outline-shape)
3291− [%union at.s ~[%'$?' %'$?('] ~[%')'] & ks]
4087+ [%union at.s ~[%'$?' %'$?('] %shut ks]
32924088 ::
32934089 %fn
32944090 =/ ks=(list outline)
32954091 ~[(outline-shape sample.s) (outline-shape product.s)]
3296− [%fn at.s ~[%'$-('] ~[%')'] | ks]
4092+ [%fn at.s ~[%'$-('] %shut ks]
32974093 ::
32984094 %generic
3299− [%generic at.s ~[%'|$'] ~ | ~[(outline-shape body.s)]]
4095+ [%generic at.s ~[%'|$'] %kid ~[(outline-shape body.s)]]
33004096 ==
4097+::
4098+:: +check-spans-test: +check-spans's own test: ~, or what went wrong
4099+::
4100+:: Each case parses a source, checks that its spans pass, then moves
4101+:: the span of every node of a kind that starts at a place, as a
4102+:: parser bug would, and checks that +check-spans says so. Run it as
4103+:: tools/hoon check-spans-test, which prints <<>> when every case
4104+:: passes.
4105+::
4106+++ check-spans-test
4107+ ^- (list tape)
4108+ =/ cases=(list [src=@t bends=(list [kind=@tas beg=loc at=span])])
4109+ :~ :: a closed bracket ending before its closer, or at its parent's
4110+ :- '++ x [a [b c]]'
4111+ ~[[%tuple [1 9] [1 9] [1 13]] [%item [1 9] [1 9] [1 13]]]
4112+ :- '++ x [a [b c]]'
4113+ ~[[%tuple [1 9] [1 9] [1 15]] [%item [1 9] [1 9] [1 15]]]
4114+ :: a bracket starting at its parent's opener
4115+ :- '++ x [[b c] a]'
4116+ ~[[%tuple [1 7] [1 6] [1 12]] [%item [1 7] [1 6] [1 12]]]
4117+ :: a group without its ), a list at the next line, a call with )
4118+ :- '++ x ~[\0a (f a)\0a++ y 1'
4119+ :~ [%group [2 3] [2 3] [2 7]]
4120+ [%list [1 6] [1 6] [2 7]]
4121+ [%value [1 1] [1 1] [2 7]]
4122+ ==
4123+ :- '++ x ~[\0a (f a)\0a++ y 1'
4124+ ~[[%list [1 6] [1 6] [3 1]] [%value [1 1] [1 1] [3 1]]]
4125+ ['++ x ~[\0a (f a)\0a++ y 1' ~[[%call [2 4] [2 4] [2 8]]]]
4126+ :: a literal running on to the next one's end
4127+ ['++ x f 1 2' ~[[%lit [1 8] [1 8] [1 11]]]]
4128+ :: a path, a string, a change and a wide union cut short
4129+ ['++ x f /a/b c' ~[[%path [1 8] [1 8] [1 10]]]]
4130+ ['++ x f "a{b}c" d' ~[[%str [1 8] [1 8] [1 13]]]]
4131+ ['++ x m(a=1) b' ~[[%change [1 6] [1 6] [1 11]]]]
4132+ :- '+$ x $?(%a %b)'
4133+ ~[[%union [1 6] [1 6] [1 14]] [%mold [1 1] [1 1] [1 14]]]
4134+ :: a mold's cell before its closer, a typed segment past its own
4135+ :- '+$ x [a=[@ @] b=@]'
4136+ ~[[%cell [1 9] [1 9] [1 13]] [%face [1 7] [1 7] [1 13]]]
4137+ :- '+$ x [p=/a/[id=@ud]]'
4138+ :~ [%typed [1 12] [1 12] [1 21]]
4139+ [%path [1 9] [1 9] [1 21]]
4140+ [%face [1 7] [1 7] [1 21]]
4141+ ==
4142+ :: an import's path cut short
4143+ ['/= c /ui/c' ~[[%jibb [1 1] [1 1] [1 11]]]]
4144+ ==
4145+ %- zing
4146+ %+ turn cases
4147+ |= [src=@t bends=(list [kind=@tas beg=loc at=span])]
4148+ ^- (list tape)
4149+ =/ name=tape "`{(trip src)}`, {<bends>}"
4150+ =/ toks=(list token) (layout /test/jibb src)
4151+ =/ res (parse-tokens /test/jibb toks)
4152+ ?: ?=(%| -.res) ~["{name}: doesn't parse: {msg.p.res}"]
4153+ =/ os=(list outline)
4154+ %+ weld (turn imports.p.res outline-import)
4155+ (turn defs.p.res outline-def)
4156+ =/ true=(unit tape) (check-outlines toks os)
4157+ ?^ true ~["{name}: its true spans fail: {u.true}"]
4158+ =/ bent=(list outline)
4159+ =/ o=(list outline) os
4160+ |- ^- (list outline)
4161+ ?~ bends o
4162+ $(bends t.bends, o (bend-outlines o kind.i.bends beg.i.bends at.i.bends))
4163+ ?: =(bent os) ~["{name}: no such node"]
4164+ ?^ (check-outlines toks bent) ~
4165+ ~["{name}: not caught"]
4166+::
4167+:: +bend-outlines: os, with the span of each node of kind kind that
4168+:: starts at beg set to at, as a parser bug could set it
4169+::
4170+++ bend-outlines
4171+ |= [os=(list outline) kind=@tas beg=loc at=span]
4172+ ^- (list outline)
4173+ ?~ os ~
4174+ =/ o=outline i.os
4175+ =? at.o &(=(kind kind.o) =(beg beg.at.o)) at
4176+ :- o(kids $(os kids.o))
4177+ $(os t.os)
33014178--