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