hare

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

commit eda5cb6b46896bd3c847ebfcd9aac3892c352827
parent d648d00dba1f03053241b0e0e1f785d068cfefaa
Author: Sebastian <sebastian@sebsite.pw>
Date:   Mon, 11 Apr 2022 20:05:48 -0400

unparse, haredoc: linewrap long function prototypes

Examples: see sort::search and hare::unparse::prototype
Signed-off-by: Sebastian <sebastian@sebsite.pw>

Diffstat:
Mcmd/haredoc/hare.ha | 30+-----------------------------
Mcmd/haredoc/html.ha | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mcmd/haredoc/tty.ha | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mhare/unparse/type.ha | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
4 files changed, 225 insertions(+), 71 deletions(-)

diff --git a/cmd/haredoc/hare.ha b/cmd/haredoc/hare.ha @@ -151,37 +151,9 @@ fn unparse_hare(out: io::handle, d: ast::decl) (size | io::error) = { }; n += fmt::fprint(out, "fn ")?; n += unparse::ident(out, f.ident)?; - n += prototype_hare(out, 0, + n += unparse::prototype(out, 0, f.prototype.repr as ast::func_type)?; }; n += fmt::fprint(out, ";")?; return n; }; - -fn prototype_hare( - out: io::handle, - indent: size, - t: ast::func_type, -) (size | io::error) = { - let n = 0z; - n += fmt::fprint(out, "(")?; - for (let i = 0z; i < len(t.params); i += 1) { - let param = t.params[i]; - n += fmt::fprintf(out, "{}: ", - if (len(param.name) == 0) "_" else param.name)?; - n += unparse::_type(out, indent, *param._type)?; - if (i + 1 == len(t.params) - && t.variadism == ast::variadism::HARE) { - n += fmt::fprintf(out, "...")?; - }; - if (i + 1 < len(t.params)) { - n += fmt::fprint(out, ", ")?; - }; - }; - if (t.variadism == ast::variadism::C) { - n += fmt::fprint(out, ", ...")?; - }; - n += fmt::fprint(out, ") ")?; - n += unparse::_type(out, indent, *t.result)?; - return n; -}; diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha @@ -11,6 +11,7 @@ use bufio; use encoding::utf8; use fmt; use hare::ast; +use hare::ast::{variadism}; use hare::lex; use hare::module; use hare::unparse; @@ -715,24 +716,73 @@ fn prototype_html( ) (size | io::error) = { let n = 0z; n += fmt::fprint(out, "(")?; - for (let i = 0z; i < len(t.params); i += 1) { - let param = t.params[i]; + + // estimate length of prototype to determine if it should span multiple + // lines + const linelen = if (len(t.params) == 0 || brief) { + yield 0z; // If no parameters or brief, only use one line. + } else { + let linelen = indent * 8 + 5; + linelen += if (len(t.params) != 0) len(t.params) * 3 - 1 else 0; + for (let i = 0z; i < len(t.params); i += 1) { + const param = t.params[i]; + linelen += unparse::_type(io::empty, indent, + *param._type)?; + linelen += if (param.name == "") 1 else len(param.name); + }; + switch (t.variadism) { + case variadism::NONE => void; + case variadism::HARE => + linelen += 3; + case variadism::C => + linelen += 5; + }; + linelen += unparse::_type(io::empty, indent, *t.result)?; + yield linelen; + }; + + // use 72 instead of 80 to give a bit of leeway for preceding text + if (linelen > 72) { + indent += 1; + for (let i = 0z; i < len(t.params); i += 1) { + const param = t.params[i]; + n += newline(out, indent)?; + n += fmt::fprintf(out, "{}: ", + if (param.name == "") "_" else param.name)?; + n += type_html(out, indent, *param._type, brief)?; + if (i + 1 == len(t.params) + && t.variadism == variadism::HARE) { + n += fmt::fprint(out, "...")?; + } else { + n += fmt::fprint(out, ",")?; + }; + }; + if (t.variadism == variadism::C) { + n += newline(out, indent)?; + n += fmt::fprint(out, "...")?; + }; + indent -= 1; + n += newline(out, indent)?; + } else for (let i = 0z; i < len(t.params); i += 1) { + const param = t.params[i]; if (!brief) { n += fmt::fprintf(out, "{}: ", - if (len(param.name) == 0) "_" else param.name)?; + if (param.name == "") "_" else param.name)?; }; n += type_html(out, indent, *param._type, brief)?; - if (i + 1 == len(t.params) - && t.variadism == ast::variadism::HARE) { - n += fmt::fprintf(out, "...")?; - }; - if (i + 1 < len(t.params)) { + if (i + 1 == len(t.params)) { + switch (t.variadism) { + case variadism::NONE => void; + case variadism::HARE => + n += fmt::fprint(out, "...")?; + case variadism::C => + n += fmt::fprint(out, ", ...")?; + }; + } else { n += fmt::fprint(out, ", ")?; }; }; - if (t.variadism == ast::variadism::C) { - n += fmt::fprint(out, ", ...")?; - }; + n += fmt::fprint(out, ") ")?; n += type_html(out, indent, *t.result, brief)?; return n; diff --git a/cmd/haredoc/tty.ha b/cmd/haredoc/tty.ha @@ -6,6 +6,7 @@ use ascii; use bufio; use fmt; use hare::ast; +use hare::ast::{variadism}; use hare::lex; use hare::unparse; use io; @@ -182,24 +183,89 @@ fn prototype_tty( ) (size | io::error) = { let n = 0z; n += fmt::fprint(out, "(")?; - for (let i = 0z; i < len(t.params); i += 1) { - let param = t.params[i]; - n += fmt::fprintf(out, "{}: ", - if (len(param.name) == 0) "_" else param.name)?; - n += type_tty(out, indent, *param._type)?; - if (i + 1 == len(t.params) - && t.variadism == ast::variadism::HARE) { - n += fmt::fprintf(out, "...")?; + + let typenames: []str = []; + // TODO: https://todo.sr.ht/~sircmpwn/hare/581 + if (len(t.params) > 0) { + typenames = alloc([""...], len(t.params)); + }; + defer strings::freeall(typenames); + let retname = ""; + defer free(retname); + + // estimate length of prototype to determine if it should span multiple + // lines + const linelen = if (len(t.params) == 0) { + let strm = strio::dynamic(); + defer io::close(&strm)!; + type_tty(&strm, indent, *t.result)?; + retname = strings::dup(strio::string(&strm)); + yield 0z; // only use one line if there's no parameters + } else { + let strm = strio::dynamic(); + defer io::close(&strm)!; + let linelen = indent * 8 + 5; + linelen += if (len(t.params) != 0) len(t.params) * 3 - 1 else 0; + for (let i = 0z; i < len(t.params); i += 1) { + const param = t.params[i]; + linelen += unparse::_type(&strm, indent, *param._type)?; + typenames[i] = strings::dup(strio::string(&strm)); + linelen += if (param.name == "") 1 else len(param.name); + strio::reset(&strm); }; - if (i + 1 < len(t.params)) { - n += fmt::fprint(out, ", ")?; + switch (t.variadism) { + case variadism::NONE => void; + case variadism::HARE => + linelen += 3; + case variadism::C => + linelen += 5; }; + linelen += type_tty(&strm, indent, *t.result)?; + retname = strings::dup(strio::string(&strm)); + yield linelen; }; - if (t.variadism == ast::variadism::C) { - n += fmt::fprint(out, ", ...")?; + + // use 72 instead of 80 to give a bit of leeway for preceding text + if (linelen > 72) { + indent += 1; + for (let i = 0z; i < len(t.params); i += 1) { + const param = t.params[i]; + n += newline(out, indent)?; + n += fmt::fprintf(out, "{}: ", + if (param.name == "") "_" else param.name)?; + n += fmt::fprint(out, typenames[i])?; + if (i + 1 == len(t.params) + && t.variadism == variadism::HARE) { + n += fmt::fprint(out, "...")?; + } else { + n += fmt::fprint(out, ",")?; + }; + }; + if (t.variadism == variadism::C) { + n += newline(out, indent)?; + n += fmt::fprint(out, "...")?; + }; + indent -= 1; + n += newline(out, indent)?; + } else for (let i = 0z; i < len(t.params); i += 1) { + const param = t.params[i]; + n += fmt::fprintf(out, "\x1b[36m" "{}" "\x1b[0m" ": ", + if (param.name == "") "_" else param.name)?; + n += fmt::fprint(out, typenames[i])?; + if (i + 1 == len(t.params)) { + switch (t.variadism) { + case variadism::NONE => void; + case variadism::HARE => + n += fmt::fprint(out, "...")?; + case variadism::C => + n += fmt::fprint(out, ", ...")?; + }; + } else { + n += fmt::fprint(out, ", ")?; + }; }; - n += fmt::fprint(out, ") ")?; - n += type_tty(out, indent, *t.result)?; + + n += fmt::fprint(out, ")", retname)?; return n; }; diff --git a/hare/unparse/type.ha b/hare/unparse/type.ha @@ -5,6 +5,7 @@ use fmt; use io; use hare::ast; +use hare::ast::{variadism}; use hare::lex; use strings; use strio; @@ -63,24 +64,89 @@ export fn prototype( ) (size | io::error) = { let n = 0z; n += fmt::fprint(out, "(")?; - for (let i = 0z; i < len(t.params); i += 1) { - let param = t.params[i]; - n += fmt::fprintf(out, "{}: ", - if (len(param.name) == 0) "_" else param.name)?; - n += _type(out, indent, *param._type)?; - if (i + 1 == len(t.params) - && t.variadism == ast::variadism::HARE) { - n += fmt::fprintf(out, "...")?; + + let typenames: []str = []; + // TODO: https://todo.sr.ht/~sircmpwn/hare/581 + if (len(t.params) > 0) { + typenames = alloc([""...], len(t.params)); + }; + defer strings::freeall(typenames); + let retname = ""; + defer free(retname); + + // estimate length of prototype to determine if it should span multiple + // lines + const linelen = if (len(t.params) == 0) { + let strm = strio::dynamic(); + defer io::close(&strm)!; + _type(&strm, indent, *t.result)?; + retname = strings::dup(strio::string(&strm)); + yield 0z; // only use one line if there's no parameters + } else { + let strm = strio::dynamic(); + defer io::close(&strm)!; + let linelen = indent * 8 + 5; + linelen += if (len(t.params) != 0) len(t.params) * 3 - 1 else 0; + for (let i = 0z; i < len(t.params); i += 1) { + const param = t.params[i]; + linelen += _type(&strm, indent, *param._type)?; + typenames[i] = strings::dup(strio::string(&strm)); + linelen += if (param.name == "") 1 else len(param.name); + strio::reset(&strm); }; - if (i + 1 < len(t.params)) { - n += fmt::fprint(out, ", ")?; + switch (t.variadism) { + case variadism::NONE => void; + case variadism::HARE => + linelen += 3; + case variadism::C => + linelen += 5; }; + linelen += _type(&strm, indent, *t.result)?; + retname = strings::dup(strio::string(&strm)); + yield linelen; }; - if (t.variadism == ast::variadism::C) { - n += fmt::fprint(out, ", ...")?; + + // use 72 instead of 80 to give a bit of leeway for preceding text + if (linelen > 72) { + indent += 1; + for (let i = 0z; i < len(t.params); i += 1) { + const param = t.params[i]; + n += newline(out, indent)?; + n += fmt::fprintf(out, "{}: ", + if (param.name == "") "_" else param.name)?; + n += fmt::fprint(out, typenames[i])?; + if (i + 1 == len(t.params) + && t.variadism == variadism::HARE) { + n += fmt::fprint(out, "...")?; + } else { + n += fmt::fprint(out, ",")?; + }; + }; + if (t.variadism == variadism::C) { + n += newline(out, indent)?; + n += fmt::fprint(out, "...")?; + }; + indent -= 1; + n += newline(out, indent)?; + } else for (let i = 0z; i < len(t.params); i += 1) { + const param = t.params[i]; + n += fmt::fprintf(out, "{}: ", + if (param.name == "") "_" else param.name)?; + n += fmt::fprint(out, typenames[i])?; + if (i + 1 == len(t.params)) { + switch (t.variadism) { + case variadism::NONE => void; + case variadism::HARE => + n += fmt::fprint(out, "...")?; + case variadism::C => + n += fmt::fprint(out, ", ...")?; + }; + } else { + n += fmt::fprint(out, ", ")?; + }; }; - n += fmt::fprint(out, ") ")?; - n += _type(out, indent, *t.result)?; + + n += fmt::fprint(out, ")", retname)?; return n; }; @@ -362,14 +428,14 @@ fn type_test(t: ast::_type, expected: str) void = { t.repr = ast::func_type { result = &type_int, attrs = 0, - variadism = ast::variadism::NONE, + variadism = variadism::NONE, params = [], }; type_test(t, "fn() int"); t.repr = ast::func_type { result = &type_int, attrs = ast::func_attrs::NORETURN, - variadism = ast::variadism::C, + variadism = variadism::C, params = [ ast::func_param { loc = loc, @@ -382,7 +448,7 @@ fn type_test(t: ast::_type, expected: str) void = { t.repr = ast::func_type { result = &type_int, attrs = 0, - variadism = ast::variadism::HARE, + variadism = variadism::HARE, params = [ ast::func_param { loc = loc,