hare

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

main.ha (4237B)


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