sys

A set of unix utils in hare!
Log | Files | Refs | README

parse.ha (1919B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use fmt;
      5 use lexical::lex;
      6 use io;
      7 use memio;
      8 
      9 // All possible error types.
     10 export type error = !lex::error;
     11 
     12 // Requires the next token to have a matching ltok. Returns that token, or an
     13 // error.
     14 export fn want(
     15 	lexer: *lex::lexer,
     16 	want: str...
     17 ) (*lex::token | error) = {
     18 	let tok = lex::next(lexer)?;
     19 	if (len(want) == 0) return tok;
     20 	for (let want .. want) if (tok.name == want) return tok;
     21 
     22 	let buf = memio::dynamic();
     23 	defer io::close(&buf)!;
     24 	lex::unlex(lexer, tok);
     25 	for (let i = 0z; i < len(want); i += 1) {
     26 		fmt::fprintf(&buf, "'{}'", want[i])!;
     27 		if (i + 1 < len(want)) fmt::fprint(&buf, ", ")!;
     28 	};
     29 	return lex::syntaxf(tok.start,
     30 		"Unexpected '{}', was expecting {}",
     31 		tok.name, memio::string(&buf)!);
     32 };
     33 
     34 // Looks for a matching ltok from the lexer, and if not present, unlexes the
     35 // token and returns void. If found, the token is consumed from the lexer and is
     36 // returned.
     37 export fn try(
     38 	lexer: *lex::lexer,
     39 	want: str...
     40 ) (*lex::token | error | void) = {
     41 	let tok = lex::next(lexer)?;
     42 	assert(len(want) > 0);
     43 	for (let want .. want) if (tok.name == want) return tok;
     44 	lex::unlex(lexer, tok);
     45 };
     46 
     47 // Looks for a matching ltok from the lexer, unlexes the token, and returns
     48 // it; or void if it was not an ltok.
     49 export fn peek(
     50 	lexer: *lex::lexer,
     51 	want: str...
     52 ) (*lex::token | error | void) = {
     53 	let tok = lex::next(lexer)?;
     54 	lex::unlex(lexer, tok);
     55 	if (len(want) == 0) return tok;
     56 	for (let want .. want) if (tok.name == want) return tok;
     57 };
     58 
     59 // Returns a syntax error if cond is false and void otherwise
     60 export fn synassert(
     61 	loc: lex::location,
     62 	cond: bool,
     63 	msg: const str,
     64 ) (void | error) = {
     65 	if (!cond) return lex::syntaxf(loc, msg);
     66 };
     67 
     68 export fn loc_from(lexer: *lex::lexer, start: lex::location) lex::ast_location = {
     69 	return lex::ast_location {
     70 		start = start,
     71 		end = lex::prevloc(lexer),
     72 	};
     73 };