hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

expr.ha (35424B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use hare::ast;
      5 use hare::lex;
      6 use hare::lex::{ltok};
      7 use math;
      8 use strings;
      9 use types;
     10 
     11 // Parses an expression.
     12 export fn expr(lexer: *lex::lexer) (ast::expr | error) = {
     13 	const loc = lex::mkloc(lexer);
     14 
     15 	// All assignment-op tokens
     16 	const atoks: []ltok = [
     17 		ltok::EQUAL, ltok::BANDEQ, ltok::BOREQ, ltok::BXOREQ,
     18 		ltok::DIVEQ, ltok::LANDEQ, ltok::LOREQ, ltok::LXOREQ,
     19 		ltok::LSHIFTEQ, ltok::MINUSEQ, ltok::MODEQ, ltok::PLUSEQ,
     20 		ltok::RSHIFTEQ, ltok::TIMESEQ,
     21 	];
     22 
     23 	const ex = match (peek(lexer, ltok::IF, ltok::FOR, ltok::BREAK,
     24 		ltok::CONTINUE, ltok::RETURN, ltok::YIELD)?) {
     25 	case void =>
     26 		yield binarithm(lexer, void, 0)?;
     27 	case let tok: lex::token =>
     28 		yield switch (tok.0) {
     29 		case ltok::IF =>
     30 			yield if_expr(lexer)?;
     31 		case ltok::FOR =>
     32 			yield for_expr(lexer)?;
     33 		case ltok::BREAK, ltok::CONTINUE, ltok::RETURN =>
     34 			yield control(lexer)?;
     35 		case ltok::YIELD =>
     36 			yield yield_expr(lexer)?;
     37 		case => abort(); // Invariant
     38 		};
     39 	};
     40 
     41 	const tok = match (try(lexer, atoks...)?) {
     42 	case let tok: lex::token =>
     43 		yield tok;
     44 	case =>
     45 		return ex;
     46 	};
     47 
     48 	const is_obj_selector = match (ex.expr) {
     49 	case (ast::access_expr | ast::slice_expr) =>
     50 		yield true;
     51 	case let ex: ast::unarithm_expr =>
     52 		yield ex.op == ast::unarithm_op::DEREF;
     53 	case =>
     54 		yield false;
     55 	};
     56 	synassert(lex::mkloc(lexer), is_obj_selector,
     57 		"Expected an object-selector, pointer dereference, or slice for assignment target")?;
     58 	const ex = ast::assign_expr {
     59 		op = switch (tok.0) {
     60 		case ltok::EQUAL =>
     61 			yield void;
     62 		case ltok::BANDEQ =>
     63 			yield ast::binarithm_op::BAND;
     64 		case ltok::BOREQ =>
     65 			yield ast::binarithm_op::BOR;
     66 		case ltok::BXOREQ =>
     67 			yield ast::binarithm_op::BXOR;
     68 		case ltok::DIVEQ =>
     69 			yield ast::binarithm_op::DIV;
     70 		case ltok::LANDEQ =>
     71 			yield ast::binarithm_op::LAND;
     72 		case ltok::LOREQ =>
     73 			yield ast::binarithm_op::LOR;
     74 		case ltok::LSHIFTEQ =>
     75 			yield ast::binarithm_op::LSHIFT;
     76 		case ltok::LXOREQ =>
     77 			yield ast::binarithm_op::LXOR;
     78 		case ltok::MINUSEQ =>
     79 			yield ast::binarithm_op::MINUS;
     80 		case ltok::MODEQ =>
     81 			yield ast::binarithm_op::MODULO;
     82 		case ltok::PLUSEQ =>
     83 			yield ast::binarithm_op::PLUS;
     84 		case ltok::RSHIFTEQ =>
     85 			yield ast::binarithm_op::RSHIFT;
     86 		case ltok::TIMESEQ =>
     87 			yield ast::binarithm_op::TIMES;
     88 		case => abort(); // unreachable
     89 		},
     90 		object = alloc(ex)!,
     91 		value = alloc(expr(lexer)?)!,
     92 	};
     93 
     94 	return ast::expr {
     95 		start = loc,
     96 		end = lex::prevloc(lexer),
     97 		expr = ex,
     98 	};
     99 };
    100 
    101 fn assert_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = {
    102 	const tok = want(lexer, ltok::ABORT, ltok::ASSERT)?;
    103 
    104 	let expr = switch (tok.0) {
    105 	case ltok::ABORT =>
    106 		want(lexer, ltok::LPAREN)?;
    107 		const msg: nullable *ast::expr =
    108 			match (peek(lexer, ltok::RPAREN)?) {
    109 			case lex::token =>
    110 				yield null;
    111 			case =>
    112 				yield alloc(expr(lexer)?)!;
    113 			};
    114 		want(lexer, ltok::RPAREN)?;
    115 
    116 		yield ast::assert_expr {
    117 			cond      = null,
    118 			message   = msg,
    119 			is_static = is_static,
    120 		};
    121 	case ltok::ASSERT =>
    122 		want(lexer, ltok::LPAREN)?;
    123 		const cond: nullable *ast::expr =
    124 			alloc(expr(lexer)?)!;
    125 		const msg: nullable *ast::expr =
    126 			match (try(lexer, ltok::COMMA)?) {
    127 			case lex::token =>
    128 				yield alloc(expr(lexer)?)!;
    129 			case =>
    130 				yield null;
    131 			};
    132 		want(lexer, ltok::RPAREN)?;
    133 
    134 		yield ast::assert_expr {
    135 			cond      = cond,
    136 			message   = msg,
    137 			is_static = is_static,
    138 		};
    139 	case => abort(); // unreachable
    140 	};
    141 
    142 	return ast::expr {
    143 		start = tok.2,
    144 		end = lex::prevloc(lexer),
    145 		expr = expr,
    146 	};
    147 };
    148 
    149 fn alloc_expr(lexer: *lex::lexer) (ast::expr | error) = {
    150 	const start = want(lexer, ltok::ALLOC)?;
    151 	want(lexer, ltok::LPAREN)?;
    152 
    153 	const init = alloc(expr(lexer)?)!;
    154 	const expr =
    155 		switch (want(lexer, ltok::COMMA, ltok::ELLIPSIS, ltok::RPAREN)?.0) {
    156 		case ltok::COMMA =>
    157 			const capacity = alloc(expr(lexer)?)!;
    158 			want(lexer, ltok::RPAREN)?;
    159 			yield ast::alloc_expr {
    160 				init = init,
    161 				form = ast::alloc_form::COPY,
    162 				capacity = capacity,
    163 			};
    164 		case ltok::ELLIPSIS =>
    165 			want(lexer, ltok::RPAREN)?;
    166 			yield ast::alloc_expr {
    167 				init = init,
    168 				form = ast::alloc_form::COPY,
    169 				capacity = null,
    170 			};
    171 		case ltok::RPAREN =>
    172 			yield ast::alloc_expr {
    173 				init = init,
    174 				form = ast::alloc_form::OBJECT,
    175 				capacity = null,
    176 			};
    177 		case => abort(); // unreachable
    178 		};
    179 
    180 	return ast::expr {
    181 		start = start.2,
    182 		end = lex::prevloc(lexer),
    183 		expr = expr,
    184 	};
    185 };
    186 
    187 fn append_insert_expr(
    188 	lexer: *lex::lexer,
    189 	is_static: bool,
    190 ) (ast::expr | error) = {
    191 	const tok = want(lexer, ltok::APPEND, ltok::INSERT)?;
    192 	want(lexer, ltok::LPAREN)?;
    193 
    194 	const object = if (tok.0 == ltok::APPEND) objsel(lexer)?
    195 		else idxexpr(lexer)?;
    196 	want(lexer, ltok::COMMA)?;
    197 	const value = expr(lexer)?;
    198 
    199 	let length: nullable *ast::expr = null;
    200 	let variadic = false;
    201 	match (try(lexer, ltok::COMMA, ltok::ELLIPSIS)?) {
    202 	case let tok: lex::token =>
    203 		switch (tok.0) {
    204 		case ltok::COMMA =>
    205 			length = alloc(expr(lexer)?)!;
    206 		case ltok::ELLIPSIS =>
    207 			variadic = true;
    208 		case => abort();
    209 		};
    210 	case void => void;
    211 	};
    212 	want(lexer, ltok::RPAREN)?;
    213 
    214 	let expr = ast::append_expr {
    215 		object = alloc(object)!,
    216 		value = alloc(value)!,
    217 		length = length,
    218 		variadic = variadic,
    219 		is_static = is_static,
    220 	};
    221 	const expr = if (tok.0 == ltok::INSERT) {
    222 		yield expr: ast::insert_expr;
    223 	} else expr;
    224 
    225 	return ast::expr {
    226 		start = tok.2,
    227 		end = lex::prevloc(lexer),
    228 		expr = expr,
    229 	};
    230 };
    231 
    232 fn measurement(lexer: *lex::lexer) (ast::expr | error) = {
    233 	const tok = want(lexer, ltok::LEN, ltok::ALIGN, ltok::SIZE, ltok::OFFSET)?;
    234 	want(lexer, ltok::LPAREN)?;
    235 	const expr = switch (tok.0) {
    236 	case ltok::LEN =>
    237 		yield alloc(expr(lexer)?)!: ast::len_expr;
    238 	case ltok::ALIGN =>
    239 		yield alloc(_type(lexer)?)!: ast::align_expr;
    240 	case ltok::SIZE =>
    241 		yield alloc(_type(lexer)?)!: ast::size_expr;
    242 	case ltok::OFFSET =>
    243 		yield alloc(expr(lexer)?)!: ast::offset_expr;
    244 	case => abort(); // unreachable
    245 	};
    246 	want(lexer, ltok::RPAREN)?;
    247 
    248 	return ast::expr {
    249 		start = tok.2,
    250 		end = lex::prevloc(lexer),
    251 		expr = expr,
    252 	};
    253 };
    254 
    255 fn binarithm(
    256 	lexer: *lex::lexer,
    257 	lvalue: (ast::expr | void),
    258 	i: int,
    259 ) (ast::expr | error) = {
    260 	// Precedence climbing parser
    261 	// https://en.wikipedia.org/wiki/Operator-precedence_parser
    262 	let lvalue = match (lvalue) {
    263 	case void =>
    264 		yield cast(lexer, void)?;
    265 	case let expr: ast::expr =>
    266 		yield expr;
    267 	};
    268 
    269 	let tok = lex::lex(lexer)?;
    270 	for (let j = precedence(tok); j >= i; j = precedence(tok)) {
    271 		const op = binop_for_tok(tok);
    272 
    273 		let rvalue = cast(lexer, void)?;
    274 		tok = lex::lex(lexer)?;
    275 
    276 		for (let k = precedence(tok); k > j; k = precedence(tok)) {
    277 			lex::unlex(lexer, tok);
    278 			rvalue = binarithm(lexer, rvalue, k)?;
    279 			tok = lex::lex(lexer)?;
    280 		};
    281 
    282 		const expr = ast::expr {
    283 			start = lvalue.start,
    284 			end = lex::prevloc(lexer),
    285 			expr = ast::binarithm_expr {
    286 				op = op,
    287 				lvalue = alloc(lvalue)!,
    288 				rvalue = alloc(rvalue)!,
    289 			},
    290 		};
    291 		lvalue = expr;
    292 	};
    293 
    294 	lex::unlex(lexer, tok);
    295 	return lvalue;
    296 };
    297 
    298 fn binding_unpack(lexer: *lex::lexer) (ast::binding_unpack | error) = {
    299 	let fields: ast::binding_unpack = [];
    300 	for (true) {
    301 		const (tok, value, _) = want(lexer, ltok::NAME,
    302 			ltok::UNDERSCORE)?;
    303 		if (tok == ltok::UNDERSCORE) {
    304 			append(fields, void)!;
    305 		} else {
    306 			append(fields, value as str)!;
    307 		};
    308 		if (len(fields) == 1) {
    309 			want(lexer, ltok::COMMA)?;
    310 		} else {
    311 			match (try(lexer, ltok::COMMA)?) {
    312 			case void => break;
    313 			case lex::token => void;
    314 			};
    315 		};
    316 	};
    317 	want(lexer, ltok::RPAREN)?;
    318 	return fields;
    319 };
    320 
    321 fn binding(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = {
    322 	const loc = lex::mkloc(lexer);
    323 	const tok = want(lexer, ltok::DEF, ltok::CONST, ltok::LET)?.0;
    324 	const kind = switch (tok) {
    325 	case ltok::DEF =>
    326 		assert(!is_static);
    327 		yield ast::binding_kind::DEF;
    328 	case ltok::CONST =>
    329 		yield ast::binding_kind::CONST;
    330 	case ltok::LET =>
    331 		yield ast::binding_kind::LET;
    332 	case => abort(); // unreachable
    333 	};
    334 
    335 	let bindings: []ast::binding = [];
    336 	for (true) {
    337 		const (tok, value, _) = want(lexer, ltok::NAME, ltok::LPAREN)?;
    338 		const name = switch (tok) {
    339 		case ltok::NAME =>
    340 			yield value as str;
    341 		case ltok::LPAREN =>
    342 			if (kind == ast::binding_kind::DEF) {
    343 				return syntaxerr(lex::mkloc(lexer),
    344 					"Can't use tuple unpacking with def");
    345 			};
    346 			yield binding_unpack(lexer)?;
    347 		case => abort();
    348 		};
    349 		const btype: nullable *ast::_type =
    350 			if (try(lexer, ltok::COLON)? is lex::token) {
    351 				yield alloc(_type(lexer)?)!;
    352 			} else null;
    353 		want(lexer, ltok::EQUAL)?;
    354 		const init = alloc(expr(lexer)?)!;
    355 		append(bindings, ast::binding {
    356 			name = name,
    357 			_type = btype,
    358 			init = init,
    359 		})!;
    360 		match (try(lexer, ltok::COMMA)?) {
    361 		case void => break;
    362 		case lex::token => void;
    363 		};
    364 	};
    365 
    366 	return ast::expr {
    367 		start = loc,
    368 		end = lex::prevloc(lexer),
    369 		expr = ast::binding_expr {
    370 			is_static = is_static,
    371 			kind = kind,
    372 			bindings = bindings,
    373 		},
    374 	};
    375 };
    376 
    377 fn builtin(lexer: *lex::lexer) (ast::expr | error) = {
    378 	const tok = match (peek(lexer, ltok::ALIGN, ltok::ALLOC, ltok::APPEND,
    379 		ltok::FREE, ltok::DELETE, ltok::ABORT, ltok::ASSERT,
    380 		ltok::INSERT, ltok::STATIC, ltok::SIZE, ltok::LEN, ltok::OFFSET,
    381 		ltok::VASTART, ltok::VAARG, ltok::VAEND)?) {
    382 	case let tok: lex::token =>
    383 		yield tok;
    384 	case void =>
    385 		return plain_expression(lexer);
    386 	};
    387 	switch (tok.0) {
    388 	case ltok::ALLOC =>
    389 		return alloc_expr(lexer);
    390 	case ltok::APPEND, ltok::INSERT =>
    391 		return append_insert_expr(lexer, false);
    392 	case ltok::DELETE =>
    393 		return delete_expr(lexer, false);
    394 	case ltok::FREE =>
    395 		return free_expr(lexer);
    396 	case ltok::ABORT, ltok::ASSERT =>
    397 		return assert_expr(lexer, false);
    398 	case ltok::STATIC =>
    399 		want(lexer, ltok::STATIC)!;
    400 		return static_expr(lexer);
    401 	case ltok::ALIGN, ltok::SIZE, ltok::LEN, ltok::OFFSET =>
    402 		return measurement(lexer);
    403 	case ltok::VASTART =>
    404 		want(lexer, ltok::VASTART)?;
    405 		want(lexer, ltok::LPAREN)?;
    406 		want(lexer, ltok::RPAREN)?;
    407 		return ast::expr {
    408 			start = tok.2,
    409 			end = lex::prevloc(lexer),
    410 			expr = void: ast::vastart_expr: ast::variadic_expr,
    411 		};
    412 	case ltok::VAARG =>
    413 		want(lexer, ltok::VAARG)?;
    414 		want(lexer, ltok::LPAREN)?;
    415 		const ap = alloc(objsel(lexer)?)!;
    416 		want(lexer, ltok::COMMA)?;
    417 		const _type = alloc(_type(lexer)?)!;
    418 		want(lexer, ltok::RPAREN)?;
    419 		return ast::expr {
    420 			start = tok.2,
    421 			end = lex::prevloc(lexer),
    422 			expr = ast::vaarg_expr {
    423 				ap = ap,
    424 				_type = _type,
    425 			},
    426 		};
    427 	case ltok::VAEND =>
    428 		want(lexer, ltok::VAEND)?;
    429 		want(lexer, ltok::LPAREN)?;
    430 		const expr = alloc(objsel(lexer)?)!;
    431 		want(lexer, ltok::RPAREN)?;
    432 		return ast::expr {
    433 			start = tok.2,
    434 			end = lex::prevloc(lexer),
    435 			expr = expr: ast::vaend_expr: ast::variadic_expr,
    436 		};
    437 	case => abort(); // Invariant
    438 	};
    439 };
    440 
    441 fn call(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = {
    442 	let args: []*ast::expr = [];
    443 	let variadic = false;
    444 
    445 	for (true) {
    446 		match (try(lexer, ltok::RPAREN)?) {
    447 		case lex::token => break;
    448 		case void => void;
    449 		};
    450 
    451 		append(args, alloc(expr(lexer)?)!)!;
    452 
    453 		match (try(lexer, ltok::ELLIPSIS)?) {
    454 		case lex::token =>
    455 			variadic = true;
    456 			want(lexer, ltok::RPAREN)?;
    457 			break;
    458 		case void => void;
    459 		};
    460 
    461 		switch (want(lexer, ltok::COMMA, ltok::RPAREN)?.0) {
    462 		case ltok::RPAREN => break;
    463 		case => void;
    464 		};
    465 	};
    466 
    467 	return ast::expr {
    468 		start = lvalue.start,
    469 		end = lex::prevloc(lexer),
    470 		expr = ast::call_expr {
    471 			lvalue = alloc(lvalue)!,
    472 			variadic = variadic,
    473 			args = args,
    474 		},
    475 	};
    476 };
    477 
    478 fn cast(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = {
    479 	const lvalue = match (lvalue) {
    480 	case void =>
    481 		yield unarithm(lexer)?;
    482 	case let e: ast::expr =>
    483 		yield e;
    484 	};
    485 	const tok = match (try(lexer, ltok::COLON, ltok::AS, ltok::IS)?) {
    486 	case void =>
    487 		return lvalue;
    488 	case let tok: lex::token =>
    489 		yield tok.0;
    490 	};
    491 	const kind = switch (tok) {
    492 	case ltok::COLON =>
    493 		yield ast::cast_kind::CAST;
    494 	case ltok::AS =>
    495 		yield ast::cast_kind::ASSERTION;
    496 	case ltok::IS =>
    497 		yield ast::cast_kind::TEST;
    498 	case => abort();
    499 	};
    500 	let typ = match (try(lexer, ltok::NULL)?) {
    501 	case let t: lex::token =>
    502 		yield alloc(ast::_type {
    503 			start = t.2,
    504 			end = lex::prevloc(lexer),
    505 			flags = 0,
    506 			repr = ast::builtin_type::NULL,
    507 		})!;
    508 	case void =>
    509 		yield alloc(_type(lexer)?)!;
    510 	};
    511 	return cast(lexer, ast::expr {
    512 		start = lvalue.start,
    513 		end = lex::prevloc(lexer),
    514 		expr = ast::cast_expr {
    515 			kind = kind,
    516 			value = alloc(lvalue)!,
    517 			_type = typ,
    518 		},
    519 	})?;
    520 };
    521 
    522 fn literal(lexer: *lex::lexer) (ast::expr | error) = {
    523 	const tok = want(lexer)?;
    524 	const expr: ast::literal_expr = switch (tok.0) {
    525 	case ltok::LIT_RCONST, ltok::LIT_STR =>
    526 		yield tok.1 as (rune | str);
    527 	case ltok::LIT_U8, ltok::LIT_U16, ltok::LIT_U32, ltok::LIT_U64,
    528 		ltok::LIT_UINT, ltok::LIT_SIZE =>
    529 		yield ast::number_literal {
    530 			suff = tok.0,
    531 			value = tok.1 as u64,
    532 			sign = false,
    533 		};
    534 	case ltok::LIT_I8, ltok::LIT_I16, ltok::LIT_I32, ltok::LIT_I64,
    535 		ltok::LIT_INT =>
    536 		const n = tok.1 as u64;
    537 		yield ast::number_literal {
    538 			suff = tok.0,
    539 			value = n: i64,
    540 			sign = false,
    541 		};
    542 	case ltok::LIT_ICONST =>
    543 		const n = tok.1 as u64;
    544 		yield ast::number_literal {
    545 			suff = tok.0,
    546 			value = if (n <= types::I64_MAX: u64) n: i64 else n,
    547 			sign = false,
    548 		};
    549 	case ltok::LIT_F32, ltok::LIT_F64, ltok::LIT_FCONST =>
    550 		yield ast::number_literal {
    551 			suff = tok.0,
    552 			value = tok.1 as f64,
    553 			sign = false,
    554 		};
    555 	case ltok::VOID =>
    556 		yield void;
    557 	case ltok::NOMEM =>
    558 		yield nomem;
    559 	case ltok::DONE =>
    560 		yield done;
    561 	case ltok::TRUE =>
    562 		yield true;
    563 	case ltok::FALSE =>
    564 		yield false;
    565 	case ltok::NULL =>
    566 		yield ast::_null;
    567 	case =>
    568 		return syntaxerr(lex::mkloc(lexer), "Expected literal expression");
    569 	};
    570 	return ast::expr {
    571 		start = tok.2,
    572 		end = lex::prevloc(lexer),
    573 		expr = expr,
    574 	};
    575 };
    576 
    577 fn control(lexer: *lex::lexer) (ast::expr | error) = {
    578 	let tok = want(lexer, ltok::BREAK, ltok::CONTINUE, ltok::RETURN)?;
    579 	let label = if (tok.0 == ltok::BREAK || tok.0 == ltok::CONTINUE) {
    580 		yield match (try(lexer, ltok::COLON)?) {
    581 		case lex::token =>
    582 			yield want(lexer, ltok::NAME)?.1 as str;
    583 		case void =>
    584 			yield "";
    585 		};
    586 	} else "";
    587 	const expr = switch (tok.0) {
    588 	case ltok::BREAK =>
    589 		yield label: ast::break_expr;
    590 	case ltok::CONTINUE =>
    591 		yield label: ast::continue_expr;
    592 	case ltok::RETURN =>
    593 		yield match (peek(lexer, ltok::COMMA, ltok::ELSE, ltok::RBRACE,
    594 			ltok::RBRACKET, ltok::RPAREN, ltok::SEMICOLON,
    595 			ltok::EOF)?) {
    596 		case void =>
    597 			yield alloc(expr(lexer)?)!: ast::return_expr;
    598 		case lex::token =>
    599 			yield null: ast::return_expr;
    600 		};
    601 	case => abort(); // unreachable
    602 	};
    603 	return ast::expr {
    604 		start = tok.2,
    605 		end = lex::prevloc(lexer),
    606 		expr = expr,
    607 	};
    608 };
    609 
    610 fn delete_expr(lexer: *lex::lexer, is_static: bool) (ast::expr | error) = {
    611 	const start = want(lexer, ltok::DELETE)?;
    612 	want(lexer, ltok::LPAREN)?;
    613 	const expr = alloc(postfix(lexer, void)?)!;
    614 	// TODO: Assert that this was an indexing expression
    615 	want(lexer, ltok::RPAREN)?;
    616 	return ast::expr {
    617 		start = start.2,
    618 		end = lex::prevloc(lexer),
    619 		expr = ast::delete_expr {
    620 			object = expr,
    621 			is_static = is_static,
    622 		},
    623 	};
    624 };
    625 
    626 fn compound_expr(lexer: *lex::lexer) (ast::expr | error) = {
    627 	let items: []*ast::expr = [];
    628 
    629 	const start = want(lexer, ltok::LBRACE, ltok::COLON)?;
    630 	const label = switch (start.0) {
    631 	case ltok::COLON =>
    632 		const tok = want(lexer, ltok::NAME)?;
    633 		want(lexer, ltok::LBRACE)?;
    634 		yield tok.1 as str;
    635 	case =>
    636 		yield "";
    637 	};
    638 
    639 	for (true) {
    640 		append(items, alloc(stmt(lexer)?)!)!;
    641 		if (try(lexer, ltok::RBRACE)? is lex::token) {
    642 			break;
    643 		};
    644 	};
    645 
    646 	return ast::expr {
    647 		start = start.2,
    648 		end = lex::prevloc(lexer),
    649 		expr = ast::compound_expr {
    650 			exprs = items,
    651 			label = label,
    652 		},
    653 	};
    654 };
    655 
    656 fn stmt(lexer: *lex::lexer) (ast::expr | error) = {
    657 	const expr = match (try(lexer, ltok::DEFER, ltok::DEF,
    658 		ltok::LET, ltok::CONST, ltok::STATIC)?) {
    659 	case let tok: lex::token =>
    660 		yield switch (tok.0) {
    661 		case ltok::DEFER =>
    662 			let expr = alloc(expr(lexer)?)!;
    663 			yield ast::expr {
    664 				start = tok.2,
    665 				end = lex::prevloc(lexer),
    666 				expr = expr: ast::defer_expr,
    667 			};
    668 		case ltok::DEF, ltok::CONST, ltok::LET =>
    669 			lex::unlex(lexer, tok);
    670 			yield binding(lexer, false)?;
    671 		case ltok::STATIC =>
    672 			yield match (peek(lexer, ltok::LET, ltok::CONST)?) {
    673 			case lex::token =>
    674 				yield binding(lexer, true)?;
    675 			case void =>
    676 				yield static_expr(lexer)?;
    677 			};
    678 		case => abort(); // unreachable
    679 		};
    680 	case void =>
    681 		yield expr(lexer)?;
    682 	};
    683 
    684 	want(lexer, ltok::SEMICOLON)?;
    685 	return expr;
    686 };
    687 
    688 fn for_expr(lexer: *lex::lexer) (ast::expr | error) = {
    689 	const tok = want(lexer, ltok::FOR)?;
    690 	const label = if (try(lexer, ltok::COLON)? is lex::token) {
    691 		const tok = want(lexer, ltok::NAME)?;
    692 		yield tok.1 as str;
    693 	} else "";
    694 	want(lexer, ltok::LPAREN)?;
    695 
    696 	let kind = void: (ast::for_kind | void);
    697 	let predicate_loc = lex::mkloc(lexer);
    698 
    699 	const bindings = match (try(lexer, ltok::LET, ltok::CONST)?) {
    700 	case let tok: lex::token =>
    701 		const binding_kind = switch (tok.0) {
    702 		case ltok::LET =>
    703 			yield ast::binding_kind::LET;
    704 		case ltok::CONST =>
    705 			yield ast::binding_kind::CONST;
    706 		case => abort(); // unreachable
    707 		};
    708 
    709 		let bindings: []ast::binding = [];
    710 
    711 		for (true) {
    712 			const (tok, value, _) = want(lexer,
    713 				ltok::NAME, ltok::LPAREN)?;
    714 			const binding_name = switch (tok) {
    715 			case ltok::NAME =>
    716 				yield value as str;
    717 			case ltok::LPAREN =>
    718 				yield binding_unpack(lexer)?;
    719 			case => abort(); // unreachable
    720 			};
    721 			const btype: nullable *ast::_type =
    722 				if (try(lexer, ltok::COLON)? is lex::token) {
    723 					yield alloc(_type(lexer)?)!;
    724 				} else null;
    725 
    726 			const (tok, _, _) = want(lexer, ltok::EQUAL,
    727 				ltok::DOUBLE_DOT, ltok::BAND, ltok::ARROW)?;
    728 
    729 			if (kind is void) {
    730 				switch (tok) {
    731 				case ltok::EQUAL =>
    732 					kind = ast::for_kind::ACCUMULATOR;
    733 				case ltok::DOUBLE_DOT =>
    734 					kind = ast::for_kind::EACH_VALUE;
    735 				case ltok::BAND =>
    736 					want(lexer, ltok::DOUBLE_DOT)?;
    737 					kind = ast::for_kind::EACH_POINTER;
    738 				case ltok::ARROW =>
    739 					kind = ast::for_kind::ITERATOR;
    740 				case => abort(); // unreachable
    741 				};
    742 			} else if (kind as ast::for_kind !=
    743 					ast::for_kind::ACCUMULATOR
    744 					|| tok != ltok::EQUAL) {
    745 				return syntaxerr(lex::mkloc(lexer),
    746 					"Cannot create multiple bindings in non-c-style loop");
    747 			};
    748 
    749 			const init_expr = alloc(expr(lexer)?)!;
    750 
    751 			append(bindings, ast::binding {
    752 				name = binding_name,
    753 				_type = btype,
    754 				init = init_expr,
    755 			})!;
    756 
    757 			match (try(lexer, ltok::COMMA)?) {
    758 			case lex::token =>
    759 				void;
    760 			case void =>
    761 				break;
    762 			};
    763 		};
    764 
    765 		if (kind as ast::for_kind == ast::for_kind::ACCUMULATOR) {
    766 			want(lexer, ltok::SEMICOLON)?;
    767 		};
    768 
    769 		yield alloc(ast::expr {
    770 			start = predicate_loc,
    771 			end = lex::prevloc(lexer),
    772 			expr = ast::binding_expr {
    773 				is_static = false,
    774 				kind = binding_kind,
    775 				bindings = bindings,
    776 			},
    777 		})!;
    778 	case void =>
    779 		kind = ast::for_kind::ACCUMULATOR;
    780 		yield null;
    781 	};
    782 
    783 	const cond: nullable *ast::expr = null;
    784 	const afterthought: nullable *ast::expr = null;
    785 
    786 	if (kind as ast::for_kind == ast::for_kind::ACCUMULATOR) {
    787 		cond = alloc(expr(lexer)?)!;
    788 		match (try(lexer, ltok::SEMICOLON)) {
    789 		case lex::token =>
    790 			afterthought = alloc(expr(lexer)?)!;
    791 		case void => void;
    792 		};
    793 	};
    794 
    795 	want(lexer, ltok::RPAREN)?;
    796 
    797 	const body = alloc(expr(lexer)?)!;
    798 	return ast::expr {
    799 		start = tok.2,
    800 		end = lex::prevloc(lexer),
    801 		expr = ast::for_expr {
    802 			kind = kind as ast::for_kind,
    803 			bindings = bindings,
    804 			cond = cond,
    805 			afterthought = afterthought,
    806 			body = body,
    807 			label = label,
    808 		},
    809 	};
    810 };
    811 
    812 fn free_expr(lexer: *lex::lexer) (ast::expr | error) = {
    813 	const start = want(lexer, ltok::FREE)?;
    814 	want(lexer, ltok::LPAREN)?;
    815 	const expr = alloc(expr(lexer)?)!;
    816 	want(lexer, ltok::RPAREN)?;
    817 	return ast::expr {
    818 		start = start.2,
    819 		end = lex::prevloc(lexer),
    820 		expr = expr: ast::free_expr,
    821 	};
    822 };
    823 
    824 fn if_expr(lexer: *lex::lexer) (ast::expr | error) = {
    825 	const start = want(lexer, ltok::IF)?;
    826 	want(lexer, ltok::LPAREN)?;
    827 	const cond = alloc(expr(lexer)?)!;
    828 	want(lexer, ltok::RPAREN)?;
    829 	const tbranch = alloc(expr(lexer)?)!;
    830 	const fbranch: nullable *ast::expr = match (try(lexer, ltok::ELSE)?) {
    831 	case void =>
    832 		yield null;
    833 	case lex::token =>
    834 		yield alloc(expr(lexer)?)!;
    835 	};
    836 	return ast::expr {
    837 		start = start.2,
    838 		end = lex::prevloc(lexer),
    839 		expr = ast::if_expr {
    840 			cond = cond,
    841 			tbranch = tbranch,
    842 			fbranch = fbranch,
    843 		},
    844 	};
    845 };
    846 
    847 fn indexing(lexer: *lex::lexer, lvalue: ast::expr) (ast::expr | error) = {
    848 	let is_slice = false;
    849 	let start: nullable *ast::expr = null, end: nullable *ast::expr = null;
    850 
    851 	if (try(lexer, ltok::DOUBLE_DOT)? is lex::token) {
    852 		is_slice = true;
    853 	} else {
    854 		start = alloc(expr(lexer)?)!;
    855 	};
    856 	if (!is_slice && try(lexer, ltok::DOUBLE_DOT)? is lex::token) {
    857 		is_slice = true;
    858 	};
    859 	if (is_slice && peek(lexer, ltok::RBRACKET)? is void) {
    860 		end = alloc(expr(lexer)?)!;
    861 	};
    862 
    863 	want(lexer, ltok::RBRACKET)?;
    864 	return ast::expr {
    865 		start = lvalue.start,
    866 		end = lex::prevloc(lexer),
    867 		expr = if (is_slice) ast::slice_expr {
    868 			object = alloc(lvalue)!,
    869 			start = start,
    870 			end = end,
    871 		} else ast::access_index {
    872 			object = alloc(lvalue)!,
    873 			index = {
    874 				assert(end == null);
    875 				yield start as *ast::expr;
    876 			},
    877 		},
    878 	};
    879 };
    880 
    881 fn objsel(lexer: *lex::lexer) (ast::expr | error) = {
    882 	let expr = postfix(lexer, void)?;
    883 	synassert(lex::mkloc(lexer), expr.expr is ast::access_expr,
    884 		"Expected object selector")?;
    885 	return expr;
    886 };
    887 
    888 fn idxexpr(lexer: *lex::lexer) (ast::expr | error) = {
    889 	const expr = postfix(lexer, void)?;
    890 	synassert(lex::mkloc(lexer), expr.expr is ast::access_expr
    891 		&& expr.expr as ast::access_expr is ast::access_index,
    892 		"Expected indexing expression")?;
    893 	return expr;
    894 };
    895 
    896 fn plain_expression(lexer: *lex::lexer) (ast::expr | error) = {
    897 	let tok = peek(lexer)? as lex::token;
    898 	if (tok.0 >= ltok::LIT_U8 && tok.0 <= ltok::LAST_LITERAL) {
    899 		return literal(lexer);
    900 	};
    901 	switch (tok.0) {
    902 	case ltok::TRUE, ltok::FALSE, ltok::NULL, ltok::VOID, ltok::DONE =>
    903 		return literal(lexer);
    904 	case ltok::LBRACKET =>
    905 		return plain_array(lexer)?;
    906 	case ltok::STRUCT =>
    907 		let s = plain_struct(lexer, [])?;
    908 		return ast::expr {
    909 			start = tok.2,
    910 			end = lex::prevloc(lexer),
    911 			expr = s,
    912 		};
    913 	case ltok::LPAREN =>
    914 		want(lexer, ltok::LPAREN)?;
    915 		let ex = expr(lexer)?;
    916 		switch (want(lexer, ltok::RPAREN, ltok::COMMA)?.0) {
    917 		case ltok::RPAREN =>
    918 			return ex;
    919 		case ltok::COMMA =>
    920 			return plain_tuple(lexer, ex, tok.2)?;
    921 		case => abort();
    922 		};
    923 	case ltok::NAME =>
    924 		let id = ident(lexer)?;
    925 		match (peek(lexer, ltok::LBRACE)?) {
    926 		case void =>
    927 			return ast::expr {
    928 				start = tok.2,
    929 				end = lex::prevloc(lexer),
    930 				expr = id: ast::access_identifier,
    931 			};
    932 		case lex::token =>
    933 			let s = plain_struct(lexer, id)?;
    934 			return ast::expr {
    935 				start = tok.2,
    936 				end = lex::prevloc(lexer),
    937 				expr = s,
    938 			};
    939 		};
    940 	case =>
    941 		return syntaxerr(lex::mkloc(lexer),
    942 			"Unexpected {}, was expecting an expression",
    943 			lex::tokstr(tok));
    944 	};
    945 };
    946 
    947 fn plain_array(lexer: *lex::lexer) (ast::expr | error) = {
    948 	const start = want(lexer, ltok::LBRACKET)?;
    949 
    950 	let values: []*ast::expr = [];
    951 	let expand = false;
    952 	for (true) {
    953 		match (try(lexer, ltok::RBRACKET)?) {
    954 		case lex::token => break;
    955 		case void => void;
    956 		};
    957 
    958 		append(values, alloc(expr(lexer)?)!)!;
    959 
    960 		match (try(lexer, ltok::COMMA, ltok::ELLIPSIS)?) {
    961 		case void =>
    962 			want(lexer, ltok::RBRACKET)?;
    963 			break;
    964 		case let tok: lex::token =>
    965 			switch (tok.0) {
    966 			case ltok::ELLIPSIS =>
    967 				expand = true;
    968 				want(lexer, ltok::RBRACKET)?;
    969 				break;
    970 			case ltok::COMMA => void;
    971 			case => abort();
    972 			};
    973 		};
    974 	};
    975 	return ast::expr {
    976 		start = start.2,
    977 		end = lex::prevloc(lexer),
    978 		expr = ast::array_literal {
    979 			expand = expand,
    980 			values = values,
    981 		},
    982 	};
    983 };
    984 
    985 fn plain_struct(
    986 	lexer: *lex::lexer,
    987 	alias: ast::ident,
    988 ) (ast::struct_literal | error) = {
    989 	if (len(alias) == 0) {
    990 		want(lexer, ltok::STRUCT)?;
    991 	};
    992 	want(lexer, ltok::LBRACE)?;
    993 
    994 	let autofill = false;
    995 	let fields: [](ast::struct_value | *ast::struct_literal) = [];
    996 	for (true) {
    997 		const tok = want(lexer, ltok::ELLIPSIS,
    998 			ltok::NAME, ltok::STRUCT)?;
    999 		switch (tok.0) {
   1000 		case ltok::ELLIPSIS =>
   1001 			synassert(lex::mkloc(lexer), len(alias) != 0,
   1002 				"Cannot use auto-fill with anonymous struct")?;
   1003 			autofill = true;
   1004 			want(lexer, ltok::RBRACE)?;
   1005 			break;
   1006 		case ltok::NAME, ltok::STRUCT =>
   1007 			lex::unlex(lexer, tok);
   1008 			append(fields, struct_field(lexer)?)!;
   1009 		case => abort(); // unreachable
   1010 		};
   1011 
   1012 		switch (want(lexer, ltok::COMMA, ltok::RBRACE)?.0) {
   1013 		case ltok::RBRACE => break;
   1014 		case ltok::COMMA =>
   1015 			if (try(lexer, ltok::RBRACE)? is lex::token) {
   1016 				break;
   1017 			};
   1018 		case => abort(); // unreachable
   1019 		};
   1020 	};
   1021 
   1022 	return ast::struct_literal {
   1023 		autofill = autofill,
   1024 		alias = alias,
   1025 		fields = fields,
   1026 	};
   1027 };
   1028 
   1029 fn struct_field(
   1030 	lexer: *lex::lexer,
   1031 ) (ast::struct_value | *ast::struct_literal | error) = {
   1032 	const tok = want(lexer, ltok::NAME, ltok::STRUCT)?;
   1033 	switch (tok.0) {
   1034 	case ltok::NAME =>
   1035 		const name = strings::dup(tok.1 as str);
   1036 		const tok = match (try(lexer, ltok::COLON,
   1037 			ltok::DOUBLE_COLON, ltok::EQUAL)?) {
   1038 		case let tok: lex::token =>
   1039 			yield tok;
   1040 		case void =>
   1041 			let id: ast::ident = alloc([name])!;
   1042 			return alloc(plain_struct(lexer, id)?)!;
   1043 		};
   1044 
   1045 		switch (tok.0) {
   1046 		case ltok::COLON =>
   1047 			const _type = alloc(_type(lexer)?)!;
   1048 			want(lexer, ltok::EQUAL)?;
   1049 			const init = alloc(expr(lexer)?)!;
   1050 			return ast::struct_value {
   1051 				name = name,
   1052 				_type = _type,
   1053 				init = init,
   1054 			};
   1055 		case ltok::DOUBLE_COLON =>
   1056 			let id: ast::ident = alloc([name])!;
   1057 			let rest = ident(lexer)?;
   1058 			append(id, rest...)!;
   1059 			return alloc(plain_struct(lexer, id)?)!;
   1060 		case ltok::EQUAL =>
   1061 			return ast::struct_value {
   1062 				name = name,
   1063 				_type = null,
   1064 				init = alloc(expr(lexer)?)!,
   1065 			};
   1066 		case => abort(); // Invariant
   1067 		};
   1068 	case ltok::STRUCT =>
   1069 		lex::unlex(lexer, tok);
   1070 		return alloc(plain_struct(lexer, [])?)!;
   1071 	case => abort(); // Invariant
   1072 	};
   1073 };
   1074 
   1075 fn plain_tuple(
   1076 	lexer: *lex::lexer,
   1077 	ex: ast::expr,
   1078 	start: lex::location
   1079 ) (ast::expr | error) = {
   1080 	let values: []*ast::expr = [];
   1081 	append(values, alloc(ex)!)!;
   1082 
   1083 	for (true) {
   1084 		append(values, alloc(expr(lexer)?)!)!;
   1085 
   1086 		match (try(lexer, ltok::COMMA)?) {
   1087 		case lex::token =>
   1088 			match (try(lexer, ltok::RPAREN)) {
   1089 			case lex::token => break;
   1090 			case => void;
   1091 			};
   1092 		case void =>
   1093 			want(lexer, ltok::RPAREN)?;
   1094 			break;
   1095 		};
   1096 	};
   1097 
   1098 	return ast::expr {
   1099 		start = start,
   1100 		end = lex::prevloc(lexer),
   1101 		expr = values: ast::tuple_literal,
   1102 	};
   1103 };
   1104 
   1105 fn postfix(lexer: *lex::lexer, lvalue: (ast::expr | void)) (ast::expr | error) = {
   1106 	let lvalue = match (lvalue) {
   1107 	case void =>
   1108 		yield builtin(lexer)?;
   1109 	case let ex: ast::expr =>
   1110 		yield ex;
   1111 	};
   1112 
   1113 	let tok = match (try(lexer, ltok::LPAREN, ltok::DOT,
   1114 		ltok::LBRACKET, ltok::QUESTION, ltok::LNOT)?) {
   1115 	case void =>
   1116 		return lvalue;
   1117 	case let tok: lex::token =>
   1118 		yield tok;
   1119 	};
   1120 
   1121 	let next = switch (tok.0) {
   1122 	case ltok::LPAREN =>
   1123 		yield call(lexer, lvalue)?;
   1124 	case ltok::DOT =>
   1125 		yield postfix_dot(lexer, lvalue)?;
   1126 	case ltok::LBRACKET =>
   1127 		yield indexing(lexer, lvalue)?;
   1128 	case ltok::QUESTION =>
   1129 		yield ast::expr {
   1130 			start = lvalue.start,
   1131 			end = lex::prevloc(lexer),
   1132 			expr = alloc(lvalue)!: ast::propagate_expr,
   1133 		};
   1134 	case ltok::LNOT =>
   1135 		yield ast::expr {
   1136 			start = lvalue.start,
   1137 			end = lex::prevloc(lexer),
   1138 			expr = alloc(lvalue)!: ast::error_assert_expr,
   1139 		};
   1140 	case => abort();
   1141 	};
   1142 
   1143 	return postfix(lexer, next);
   1144 };
   1145 
   1146 fn postfix_dot(
   1147 	lexer: *lex::lexer,
   1148 	lvalue: ast::expr,
   1149 ) (ast::expr | error) = {
   1150 	match (try(lexer, ltok::NAME)?) {
   1151 	case let tok: lex::token =>
   1152 		return ast::expr {
   1153 			start = lvalue.start,
   1154 			end = lex::prevloc(lexer),
   1155 			expr = ast::access_field {
   1156 				object = alloc(lvalue)!,
   1157 				field = tok.1 as str,
   1158 			},
   1159 		};
   1160 	case void =>
   1161 		let lit = literal(lexer)?;
   1162 		let val = lit.expr as ast::literal_expr;
   1163 		synassert(lex::mkloc(lexer), val is ast::number_literal,
   1164 			"Expected integer literal")?;
   1165 		let val = val as ast::number_literal;
   1166 		return ast::expr {
   1167 			start = lvalue.start,
   1168 			end = lex::prevloc(lexer),
   1169 			expr = ast::access_tuple {
   1170 				object = alloc(lvalue)!,
   1171 				value = alloc(lit)!,
   1172 			},
   1173 		};
   1174 	};
   1175 };
   1176 
   1177 fn static_expr(lexer: *lex::lexer) (ast::expr | error) = {
   1178 	const tok = want(lexer, ltok::ABORT, ltok::ASSERT, ltok::APPEND,
   1179 		ltok::INSERT, ltok::DELETE)?;
   1180 	lex::unlex(lexer, tok);
   1181 
   1182 	switch (tok.0) {
   1183 	case ltok::ABORT, ltok::ASSERT =>
   1184 		return assert_expr(lexer, true);
   1185 	case ltok::APPEND, ltok::INSERT =>
   1186 		let expr = append_insert_expr(lexer, true)?;
   1187 		return postfix(lexer, expr);
   1188 	case ltok::DELETE =>
   1189 		return delete_expr(lexer, true);
   1190 	case => abort(); // unreachable
   1191 	};
   1192 };
   1193 
   1194 fn switch_expr(lexer: *lex::lexer) (ast::expr | error) = {
   1195 	const start = want(lexer, ltok::SWITCH)?;
   1196 
   1197 	const label = if (try(lexer, ltok::COLON)? is lex::token) {
   1198 		const tok = want(lexer, ltok::NAME)?;
   1199 		yield tok.1 as str;
   1200 	} else "";
   1201 
   1202 	want(lexer, ltok::LPAREN)?;
   1203 	const value = expr(lexer)?;
   1204 	want(lexer, ltok::RPAREN)?;
   1205 
   1206 	want(lexer, ltok::LBRACE)?;
   1207 
   1208 	let cases: []ast::switch_case = [];
   1209 	for (true) {
   1210 		want(lexer, ltok::CASE)?;
   1211 
   1212 		let opts: []*ast::expr = [];
   1213 		if (try(lexer, ltok::ARROW)? is void) for (true) {
   1214 			append(opts, alloc(expr(lexer)?)!)!;
   1215 			switch (want(lexer, ltok::ARROW, ltok::COMMA)?.0) {
   1216 			case ltok::ARROW =>
   1217 				break;
   1218 			case ltok::COMMA =>
   1219 				if (try(lexer, ltok::ARROW)? is lex::token) {
   1220 					break;
   1221 				};
   1222 			case => abort(); // unreachable
   1223 			};
   1224 		};
   1225 
   1226 		let exprs: []*ast::expr = [];
   1227 		for (true) {
   1228 			append(exprs, alloc(stmt(lexer)?)!)!;
   1229 			match (peek(lexer, ltok::CASE, ltok::RBRACE)?) {
   1230 			case lex::token =>
   1231 				break;
   1232 			case void => void;
   1233 			};
   1234 		};
   1235 
   1236 		append(cases, ast::switch_case {
   1237 			options = opts,
   1238 			exprs = exprs,
   1239 		})!;
   1240 
   1241 		if (try(lexer, ltok::RBRACE)? is lex::token) {
   1242 			break;
   1243 		};
   1244 	};
   1245 
   1246 	return ast::expr {
   1247 		start = start.2,
   1248 		end = lex::prevloc(lexer),
   1249 		expr = ast::switch_expr {
   1250 			value = alloc(value)!,
   1251 			cases = cases,
   1252 			label = label,
   1253 		},
   1254 	};
   1255 };
   1256 
   1257 fn match_case(lexer: *lex::lexer) (ast::match_case | error) = {
   1258 	want(lexer, ltok::CASE)?;
   1259 	let tok = lex::lex(lexer)?;
   1260 	let loc = tok.2;
   1261 	let name: str = "", typ: nullable *ast::_type = null;
   1262 	switch (tok.0) {
   1263 	case ltok::NULL =>
   1264 		typ = alloc(ast::_type {
   1265 			start = loc,
   1266 			end = lex::prevloc(lexer),
   1267 			flags = 0,
   1268 			repr = ast::builtin_type::NULL,
   1269 		})!;
   1270 	case ltok::LET =>
   1271 		name = want(lexer, ltok::NAME)?.1 as str;
   1272 		want(lexer, ltok::COLON)?;
   1273 		typ = alloc(_type(lexer)?)!;
   1274 	case ltok::ARROW =>
   1275 		lex::unlex(lexer, tok);
   1276 	case =>
   1277 		lex::unlex(lexer, tok);
   1278 		typ = alloc(_type(lexer)?)!;
   1279 	};
   1280 	want(lexer, ltok::ARROW)?;
   1281 	let exprs: []*ast::expr = [];
   1282 	for (true) {
   1283 		append(exprs, alloc(stmt(lexer)?)!)!;
   1284 		if (peek(lexer, ltok::CASE, ltok::RBRACE)? is lex::token) {
   1285 			break;
   1286 		};
   1287 	};
   1288 
   1289 	return ast::match_case {
   1290 		name = name,
   1291 		_type = typ,
   1292 		exprs = exprs,
   1293 	};
   1294 };
   1295 
   1296 fn match_expr(lexer: *lex::lexer) (ast::expr | error) = {
   1297 	const start = want(lexer, ltok::MATCH)?;
   1298 	const label = if (try(lexer, ltok::COLON)? is lex::token) {
   1299 		const tok = want(lexer, ltok::NAME)?;
   1300 		yield tok.1 as str;
   1301 	} else "";
   1302 	want(lexer, ltok::LPAREN)?;
   1303 	const value = expr(lexer)?;
   1304 	want(lexer, ltok::RPAREN)?;
   1305 	want(lexer, ltok::LBRACE)?;
   1306 
   1307 	let cases: []ast::match_case = [];
   1308 	for (true) {
   1309 		append(cases, match_case(lexer)?)!;
   1310 		if (try(lexer, ltok::RBRACE)? is lex::token) {
   1311 			break;
   1312 		};
   1313 	};
   1314 
   1315 	return ast::expr {
   1316 		start = start.2,
   1317 		end = lex::prevloc(lexer),
   1318 		expr = ast::match_expr {
   1319 			value = alloc(value)!,
   1320 			cases = cases,
   1321 			label = label,
   1322 		},
   1323 	};
   1324 };
   1325 
   1326 fn unarithm(lexer: *lex::lexer) (ast::expr | error) = {
   1327 	const tok = match (try(lexer,
   1328 		ltok::MINUS, ltok::BNOT, ltok::LNOT, ltok::TIMES, ltok::BAND,
   1329 		ltok::SWITCH, ltok::MATCH, ltok::COLON, ltok::LBRACE)?) {
   1330 	case void =>
   1331 		return postfix(lexer, void);
   1332 	case let tok: lex::token =>
   1333 		yield switch (tok.0) {
   1334 		case ltok::SWITCH =>
   1335 			lex::unlex(lexer, tok);
   1336 			return switch_expr(lexer);
   1337 		case ltok::MATCH =>
   1338 			lex::unlex(lexer, tok);
   1339 			return match_expr(lexer);
   1340 		case ltok::COLON, ltok::LBRACE =>
   1341 			lex::unlex(lexer, tok);
   1342 			return compound_expr(lexer);
   1343 		case =>
   1344 			yield tok;
   1345 		};
   1346 	};
   1347 
   1348 	const op = switch (tok.0) {
   1349 	case ltok::MINUS =>
   1350 		yield ast::unarithm_op::MINUS;
   1351 	case ltok::BNOT =>
   1352 		yield ast::unarithm_op::BNOT;
   1353 	case ltok::LNOT =>
   1354 		yield ast::unarithm_op::LNOT;
   1355 	case ltok::TIMES =>
   1356 		yield ast::unarithm_op::DEREF;
   1357 	case ltok::BAND =>
   1358 		yield ast::unarithm_op::ADDR;
   1359 	case => abort();
   1360 	};
   1361 
   1362 	const operand = unarithm(lexer)?;
   1363 	const expr = :blk {
   1364 		if (op == ast::unarithm_op::MINUS) match (operand.expr) {
   1365 		case let c: ast::literal_expr =>
   1366 			match (c) {
   1367 			case let n: ast::number_literal =>
   1368 				let sign = false;
   1369 				const val = match (n.value) {
   1370 				case let i: i64 =>
   1371 					sign = i < 0;
   1372 					yield -i;
   1373 				case let u: u64 => void;
   1374 				case let f: f64 =>
   1375 					sign = math::signf64(f) < 0;
   1376 					yield -f;
   1377 				};
   1378 
   1379 				if (val is void) yield;
   1380 				yield :blk, ast::number_literal {
   1381 					suff = n.suff,
   1382 					value = val as (i64 | f64),
   1383 					sign = sign,
   1384 				}: ast::literal_expr;
   1385 			case => void;
   1386 			};
   1387 		case => void;
   1388 		};
   1389 
   1390 		yield ast::unarithm_expr {
   1391 			op = op,
   1392 			operand = alloc(operand)!,
   1393 		};
   1394 	};
   1395 	return ast::expr {
   1396 		start = tok.2,
   1397 		end = lex::prevloc(lexer),
   1398 		expr = expr,
   1399 	};
   1400 };
   1401 
   1402 fn yield_expr(lexer: *lex::lexer) (ast::expr | error) = {
   1403 	const start = want(lexer, ltok::YIELD)?;
   1404 	let label = "";
   1405 	let value: nullable *ast::expr = null;
   1406 	match (try(lexer, ltok::COLON, ltok::COMMA, ltok::ELSE, ltok::RBRACE,
   1407 		ltok::RBRACKET, ltok::RPAREN, ltok::SEMICOLON, ltok::EOF)?) {
   1408 	case void =>
   1409 		value = alloc(expr(lexer)?)!;
   1410 	case let t: lex::token =>
   1411 		if (t.0 == ltok::COLON) {
   1412 			label = want(lexer, ltok::NAME)?.1 as str;
   1413 			match (try(lexer, ltok::COMMA)?) {
   1414 			case void => void;
   1415 			case lex::token =>
   1416 				value = alloc(expr(lexer)?)!;
   1417 			};
   1418 		} else {
   1419 			lex::unlex(lexer, t);
   1420 		};
   1421 	};
   1422 	return ast::expr {
   1423 		start = start.2,
   1424 		end = lex::prevloc(lexer),
   1425 		expr = ast::yield_expr {
   1426 			label = label,
   1427 			value = value,
   1428 		},
   1429 	};
   1430 };
   1431 
   1432 fn binop_for_tok(tok: lex::token) ast::binarithm_op = {
   1433 	switch (tok.0) {
   1434 	case ltok::BAND =>
   1435 		return ast::binarithm_op::BAND;
   1436 	case ltok::BOR =>
   1437 		return ast::binarithm_op::BOR;
   1438 	case ltok::BXOR =>
   1439 		return ast::binarithm_op::BXOR;
   1440 	case ltok::DIV =>
   1441 		return ast::binarithm_op::DIV;
   1442 	case ltok::GT =>
   1443 		return ast::binarithm_op::GT;
   1444 	case ltok::GTEQ =>
   1445 		return ast::binarithm_op::GTEQ;
   1446 	case ltok::LAND =>
   1447 		return ast::binarithm_op::LAND;
   1448 	case ltok::LEQUAL =>
   1449 		return ast::binarithm_op::LEQUAL;
   1450 	case ltok::LESS =>
   1451 		return ast::binarithm_op::LESS;
   1452 	case ltok::LESSEQ =>
   1453 		return ast::binarithm_op::LESSEQ;
   1454 	case ltok::LOR =>
   1455 		return ast::binarithm_op::LOR;
   1456 	case ltok::LSHIFT =>
   1457 		return ast::binarithm_op::LSHIFT;
   1458 	case ltok::LXOR =>
   1459 		return ast::binarithm_op::LXOR;
   1460 	case ltok::MINUS =>
   1461 		return ast::binarithm_op::MINUS;
   1462 	case ltok::MODULO =>
   1463 		return ast::binarithm_op::MODULO;
   1464 	case ltok::NEQUAL =>
   1465 		return ast::binarithm_op::NEQUAL;
   1466 	case ltok::PLUS =>
   1467 		return ast::binarithm_op::PLUS;
   1468 	case ltok::RSHIFT =>
   1469 		return ast::binarithm_op::RSHIFT;
   1470 	case ltok::TIMES =>
   1471 		return ast::binarithm_op::TIMES;
   1472 	case => abort();
   1473 	};
   1474 };
   1475 
   1476 fn precedence(tok: lex::token) int = {
   1477 	switch (tok.0) {
   1478 	case ltok::LOR =>
   1479 		return 0;
   1480 	case ltok::LXOR =>
   1481 		return 1;
   1482 	case ltok::LAND =>
   1483 		return 2;
   1484 	case ltok::LEQUAL, ltok::NEQUAL =>
   1485 		return 3;
   1486 	case ltok::LESS, ltok::LESSEQ, ltok::GT, ltok::GTEQ =>
   1487 		return 4;
   1488 	case ltok::BOR =>
   1489 		return 5;
   1490 	case ltok::BXOR =>
   1491 		return 6;
   1492 	case ltok::BAND =>
   1493 		return 7;
   1494 	case ltok::LSHIFT, ltok::RSHIFT =>
   1495 		return 8;
   1496 	case ltok::PLUS, ltok::MINUS =>
   1497 		return 9;
   1498 	case ltok::TIMES, ltok::DIV, ltok::MODULO =>
   1499 		return 10;
   1500 	case =>
   1501 		return -1;
   1502 	};
   1503 };