hare

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

commit b706c298c936e918e1ec7aa8349f014e40e0efab
parent 7a3f017376ed8e029f925726cefc6abc93d26fb4
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu, 22 Apr 2021 10:57:02 -0400

hare::parse: separate constants and globals

Fixes #390

Diffstat:
Mcmd/haredoc/html.ha | 29++++++++++++++++++++++++++++-
Mcmd/haredoc/sort.ha | 21++++++++++++++++++++-
Mhare/ast/decl.ha | 11++++++++++-
Mhare/parse/decl.ha | 54+++++++++++++++++++++++++++++++++++++++---------------
Mhare/unparse/decl.ha | 19+++++++++++++++----
5 files changed, 112 insertions(+), 22 deletions(-)

diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha @@ -71,6 +71,7 @@ fn emit_html(ctx: *context) (void | error) = { if (len(decls.types) == 0 && len(decls.errors) == 0 + && len(decls.constants) == 0 && len(decls.globals) == 0 && len(decls.funcs) == 0) { return; @@ -79,6 +80,7 @@ fn emit_html(ctx: *context) (void | error) = { fmt::println("<h3>Index</h3>")?; tocentries(decls.types, "Types", "types")?; tocentries(decls.errors, "Errors", "Errors")?; + tocentries(decls.constants, "Constants", "constants")?; tocentries(decls.globals, "Globals", "globals")?; tocentries(decls.funcs, "Functions", "functions")?; @@ -96,6 +98,13 @@ fn emit_html(ctx: *context) (void | error) = { }; }; + if (len(decls.constants) != 0) { + fmt::println("<h3>Constants</h3>")?; + for (let i = 0z; i < len(decls.constants); i += 1) { + details(ctx, decls.constants[i])?; + }; + }; + if (len(decls.globals) != 0) { fmt::println("<h3>Globals</h3>")?; for (let i = 0z; i < len(decls.globals); i += 1) { @@ -137,6 +146,7 @@ fn tocentry(decl: ast::decl) (void | error) = { match (decl.decl) { _: ast::decl_func => "fn", _: []ast::decl_type => "type", + _: []ast::decl_const => "const", _: []ast::decl_global => "let", }); fmt::printf("<a href='#"); @@ -151,6 +161,11 @@ fn tocentry(decl: ast::decl) (void | error) = { fmt::print(": ")?; type_html(os::stdout, 0, g._type, true)?; }, + c: []ast::decl_const => { + let c = c[0]; + fmt::print(": ")?; + type_html(os::stdout, 0, c._type, true)?; + }, t: []ast::decl_type => void, f: ast::decl_func => prototype_html(os::stdout, 0, f.prototype._type as ast::func_type, @@ -169,6 +184,7 @@ fn details(ctx: *context, decl: ast::decl) (void | error) = { match (decl.decl) { _: ast::decl_func => "fn", _: []ast::decl_type => "type", + _: []ast::decl_const => "def", _: []ast::decl_global => "let", }); unparse::ident(os::stdout, decl_ident(decl))?; @@ -285,9 +301,20 @@ fn markup_html(ctx: *context, in: *io::stream) (void | io::error) = { fn unparse_html(out: *io::stream, d: ast::decl) (size | io::error) = { let n = 0z; match (d.decl) { + c: []ast::decl_const => { + n += fmt::fprintf(out, "<span class='keyword'>def</span> ")?; + for (let i = 0z; i < len(c); i += 1) { + n += unparse::ident(out, c[i].ident)?; + n += fmt::fprint(out, ": ")?; + n += type_html(out, 0, c[i]._type, false)?; + if (i + 1 < len(c)) { + n += fmt::fprint(out, ", ")?; + }; + }; + }, g: []ast::decl_global => { n += fmt::fprintf(out, "<span class='keyword'>{}</span>", - if (g[0].is_const) "def " else "let ")?; + if (g[0].is_const) "const " else "let ")?; for (let i = 0z; i < len(g); i += 1) { n += unparse::ident(out, g[i].ident)?; n += fmt::fprint(out, ": ")?; diff --git a/cmd/haredoc/sort.ha b/cmd/haredoc/sort.ha @@ -3,7 +3,7 @@ use hare::ast; use sort; type summary = struct { - // TODO: Constants + constants: []ast::decl, errors: []ast::decl, types: []ast::decl, globals: []ast::decl, @@ -43,6 +43,20 @@ fn sort_decls(decls: []ast::decl) summary = { docs = decl.docs, }); }, + c: []ast::decl_const => + for (let j = 0z; j < len(c); j += 1) { + append(sorted.constants, ast::decl { + exported = true, + loc = decl.loc, + decl = { + // XXX: Kind of bad + let new: []ast::decl_const = []; + append(new, c[j]); + new; + }, + docs = decl.docs, + }); + }, g: []ast::decl_global => for (let j = 0z; j < len(g); j += 1) { append(sorted.globals, ast::decl { @@ -60,6 +74,7 @@ fn sort_decls(decls: []ast::decl) summary = { }; }; + sort::sort(sorted.constants, size(ast::decl), &decl_cmp); sort::sort(sorted.errors, size(ast::decl), &decl_cmp); sort::sort(sorted.types, size(ast::decl), &decl_cmp); sort::sort(sorted.globals, size(ast::decl), &decl_cmp); @@ -85,6 +100,10 @@ fn decl_ident(decl: ast::decl) ast::ident = match (decl.decl) { assert(len(t) == 1); t[0].ident; }, + c: []ast::decl_const => { + assert(len(c) == 1); + c[0].ident; + }, g: []ast::decl_global => { assert(len(g) == 1); g[0].ident; diff --git a/hare/ast/decl.ha b/hare/ast/decl.ha @@ -1,5 +1,14 @@ use hare::lex; +// A constant declaration. +// +// def foo: int = 0; +export type decl_const = struct { + ident: ident, + _type: _type, + init: *expr, +}; + // A global declaration. // // let foo: int = 0; @@ -43,7 +52,7 @@ export type decl_func = struct { export type decl = struct { exported: bool, loc: lex::location, - decl: ([]decl_global | []decl_type | decl_func), + decl: ([]decl_const | []decl_global | []decl_type | decl_func), // Only valid if the lexer has comments enabled docs: str, diff --git a/hare/parse/decl.ha b/hare/parse/decl.ha @@ -26,24 +26,44 @@ fn attr_symbol(lexer: *lex::lexer) (str | error) = { return s; }; +fn decl_const( + lexer: *lex::lexer, + tok: ltok, +) ([]ast::decl_const | error) = { + let decl: []ast::decl_const = []; + for (true) { + const ident = ident(lexer)?; + want(lexer, ltok::COLON)?; + const _type = _type(lexer)?; + want(lexer, ltok::EQUAL)?; + const init: *ast::expr = alloc(expression(lexer)?); + append(decl, ast::decl_const { + ident = ident, + _type = _type, + init = init, + }); + + if (try(lexer, ltok::COMMA)? is void) { + break; + }; + }; + return decl; + +}; + fn decl_global( lexer: *lex::lexer, - tok: ltok + tok: ltok, ) ([]ast::decl_global | error) = { let decl: []ast::decl_global = []; for (true) { - let symbol = if (tok == ltok::CONST || tok == ltok::LET) { - match (try(lexer, ltok::ATTR_SYMBOL)?) { - _: void => "", - _: lex::token => attr_symbol(lexer)?, - }; - } else ""; + const symbol = match (try(lexer, ltok::ATTR_SYMBOL)?) { + _: void => "", + _: lex::token => attr_symbol(lexer)?, + }; const ident = ident(lexer)?; want(lexer, ltok::COLON)?; - let _type = _type(lexer)?; - if (tok == ltok::CONST) { - _type.flags |= ast::type_flags::CONST; - }; + const _type = _type(lexer)?; const init: nullable *ast::expr = match (try(lexer, ltok::EQUAL)?) { _: lex::token => alloc(expression(lexer)?), @@ -51,7 +71,7 @@ fn decl_global( }; const btok = try(lexer, ltok::COMMA)?; append(decl, ast::decl_global { - is_const = tok == ltok::DEF, + is_const = tok == ltok::CONST, symbol = symbol, ident = ident, _type = _type, @@ -160,9 +180,13 @@ export fn decls(lexer: *lex::lexer) ([]ast::decl | error) = { }; let decl = match (next) { _: void => decl_func(lexer)?, - t: lex::token => - if (t.0 == ltok::TYPE) decl_type(lexer)? - else decl_global(lexer, t.0)?, + t: lex::token => switch (t.0) { + ltok::TYPE => decl_type(lexer)?, + ltok::LET, ltok::CONST => + decl_global(lexer, t.0)?, + ltok::DEF => decl_const(lexer, t.0)?, + * => abort(), + }, }; append(decls, ast::decl { exported = exported, diff --git a/hare/unparse/decl.ha b/hare/unparse/decl.ha @@ -10,9 +10,22 @@ export fn decl(out: *io::stream, d: ast::decl) (size | io::error) = { n += fmt::fprint(out, "export ")?; }; match (d.decl) { + c: []ast::decl_const => { + n += fmt::fprint(out, "def ")?; + for (let i = 0z; i < len(c); i += 1) { + n += ident(out, c[i].ident)?; + n += fmt::fprint(out, ": ")?; + n += _type(out, 0, c[i]._type)?; + n += fmt::fprint(out, " = ")?; + n += expr(out, 0, *c[i].init)?; + if (i + 1 < len(c)) { + n += fmt::fprint(out, ", ")?; + }; + }; + }, g: []ast::decl_global => { n += fmt::fprint(out, - if (g[0].is_const) "def " else "let ")?; + if (g[0].is_const) "const " else "let ")?; for (let i = 0z; i < len(g); i += 1) { if (len(g[i].symbol) != 0) { n += fmt::fprintf(out, @@ -142,12 +155,10 @@ fn decl_test(d: ast::decl, expected: str) bool = { d.exported = true; d.decl = [ - ast::decl_global { - is_const = true, + ast::decl_const { ident = ["foo"], _type = type_int, init = alloc(expr_void), - ... }, ]; assert(decl_test(d, "export def foo: int = void;"));