frankpfenning / C0

C0 Language
4 stars 0 forks source link

Elevate error() to language level? #5

Closed robsimmons closed 11 years ago

robsimmons commented 12 years ago

The error() function is somewhat fundamental as a way to signal user error (as opposed to the built-in assert() function, which should signal some sort of program error), but its use currently requires including conio.

Frank pointed out that because we know that it never returns, a language-level error() could take advantage of the fact that it is known to be at the end of a control-flow path. Right now, we need to do some weird things, because code like:

if (..) error (...) else return 4;

raises a compile-time error if it is the only thing in the body of a function. You actually have to write

if (...) error(...);
return 4;
robsimmons commented 11 years ago

I've added the intended semantics of the error(s); statement to the language reference in the repository as of revision 165. The language's syntax still fits on a page :).

It occurs to me that because the error statement introduces a new behavior to the language (namely the ability to return EXIT_FAILURE) , we're gonna need a bytecode for it! It also occurs to me that this will give students (and us) a way to test their ALDC instruction much earlier in the process of writing the VM than we previously were able to manage.

robsimmons commented 11 years ago

Revision 167 adds error() to the cc0 compiler and c0-mode, though it remains to add it to the bytecode and the coin interpreter. Revision 168 removes error() from the library reference.

Several tests of error() exist in tests/rjs-basic/error*.c0, illustrating how it can substitue for return in terms of the check that makes sure every branch of a function returns. These tests fail the regression suite, which doesn't yet understand the observation "failure", which is associated with error(). Unfortunately, I already named the observation "error" for "compiler threw an error," but since error() is associated with EXIT_FAILURE, "failure" is a reasonable name.

robsimmons commented 11 years ago

Added the error() behavior ("failure") to the cc0 regression test, it will be checked in as r169 or so.

I propose 0xbf with memonic of either aerror or athrow for the error() implementation within the VM, following the same instruction in the JVM: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.athrow

robsimmons commented 11 years ago

r170 adds error() to coin, but for some reason coin's library loader stopped working. I'm going to see if going back to the static c0ffi-compiled library helps us here, I'm clueless as to what the problem is.

As for the bytecode, we're in more trouble than I realized: assertions were previously compiled into invokenative and a call to error(), but we don't have calls to error() anymore. So now we need a bytecode representation not just for the SIGABRT termination behavior, but also for the EXIT_FAILURE termination behavior. We could add abort() and exit_failure() to conio or another library, but these "feel" like they should actually be primitive actions supported in bytecode. On the VM assignment we could just give those cases to students like we do now with dup and swap.

robsimmons commented 11 years ago

I have fixed the VM by making 0xBF (ATHROW) implement the behavior of error; this is checked in, and the reference compiler is updated, in r171. @varming, could you update the fast vm implementation?

The behavior of contracts is still managed by a FFI call to the new conio function abort(), which has precisely the semantics of the old error() - print the string argument and raise SIGABRT. It would make a great deal of sense to have abort be a bytecode instruction instead of a library function, of course. However, there is no bytecode instruction from the JVM that stands ready to implement this behavior. A possibility would be the unassigned 0xCF (AABORT); if someone wants to add considering this extension as a new issue I'll leave that to them.

varming commented 11 years ago

I don't understand the need for a bytecode instruction for abort, error, etc. Foreign functions seems just fine. It is mentioned above that signalling return of control might be of use, but I fail to see how this is important on the bytecode level. By the time we hit bytecode or assembly code we should not be doing much program analysis anyway. It is worth mentioning that the problem of "no return" is usually handled by the empty type (sometimes called type void; not to be confused with the unit type represented by void in C). In C11 they added the NoReturn type qualifier that can be added to void as a way to represent the empty type, and gcc have had a "noreturn" attribute since the dark ages. If we need a noreturn then I suggest that we implement a form of the empty type.

robsimmons commented 11 years ago

ATHROW seems to have a semantics that is ready-made for this, so I'd argue that makes some sense. In terms of the VM assignment, error is useful for testing ALDC before INVOKENATIVE is considered, which I like quite a bit.

They can be implemented as invokenative, of course, but I don't see the need for adding unnecessary FFI to the libraries to deal with bytecode. It's gotta go somewhere, lots of things potentially make sense.