process.ha (7991B)
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 };