resolve.ha (4147B)
1 // SPDX-License-Identifier: GPL-3.0-only 2 // (c) Hare authors <https://harelang.org> 3 4 use bufio; 5 use fmt; 6 use fs; 7 use hare::ast; 8 use hare::lex; 9 use hare::module; 10 use hare::parse; 11 use io; 12 use os; 13 use path; 14 use types; 15 16 type symkind = enum { 17 LOCAL, 18 MODULE, 19 SYMBOL, 20 ENUM_LOCAL, 21 ENUM_REMOTE, 22 }; 23 24 // Resolves a reference. Given an identifier, determines if it refers to a local 25 // symbol, a module, or a symbol in a remote module, then returns this 26 // information combined with a corrected ident if necessary. 27 fn resolve(ctx: *context, what: ast::ident) ((ast::ident, symkind) | void | error) = { 28 if (is_local(ctx, what)) { 29 return (what, symkind::LOCAL); 30 }; 31 32 if (len(what) > 1) { 33 // Look for symbol in remote module 34 let partial = what[..len(what) - 1]; 35 36 match (module::find(ctx.mctx, partial)) { 37 case let r: (str, module::srcset) => 38 module::finish_srcset(&r.1); 39 return (what, symkind::SYMBOL); 40 case module::error => void; 41 }; 42 }; 43 if (len(what) == 2) { 44 match (lookup_local_enum(ctx, what)) { 45 case let id: ast::ident => 46 return (id, symkind::ENUM_LOCAL); 47 case => void; 48 }; 49 }; 50 if (len(what) > 2) { 51 match (lookup_remote_enum(ctx, what)?) { 52 case let id: ast::ident => 53 return (id, symkind::ENUM_REMOTE); 54 case => void; 55 }; 56 }; 57 58 match (module::find(ctx.mctx, what)) { 59 case let r: (str, module::srcset) => 60 module::finish_srcset(&r.1); 61 return (what, symkind::MODULE); 62 case module::error => void; 63 }; 64 65 return; 66 }; 67 68 fn is_local(ctx: *context, what: ast::ident) bool = { 69 if (len(what) != 1) { 70 return false; 71 }; 72 73 const summary = ctx.summary; 74 for (let c &.. summary.constants) { 75 const name = decl_ident(c)[0]; 76 if (name == what[0]) { 77 return true; 78 }; 79 }; 80 for (let e &.. summary.errors) { 81 const name = decl_ident(e)[0]; 82 if (name == what[0]) { 83 return true; 84 }; 85 }; 86 for (let t &.. summary.types) { 87 const name = decl_ident(t)[0]; 88 if (name == what[0]) { 89 return true; 90 }; 91 }; 92 for (let g &.. summary.globals) { 93 const name = decl_ident(g)[0]; 94 if (name == what[0]) { 95 return true; 96 }; 97 }; 98 for (let f &.. summary.funcs) { 99 const name = decl_ident(f)[0]; 100 if (name == what[0]) { 101 return true; 102 }; 103 }; 104 105 return false; 106 }; 107 108 fn lookup_local_enum(ctx: *context, what: ast::ident) (ast::ident | void) = { 109 for (let decl &.. ctx.summary.types) { 110 const name = decl_ident(decl)[0]; 111 if (name == what[0]) { 112 const t = (decl.decl as []ast::decl_type)[0]; 113 const e = match (t._type.repr) { 114 case let e: ast::enum_type => 115 yield e; 116 case => 117 return; 118 }; 119 for (let value .. e.values) { 120 if (value.name == what[1]) { 121 return what; 122 }; 123 }; 124 }; 125 }; 126 }; 127 128 fn lookup_remote_enum(ctx: *context, what: ast::ident) (ast::ident | void | error) = { 129 // mod::decl_name::member 130 const mod = what[..len(what) - 2]; 131 const decl_name = what[len(what) - 2]; 132 const member = what[len(what) - 1]; 133 134 const srcs = match (module::find(ctx.mctx, mod)) { 135 case let s: (str, module::srcset) => 136 yield s.1; 137 case let e: module::error => 138 module::finish_error(e); 139 return void; 140 }; 141 142 // This would take a lot of memory to load 143 let decls: []ast::decl = []; 144 defer { 145 for (let decl .. decls) { 146 ast::decl_finish(decl); 147 }; 148 free(decls); 149 }; 150 for (let in .. srcs.ha) { 151 let u = scan(in)?; 152 append(decls, u.decls...); 153 }; 154 155 for (let decl .. decls) { 156 const decls = match (decl.decl) { 157 case let t: []ast::decl_type => 158 yield t; 159 case => 160 continue; 161 }; 162 163 for (let d .. decls) { 164 if (d.ident[0] == decl_name) { 165 const e = match (d._type.repr) { 166 case let e: ast::enum_type => 167 yield e; 168 case => 169 abort(); 170 }; 171 for (let value .. e.values) { 172 if (value.name == member) { 173 return what; 174 }; 175 }; 176 }; 177 }; 178 }; 179 }; 180 181 export fn scan(path: str) (ast::subunit | error) = { 182 const input = match (os::open(path)) { 183 case let f: io::file => 184 yield f; 185 case let err: fs::error => 186 fmt::fatalf("Error reading {}: {}", path, fs::strerror(err)); 187 }; 188 defer io::close(input)!; 189 let sc = bufio::newscanner(input, types::SIZE_MAX); 190 defer bufio::finish(&sc); 191 let lexer = lex::init(&sc, path, lex::flag::COMMENTS); 192 return parse::subunit(&lexer)?; 193 };