hare

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

commit 2ab02483e5356939d332ee44933787f6bc3e7cc2
parent 0a91e248b228a07bb36a7b14840ead5f64bcd45c
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 24 Mar 2021 10:14:18 -0400

hare::parse: improve error messages

Diffstat:
Mhare/parse/decl.ha | 19+++++++++++--------
Mhare/parse/type.ha | 8+++++---
Mhare/parse/types.ha | 11+++++++++--
Mhare/parse/util.ha | 33+++++++++++++++++++++------------
Mscripts/gen-stdlib | 4++--
Mstdlib.mk | 4++--
6 files changed, 50 insertions(+), 29 deletions(-)

diff --git a/hare/parse/decl.ha b/hare/parse/decl.ha @@ -1,7 +1,8 @@ use ascii; -use hare::lex; -use hare::lex::{btoken}; use hare::ast; +use hare::lex::{btoken}; +use hare::lex; +use hare::unparse; use strings; fn attr_symbol(lexer: *lex::lexer) (str | error) = { @@ -13,10 +14,12 @@ fn attr_symbol(lexer: *lex::lexer) (str | error) = { l: lex::literal => match (l) { s: str => (s, t.1), * => return syntaxerr(t.1, - "Expected string, got <something else>"), + "Unexpected {}, was expecting string", + lex::tokstr(t.0)), }, * => return syntaxerr(t.1, - "Expected string, got <something else>"), + "Unexpected {}, was expecting string", + lex::tokstr(t.0)), }, }; let d = strings::iter(s.0); @@ -122,7 +125,7 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = { let body = switch (tok) { btoken::EQUAL => { synassert(ident_loc, len(ident) == 1, - "Expected name, found identifier")?; + "Unexpected identifier, was expecting name")?; const params = prototype.params; for (let i = 0z; i < len(params); i += 1) { synassert(params[i].loc, @@ -158,14 +161,14 @@ export fn decls(lexer: *lex::lexer) ([]ast::decl | error) = { }; let tok = match(lex::lex(lexer)?) { io::EOF => return syntaxerr(mkloc(lexer), - "Expected declaration, found EOF"), + "Unexpected EOF, was expecting declaration"), t: (lex::token, lex::location) => t, }; let btok = match (tok.0) { b: lex::btoken => b, - // TODO: Use fmt+lex::tokstr here: * => return syntaxerr(mkloc(lexer), - "Expected declaration, found <something else>"), + "Unexpected {}, was expecting declaration", + lex::tokstr(tok.0)), }; let decl = switch (btok) { btoken::CONST, btoken::LET, btoken::DEF => diff --git a/hare/parse/type.ha b/hare/parse/type.ha @@ -86,7 +86,8 @@ fn primitive_type(lexer: *lex::lexer) (ast::_type | error) = { let b = match (t.0) { b: lex::btoken => b, * => return syntaxerr(mkloc(lexer), - "Expected primitive type, got <something else>"), + "Unexpected {}, was expecting primitive type", + lex::tokstr(t.0)), }; let builtin = switch (b) { btoken::CHAR, btoken::I16, btoken::I32, btoken::I64, @@ -211,7 +212,7 @@ export fn _type(lexer: *lex::lexer) (ast::_type | error) = { }; let t = match (lex::lex(lexer)?) { io::EOF => return syntaxerr(mkloc(lexer), - "Expected type, found EOF"), + "Unexpected EOF, was expecting type"), t: (lex::token, lex::location) => t, }; lex::unlex(lexer, t); @@ -243,7 +244,8 @@ export fn _type(lexer: *lex::lexer) (ast::_type | error) = { }, lex::name => alias_type(lexer)?, * => return syntaxerr(mkloc(lexer), - "Expected type, found <something>"), + "Unexpected {}, was expecting type", + lex::tokstr(t.0)), }; match (try_btoken(lexer, btoken::LNOT)?) { diff --git a/hare/parse/types.ha b/hare/parse/types.ha @@ -1,3 +1,4 @@ +use fmt; use hare::lex; // All possible error types @@ -6,8 +7,14 @@ export type error = lex::error!; // Convert an error into a human-friendly string export fn errstr(err: error) const str = lex::errstr(err: lex::error); -fn syntaxerr(loc: lex::location, why: str) lex::error = - (loc, why): lex::syntax: lex::error; +fn syntaxerr( + loc: lex::location, + fmt: str, + args: fmt::formattable... +) lex::error = { + let why = fmt::asprintf(fmt, args...); + return (loc, why): lex::syntax: lex::error; +}; fn mkloc(lex: *lex::lexer) lex::location = lex::location { path = lex.path, diff --git a/hare/parse/util.ha b/hare/parse/util.ha @@ -1,16 +1,19 @@ +use fmt; use hare::ast; use hare::lex; +use io; +use strio; // Requires the next token to be a name. Returns that name, or an error. fn want_name(lexer: *lex::lexer) (lex::name | error) = { match (lex::lex(lexer)?) { io::EOF => return syntaxerr(mkloc(lexer), - "Expected name, found EOF"), + "Unexpected EOF, was expecting name"), t: (lex::token, lex::location) => match (t.0) { n: lex::name => return n, - // TODO: Use fmt+lex::tokstr here: * => return syntaxerr(mkloc(lexer), - "Expected name, got <something else>"), + "Unexpected {}, was expecting name", + lex::tokstr(t.0)), }, }; }; @@ -34,9 +37,8 @@ fn want_btoken( lexer: *lex::lexer, want: lex::btoken... ) (lex::btoken | error) = { - match (lex::lex(lexer)?) { - io::EOF => return syntaxerr(mkloc(lexer), - "Expected name, found EOF"), + let tok: lex::token = match (lex::lex(lexer)?) { + io::EOF => return syntaxerr(mkloc(lexer), "Unexpected EOF"), t: (lex::token, lex::location) => match (t.0) { b: lex::btoken => { if (len(want) == 0) { @@ -47,15 +49,22 @@ fn want_btoken( return b; }; }; - // TODO: Use fmt+lex::tokstr here: - return syntaxerr(mkloc(lexer), - "Expected <something>, got <something else>"); + t.0; }, - // TODO: Use fmt+lex::tokstr here: - * => return syntaxerr(mkloc(lexer), - "Expected <something>, got <something else>"), + * => t.0, }, }; + + let buf = strio::dynamic(); + defer io::close(buf); + for (let i = 0z; i < len(want); i += 1) { + fmt::fprintf(buf, lex::tokstr(want[i])); + if (i + 1 < len(want)) { + fmt::fprint(buf, ", "); + }; + }; + return syntaxerr(mkloc(lexer), "Unexpected {}, was expecting {}", + lex::tokstr(tok), strio::string(buf)); }; // Looks for a matching btoken from the lexer, and if not present, unlexes the diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -315,12 +315,12 @@ hare_parse() { if [ $testing -eq 0 ] then gensrcs_hare_parse - gen_ssa hare::parse hare::ast hare::lex + gen_ssa hare::parse hare::ast hare::lex hare::unparse fmt else gensrcs_hare_parse \ +test.ha gen_ssa hare::parse bufio fmt hare::ast hare::lex hare::unparse io \ - strings strio + strings strio fmt fi } diff --git a/stdlib.mk b/stdlib.mk @@ -400,7 +400,7 @@ stdlib_hare_parse_srcs= \ $(STDLIB)/hare/parse/unit.ha \ $(STDLIB)/hare/parse/util.ha -$(HARECACHE)/hare/parse/hare_parse.ssa: $(stdlib_hare_parse_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_lex) +$(HARECACHE)/hare/parse/hare_parse.ssa: $(stdlib_hare_parse_srcs) $(stdlib_rt) $(stdlib_hare_ast) $(stdlib_hare_lex) $(stdlib_hare_unparse) $(stdlib_fmt) @printf 'HAREC \t$@\n' @mkdir -p $(HARECACHE)/hare/parse @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nhare::parse \ @@ -1053,7 +1053,7 @@ testlib_hare_parse_srcs= \ $(STDLIB)/hare/parse/util.ha \ $(STDLIB)/hare/parse/+test.ha -$(TESTCACHE)/hare/parse/hare_parse.ssa: $(testlib_hare_parse_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_fmt) $(testlib_hare_ast) $(testlib_hare_lex) $(testlib_hare_unparse) $(testlib_io) $(testlib_strings) $(testlib_strio) +$(TESTCACHE)/hare/parse/hare_parse.ssa: $(testlib_hare_parse_srcs) $(testlib_rt) $(testlib_bufio) $(testlib_fmt) $(testlib_hare_ast) $(testlib_hare_lex) $(testlib_hare_unparse) $(testlib_io) $(testlib_strings) $(testlib_strio) $(testlib_fmt) @printf 'HAREC \t$@\n' @mkdir -p $(TESTCACHE)/hare/parse @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nhare::parse \