hare

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

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 };