hare

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

process.ha (11708B)


      1 // License: MPL-2.0
      2 // (c) 2021 Alexey Yerin <yyp@disroot.org>
      3 // (c) 2021 Bor Grošelj Simić <bor.groseljsimic@telemach.net>
      4 // (c) 2021 Drew DeVault <sir@cmpwn.com>
      5 // (c) 2021 Eyal Sawady <ecs@d2evs.net>
      6 // (c) 2022 Sebastian <sebastian@sebsite.pw>
      7 use hare::ast;
      8 use hare::lex;
      9 use hare::types;
     10 
     11 fn process(ctx: *context, subunits: const []ast::subunit) (unit | error) = {
     12 	let unit = unit {
     13 		ident = [], // TODO
     14 		decls = [],
     15 	};
     16 
     17 	for (let i = 0z; i < len(subunits); i += 1) {
     18 		let subunit = subunits[i];
     19 		for (let j = 0z; j < len(subunit.decls); j += 1) {
     20 			let adecl = &subunit.decls[j];
     21 			let decl = match (process_decl(ctx, adecl)) {
     22 			case let d: decl =>
     23 				yield d;
     24 			case error =>
     25 				abort(); // TODO
     26 			};
     27 			append(unit.decls, decl);
     28 		};
     29 	};
     30 
     31 	return unit;
     32 };
     33 
     34 fn process_decl(
     35 	ctx: *context,
     36 	decl: *ast::decl,
     37 ) (decl | error) = {
     38 	// TODO: match on &decl.decl
     39 	match (decl.decl) {
     40 	case let co: []ast::decl_const =>
     41 		abort(); // TODO
     42 	case let gl: []ast::decl_global =>
     43 		abort(); // TODO
     44 	case let ty: []ast::decl_type =>
     45 		abort(); // TODO
     46 	case let fu: ast::decl_func =>
     47 		return process_func(ctx, decl, fu);
     48 	};
     49 };
     50 
     51 fn process_func(
     52 	ctx: *context,
     53 	adecl: *ast::decl,
     54 	func: ast::decl_func,
     55 ) (decl | error) = {
     56 	assert(func.attrs & ast::fndecl_attrs::TEST == 0); // TODO
     57 	const afndecl = adecl.decl as ast::decl_func;
     58 	const prototype = types::lookup(ctx.store, &func.prototype)!;
     59 	const fntype = prototype.repr as types::func;
     60 	assert(fntype.variadism == types::variadism::NONE); // TODO
     61 	assert(len(fntype.params) == 0); // TODO
     62 
     63 	ctx.fntype = &fntype;
     64 	const body: nullable *expr = match (afndecl.body) {
     65 	case let abody: ast::expr =>
     66 		yield process_expr(ctx, &abody)?;
     67 	case void =>
     68 		yield null;
     69 	};
     70 
     71 	return decl {
     72 		exported = adecl.exported,
     73 		start = adecl.start,
     74 		end = adecl.end,
     75 		decl = decl_func {
     76 			symbol = afndecl.symbol,
     77 			// TODO: Add namespace to ident
     78 			ident = ast::ident_dup(afndecl.ident),
     79 			prototype = prototype,
     80 			body = body,
     81 			// TODO: We should make these enums inherited
     82 			attrs = afndecl.attrs: ast::fndecl_attrs,
     83 		},
     84 	};
     85 };
     86 
     87 fn process_expr(
     88 	ctx: *context,
     89 	expr: *ast::expr,
     90 ) (*expr | error) = {
     91 	match (expr.expr) {
     92 	case ast::access_expr =>
     93 		return process_access(ctx, expr);
     94 	case ast::alloc_expr =>
     95 		abort(); // TODO
     96 	case ast::append_expr =>
     97 		abort(); // TODO
     98 	case ast::assert_expr =>
     99 		abort(); // TODO
    100 	case ast::assign_expr =>
    101 		abort(); // TODO
    102 	case ast::binarithm_expr =>
    103 		abort(); // TODO
    104 	case ast::binding_expr =>
    105 		return process_binding(ctx, expr);
    106 	case ast::break_expr =>
    107 		abort(); // TODO
    108 	case ast::call_expr =>
    109 		abort(); // TODO
    110 	case ast::cast_expr =>
    111 		abort(); // TODO
    112 	case ast::compound_expr =>
    113 		return process_compound(ctx, expr);
    114 	case ast::constant_expr =>
    115 		return process_constant(ctx, expr);
    116 	case ast::continue_expr =>
    117 		abort(); // TODO
    118 	case ast::defer_expr =>
    119 		abort(); // TODO
    120 	case ast::delete_expr =>
    121 		abort(); // TODO
    122 	case ast::for_expr =>
    123 		abort(); // TODO
    124 	case ast::free_expr =>
    125 		abort(); // TODO
    126 	case ast::if_expr =>
    127 		abort(); // TODO
    128 	case ast::match_expr =>
    129 		abort(); // TODO
    130 	case ast::len_expr =>
    131 		abort(); // TODO
    132 	case ast::size_expr =>
    133 		abort(); // TODO
    134 	case ast::offset_expr =>
    135 		abort(); // TODO
    136 	case ast::propagate_expr =>
    137 		abort(); // TODO
    138 	case ast::return_expr =>
    139 		return process_return(ctx, expr);
    140 	case ast::slice_expr =>
    141 		abort(); // TODO
    142 	case ast::switch_expr =>
    143 		abort(); // TODO
    144 	case ast::unarithm_expr =>
    145 		abort(); // TODO
    146 	};
    147 };
    148 
    149 fn process_access(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    150 	const access_expr = aexpr.expr as ast::access_expr;
    151 	const (result, ex) = match (access_expr) {
    152 	case let ai: ast::access_identifier =>
    153 		const object = match (ctx_lookup(ctx, ai)) {
    154 		case null =>
    155 			abort(); // TODO: Error
    156 		case let obj: *object =>
    157 			yield obj;
    158 		};
    159 		yield (object._type, object);
    160 	case let ai: ast::access_index =>
    161 		abort(); // TODO
    162 	case let af: ast::access_field =>
    163 		abort(); // TODO
    164 	case let at: ast::access_tuple =>
    165 		abort(); // TODO
    166 	};
    167 	return alloc(expr {
    168 		start = aexpr.start,
    169 		end = aexpr.end,
    170 		result = result,
    171 		expr = ex,
    172 		terminates = false,
    173 	});
    174 };
    175 
    176 @test fn access() void = {
    177 	// TODO: Test error cases, more access types
    178 	const ctx = mktestctx();
    179 	defer freetestctx(&ctx);
    180 	const object = scope_insert(&ctx, object {
    181 		kind = object_kind::BIND,
    182 		ident = ["hello"],
    183 		name = ["hello"],
    184 		_type = &types::builtin_u32,
    185 		...
    186 	});
    187 	const aexpr = parse_expr("hello");
    188 	defer ast::expr_finish(aexpr);
    189 	const expr = process_access(&ctx, aexpr)!;
    190 	const access = expr.expr as access;
    191 	const ao = access as access_object;
    192 	assert(ao == object);
    193 	assert(expr.result == &types::builtin_u32);
    194 };
    195 
    196 fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    197 	const bind = aexpr.expr as ast::binding_expr;
    198 	assert(!bind.is_static && !bind.is_const); // TODO
    199 
    200 	let bindings: bindings = [];
    201 	for (let i = 0z; i < len(bind.bindings); i += 1) {
    202 		const item = bind.bindings[i];
    203 		const init = process_expr(ctx, item.init)?;
    204 		const _type = match (item._type) {
    205 		case null =>
    206 			abort(); // TODO
    207 		case let ty: *ast::_type =>
    208 			yield types::lookup(ctx.store, ty)!;
    209 		};
    210 		const object = scope_insert(ctx, object {
    211 			kind = object_kind::BIND,
    212 			// TODO: tuple unpacking
    213 			ident = ast::ident_dup([item.name as str]),
    214 			name = ast::ident_dup([item.name as str]),
    215 			_type = _type,
    216 			...
    217 		});
    218 		append(bindings, binding {
    219 			object = object,
    220 			init = init,
    221 		});
    222 	};
    223 	return alloc(expr {
    224 		start = aexpr.start,
    225 		end = aexpr.end,
    226 		result = &types::builtin_void,
    227 		expr = bindings,
    228 		...
    229 	});
    230 };
    231 
    232 fn process_compound(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    233 	const compound_expr = aexpr.expr as ast::compound_expr;
    234 	const scope = scope_push(ctx, scope_class::COMPOUND);
    235 
    236 	let exprs: compound = alloc([], len(compound_expr.exprs));
    237 	let i = 0z;
    238 	for (i < len(compound_expr.exprs); i += 1) {
    239 		append(exprs, process_expr(ctx, compound_expr.exprs[i])?);
    240 	};
    241 
    242 	scope_pop(ctx);
    243 	return alloc(expr {
    244 		start = aexpr.start,
    245 		end = aexpr.end,
    246 		result = &types::builtin_void, // TODO: Pick result type
    247 		expr = exprs,
    248 		terminates = exprs[i - 1].terminates,
    249 		...
    250 	});
    251 };
    252 
    253 @test fn compound() void = {
    254 	const ctx = mktestctx();
    255 	defer freetestctx(&ctx);
    256 	const aexpr = parse_expr("{ void; void; void; }");
    257 	defer ast::expr_finish(aexpr);
    258 	const expr = process_compound(&ctx, aexpr)!;
    259 	assert(expr.result.repr as types::builtin == types::builtin::VOID);
    260 	const compound = expr.expr as compound;
    261 	assert(len(compound) == 3);
    262 
    263 	const aexpr = parse_expr("{ return; }");
    264 	defer ast::expr_finish(aexpr);
    265 	const expr = process_compound(&ctx, aexpr)!;
    266 	assert(expr.terminates);
    267 
    268 	// TODO: test yields
    269 };
    270 
    271 fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    272 	const constexpr = aexpr.expr as ast::constant_expr;
    273 	const (result, ex) = match (constexpr) {
    274 	case let v: ast::value =>
    275 		yield (
    276 			// TODO: iconst/fconst lowering
    277 			types::lookup_builtin(ctx.store, match (v) {
    278 			case ast::_null =>
    279 				yield ast::builtin_type::NULL;
    280 			case let b: bool =>
    281 				yield ast::builtin_type::BOOL;
    282 			case let s: str =>
    283 				yield ast::builtin_type::STR;
    284 			case let r: rune =>
    285 				yield ast::builtin_type::RUNE;
    286 			case void =>
    287 				yield ast::builtin_type::VOID;
    288 			}),
    289 			v: constant,
    290 		);
    291 	case ast::array_constant =>
    292 		abort(); // TODO
    293 	case let v: ast::number_constant =>
    294 		yield (
    295 			types::lookup_builtin(ctx.store, switch (v.suff) {
    296 			case lex::ltok::LIT_U8 =>
    297 				yield ast::builtin_type::U8;
    298 			case lex::ltok::LIT_U16 =>
    299 				yield ast::builtin_type::U16;
    300 			case lex::ltok::LIT_U32 =>
    301 				yield ast::builtin_type::U32;
    302 			case lex::ltok::LIT_U64 =>
    303 				yield ast::builtin_type::U64;
    304 			case lex::ltok::LIT_UINT =>
    305 				yield ast::builtin_type::UINT;
    306 			case lex::ltok::LIT_SIZE =>
    307 				yield ast::builtin_type::SIZE;
    308 			case lex::ltok::LIT_I8 =>
    309 				yield ast::builtin_type::I8;
    310 			case lex::ltok::LIT_I16 =>
    311 				yield ast::builtin_type::I16;
    312 			case lex::ltok::LIT_I32 =>
    313 				yield ast::builtin_type::I32;
    314 			case lex::ltok::LIT_I64 =>
    315 				yield ast::builtin_type::I64;
    316 			case lex::ltok::LIT_INT, lex::ltok::LIT_ICONST =>
    317 				yield ast::builtin_type::INT;
    318 			case lex::ltok::LIT_F32 =>
    319 				yield ast::builtin_type::F32;
    320 			case lex::ltok::LIT_F64, lex::ltok::LIT_FCONST =>
    321 				yield ast::builtin_type::F64;
    322 			}),
    323 			v.value: constant,
    324 		);
    325 	case ast::struct_constant =>
    326 		abort(); // TODO
    327 	case ast::tuple_constant =>
    328 		abort(); // TODO
    329 	};
    330 	return alloc(expr {
    331 		start = aexpr.start,
    332 		end = aexpr.end,
    333 		result = result,
    334 		expr = ex,
    335 		...
    336 	});
    337 };
    338 
    339 @test fn constant() void = {
    340 	const ctx = mktestctx();
    341 	defer freetestctx(&ctx);
    342 	const aexpr = parse_expr("void");
    343 	defer ast::expr_finish(aexpr);
    344 	const expr = process_constant(&ctx, aexpr)!;
    345 	assert(expr.result.repr as types::builtin == types::builtin::VOID);
    346 	const constexpr = expr.expr as constant;
    347 	assert(constexpr is void);
    348 
    349 	const aexpr = parse_expr("true");
    350 	defer ast::expr_finish(aexpr);
    351 	const expr = process_constant(&ctx, aexpr)!;
    352 	assert(expr.result.repr as types::builtin == types::builtin::BOOL);
    353 	const constexpr = expr.expr as constant;
    354 	assert(constexpr as bool == true);
    355 
    356 	const aexpr = parse_expr("false");
    357 	defer ast::expr_finish(aexpr);
    358 	const expr = process_constant(&ctx, aexpr)!;
    359 	assert(expr.result.repr as types::builtin == types::builtin::BOOL);
    360 	const constexpr = expr.expr as constant;
    361 	assert(constexpr as bool == false);
    362 
    363 	const aexpr = parse_expr("null");
    364 	defer ast::expr_finish(aexpr);
    365 	const expr = process_constant(&ctx, aexpr)!;
    366 	assert(expr.result.repr as types::builtin == types::builtin::NULL);
    367 	assert(expr.expr is constant);
    368 
    369 	const cases: [_](str, types::builtin, constant) = [
    370 		("1234", types::builtin::INT, 1234),
    371 		("1234u", types::builtin::UINT, 1234u),
    372 		("\"hello world\"", types::builtin::STR, "hello world"),
    373 		("'!'", types::builtin::RUNE, '!'),
    374 		("13.37", types::builtin::F64, 13.37f64),
    375 	];
    376 	for (let i = 0z; i < len(cases); i += 1) {
    377 		const _case = cases[i];
    378 		const aexpr = parse_expr(_case.0);
    379 		defer ast::expr_finish(aexpr);
    380 		const expr = process_constant(&ctx, aexpr)!;
    381 		assert(expr.result.repr as types::builtin == _case.1);
    382 		const constexpr = expr.expr as constant;
    383 		match (_case.2) {
    384 		case let s: str =>
    385 			assert(constexpr as str == s);
    386 		case let r: rune =>
    387 			assert(constexpr as rune == r);
    388 		case let i: i64 =>
    389 			assert(constexpr as i64 == i);
    390 		case let u: u64 =>
    391 			assert(constexpr as u64 == u);
    392 		case let f: f64 =>
    393 			assert(constexpr as f64 == f);
    394 		case void =>
    395 			abort();
    396 		};
    397 	};
    398 };
    399 
    400 fn process_return(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    401 	const ret = aexpr.expr as ast::return_expr;
    402 	const rval = match (ret) {
    403 	case null =>
    404 		yield null;
    405 	case let aexpr: *ast::expr =>
    406 		yield process_expr(ctx, aexpr)?;
    407 	};
    408 	// TODO: assert(types::assignable(ctx.fntype.result, rval.type));
    409 	return alloc(expr {
    410 		start = aexpr.start,
    411 		end = aexpr.end,
    412 		terminates = true,
    413 		result = &types::builtin_void,
    414 		expr = rval: _return,
    415 	});
    416 };
    417 
    418 @test fn _return() void = {
    419 	const ctx = mktestctx();
    420 	defer freetestctx(&ctx);
    421 	const aexpr = parse_expr("return;");
    422 	defer ast::expr_finish(aexpr);
    423 	const ret_expr = process_return(&ctx, aexpr)!;
    424 	assert(ret_expr.terminates);
    425 	assert(ret_expr.result.repr as types::builtin == types::builtin::VOID);
    426 	const rval = ret_expr.expr as _return;
    427 	assert(rval == null);
    428 
    429 	const aexpr = parse_expr("return 10;");
    430 	defer ast::expr_finish(aexpr);
    431 	const ret_expr = process_return(&ctx, aexpr)!;
    432 	assert(ret_expr.terminates);
    433 	assert(ret_expr.result.repr as types::builtin == types::builtin::VOID);
    434 	const rval = ret_expr.expr as _return;
    435 	assert((rval as *expr).expr is constant);
    436 };