hare

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

types.ha (3212B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use encoding::utf8;
      5 use fs;
      6 use hare::ast;
      7 use hare::parse;
      8 use hare::unparse;
      9 use io;
     10 use memio;
     11 use path;
     12 use strings;
     13 
     14 // A module was not found.
     15 export type not_found = !void;
     16 
     17 // A tag contains a dot.
     18 export type tag_has_dot = !void;
     19 
     20 // Generic badly formatted tag error.
     21 export type tag_bad_format = !void;
     22 
     23 // A dependency cycle error.
     24 export type dep_cycle = ![]str;
     25 
     26 // Two files in a module have the same basename and extension, and the
     27 // same number of compatible tags with the input tagset, so it is unknown
     28 // which should be used.
     29 export type file_conflict = ![]str;
     30 
     31 // Context for another error.
     32 export type errcontext = !(str, *error);
     33 
     34 // Tagged union of all possible error types. Must be freed with [[finish_error]]
     35 // unless it's passed to [[strerror]].
     36 export type error = !(
     37 	fs::error |
     38 	io::error |
     39 	path::error |
     40 	parse::error |
     41 	utf8::invalid |
     42 	file_conflict |
     43 	not_found |
     44 	dep_cycle |
     45 	tag_has_dot |
     46 	tag_bad_format |
     47 	errcontext |
     48 );
     49 
     50 // A container struct for context, used by [[gather]].
     51 export type context = struct {
     52 	harepath: str,
     53 	harecache: str,
     54 	tags: []str,
     55 };
     56 
     57 // The location of a module
     58 export type location = (*path::buffer | ast::ident);
     59 
     60 // Returns a string representation of a [[location]]. The result must be freed
     61 // by the caller.
     62 export fn locstr(loc: location) str = {
     63 	match (loc) {
     64 	case let buf: *path::buffer =>
     65 		return strings::dup(path::string(buf));
     66 	case let id: ast::ident =>
     67 		return unparse::identstr(id);
     68 	};
     69 };
     70 
     71 // XXX: this shouldn't be necessary, the language should have some built-in way
     72 // to carry context with errors
     73 fn attach(ctx: str, e: error) errcontext = (ctx, alloc(e)): errcontext;
     74 
     75 // Free the resources associated with an [[error]].
     76 export fn finish_error(e: error) void = {
     77 	match (e) {
     78 	case let e: dep_cycle =>
     79 		strings::freeall(e);
     80 	case let e: file_conflict =>
     81 		strings::freeall(e);
     82 	case let ctx: errcontext =>
     83 		finish_error(*ctx.1);
     84 		free(ctx.0);
     85 		free(ctx.1);
     86 	case => void;
     87 	};
     88 };
     89 
     90 // Turns an [[error]] into a human-readable string. The result is
     91 // statically allocated. Consumes the error.
     92 export fn strerror(e: error) str = {
     93 	defer finish_error(e);
     94 	static let buf: [2*path::MAX]u8 = [0...];
     95 	let buf = memio::fixed(buf[..]);
     96 	_strerror(e, &buf);
     97 	return memio::string(&buf)!;
     98 };
     99 
    100 fn _strerror(e: error, buf: *memio::stream) void = {
    101 	let s = match (e) {
    102 	case let e: fs::error =>
    103 		yield fs::strerror(e);
    104 	case let e: io::error =>
    105 		yield io::strerror(e);
    106 	case let e: parse::error =>
    107 		yield parse::strerror(e);
    108 	case let e: path::error =>
    109 		yield path::strerror(e);
    110 	case utf8::invalid =>
    111 		yield "Invalid UTF-8";
    112 	case not_found =>
    113 		yield "Module not found";
    114 	case tag_has_dot =>
    115 		yield "Tag contains a '.'";
    116 	case tag_bad_format =>
    117 		yield "Bad tag format";
    118 	case let e: dep_cycle =>
    119 		memio::concat(buf, "Dependency cycle: ")!;
    120 		memio::join(buf, " -> ", e...)!;
    121 		return;
    122 	case let e: file_conflict =>
    123 		memio::concat(buf, "File conflict: ")!;
    124 		memio::join(buf, ", ", e...)!;
    125 		return;
    126 	case let ctx: errcontext =>
    127 		memio::concat(buf, ctx.0, ": ")!;
    128 		_strerror(*ctx.1, buf);
    129 		return;
    130 	};
    131 	memio::concat(buf, s)!;
    132 };