mirror of https://github.com/Wilfred/difftastic/
193 lines
4.0 KiB
Plaintext
193 lines
4.0 KiB
Plaintext
use io;
|
|
use fmt;
|
|
use hare::ast;
|
|
use hare::lex;
|
|
use strio;
|
|
|
|
export fn decl(out: *io::stream, d: ast::decl) (size | io::error) = {
|
|
let n = 0z;
|
|
if (d.exported) {
|
|
n += fmt::fprint(out, "export ")?;
|
|
};
|
|
match (d.decl) {
|
|
g: []ast::decl_global => {
|
|
n += fmt::fprint(out,
|
|
if (g[0].is_const) "def " else "let ")?;
|
|
for (let i = 0z; i < len(g); i += 1) {
|
|
if (len(g[i].symbol) != 0) {
|
|
n += fmt::fprintf(out,
|
|
"@symbol(\"{}\") ", g[i].symbol)?;
|
|
};
|
|
n += ident(out, g[i].ident)?;
|
|
n += fmt::fprint(out, ": ")?;
|
|
n += _type(out, 0, g[i]._type)?;
|
|
n += fmt::fprint(out, " = ")?;
|
|
n += expr(out, 0, g[i].init)?;
|
|
if (i + 1 < len(g)) {
|
|
n += fmt::fprint(out, ", ")?;
|
|
};
|
|
};
|
|
},
|
|
t: []ast::decl_type => {
|
|
n += fmt::fprint(out, "type ")?;
|
|
for (let i = 0z; i < len(t); i += 1) {
|
|
n += ident(out, t[i].ident)?;
|
|
n += fmt::fprint(out, " = ")?;
|
|
n += _type(out, 0, t[i]._type)?;
|
|
if (i + 1 < len(t)) {
|
|
n += fmt::fprint(out, ", ")?;
|
|
};
|
|
};
|
|
},
|
|
f: ast::decl_func => {
|
|
n += fmt::fprint(out, switch (f.attrs) {
|
|
ast::fndecl_attrs::NONE => "",
|
|
ast::fndecl_attrs::FINI => "@fini ",
|
|
ast::fndecl_attrs::INIT => "@init ",
|
|
ast::fndecl_attrs::TEST => "@test ",
|
|
})?;
|
|
let p = f.prototype._type as ast::func_type;
|
|
if (p.attrs & ast::func_attrs::NORETURN != 0) {
|
|
n += fmt::fprint(out, "@noreturn ")?;
|
|
};
|
|
if (len(f.symbol) != 0) {
|
|
n += fmt::fprintf(out, "@symbol(\"{}\") ",
|
|
f.symbol)?;
|
|
};
|
|
n += fmt::fprint(out, "fn ")?;
|
|
n += ident(out, f.ident)?;
|
|
n += prototype(out, 0,
|
|
f.prototype._type as ast::func_type)?;
|
|
match (f.body) {
|
|
void => void,
|
|
e: ast::expr => {
|
|
n += fmt::fprint(out, " = ")?;
|
|
n += expr(out, 0, e)?;
|
|
},
|
|
};
|
|
},
|
|
};
|
|
n += fmt::fprint(out, ";")?;
|
|
return n;
|
|
};
|
|
|
|
fn decl_test(d: ast::decl, expected: str) bool = {
|
|
let buf = strio::dynamic();
|
|
decl(buf, d) as size;
|
|
let s = strio::finish(buf);
|
|
defer free(s);
|
|
return s == expected;
|
|
};
|
|
|
|
@test fn decl() void = {
|
|
let loc = lex::location {
|
|
path = "<test>",
|
|
line = 0,
|
|
col = 0,
|
|
};
|
|
let type_int = ast::_type {
|
|
loc = loc,
|
|
flags = 0,
|
|
_type = ast::builtin_type::INT,
|
|
};
|
|
let type_fn = ast::_type {
|
|
loc = loc,
|
|
flags = ast::type_flags::CONST,
|
|
_type = ast::func_type {
|
|
result = &type_int,
|
|
attrs = ast::func_attrs::NORETURN,
|
|
variadism = ast::variadism::HARE,
|
|
params = [
|
|
ast::func_param {
|
|
loc = loc,
|
|
name = "foo",
|
|
_type = &type_int,
|
|
},
|
|
ast::func_param {
|
|
loc = loc,
|
|
name = "bar",
|
|
_type = &type_int,
|
|
},
|
|
],
|
|
},
|
|
};
|
|
let expr_void = void: ast::constant_expr: ast::expr;
|
|
|
|
let d = ast::decl {
|
|
loc = loc,
|
|
exported = false,
|
|
decl = [
|
|
ast::decl_global {
|
|
is_const = false,
|
|
symbol = "",
|
|
ident = ["foo", "bar"],
|
|
_type = type_int,
|
|
init = expr_void,
|
|
},
|
|
ast::decl_global {
|
|
is_const = false,
|
|
symbol = "foobar",
|
|
ident = ["baz"],
|
|
_type = type_int,
|
|
init = expr_void,
|
|
},
|
|
],
|
|
};
|
|
assert(decl_test(d, "let foo::bar: int = void, @symbol(\"foobar\") baz: int = void;"));
|
|
|
|
d.exported = true;
|
|
d.decl = [
|
|
ast::decl_global {
|
|
is_const = true,
|
|
ident = ["foo"],
|
|
_type = type_int,
|
|
init = expr_void,
|
|
...
|
|
},
|
|
];
|
|
assert(decl_test(d, "export def foo: int = void;"));
|
|
|
|
d.exported = false;
|
|
d.decl = [
|
|
ast::decl_type {
|
|
ident = ["foo"],
|
|
_type = type_int,
|
|
},
|
|
ast::decl_type {
|
|
ident = ["bar"],
|
|
_type = type_int,
|
|
},
|
|
];
|
|
assert(decl_test(d, "type foo = int, bar = int;"));
|
|
|
|
d.decl = ast::decl_func {
|
|
symbol = "foo",
|
|
ident = ["foo"],
|
|
prototype = type_fn,
|
|
body = void,
|
|
attrs = ast::fndecl_attrs::FINI,
|
|
};
|
|
assert(decl_test(d, "@fini @noreturn @symbol(\"foo\") fn foo(foo: int, bar: int...) int;"));
|
|
|
|
type_fn._type = ast::func_type {
|
|
result = &type_int,
|
|
attrs = 0,
|
|
variadism = ast::variadism::NONE,
|
|
params = [
|
|
ast::func_param {
|
|
loc = loc,
|
|
name = "",
|
|
_type = &type_int,
|
|
},
|
|
],
|
|
};
|
|
d.decl = ast::decl_func {
|
|
symbol = "",
|
|
ident = ["foo"],
|
|
prototype = type_fn,
|
|
body = expr_void,
|
|
attrs = 0,
|
|
};
|
|
assert(decl_test(d, "fn foo(_: int) int = void;"));
|
|
};
|