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