bootstrap: turn 'assert' back into a built in syntax form

Now that we have optional '->' for unambiguously-expected blocks in the
syntax, this works quite nicely. Also, 'inline pre' make it necessary
for 'pre' to be a builtin, so we might as well make the other ones too
(assert, post; invariant always was a builtin).
bootstrap: change example to take a Void block, not a Bool

While it was cute to have
	example true != false

On most real-life examples, multiple conditions are checked. So assert
ended up being used multiple times. The last statement had a different
status and that was a little strange. Often, that last statement had to
be a plain 'true'.

The alternative of making example blocks special, so that any statement
can either be Void, or Bool (in which case it would asserted over), was
rejected as being too fancy for its own good.
bootstrap:cprinter: remove dead code in print_defname()

Unneeded since DEFNAME and DEFALIAS have been separated.
bootstrap:ssa: support simple rewrites in global let values

let global = @"string"

The declaration is rewritten into 2 declarations, so that we can
generate this C code:

static const char *s = "string";
static const char **global = @s;
bootstrap: support resolving bare names in the type definition's scope

We already supported this for enums and unions, we now support it for
structs. For instance:

struct Color =
	r	:Float
	g	:Float
	b	:Float
	let RED = {r=1}
	let GREEN = {g=1}
	let BLUE = {b=1}

fun red = Color
	return RED
fun darkred = Color
	return {r=.5}
lib/n/builtins: turn Error into a struct (from an enum)

In the scope of Error will be defined a number of standard errors (OK,
INVAL, ...). Thanks to the previous commit, the compiler is able to look
these up without an 'Error.' prefix:
	fun foo = Error
		return INVAL

By not making it an enum, anyone can define their own error kind,
typically a global constant:

	let Error_no_such_glyph = {Msg=@"Glyph not found"}

The semantic constraints will still support restricting the range of
possible errors:
	fun foo = Error::|INVAL
		return INVAL
lib/n/bytes: return (slice, Error) not (Error, slice)

By convention (to be enforced by semantic constraints), when a function
returns a tuple that contains an Error value, if the error is not OK,
then the values that appear after the Error are to be ignored.

However, for Read and Write, the slice is always valid. On error, the
slice may be empty, or it may contain some valid content on EOF.