{
: show
}

Where

Define (show file_name text message i)
    Let {line start} (locate_token text i)
    Let end i
    In
    Begin
        (STDIO.print_line
            (STRING.concat
                [Right
                    file_name &
                    ":" &
                    (Z.show line) &
                    ": " &
                    message &
                    'nil]))
        When [start < (STRING.length text)]
            (show_token text start end)
        End
    End

Where

Define (locate_token text j)
    Let {k line}
        Iterate {i line k} From {0 1 0}
            If [i = j]
                {k line}
                If [(STRING.fetch text i) = `\n`]
                    (Continue [i + 1] [line + 1] i)
                    (Continue [i + 1] line k)
    In
    Iterate i From k
        Let start (SCAN.whitespace text i)
        In
        Let {i _} (SCAN.token text i)
        In
        If [i = j]
            {line start}
            (Continue i)

Define (show_token text start end)
    Let n (STRING.length text)
    In
    Iterate {j line line_start} From {0 0 0}
        Cond
        | [j = n]
            (OS.die "Unexpected EOF.")
        | [j = start]
            Let line_end
                Iterate i From j
                    Cond
                    | [i = n]
                        (OS.die "Unexpected EOF.")
                    | [(STRING.fetch text i) = `\n`]
                        i
                    | True
                        (Continue [i + 1])
                    ;
            In
            Begin
                (STDIO.print_line (STRING.clip text line_start line_end))
                Iterate i From line_start
                    When [i != start]
                        (STDIO.print " ")
                        (Continue [i + 1])
                    End
                Iterate i From start
                    When [i != end]
                        (STDIO.print "^")
                        (Continue [i + 1])
                    End
                (STDIO.print_line "")
            End
        | [(STRING.fetch text j) = `\n`]
            (Continue [j + 1] [line + 1] [j + 1])
        | True
            (Continue [j + 1] line line_start)
        ;

Where

Let OS Package "os"
Let SCAN Package "scan"
Let STDIO Package "stdio"
Let STRING Package "string"
Let Z Package "z"