hare

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

main.ha (4088B)


      1 use bufio;
      2 use fmt;
      3 use hare::ast;
      4 use hare::lex;
      5 use hare::lex::{ltok};
      6 use hare::parse;
      7 use hare::types;
      8 use io;
      9 use os;
     10 use regex;
     11 use strings;
     12 
     13 let ioctlre: regex::regex = regex::regex { ... };
     14 let typedefre: regex::regex = regex::regex { ... };
     15 
     16 @init fn init() void = {
     17 	ioctlre = regex::compile(`@(_IO[RW]*)\((.*)\)`)!;
     18 	typedefre = regex::compile(`^(export )?type `)!;
     19 };
     20 
     21 @fini fn fini() void = {
     22 	regex::finish(&ioctlre);
     23 	regex::finish(&typedefre);
     24 };
     25 
     26 type dir = enum u32 {
     27 	IO = 0,
     28 	IOW = 1,
     29 	IOR = 2,
     30 	IOWR = IOW | IOR,
     31 };
     32 
     33 type ioctl = (dir, rune, u32, const nullable *types::_type);
     34 
     35 export fn main() void = {
     36 	// TODO: Configurable arch
     37 	const store = types::store(types::x86_64, null, null);
     38 	defer types::store_free(store);
     39 
     40 	for (true) {
     41 		const line = match (bufio::scanline(os::stdin)!) {
     42 		case io::EOF =>
     43 			break;
     44 		case let line: []u8 =>
     45 			yield strings::fromutf8(line);
     46 		};
     47 		defer free(line);
     48 
     49 		if (regex::test(&typedefre, line)) {
     50 			bufio::unreadrune(os::stdin, '\n');
     51 			bufio::unread(os::stdin, strings::toutf8(line));
     52 			loadtype(store);
     53 			continue;
     54 		};
     55 
     56 		let groups = match (regex::find(&ioctlre, line)) {
     57 		case void =>
     58 			fmt::println(line)!;
     59 			continue;
     60 		case let cap: []regex::capture =>
     61 			yield cap;
     62 		};
     63 		defer free(groups);
     64 
     65 		const dir = switch (groups[1].content) {
     66 		case "_IO" =>
     67 			yield dir::IO;
     68 		case "_IOR" =>
     69 			yield dir::IOR;
     70 		case "_IOW" =>
     71 			yield dir::IOW;
     72 		case "_IOWR" =>
     73 			yield dir::IOWR;
     74 		case =>
     75 			fmt::fatalf("Unknown ioctl direction {}",
     76 				groups[1].content);
     77 		};
     78 		const ioctl = parseioctl(store, dir, groups[2].content);
     79 
     80 		const prefix = strings::sub(line, 0, groups[1].start - 1);
     81 		fmt::printfln("{}0x{:x};", prefix, ioctlno(&ioctl))!;
     82 	};
     83 };
     84 
     85 fn loadtype(store: *types::typestore) void = {
     86 	const tee = io::tee(os::stdin, os::stdout);
     87 	const lex = lex::init(&tee, "<ioctl>");
     88 	const decl = match (parse::decl(&lex)) {
     89 	case let err: parse::error =>
     90 		fmt::fatal("Error parsing type declaration:",
     91 			parse::strerror(err));
     92 	case let decl: ast::decl =>
     93 		yield decl;
     94 	};
     95 
     96 	const tdecl = decl.decl as []ast::decl_type;
     97 	if (len(tdecl) != 1) {
     98 		fmt::fatal("Multiple type declarations are unsupported");
     99 	};
    100 	const tdecl = tdecl[0];
    101 	const of = types::lookup(store, &tdecl._type)!;
    102 	types::newalias(store, tdecl.ident, of);
    103 };
    104 
    105 fn parseioctl(store: *types::typestore, d: dir, params: str) ioctl = {
    106 	const buf = bufio::fixed(strings::toutf8(params), io::mode::READ);
    107 	const lex = lex::init(&buf, "<ioctl>");
    108 
    109 	const rn = expect(&lex, ltok::LIT_RUNE).1 as rune;
    110 	expect(&lex, ltok::COMMA);
    111 	const num = expect(&lex, ltok::LIT_ICONST).1 as i64;
    112 
    113 	if (d == dir::IO) {
    114 		return (d, rn, num: u32, null);
    115 	};
    116 
    117 	expect(&lex, ltok::COMMA);
    118 	const ty = match (parse::_type(&lex)) {
    119 	case let ty: ast::_type =>
    120 		yield ty;
    121 	case let err: parse::error =>
    122 		fmt::fatal("Error:", parse::strerror(err));
    123 	};
    124 
    125 	const ty = match (types::lookup(store, &ty)) {
    126 	case let err: types::error =>
    127 		fmt::fatal("Error:", types::strerror(err));
    128 	case types::deferred =>
    129 		fmt::fatal("Error: this tool does not support forward references");
    130 	case let ty: const *types::_type =>
    131 		yield ty;
    132 	};
    133 
    134 	return (d, rn, num: u32, ty);
    135 };
    136 
    137 fn expect(lex: *lex::lexer, want: ltok) lex::token = {
    138 	match (lex::lex(lex)) {
    139 	case let err: lex::error =>
    140 		fmt::fatal("Error:", lex::strerror(err));
    141 	case let tok: lex::token =>
    142 		if (tok.0 != want) {
    143 			fmt::fatalf("Error: unexpected {}", lex::tokstr(tok));
    144 		};
    145 		return tok;
    146 	};
    147 };
    148 
    149 def IOC_NRBITS: u32 = 8;
    150 def IOC_TYPEBITS: u32 = 8;
    151 def IOC_SIZEBITS: u32 = 14; // XXX: Arch-specific
    152 def IOC_DIRBITS: u32 = 2; // XXX: Arch-specific
    153 
    154 def IOC_NRSHIFT: u32 = 0;
    155 def IOC_TYPESHIFT: u32 = IOC_NRSHIFT + IOC_NRBITS;
    156 def IOC_SIZESHIFT: u32 = IOC_TYPESHIFT + IOC_TYPEBITS;
    157 def IOC_DIRSHIFT: u32 = IOC_SIZESHIFT + IOC_SIZEBITS;
    158 
    159 fn ioctlno(io: *ioctl) u32 = {
    160 	const ty = match (io.3) {
    161 	case let ty: const *types::_type =>
    162 		yield ty.sz;
    163 	case null =>
    164 		yield 0z;
    165 	};
    166 	return (io.0: u32 << IOC_DIRSHIFT) |
    167 		(io.1: u32 << IOC_TYPESHIFT) |
    168 		(io.2 << IOC_NRSHIFT) |
    169 		(ty: u32 << IOC_SIZESHIFT);
    170 };