hare

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

resolver.ha (4171B)


      1 // License: GPL-3.0
      2 // (c) 2021 Drew DeVault <sir@cmpwn.com>
      3 // (c) 2021 Eyal 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::extension(in.path);
    145 		if (ext.1 != ".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 };