{Record show}

Where

Let (show file_name text message i)
    Let {line start} (locate_token text i)
    Let end i
    In
    Do (STDIO.print_line
        (STRING.concat [file_name ":" (Z.show line) ": " message]))
    Do If (start < (STRING.length text))
        (show_token text start end)
        {}
    In
    {}

Where

Let (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}

Let (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
            Do (STDIO.print_line (STRING.clip text line_start line_end))
            Do Iterate {i} From {line_start}
                Cond
                | !(i = start)
                    Do (STDIO.print " ")
                    In
                    Continue {(i + 1)}
                | True {}
                ;
            Do Iterate {i} From {start}
                Cond
                | !(i = end)
                    Do (STDIO.print "^")
                    In
                    Continue {(i + 1)}
                | True {}
                ;
            Do (STDIO.print_line "")
            In
            {}
        | ((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"