hare

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

resolve.ha (4181B)


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