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