parse.ha (2395B)
1 // License: MPL-2.0 2 // (c) 2022 Alexey Yerin <yyp@disroot.org> 3 // (c) 2021 Byron Torres <b@torresjrjr.com> 4 // (c) 2021 Drew DeVault <sir@cmpwn.com> 5 // (c) 2021 Ember Sawady <ecs@d2evs.net> 6 use fmt; 7 use hare::lex::{ltok}; 8 use hare::lex; 9 use io; 10 use memio; 11 12 // All possible error types. 13 export type error = !lex::error; 14 15 // Convert an error into a human-friendly string. 16 export fn strerror(err: error) const str = lex::strerror(err: lex::error); 17 18 fn syntaxerr( 19 loc: lex::location, 20 fmt: str, 21 args: fmt::field... 22 ) lex::error = { 23 let why = fmt::asprintf(fmt, args...); 24 return lex::syntaxerr(loc, why); 25 }; 26 27 // Requires the next token to have a matching ltok. Returns that token, or an 28 // error. 29 fn want(lexer: *lex::lexer, want: lex::ltok...) (lex::token | error) = { 30 let tok = lex::lex(lexer)?; 31 if (len(want) == 0) { 32 return tok; 33 }; 34 for (let i = 0z; i < len(want); i += 1) { 35 if (tok.0 == want[i]) { 36 return tok; 37 }; 38 }; 39 40 let buf = memio::dynamic(); 41 defer io::close(&buf)!; 42 for (let i = 0z; i < len(want); i += 1) { 43 const tstr = if (want[i] == ltok::NAME) "name" 44 else lex::tokstr((want[i], void, lex::mkloc(lexer))); 45 fmt::fprintf(&buf, "'{}'", tstr)!; 46 if (i + 1 < len(want)) { 47 fmt::fprint(&buf, ", ")!; 48 }; 49 }; 50 lex::unlex(lexer, tok); 51 return syntaxerr(lex::mkloc(lexer), "Unexpected '{}', was expecting {}", 52 lex::tokstr(tok), memio::string(&buf)!); 53 }; 54 55 // Looks for a matching ltok from the lexer, and if not present, unlexes the 56 // token and returns void. If found, the token is consumed from the lexer and is 57 // returned. 58 fn try( 59 lexer: *lex::lexer, 60 want: lex::ltok... 61 ) (lex::token | error | void) = { 62 let tok = lex::lex(lexer)?; 63 assert(len(want) > 0); 64 for (let i = 0z; i < len(want); i += 1) { 65 if (tok.0 == want[i]) { 66 return tok; 67 }; 68 }; 69 lex::unlex(lexer, tok); 70 }; 71 72 // Looks for a matching ltok from the lexer, unlexes the token, and returns 73 // it; or void if it was not an ltok. 74 fn peek( 75 lexer: *lex::lexer, 76 want: lex::ltok... 77 ) (lex::token | error | void) = { 78 let tok = lex::lex(lexer)?; 79 lex::unlex(lexer, tok); 80 if (len(want) == 0) { 81 return tok; 82 }; 83 for (let i = 0z; i < len(want); i += 1) { 84 if (tok.0 == want[i]) { 85 return tok; 86 }; 87 }; 88 }; 89 90 // Returns a syntax error if cond is false and void otherwise 91 fn synassert(loc: lex::location, cond: bool, msg: str) (void | error) = { 92 if (!cond) { 93 return syntaxerr(loc, "{}", msg); 94 }; 95 };