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:
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,