hare

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

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