hare

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

process.ha (7982B)


      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::types;
      7 
      8 fn process(ctx: *context, subunits: const []ast::subunit) (unit | error) = {
      9 	let unit = unit {
     10 		ident = [], // TODO
     11 		decls = [],
     12 	};
     13 
     14 	for (let i = 0z; i < len(subunits); i += 1) {
     15 		let subunit = subunits[i];
     16 		for (let j = 0z; j < len(subunit.decls); j += 1) {
     17 			let adecl = &subunit.decls[j];
     18 			let decl = match (process_decl(ctx, adecl)) {
     19 			case let d: decl =>
     20 				yield d;
     21 			case error =>
     22 				abort(); // TODO
     23 			};
     24 			append(unit.decls, decl);
     25 		};
     26 	};
     27 
     28 	return unit;
     29 };
     30 
     31 fn process_decl(
     32 	ctx: *context,
     33 	decl: *ast::decl,
     34 ) (decl | error) = {
     35 	// TODO: match on &decl.decl
     36 	match (decl.decl) {
     37 	case let co: []ast::decl_const =>
     38 		abort(); // TODO
     39 	case let gl: []ast::decl_global =>
     40 		abort(); // TODO
     41 	case let ty: []ast::decl_type =>
     42 		abort(); // TODO
     43 	case let fu: ast::decl_func =>
     44 		return process_func(ctx, decl, &fu);
     45 	case let ex: ast::assert_expr =>
     46 		abort(); // TODO
     47 	};
     48 };
     49 
     50 fn process_func(
     51 	ctx: *context,
     52 	adecl: *ast::decl,
     53 	func: *ast::decl_func,
     54 ) (decl | error) = {
     55 	assert(func.attrs & ast::fndecl_attr::TEST == 0); // TODO
     56 	const afndecl = adecl.decl as ast::decl_func;
     57 	const prototype = types::lookup(ctx.store, func.prototype)!;
     58 	const fntype = prototype.repr as types::func;
     59 	assert(fntype.variadism == types::variadism::NONE); // TODO
     60 	assert(len(fntype.params) == 0); // TODO
     61 
     62 	ctx.fntype = &fntype;
     63 	const body: nullable *expr = match (afndecl.body) {
     64 	case let abody: *ast::expr =>
     65 		yield process_expr(ctx, abody)?;
     66 	case null =>
     67 		yield null;
     68 	};
     69 
     70 	return decl {
     71 		exported = adecl.exported,
     72 		start = adecl.start,
     73 		end = adecl.end,
     74 		decl = decl_func {
     75 			symbol = afndecl.symbol,
     76 			// TODO: Add namespace to ident
     77 			ident = ast::ident_dup(afndecl.ident),
     78 			prototype = prototype,
     79 			body = body,
     80 			// TODO: We should make these enums inherited
     81 			attrs = afndecl.attrs: ast::fndecl_attr,
     82 		},
     83 	};
     84 };
     85 
     86 fn process_expr(
     87 	ctx: *context,
     88 	expr: *ast::expr,
     89 ) (*expr | error) = {
     90 	match (expr.expr) {
     91 	case ast::access_expr =>
     92 		return process_access(ctx, expr);
     93 	case ast::alloc_expr =>
     94 		abort(); // TODO
     95 	case ast::append_expr =>
     96 		abort(); // TODO
     97 	case ast::assert_expr =>
     98 		abort(); // TODO
     99 	case ast::assign_expr =>
    100 		abort(); // TODO
    101 	case ast::binarithm_expr =>
    102 		abort(); // TODO
    103 	case ast::binding_expr =>
    104 		return process_binding(ctx, expr);
    105 	case ast::break_expr =>
    106 		abort(); // TODO
    107 	case ast::call_expr =>
    108 		abort(); // TODO
    109 	case ast::cast_expr =>
    110 		abort(); // TODO
    111 	case ast::compound_expr =>
    112 		return process_compound(ctx, expr);
    113 	case ast::literal_expr =>
    114 		return process_constant(ctx, expr);
    115 	case ast::continue_expr =>
    116 		abort(); // TODO
    117 	case ast::defer_expr =>
    118 		abort(); // TODO
    119 	case ast::delete_expr =>
    120 		abort(); // TODO
    121 	case ast::error_assert_expr =>
    122 		abort(); // TODO
    123 	case ast::for_expr =>
    124 		abort(); // TODO
    125 	case ast::free_expr =>
    126 		abort(); // TODO
    127 	case ast::if_expr =>
    128 		abort(); // TODO
    129 	case ast::match_expr =>
    130 		abort(); // TODO
    131 	case ast::len_expr =>
    132 		abort(); // TODO
    133 	case ast::size_expr =>
    134 		abort(); // TODO
    135 	case ast::offset_expr =>
    136 		abort(); // TODO
    137 	case ast::propagate_expr =>
    138 		abort(); // TODO
    139 	case ast::return_expr =>
    140 		return process_return(ctx, expr);
    141 	case ast::slice_expr =>
    142 		abort(); // TODO
    143 	case ast::switch_expr =>
    144 		abort(); // TODO
    145 	case ast::unarithm_expr =>
    146 		abort(); // TODO
    147 	};
    148 };
    149 
    150 fn process_access(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    151 	const access_expr = aexpr.expr as ast::access_expr;
    152 	const (result, ex) = match (access_expr) {
    153 	case let ai: ast::access_identifier =>
    154 		const object = match (ctx_lookup(ctx, ai)) {
    155 		case null =>
    156 			abort(); // TODO: Error
    157 		case let obj: *object =>
    158 			yield obj;
    159 		};
    160 		yield (object._type, object);
    161 	case let ai: ast::access_index =>
    162 		abort(); // TODO
    163 	case let af: ast::access_field =>
    164 		abort(); // TODO
    165 	case let at: ast::access_tuple =>
    166 		abort(); // TODO
    167 	};
    168 	return alloc(expr {
    169 		start = aexpr.start,
    170 		end = aexpr.end,
    171 		result = result,
    172 		expr = ex,
    173 		terminates = false,
    174 	});
    175 };
    176 
    177 fn process_binding(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    178 	const bind = aexpr.expr as ast::binding_expr;
    179 	assert(!bind.is_static && bind.kind == ast::binding_kind::LET);
    180 
    181 	let bindings: bindings = [];
    182 	for (let i = 0z; i < len(bind.bindings); i += 1) {
    183 		const item = bind.bindings[i];
    184 		const init = process_expr(ctx, item.init)?;
    185 		const _type = match (item._type) {
    186 		case null =>
    187 			abort(); // TODO
    188 		case let ty: *ast::_type =>
    189 			yield types::lookup(ctx.store, ty)!;
    190 		};
    191 		const object = scope_insert(ctx, object {
    192 			kind = object_kind::BIND,
    193 			// TODO: tuple unpacking
    194 			ident = ast::ident_dup([item.name as str]),
    195 			name = ast::ident_dup([item.name as str]),
    196 			_type = _type,
    197 			...
    198 		});
    199 		append(bindings, binding {
    200 			object = object,
    201 			init = init,
    202 		});
    203 	};
    204 	return alloc(expr {
    205 		start = aexpr.start,
    206 		end = aexpr.end,
    207 		result = &types::builtin_void,
    208 		expr = bindings,
    209 		...
    210 	});
    211 };
    212 
    213 fn process_compound(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    214 	const compound_expr = aexpr.expr as ast::compound_expr;
    215 	const scope = scope_push(ctx, scope_class::COMPOUND);
    216 
    217 	let exprs: compound = alloc([], len(compound_expr.exprs));
    218 	let i = 0z;
    219 	for (i < len(compound_expr.exprs); i += 1) {
    220 		append(exprs, process_expr(ctx, compound_expr.exprs[i])?);
    221 	};
    222 
    223 	scope_pop(ctx);
    224 	return alloc(expr {
    225 		start = aexpr.start,
    226 		end = aexpr.end,
    227 		result = &types::builtin_void, // TODO: Pick result type
    228 		expr = exprs,
    229 		terminates = exprs[i - 1].terminates,
    230 		...
    231 	});
    232 };
    233 
    234 fn process_constant(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    235 	const constexpr = aexpr.expr as ast::literal_expr;
    236 	const (result, ex) = match (constexpr) {
    237 	case let v: ast::value =>
    238 		yield (
    239 			// TODO: iconst/fconst lowering
    240 			types::lookup_builtin(ctx.store, match (v) {
    241 			case ast::_null =>
    242 				yield ast::builtin_type::NULL;
    243 			case let b: bool =>
    244 				yield ast::builtin_type::BOOL;
    245 			case let s: str =>
    246 				yield ast::builtin_type::STR;
    247 			case let r: rune =>
    248 				yield ast::builtin_type::RUNE;
    249 			case void =>
    250 				yield ast::builtin_type::VOID;
    251 			}),
    252 			v: constant,
    253 		);
    254 	case ast::array_literal =>
    255 		abort(); // TODO
    256 	case let v: ast::number_literal =>
    257 		yield (
    258 			types::lookup_builtin(ctx.store, switch (v.suff) {
    259 			case lex::ltok::LIT_U8 =>
    260 				yield ast::builtin_type::U8;
    261 			case lex::ltok::LIT_U16 =>
    262 				yield ast::builtin_type::U16;
    263 			case lex::ltok::LIT_U32 =>
    264 				yield ast::builtin_type::U32;
    265 			case lex::ltok::LIT_U64 =>
    266 				yield ast::builtin_type::U64;
    267 			case lex::ltok::LIT_UINT =>
    268 				yield ast::builtin_type::UINT;
    269 			case lex::ltok::LIT_SIZE =>
    270 				yield ast::builtin_type::SIZE;
    271 			case lex::ltok::LIT_I8 =>
    272 				yield ast::builtin_type::I8;
    273 			case lex::ltok::LIT_I16 =>
    274 				yield ast::builtin_type::I16;
    275 			case lex::ltok::LIT_I32 =>
    276 				yield ast::builtin_type::I32;
    277 			case lex::ltok::LIT_I64 =>
    278 				yield ast::builtin_type::I64;
    279 			case lex::ltok::LIT_INT, lex::ltok::LIT_ICONST =>
    280 				yield ast::builtin_type::INT;
    281 			case lex::ltok::LIT_F32 =>
    282 				yield ast::builtin_type::F32;
    283 			case lex::ltok::LIT_F64, lex::ltok::LIT_FCONST =>
    284 				yield ast::builtin_type::F64;
    285 			case => abort(); // unreachable
    286 			}),
    287 			v.value: constant,
    288 		);
    289 	case ast::struct_literal =>
    290 		abort(); // TODO
    291 	case ast::tuple_literal =>
    292 		abort(); // TODO
    293 	};
    294 	return alloc(expr {
    295 		start = aexpr.start,
    296 		end = aexpr.end,
    297 		result = result,
    298 		expr = ex,
    299 		...
    300 	});
    301 };
    302 
    303 fn process_return(ctx: *context, aexpr: *ast::expr) (*expr | error) = {
    304 	const ret = aexpr.expr as ast::return_expr;
    305 	const rval = match (ret) {
    306 	case null =>
    307 		yield null;
    308 	case let aexpr: *ast::expr =>
    309 		yield process_expr(ctx, aexpr)?;
    310 	};
    311 	// TODO: assert(types::assignable(ctx.fntype.result as *types::func, rval.type));
    312 	return alloc(expr {
    313 		start = aexpr.start,
    314 		end = aexpr.end,
    315 		terminates = true,
    316 		result = &types::builtin_void,
    317 		expr = rval: _return,
    318 	});
    319 };