123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 | # Where comments end up. A comment at the end of the last line of a file used
# to be written out twice on the second pass, because a spoofed file counted
# its NUL terminator as a byte and the end-of-file comment scan ran past the
# end. The ones a list or table writes between its elements used to be
# appended where the last element stopped, on the back of its comma. The ones
# written among a call's arguments were dropped outright: an argument carried
# no span and no comment for them to be recorded in.
func f(a:Int -> Int)
return a
func g(
# above a parameter
a:Int,
b:Int, # after the last, before the close
)
return a + b
func multi_line_comments(
# A comment written on several lines comes back out on several lines. The
# text on the argument is the lines joined into one paragraph, which is
# what the compiler wants -- a parameter's comment is its description on
# the command line -- and not what was written here, so the formatter
# reads the source between the argument's comment positions instead.
a:Int,
# Names sharing a type are one line, so what is written above any of them
# belongs above that line:
x, y:Int,
)
return a + x + y
func containers()
xs := [
# opening
1,
# trailing
# on its own
2,
# left over at the end
]
t := {
1: 2,
# trailing
# left over at the end
}
return xs.length + t.length
func calls()
>> g(
# before the first
1,
# between the arguments
2, # after the last, before the close
)
# A lone argument hugs the delimiters, but not when it carries a comment:
# only the multi-line form writes those out.
>> f(
1, # explaining the argument
)
func main()
>> containers()
>> calls() # the last line of the file
func doubled()
# A comment on the line a statement ends on belongs to the innermost block
# that ends there. Claimed by the enclosing one as well, it was written
# twice per pass, so `tomo format -i` run twice over this file used to
# leave four copies of the comment below, and eight after a third.
>> 1 # on the last line of a body
func after_a_block()
# ...but a statement whose own last line is at its level, like the `]`
# closing this list, keeps the comment written after it.
xs := [
11111111111111111, 22222222222222222, 33333333333333333, 44444444444444444, 555555555555,
66666666666666, 7777777777777,
] # after the list
return xs.length
enum E(A{q:Int}, B)
func gaps(e:E)
# A comment written in a gap between the parts of one statement -- before
# an `else`, after a `match` subject, before a `case` -- belongs to no
# block, so nothing used to write it out. It takes a line of its own at the
# statement's level.
if yes
say("a")
# before else
else
say("b")
match e
# after the subject and before the first case
case A{q}
say("$q")
# before a later case
case B
say("b")
# before the else
else
say("other")
func inside_expressions()
xs := [1, 2, 3]
# A comment written inside an expression stays where it was written. It can
# only follow an operator, never precede one: `a # c` and then `+ b` on the
# next line is not an expression the parser puts back together.
v := 1 + # after the operator
2
w := (
# after the open paren
1 + 2
)
y := (
1 + 2 # before the close paren
)
z := [
(x # between the expression and its `for`
for x in xs),
]
return v + w + y + z.length
struct Point{x, y:Int} # a struct's header line
func norm(p:Point -> Int) # and a method's
return p.x + p.y
func header_lines(e:E, p:Point) # ...and a function's
# A comment at the end of a header line belongs to that line, not to the
# body indented under it. The body block starts on the line below for just
# this reason: left to scan from where it really begins, which is straight
# after the header, it used to claim the comment and write it out as the
# first line of the body.
n := p.norm()
if n > 1 # the condition holds
say("big")
else # and when it does not
say("small")
while n > 0 # counting down
n -= 1
repeat # until something stops it
stop
for i in 3 # each of them
say("$i")
else # or none at all
say("empty")
match e # on the header, where `# after the subject` above is not
case A{q} # and on a case
say("$q")
else
pass
defer # on the way out
say("done")
func arg_comments(xs:&[Int])
# A comment among a call's arguments belongs to the argument it precedes.
# Only the plain-call parser used to record them, so the same comment
# survived `f(...)` and was dropped by `x.f(...)` and by `Foo{...}`.
xs.insert(
# which value
7,
)
>> Point{
# across
1,
# up
2,
}
func trailing(xs:&[Int])
# A comment at the end of the line an item finished on belongs to that
# item. Written back on the line below it would say about the next one
# what its author said about this one, and `# one` would describe `2`.
>> [
1, # one
2, # two
]
>> {
1: 2, # entry one
3: 4, # entry two
}
xs.insert(
7, # which value
at=1, # and where
)
func suffix_comments(
a:Int,
-> Int # what comes back
; inline
# ...and what is written below the flags, which has no line of its own on
# the one-line form, so carrying it is itself a reason to break
)
# Neither the return type nor a flag is a node that could hold a comment,
# and nothing scanned the gaps between them, so both used to be dropped.
return a
struct Spanned{x:Int}
FIELD := 1
# A block consumes the whitespace after it as it parses, so this definition's
# span runs past the blank line above and over this comment. Left to the
# namespace, the comment was indented into it and the blank line vanished.
func after_a_namespace(-> Int)
return Spanned.FIELD
|