=?UTF-8?q?Bor=20Gro=C5=A1elj=20Simi=C4=87?=: 1 hare::parse: parse attributes better 8 files changed, 69 insertions(+), 45 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~sircmpwn/hare-dev/patches/56986/mbox | git am -3Learn more about email & git
Only allow one attribute per function, and represent lack of symbol as void, not as an empty string. Breaking-Change: hare::ast::, hare::unit:: Signed-off-by: Bor Grošelj Simić <bgs@turminal.net> --- This implements the spec change that I've just sent. cmd/haredoc/doc/sort.ha | 2 +- cmd/haredoc/main.ha | 24 ++++++++++++++++-------- hare/ast/decl.ha | 14 +++++++++----- hare/parse/decl.ha | 26 ++++++++++++-------------- hare/unit/process.ha | 4 ++-- hare/unit/scan.ha | 2 +- hare/unit/unit.ha | 4 ++-- hare/unparse/decl.ha | 38 ++++++++++++++++++++++++++------------ 8 files changed, 69 insertions(+), 45 deletions(-) diff --git a/cmd/haredoc/doc/sort.ha b/cmd/haredoc/doc/sort.ha index 66febc47..a64c6f79 100644 --- a/cmd/haredoc/doc/sort.ha +++ b/cmd/haredoc/doc/sort.ha @@ -33,7 +33,7 @@ export fn sort_decls(decls: []ast::decl) summary = { ident = f.ident, prototype = f.prototype, body = null, - attrs = f.attrs, + attr = f.attr, }, docs = decl.docs, })!; diff --git a/cmd/haredoc/main.ha b/cmd/haredoc/main.ha index f301d697..da1cdbb1 100644 --- a/cmd/haredoc/main.ha +++ b/cmd/haredoc/main.ha @@ -397,22 +397,30 @@ fn has_decl(decl: ast::decl, name: str) bool = { if (len(d.ident) == 1 && d.ident[0] == name) { return true; }; - let tok = strings::rtokenize(d.symbol, "."); - match (strings::next_token(&tok)) { - case done => void; + match (d.symbol) { + case void => void; case let s: str => - return s == name; + let tok = strings::rtokenize(s, "."); + match (strings::next_token(&tok)) { + case done => void; + case let s: str => + return s == name; + }; }; case let globals: []ast::decl_global => for (let d .. globals) { if (len(d.ident) == 1 && d.ident[0] == name) { return true; }; - let tok = strings::rtokenize(d.symbol, "."); - match (strings::next_token(&tok)) { - case done => void; + match (d.symbol) { + case void => void; case let s: str => - return s == name; + let tok = strings::rtokenize(s, "."); + match (strings::next_token(&tok)) { + case done => void; + case let s: str => + return s == name; + }; }; }; case let types: []ast::decl_type => diff --git a/hare/ast/decl.ha b/hare/ast/decl.ha index ba9c2fd9..85daed8a 100644 --- a/hare/ast/decl.ha +++ b/hare/ast/decl.ha @@ -19,7 +19,7 @@ export type decl_const = struct { export type decl_global = struct { is_const: bool, is_threadlocal: bool, - symbol: str, + symbol: (str | void), ident: ident, _type: nullable *_type, init: nullable *expr, @@ -45,11 +45,11 @@ export type fndecl_attr = enum { // // fn main() void = void; export type decl_func = struct { - symbol: str, + symbol: (str | void), ident: ident, prototype: *_type, body: nullable *expr, - attrs: fndecl_attr, + attr: fndecl_attr, }; // A Hare declaration. @@ -70,7 +70,9 @@ export fn decl_finish(d: decl) void = { match (d.decl) { case let g: []decl_global => for (let i = 0z; i < len(g); i += 1) { - free(g[i].symbol); + if (g[i].symbol is str) { + free(g[i].symbol: str); + }; ident_free(g[i].ident); type_finish(g[i]._type); free(g[i]._type); @@ -86,7 +88,9 @@ export fn decl_finish(d: decl) void = { }; free(t); case let f: decl_func => - free(f.symbol); + if (f.symbol is str) { + free(f.symbol: str);
ditto other than that, this lgtm
+ }; ident_free(f.ident); type_finish(f.prototype); free(f.prototype); diff --git a/hare/parse/decl.ha b/hare/parse/decl.ha index 85cd106d..2f4d76f3 100644 --- a/hare/parse/decl.ha +++ b/hare/parse/decl.ha @@ -67,12 +67,12 @@ fn decl_global( const (symbol, threadlocal) = match (try(lexer, ltok::ATTR_SYMBOL, ltok::ATTR_THREADLOCAL)?) { case void => - yield ("", false); + yield (void: (void | str), false); case let t: lex::token => yield if (t.0 == ltok::ATTR_SYMBOL) { - yield (attr_symbol(lexer)?, false); + yield (attr_symbol(lexer)?: (void | str), false); } else { - yield ("", true); + yield (void: (void | str), true); }; }; const ident = ident(lexer)?; @@ -130,24 +130,22 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = { ltok::ATTR_FINI, ltok::ATTR_INIT, ltok::ATTR_TEST, ltok::ATTR_SYMBOL ]; - for (true) match (try(lexer, attrs...)?) { + let (sym, attr) = match (try(lexer, attrs...)?) { case void => - break; + yield (void: (str | void), ast::fndecl_attr::NONE); case let t: lex::token => - synassert(t.2, t.0 == ltok::ATTR_SYMBOL || attr == 0, - "Only one of @init, @fini, or @test may be provided")?; - switch (t.0) { + yield switch (t.0) { case ltok::ATTR_FINI => - attr = ast::fndecl_attr::FINI; + yield (void, ast::fndecl_attr::FINI); case ltok::ATTR_INIT => - attr = ast::fndecl_attr::INIT; + yield (void, ast::fndecl_attr::INIT); case ltok::ATTR_TEST => - attr = ast::fndecl_attr::TEST; + yield (void, ast::fndecl_attr::TEST); case ltok::ATTR_SYMBOL => - sym = attr_symbol(lexer)?; + yield (attr_symbol(lexer)?, ast::fndecl_attr::NONE); case => abort("unreachable"); - }; + }: ((void | str), ast::fndecl_attr); }; want(lexer, ltok::FN)?; @@ -182,7 +180,7 @@ fn decl_func(lexer: *lex::lexer) (ast::decl_func | error) = { repr = prototype, })!, body = body, - attrs = attr, + attr = attr, }; }; diff --git a/hare/unit/process.ha b/hare/unit/process.ha index da77dc44..b18ed4d8 100644 --- a/hare/unit/process.ha +++ b/hare/unit/process.ha @@ -52,7 +52,7 @@ fn process_func( adecl: *ast::decl, func: *ast::decl_func, ) (decl | error) = { - assert(func.attrs & ast::fndecl_attr::TEST == 0); // TODO + assert(func.attr != ast::fndecl_attr::TEST); // TODO const afndecl = adecl.decl as ast::decl_func; const prototype = types::lookup(ctx.store, func.prototype)!; const fntype = prototype.repr as types::func; @@ -78,7 +78,7 @@ fn process_func( prototype = prototype, body = body, // TODO: We should make these enums inherited - attrs = afndecl.attrs: ast::fndecl_attr, + attr = afndecl.attr, }, }; }; diff --git a/hare/unit/scan.ha b/hare/unit/scan.ha index a40a7119..ca607b0a 100644 --- a/hare/unit/scan.ha +++ b/hare/unit/scan.ha @@ -50,7 +50,7 @@ fn scan_func( decl: *ast::decl, func: *ast::decl_func, ) (void | types::deferred | error) = { - assert(func.attrs & ast::fndecl_attr::TEST == 0); // TODO + assert(func.attr != ast::fndecl_attr::TEST); // TODO const fntype = match (types::lookup(ctx.store, func.prototype)) { case let err: types::error => return err; diff --git a/hare/unit/unit.ha b/hare/unit/unit.ha index 8e47ca87..e1572618 100644 --- a/hare/unit/unit.ha +++ b/hare/unit/unit.ha @@ -8,11 +8,11 @@ use hare::types; // A function declaration. export type decl_func = struct { - symbol: str, + symbol: (str | void), ident: ast::ident, prototype: const *types::_type, body: nullable *expr, - attrs: ast::fndecl_attr, + attr: ast::fndecl_attr, }; // A declaration within a unit. diff --git a/hare/unparse/decl.ha b/hare/unparse/decl.ha index 0e7b6e87..1f25efa5 100644 --- a/hare/unparse/decl.ha +++ b/hare/unparse/decl.ha @@ -58,12 +58,15 @@ export fn decl( synkind::KEYWORD)?; n += space(&ctx)?; for (let i = 0z; i < len(g); i += 1) { - if (len(g[i].symbol) != 0) { + match (g[i].symbol) { + case let s: str => n += syn(&ctx, "@symbol(", synkind::ATTRIBUTE)?; - n += literal(&ctx, syn, g[i].symbol)?; + n += literal(&ctx, syn, s)?; n += syn(&ctx, ")", synkind::ATTRIBUTE)?; n += space(&ctx)?; - } else if (g[i].is_threadlocal) { + case => void; + }; + if (g[i].is_threadlocal) { n += syn(&ctx, "@threadlocal", synkind::ATTRIBUTE)?; n += space(&ctx)?; @@ -119,7 +122,7 @@ export fn decl( ctx.stack = stack.up; }; - switch (f.attrs) { + switch (f.attr) { case ast::fndecl_attr::NONE => void; case ast::fndecl_attr::FINI => n += syn(&ctx, "@fini", synkind::ATTRIBUTE)?; @@ -132,11 +135,13 @@ export fn decl( n += space(&ctx)?; }; let p = f.prototype.repr as ast::func_type; - if (len(f.symbol) != 0) { + match (f.symbol) { + case let s: str => n += syn(&ctx, "@symbol(", synkind::ATTRIBUTE)?; - n += literal(&ctx, syn, f.symbol)?; + n += literal(&ctx, syn, s)?; n += syn(&ctx, ")", synkind::ATTRIBUTE)?; n += space(&ctx)?; + case => void; }; n += syn(&ctx, "fn", synkind::KEYWORD)?; n += space(&ctx)?; @@ -234,7 +239,7 @@ fn decl_test(d: *ast::decl, expected: str) bool = { ast::decl_global { is_const = false, is_threadlocal = false, - symbol = "", + symbol = void, ident = ["foo", "bar"], _type = &type_int, init = &expr_void, @@ -242,7 +247,7 @@ fn decl_test(d: *ast::decl, expected: str) bool = { ast::decl_global { is_const = false, is_threadlocal = true, - symbol = "", + symbol = void, ident = ["boo"], _type = &type_int, init = &expr_void, @@ -288,9 +293,18 @@ fn decl_test(d: *ast::decl, expected: str) bool = { ident = ["foo"], prototype = &type_fn, body = null, - attrs = ast::fndecl_attr::FINI, + attr = ast::fndecl_attr::NONE, + }; + assert(decl_test(&d, "@symbol(\"foo\") fn foo(foo: int, bar: int...) int;")); + + d.decl = ast::decl_func { + symbol = void, + ident = ["foo"], + prototype = &type_fn, + body = null, + attr = ast::fndecl_attr::FINI, }; - assert(decl_test(&d, "@fini @symbol(\"foo\") fn foo(foo: int, bar: int...) int;")); + assert(decl_test(&d, "@fini fn foo(foo: int, bar: int...) int;")); type_fn.repr = ast::func_type { result = &type_int, @@ -312,11 +326,11 @@ fn decl_test(d: *ast::decl, expected: str) bool = { ], }; d.decl = ast::decl_func { - symbol = "", + symbol = void, ident = ["foo"], prototype = &type_fn, body = &expr_void, - attrs = 0, + attr = ast::fndecl_attr::NONE, }; assert(decl_test(&d, "fn foo(int = 4) int = void;")); }; -- 2.47.1
i'd prefer `as` rather than `:` here; in the future, we can use if (let) instead