resolver.ha (4204B)
1 // License: GPL-3.0 2 // (c) 2021 Drew DeVault <sir@cmpwn.com> 3 // (c) 2021 Ember Sawady <ecs@d2evs.net> 4 // (c) 2022 Alexey Yerin <yyp@disroot.org> 5 use fmt; 6 use hare::ast; 7 use hare::module; 8 use path; 9 10 type symkind = enum { 11 LOCAL, 12 MODULE, 13 SYMBOL, 14 ENUM_LOCAL, 15 ENUM_REMOTE, 16 }; 17 18 // Resolves a reference. Given an identifier, determines if it refers to a local 19 // symbol, a module, or a symbol in a remote module, then returns this 20 // information combined with a corrected ident if necessary. 21 fn resolve(ctx: *context, what: ast::ident) ((ast::ident, symkind) | void) = { 22 if (is_local(ctx, what)) { 23 return (what, symkind::LOCAL); 24 }; 25 26 if (len(what) > 1) { 27 // Look for symbol in remote module 28 let partial = what[..len(what) - 1]; 29 30 match (module::lookup(ctx.mctx, partial)) { 31 case let ver: module::version => 32 return (what, symkind::SYMBOL); 33 case module::error => void; 34 }; 35 }; 36 if (len(what) == 2) { 37 match (lookup_local_enum(ctx, what)) { 38 case let id: ast::ident => 39 return (id, symkind::ENUM_LOCAL); 40 case => void; 41 }; 42 }; 43 if (len(what) > 2) { 44 match (lookup_remote_enum(ctx, what)) { 45 case let id: ast::ident => 46 return (id, symkind::ENUM_REMOTE); 47 case => void; 48 }; 49 }; 50 51 match (module::lookup(ctx.mctx, what)) { 52 case let ver: module::version => 53 return (what, symkind::MODULE); 54 case module::error => void; 55 }; 56 57 return; 58 }; 59 60 fn is_local(ctx: *context, what: ast::ident) bool = { 61 if (len(what) != 1) { 62 return false; 63 }; 64 65 const summary = ctx.summary; 66 for (let i = 0z; i < len(summary.constants); i += 1) { 67 const name = decl_ident(summary.constants[i])[0]; 68 if (name == what[0]) { 69 return true; 70 }; 71 }; 72 for (let i = 0z; i < len(summary.errors); i += 1) { 73 const name = decl_ident(summary.errors[i])[0]; 74 if (name == what[0]) { 75 return true; 76 }; 77 }; 78 for (let i = 0z; i < len(summary.types); i += 1) { 79 const name = decl_ident(summary.types[i])[0]; 80 if (name == what[0]) { 81 return true; 82 }; 83 }; 84 for (let i = 0z; i < len(summary.globals); i += 1) { 85 const name = decl_ident(summary.globals[i])[0]; 86 if (name == what[0]) { 87 return true; 88 }; 89 }; 90 for (let i = 0z; i < len(summary.funcs); i += 1) { 91 const name = decl_ident(summary.funcs[i])[0]; 92 if (name == what[0]) { 93 return true; 94 }; 95 }; 96 97 return false; 98 }; 99 100 fn lookup_local_enum(ctx: *context, what: ast::ident) (ast::ident | void) = { 101 for (let i = 0z; i < len(ctx.summary.types); i += 1) { 102 const decl = ctx.summary.types[i]; 103 const name = decl_ident(decl)[0]; 104 if (name == what[0]) { 105 const t = (decl.decl as []ast::decl_type)[0]; 106 const e = match (t._type.repr) { 107 case let e: ast::enum_type => 108 yield e; 109 case => 110 return; 111 }; 112 for (let i = 0z; i < len(e.values); i += 1) { 113 if (e.values[i].name == what[1]) { 114 return what; 115 }; 116 }; 117 }; 118 }; 119 }; 120 121 fn lookup_remote_enum(ctx: *context, what: ast::ident) (ast::ident | void) = { 122 // mod::decl_name::member 123 const mod = what[..len(what) - 2]; 124 const decl_name = what[len(what) - 2]; 125 const member = what[len(what) - 1]; 126 127 const version = match (module::lookup(ctx.mctx, mod)) { 128 case let ver: module::version => 129 yield ver; 130 case module::error => 131 abort(); 132 }; 133 134 // This would take a lot of memory to load 135 let decls: []ast::decl = []; 136 defer { 137 for (let i = 0z; i < len(decls); i += 1) { 138 ast::decl_finish(decls[i]); 139 }; 140 free(decls); 141 }; 142 for (let i = 0z; i < len(version.inputs); i += 1) { 143 const in = version.inputs[i]; 144 const ext = path::peek_ext(&path::init(in.path)!); 145 if (ext is void || ext as str != "ha") { 146 continue; 147 }; 148 match (scan(in.path)) { 149 case let u: ast::subunit => 150 append(decls, u.decls...); 151 case let err: error => 152 fmt::fatal("Error:", strerror(err)); 153 }; 154 }; 155 156 for (let i = 0z; i < len(decls); i += 1) { 157 const decl = match (decls[i].decl) { 158 case let t: []ast::decl_type => 159 yield t; 160 case => continue; 161 }; 162 for (let i = 0z; i < len(decl); i += 1) { 163 if (decl[i].ident[0] == decl_name) { 164 const e = match (decl[i]._type.repr) { 165 case let e: ast::enum_type => 166 yield e; 167 case => 168 abort(); 169 }; 170 for (let i = 0z; i < len(e.values); i += 1) { 171 if (e.values[i].name == member) { 172 return what; 173 }; 174 }; 175 }; 176 }; 177 }; 178 };