hare

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

commit b45186d80229a7f947149f5d0584f32c09a4bc19
parent a251d8176239e4c45b9cb39bb83fde28770f37df
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Fri, 28 May 2021 11:45:12 -0400

hare::parse: add location tests

Signed-off-by: Eyal Sawady <ecs@d2evs.net>

Diffstat:
Ahare/parse/+test/loc.ha | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mscripts/gen-stdlib | 1+
Mstdlib.mk | 1+
3 files changed, 126 insertions(+), 0 deletions(-)

diff --git a/hare/parse/+test/loc.ha b/hare/parse/+test/loc.ha @@ -0,0 +1,124 @@ +use bufio; +use encoding::utf8; +use fmt; +use hare::ast; +use hare::lex; +use io; +use io::{mode}; +use strings; + +fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { + let buf = bufio::fixed(strings::toutf8(srcs[i]), mode::READ); + defer io::close(buf); + let lexer = lex::init(buf, "<test>"); + let exp = match (expression(&lexer)) { + exp: ast::expr => exp, + err: error => { + fmt::errorln(strerror(err))!; + abort(); + }, + }; + defer ast::expr_free(exp); + let runes = 0z; + let d = utf8::decode(srcs[i]); + for (true) match (utf8::next(&d)!) { + void => break, + rune => runes += 1, + }; + assert(exp.start.line == 1 && exp.start.col == 1); + assert(exp.end.line == 1 && exp.end.col == runes); +}; + +@test fn expr_loc() void = { + expr_testloc("foo", "foo[bar]", "foo.bar", "foo.1"); + expr_testloc("alloc(foo)"); + expr_testloc("append(foo, bar)", "append(foo, bar, baz)"); + expr_testloc("assert(foo)", "assert(foo, \"bar\")", "abort()", + "abort(\"foo\")"); + expr_testloc("foo = bar"); + expr_testloc("foo * bar"); + expr_testloc("let foo: bar = baz", "let foo: bar = baz, quux = quuux", + "const foo: bar = baz", "const foo: bar = baz, quux = quuux"); + expr_testloc("break", "break :foo"); + expr_testloc("foo(bar)"); + expr_testloc("foo: bar"); + expr_testloc("[foo, bar]", "[foo, bar...]"); + expr_testloc("foo { bar = baz, ... }", "struct { foo: bar = baz, }"); + expr_testloc("(foo, bar)"); + expr_testloc("null", "void", "true", "\"שלום\""); + expr_testloc("continue :foo"); + expr_testloc("defer foo"); + expr_testloc("delete(foo[bar])", "delete(foo[bar..baz])"); + expr_testloc("for (let foo = 0; bar; baz) quux", + ":foo for (let bar = 0; baz; quux) quuux"); + expr_testloc("free(foo)"); + expr_testloc("if (foo) bar", "if (foo) bar else baz"); + expr_testloc("len(foo)"); + expr_testloc("{ foo; bar; }"); + expr_testloc("match (foo) { * => bar }"); + expr_testloc("foo?"); + expr_testloc("return foo"); + expr_testloc("size(int)"); + expr_testloc("switch (foo) { * => bar }"); + expr_testloc("foo[bar..baz]"); + expr_testloc("&foo"); + + // We want to check the location of nested expressions, so this can't + // use expr_testloc + let buf = bufio::fixed(strings::toutf8("foo: bar: baz"), mode::READ); + defer io::close(buf); + let lexer = lex::init(buf, "<test>"); + let exp = match (expression(&lexer)) { + exp: ast::expr => exp, + err: error => { + fmt::errorln(strerror(err))!; + abort(); + }, + }; + defer ast::expr_free(exp); + assert(exp.start.line == 1 && exp.start.col == 1); + assert(exp.end.line == 1 && exp.end.col == 13); + let c = exp.expr as ast::cast_expr; + exp = *c.value; + assert(exp.start.line == 1 && exp.start.col == 1); + assert(exp.end.line == 1 && exp.end.col == 8); + c = exp.expr as ast::cast_expr; + exp = *c.value; + assert(exp.start.line == 1 && exp.start.col == 1); + assert(exp.end.line == 1 && exp.end.col == 3); +}; + +fn type_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { + let buf = bufio::fixed(strings::toutf8(srcs[i]), mode::READ); + defer io::close(buf); + let lexer = lex::init(buf, "<test>"); + let typ = match (_type(&lexer)) { + typ: ast::_type => typ, + err: error => { + fmt::errorln(strerror(err))!; + abort(); + }, + }; + defer ast::type_free(typ); + let runes = 0z; + let d = utf8::decode(srcs[i]); + for (true) match (utf8::next(&d)!) { + void => break, + rune => runes += 1, + }; + assert(typ.start.line == 1 && typ.start.col == 1); + assert(typ.end.line == 1 && typ.end.col == runes); +}; + +@test fn type_loc() void = { + type_testloc("foo", "...foo"); + type_testloc("int"); + type_testloc("enum { FOO = bar }"); + type_testloc("fn(foo: bar) baz", "@noreturn fn(foo: bar) baz"); + type_testloc("[foo]bar", "[*]foo", "[]foo", "[_]int"); + type_testloc("*foo", "nullable *int"); + type_testloc("struct { foo: bar }"); + type_testloc("union { foo: bar }"); + type_testloc("(foo | bar)"); + type_testloc("(foo, bar)"); +}; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -440,6 +440,7 @@ hare_parse() { gensrcs_hare_parse \ +test/expr.ha \ +test/ident.ha \ + +test/loc.ha \ +test/roundtrip.ha \ +test/types.ha \ +test/unit.ha diff --git a/stdlib.mk b/stdlib.mk @@ -1698,6 +1698,7 @@ testlib_hare_parse_srcs= \ $(STDLIB)/hare/parse/unit.ha \ $(STDLIB)/hare/parse/+test/expr.ha \ $(STDLIB)/hare/parse/+test/ident.ha \ + $(STDLIB)/hare/parse/+test/loc.ha \ $(STDLIB)/hare/parse/+test/roundtrip.ha \ $(STDLIB)/hare/parse/+test/types.ha \ $(STDLIB)/hare/parse/+test/unit.ha