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:
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;"));