unit.ha (4477B)
1 // License: MPL-2.0 2 // (c) 2022 Alexey Yerin <yyp@disroot.org> 3 // (c) 2021 Armin Weigl <tb46305@gmail.com> 4 // (c) 2021 Drew DeVault <sir@cmpwn.com> 5 // (c) 2021 Ember Sawady <ecs@d2evs.net> 6 // (c) 2022 Sebastian <sebastian@sebsite.pw> 7 use bufio; 8 use hare::ast; 9 use hare::lex; 10 use io::{mode}; 11 use strings; 12 13 fn import_eq(i1: ast::import, i2: ast::import) bool = { 14 if (i1.mode != i2.mode) { 15 return false; 16 }; 17 if (!ast::ident_eq(i1.ident, i2.ident)) { 18 return false; 19 }; 20 let mode = i1.mode; 21 if (mode & ast::import_mode::ALIAS != 0 && i1.alias != i2.alias) { 22 return false; 23 }; 24 if (mode & ast::import_mode::MEMBERS != 0) { 25 for (let i = 0z; i < len(i1.objects); i += 1) { 26 let o1 = i1.objects[i], o2 = i2.objects[i]; 27 if (o1.0 is void ^^ o2.0 is void) { 28 return false; 29 }; 30 if (o1.0 is str && o1.0: str != o2.0: str) { 31 return false; 32 }; 33 if (o1.1 != o2.1) { 34 return false; 35 }; 36 }; 37 }; 38 return true; 39 }; 40 41 type import_tuple = (ast::import_mode, ast::ident, str, []((str | void), str)); 42 43 fn tup_to_import(tup: import_tuple) ast::import = ast::import { 44 mode = tup.0, 45 ident = tup.1, 46 alias = tup.2, 47 objects = tup.3, 48 ... 49 }; 50 51 @test fn imports() void = { 52 const in = 53 "use foo;\n" 54 "use bar;\n" 55 "use baz::bat;\n\n" 56 57 "use foo = bar;\n" 58 "use baz = bat;\n" 59 "use qux = quux::corge;\n" 60 61 "use foo::*;" 62 "use foo::bar::quux::*;" 63 64 "use foo::{bar};\n" 65 "use foo::{bar,};\n" 66 "use baz::{bat, qux};\n" 67 "use quux::corge::{grault, garply,};\n" 68 69 "use quux::{alias = grault};\n" 70 "use quux::{alias = grault,};\n" 71 "use quux::{alias = grault, garply};\n" 72 "use quux::{alias = grault, alias2 = garply};\n" 73 74 "use alias = quux::corge::{grault, garply,};\n" 75 "use modalias = quux::{alias = grault, alias2 = garply};\n" 76 77 "export fn main() void = void;"; 78 let buf = bufio::fixed(strings::toutf8(in), mode::READ); 79 let lexer = lex::init(&buf, "<test>"); 80 let mods = imports(&lexer)!; 81 defer for (let i = 0z; i < len(mods); i += 1) { 82 ast::import_finish(mods[i]); 83 }; 84 85 let expected: [_]import_tuple = [ 86 (ast::import_mode::IDENT, ["foo"], "", []), 87 (ast::import_mode::IDENT, ["bar"], "", []), 88 (ast::import_mode::IDENT, ["baz", "bat"], "", []), 89 (ast::import_mode::ALIAS, ["bar"], "foo", []), 90 (ast::import_mode::ALIAS, ["bat"], "baz", []), 91 (ast::import_mode::ALIAS, ["quux", "corge"], "qux", []), 92 (ast::import_mode::WILDCARD, ["foo"], "", []), 93 (ast::import_mode::WILDCARD, ["foo", "bar", "quux"], "", []), 94 (ast::import_mode::MEMBERS, ["foo"], "", [(void, "bar")]), 95 (ast::import_mode::MEMBERS, ["foo"], "", [(void, "bar")]), 96 (ast::import_mode::MEMBERS, ["baz"], "", [(void, "bat"), (void, "qux")]), 97 (ast::import_mode::MEMBERS, 98 ["quux", "corge"], "", [(void, "grault"), (void, "garply")]), 99 (ast::import_mode::MEMBERS, ["quux"], "", [("alias", "grault")]), 100 (ast::import_mode::MEMBERS, ["quux"], "", [("alias", "grault")]), 101 (ast::import_mode::MEMBERS, 102 ["quux"], "", [("alias", "grault"), (void, "garply")]), 103 (ast::import_mode::MEMBERS, 104 ["quux"], "", [("alias", "grault"), ("alias2", "garply")]), 105 (ast::import_mode::MEMBERS | ast::import_mode::ALIAS, 106 ["quux", "corge"], "alias", [(void, "grault"), (void, "garply")]), 107 (ast::import_mode::MEMBERS | ast::import_mode::ALIAS, 108 ["quux"], "modalias", [("alias", "grault"), ("alias2", "garply")]), 109 ]; 110 111 assert(len(mods) == len(expected)); 112 for (let i = 0z; i < len(mods); i += 1) { 113 assert(import_eq(mods[i], tup_to_import(expected[i]))); 114 }; 115 116 let tok = lex::lex(&lexer) as lex::token; 117 assert(tok.0 == lex::ltok::EXPORT); 118 }; 119 120 @test fn decls() void = { 121 roundtrip("export type foo::bar = *int, baz = const void;\n\n" 122 "type foo = ...bar;\n\n" 123 "type foo = nullable *fn(x: rune, _: int) void;\n\n" 124 "export let @symbol(\"_\") foo::bar: int = void, baz: int = void;\n\n" 125 "def foo::bar: int = void;\n\n" 126 "@symbol(\".f9$oo\") fn foo(bar: int, baz: int...) void;\n\n" 127 "@test fn foo(_: int, ...) void;\n\n" 128 "export fn main() void = void;\n\n" 129 "fn long(\n" 130 "\tfirst: *const void,\n" 131 "\tsecond: (void | rune | str),\n" 132 "\tthird: size...\n" 133 ") nullable *const void;\n"); 134 }; 135 136 @test fn docs() void = { 137 roundtrip("// According to all known laws of aviation, there is no\n" 138 "// way that a bee should be able to fly. Its wings are too\n" 139 "// small to get its fat little body off the ground. The bee,\n" 140 "// of course, flies anyway, because bees don't care what\n" 141 "// humans think is impossible.\n" 142 "export fn main() void = void;\n"); 143 };