hare

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

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 };