llm
Download
207 lines 6.1 KiBTomoModified 2026-09-09 raw
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