hare.ha (4676B)
1 // License: GPL-3.0 2 // (c) 2021 Alexey Yerin <yyp@disroot.org> 3 // (c) 2021 Drew DeVault <sir@cmpwn.com> 4 // (c) 2021 Ember Sawady <ecs@d2evs.net> 5 use bufio; 6 use fmt; 7 use hare::ast; 8 use hare::lex; 9 use hare::module; 10 use hare::unparse; 11 use io; 12 use os; 13 use strings; 14 use strio; 15 16 // Formats output as Hare source code (prototypes) 17 fn emit_hare(ctx: *context) (void | error) = { 18 const summary = ctx.summary; 19 20 let first = true; 21 match (ctx.readme) { 22 case let readme: io::file => 23 first = false; 24 for (true) { 25 match (bufio::scanline(readme)?) { 26 case io::EOF => break; 27 case let b: []u8 => 28 fmt::fprintfln(ctx.out, 29 "// {}", strings::fromutf8(b)!)?; 30 free(b); 31 }; 32 }; 33 case void => void; 34 }; 35 36 emit_submodules_hare(ctx)?; 37 38 // XXX: Should we emit the dependencies, too? 39 for (let i = 0z; i < len(summary.types); i += 1) { 40 if (!first) { 41 fmt::fprintln(ctx.out)?; 42 }; 43 first = false; 44 details_hare(ctx, summary.types[i])?; 45 }; 46 for (let i = 0z; i < len(summary.constants); i += 1) { 47 if (!first) { 48 fmt::fprintln(ctx.out)?; 49 }; 50 first = false; 51 details_hare(ctx, summary.constants[i])?; 52 }; 53 for (let i = 0z; i < len(summary.errors); i += 1) { 54 if (!first) { 55 fmt::fprintln(ctx.out)?; 56 }; 57 first = false; 58 details_hare(ctx, summary.errors[i])?; 59 }; 60 for (let i = 0z; i < len(summary.globals); i += 1) { 61 if (!first) { 62 fmt::fprintln(ctx.out)?; 63 }; 64 first = false; 65 details_hare(ctx, summary.globals[i])?; 66 }; 67 for (let i = 0z; i < len(summary.funcs); i += 1) { 68 if (!first) { 69 fmt::fprintln(ctx.out)?; 70 }; 71 first = false; 72 details_hare(ctx, summary.funcs[i])?; 73 }; 74 }; 75 76 fn emit_submodules_hare(ctx: *context) (void | error) = { 77 const submodules = submodules(ctx)?; 78 defer strings::freeall(submodules); 79 80 if (len(submodules) != 0) { 81 fmt::fprintln(ctx.out)?; 82 if (len(ctx.ident) == 0) { 83 fmt::fprintln(ctx.out, "// Modules")?; 84 } else { 85 fmt::fprintln(ctx.out, "// Submodules")?; 86 }; 87 for (let i = 0z; i < len(submodules); i += 1) { 88 let submodule = if (len(ctx.ident) != 0) { 89 const s = unparse::identstr(ctx.ident); 90 defer free(s); 91 yield strings::concat(s, "::", submodules[i]); 92 } else { 93 yield strings::dup(submodules[i]); 94 }; 95 defer free(submodule); 96 97 fmt::fprintf(ctx.out, "// - [[")?; 98 fmt::fprintf(ctx.out, submodule)?; 99 fmt::fprintfln(ctx.out, "]]")?; 100 }; 101 }; 102 }; 103 104 fn details_hare(ctx: *context, decl: ast::decl) (void | error) = { 105 if (len(decl.docs) == 0 && !ctx.show_undocumented) { 106 return; 107 }; 108 109 const iter = strings::tokenize(decl.docs, "\n"); 110 for (true) { 111 match (strings::next_token(&iter)) { 112 case void => break; 113 case let s: str => 114 if (len(s) != 0) { 115 fmt::fprintfln(ctx.out, "//{}", s)?; 116 }; 117 }; 118 }; 119 120 unparse_hare(ctx.out, decl)?; 121 fmt::fprintln(ctx.out)?; 122 return; 123 }; 124 125 // Forked from [[hare::unparse]] 126 fn unparse_hare(out: io::handle, d: ast::decl) (size | io::error) = { 127 let n = 0z; 128 match (d.decl) { 129 case let g: []ast::decl_global => 130 n += fmt::fprint(out, 131 if (g[0].is_const) "const " else "let ")?; 132 for (let i = 0z; i < len(g); i += 1) { 133 if (len(g[i].symbol) != 0) { 134 n += fmt::fprintf(out, 135 "@symbol(\"{}\") ", g[i].symbol)?; 136 }; 137 n += unparse::ident(out, g[i].ident)?; 138 n += fmt::fprint(out, ": ")?; 139 n += unparse::_type(out, 0, g[i]._type)?; 140 if (i + 1 < len(g)) { 141 n += fmt::fprint(out, ", ")?; 142 }; 143 }; 144 case let t: []ast::decl_type => 145 n += fmt::fprint(out, "type ")?; 146 for (let i = 0z; i < len(t); i += 1) { 147 n += unparse::ident(out, t[i].ident)?; 148 n += fmt::fprint(out, " = ")?; 149 n += unparse::_type(out, 0, t[i]._type)?; 150 if (i + 1 < len(t)) { 151 n += fmt::fprint(out, ", ")?; 152 }; 153 }; 154 case let c: []ast::decl_const => 155 n += fmt::fprint(out, "def ")?; 156 for (let i = 0z; i < len(c); i += 1) { 157 n += unparse::ident(out, c[i].ident)?; 158 n += fmt::fprint(out, ": ")?; 159 n += unparse::_type(out, 0, c[i]._type)?; 160 if (i + 1 < len(c)) { 161 n += fmt::fprint(out, ", ")?; 162 }; 163 }; 164 case let f: ast::decl_func => 165 n += fmt::fprint(out, switch (f.attrs) { 166 case ast::fndecl_attrs::NONE => 167 yield ""; 168 case ast::fndecl_attrs::FINI => 169 yield "@fini "; 170 case ast::fndecl_attrs::INIT => 171 yield "@init "; 172 case ast::fndecl_attrs::TEST => 173 yield "@test "; 174 })?; 175 let p = f.prototype.repr as ast::func_type; 176 if (p.attrs & ast::func_attrs::NORETURN != 0) { 177 n += fmt::fprint(out, "@noreturn ")?; 178 }; 179 if (len(f.symbol) != 0) { 180 n += fmt::fprintf(out, "@symbol(\"{}\") ", 181 f.symbol)?; 182 }; 183 n += fmt::fprint(out, "fn ")?; 184 n += unparse::ident(out, f.ident)?; 185 n += unparse::prototype(out, 0, 186 f.prototype.repr as ast::func_type)?; 187 }; 188 n += fmt::fprint(out, ";")?; 189 return n; 190 };