loc.ha (4369B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use bufio; 5 use fmt; 6 use hare::ast; 7 use hare::lex; 8 use io; 9 use io::{mode}; 10 use memio; 11 use strings; 12 13 fn expr_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { 14 let buf = memio::fixed(strings::toutf8(srcs[i])); 15 let sc = bufio::newscanner(&buf); 16 defer bufio::finish(&sc); 17 let lexer = lex::init(&sc, "<test>"); 18 let exp = match (expr(&lexer)) { 19 case let exp: ast::expr => 20 yield exp; 21 case let err: error => 22 fmt::errorfln("{}: {}", srcs[i], strerror(err))!; 23 abort(); 24 }; 25 defer ast::expr_finish(&exp); 26 let runes = 0z; 27 let it = strings::iter(srcs[i]); 28 for (strings::next(&it) is rune) { 29 runes += 1; 30 }; 31 assert(exp.start.line == 1 && exp.start.col == 1); 32 assert(exp.end.line == 1 && exp.end.col == runes); 33 }; 34 35 @test fn expr_loc() void = { 36 expr_testloc("foo", "foo[bar]", "foo.bar", "foo.1"); 37 expr_testloc("alloc(foo)"); 38 expr_testloc("append(foo, bar)", "append(foo, bar, baz)"); 39 expr_testloc("assert(foo)", `assert(foo, "bar")`, "abort()", 40 `abort("foo")`); 41 expr_testloc("foo is bar", "foo as bar"); 42 expr_testloc("foo = bar"); 43 expr_testloc("foo * bar", "foo && bar"); 44 expr_testloc("break", "break :foo"); 45 expr_testloc("foo(bar)"); 46 expr_testloc("foo: bar"); 47 expr_testloc("[foo, bar]", "[foo, bar...]"); 48 expr_testloc("foo { bar = baz, ... }", "struct { foo: bar = baz, }"); 49 expr_testloc("(foo, bar)"); 50 expr_testloc("null", "void", "true", `"שלום"`, "'a'"); 51 expr_testloc("[foo, bar]"); 52 expr_testloc("123", "-123.456", "123z", "123e+3"); 53 expr_testloc("continue", "continue :foo"); 54 expr_testloc("delete(foo[bar])", "delete(foo[bar..baz])"); 55 expr_testloc("for (let foo = 0; bar; baz) quux", 56 "for (let bar = 0; baz; quux) quuux"); 57 expr_testloc("free(foo)"); 58 expr_testloc("if (foo) bar", "if (foo) bar else baz"); 59 expr_testloc("insert(foo[0], bar)", "insert(foo[0], bar, baz)"); 60 expr_testloc("len(foo)"); 61 expr_testloc("{ foo; bar; }", "{ defer foo; }", 62 "{ let foo: bar = baz; }", "{ let foo: bar = baz, quux = quuux; }", 63 "{ const foo: bar = baz; }", "{ const foo: bar = baz, quux = quuux; }"); 64 expr_testloc("match (foo) { case => bar; }"); 65 expr_testloc("offset(foo)"); 66 expr_testloc("foo?", "foo!"); 67 expr_testloc("return", "return foo"); 68 expr_testloc("size(int)"); 69 expr_testloc("switch (foo) { case => bar; }"); 70 expr_testloc("foo[bar..baz]"); 71 expr_testloc("&foo"); 72 expr_testloc("vastart()", "vaarg(ap)", "vaend(ap)"); 73 expr_testloc("yield", "yield foo", "yield :foo, bar"); 74 75 // We want to check the location of nested expressions, so this can't 76 // use expr_testloc 77 let buf = memio::fixed(strings::toutf8("foo: bar: baz")); 78 let sc = bufio::newscanner(&buf); 79 defer bufio::finish(&sc); 80 let lexer = lex::init(&sc, "<test>"); 81 let exp = match (expr(&lexer)) { 82 case let exp: ast::expr => 83 yield exp; 84 case let err: error => 85 fmt::errorln(strerror(err))!; 86 abort(); 87 }; 88 defer ast::expr_finish(&exp); 89 assert(exp.start.line == 1 && exp.start.col == 1); 90 assert(exp.end.line == 1 && exp.end.col == 13); 91 let c = exp.expr as ast::cast_expr; 92 exp = *c.value; 93 assert(exp.start.line == 1 && exp.start.col == 1); 94 assert(exp.end.line == 1 && exp.end.col == 8); 95 c = exp.expr as ast::cast_expr; 96 exp = *c.value; 97 assert(exp.start.line == 1 && exp.start.col == 1); 98 assert(exp.end.line == 1 && exp.end.col == 3); 99 }; 100 101 fn type_testloc(srcs: str...) void = for (let i = 0z; i < len(srcs); i += 1) { 102 let buf = memio::fixed(strings::toutf8(srcs[i])); 103 let sc = bufio::newscanner(&buf); 104 defer bufio::finish(&sc); 105 let lexer = lex::init(&sc, "<test>"); 106 let typ = match (_type(&lexer)) { 107 case let typ: ast::_type => 108 yield typ; 109 case let err: error => 110 fmt::errorln(strerror(err))!; 111 abort(); 112 }; 113 defer ast::type_finish(&typ); 114 let runes = 0z; 115 let it = strings::iter(srcs[i]); 116 for (strings::next(&it) is rune) { 117 runes += 1; 118 }; 119 assert(typ.start.line == 1 && typ.start.col == 1); 120 assert(typ.end.line == 1 && typ.end.col == runes); 121 }; 122 123 @test fn type_loc() void = { 124 type_testloc("foo", "...foo"); 125 type_testloc("int"); 126 type_testloc("enum { FOO = bar }"); 127 type_testloc("fn(foo: bar) baz"); 128 type_testloc("[foo]bar", "[*]foo", "[]foo", "[_]int"); 129 type_testloc("*foo", "nullable *int"); 130 type_testloc("struct { foo: bar }"); 131 type_testloc("union { foo: bar }"); 132 type_testloc("(foo | bar)"); 133 type_testloc("(foo, bar)"); 134 };