Skip to content

An unknown operator aborts the process instead of reporting a compile error #63

Description

@gitosaurus

A token that scans as an operator but is not one kills the process with
SIGABRT instead of reporting a compile error.

$ cat bad.arch
null main
methods
  'START' : if 1 <> 2 then write "ne"
end

$ archetype --source=bad.arch
At bad.arch, line 3, column 17:
  'START' : if 1 <> 2 then write "ne"
                ^
Unknown operator: <>
libc++abi: terminating
$ echo $?
134

<> is a plausible typo — it is the not-equal operator in Pascal, which is
what Archetype was originally written in, and the 1995 HOW-TO document uses it
in one of its examples. Whatever the input, the answer should be a diagnostic
and a clean exit.

Cause

TokenStream.cc:315-322 prints the position and message by hand and then calls
terminate():

else if (not Keywords::instance().Operators.has(s)) {
    source_->showPosition(cout);
    cout << "Unknown operator: " << s << endl;
    terminate();
}

This is the only call to terminate() in src/.

What the neighbours do

Every other error in the same function reports and unwinds. Twelve lines
further down, an unterminated string literal does this:

source_->showPosition(cout);
throw std::runtime_error("Unterminated literal");

which is caught upstream and produces ERROR: Unterminated literal with exit
status 1. Ordinary parse errors go through errorMessage() and also exit 1.

Fix

errorMessage() already does the showPosition plus message that this site
open-codes, so the smallest correct change is to match the unterminated-literal
neighbour:

else if (not Keywords::instance().Operators.has(s)) {
    source_->showPosition(cout);
    throw std::runtime_error(format("Unknown operator: {}", s));
}

Returning false from fetch() instead would be tempting but wrong: false
means end of stream, so the caller would follow the real message with a
spurious "Expected Archetype statement, found end of file".

A test in TestTokenStream.cc asserting that scanning <> throws rather than
aborts would pin it. Worth checking at the same time whether any other input
reaches an abort — the exit status of a failed compile should be 1 for every
kind of bad input.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions