123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 |
- #import "os.odin";
- #import "mem.odin";
- #import "utf8.odin";
- PRINT_BUF_SIZE :: 1<<12;
- Buffer :: struct {
- data: []byte;
- length: int;
- }
- fprint :: proc(fd: os.Handle, args: ...any) -> int {
- data: [PRINT_BUF_SIZE]byte;
- buf := Buffer{data[:], 0};
- bprint(^buf, ...args);
- os.write(fd, buf.data[:buf.length]);
- return buf.length;
- }
- fprintln :: proc(fd: os.Handle, args: ...any) -> int {
- data: [PRINT_BUF_SIZE]byte;
- buf := Buffer{data[:], 0};
- bprintln(^buf, ...args);
- os.write(fd, buf.data[:buf.length]);
- return buf.length;
- }
- fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int {
- data: [PRINT_BUF_SIZE]byte;
- buf := Buffer{data[:], 0};
- bprintf(^buf, fmt, ...args);
- os.write(fd, buf.data[:buf.length]);
- return buf.length;
- }
- print :: proc(args: ...any) -> int {
- return fprint(os.stdout, ...args);
- }
- println :: proc(args: ...any) -> int {
- return fprintln(os.stdout, ...args);
- }
- printf :: proc(fmt: string, args: ...any) -> int {
- return fprintf(os.stdout, fmt, ...args);
- }
- fprint_type :: proc(fd: os.Handle, info: ^Type_Info) {
- data: [PRINT_BUF_SIZE]byte;
- buf := Buffer{data[:], 0};
- bprint_type(^buf, info);
- os.write(fd, buf.data[:buf.length]);
- }
- print_byte_buffer :: proc(buf: ^Buffer, b: []byte) {
- if buf.length < buf.data.count {
- n := min(buf.data.count-buf.length, b.count);
- if n > 0 {
- copy(buf.data[buf.length:], b[:n]);
- buf.length += n;
- }
- }
- }
- bprint_string :: proc(buf: ^Buffer, s: string) {
- print_byte_buffer(buf, s as []byte);
- }
- byte_reverse :: proc(b: []byte) {
- n := b.count;
- for i : 0..<n/2 {
- b[i], b[n-1-i] = b[n-1-i], b[i];
- }
- }
- bprint_rune :: proc(buf: ^Buffer, r: rune) {
- b, n := utf8.encode_rune(r);
- bprint_string(buf, b[:n] as string);
- }
- bprint_space :: proc(buf: ^Buffer) { bprint_rune(buf, ' '); }
- bprint_nl :: proc (buf: ^Buffer) { bprint_rune(buf, '\n'); }
- __NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$";
- bprint_bool :: proc(buffer: ^Buffer, b: bool) {
- bprint_string(buffer, if b { give "true" } else { give "false" });
- }
- bprint_pointer :: proc(buffer: ^Buffer, p: rawptr) #inline {
- bprint_string(buffer, "0x");
- bprint_u64(buffer, p as uint as u64);
- }
- // bprint_f16 :: proc(buffer: ^Buffer, f: f32) #inline { print__f64(buffer, f as f64, 4); }
- bprint_f32 :: proc(buffer: ^Buffer, f: f32) #inline { print__f64(buffer, f as f64, 7); }
- bprint_f64 :: proc(buffer: ^Buffer, f: f64) #inline { print__f64(buffer, f as f64, 16); }
- bprint_u64 :: proc(buffer: ^Buffer, value: u64) {
- i := value;
- buf :[20]byte;
- len := 0;
- if i == 0 {
- buf[len] = '0';
- len += 1;
- }
- while i > 0 {
- buf[len] = __NUM_TO_CHAR_TABLE[i % 10];
- len += 1;
- i /= 10;
- }
- byte_reverse(buf[:len]);
- bprint_string(buffer, buf[:len] as string);
- }
- bprint_i64 :: proc(buffer: ^Buffer, value: i64) {
- // TODO(bill): Cleanup printing
- i := value;
- if i < 0 {
- i = -i;
- bprint_rune(buffer, '-');
- }
- bprint_u64(buffer, i as u64);
- }
- /*
- bprint_u128 :: proc(buffer: ^Buffer, value u128) {
- a := value transmute [2]u64;
- if a[1] != 0 {
- bprint_u64(buffer, a[1]);
- }
- bprint_u64(buffer, a[0]);
- }
- bprint_i128 :: proc(buffer: ^Buffer, value i128) {
- i := value;
- if i < 0 {
- i = -i;
- bprint_rune(buffer, '-');
- }
- bprint_u128(buffer, i as u128);
- }
- */
- print__f64 :: proc(buffer: ^Buffer, value: f64, decimal_places: int) {
- f := value;
- if f == 0 {
- bprint_rune(buffer, '0');
- return;
- }
- if f < 0 {
- bprint_rune(buffer, '-');
- f = -f;
- }
- i := f as u64;
- bprint_u64(buffer, i);
- f -= i as f64;
- bprint_rune(buffer, '.');
- mult: f64 = 10.0;
- while decimal_places >= 0 {
- i = (f * mult) as u64;
- bprint_u64(buffer, i as u64);
- f -= i as f64 / mult;
- mult *= 10;
- decimal_places -= 1;
- }
- }
- bprint_type :: proc(buf: ^Buffer, ti: ^Type_Info) {
- if ti == nil {
- return;
- }
- using Type_Info;
- match type info : ti {
- case Named:
- bprint_string(buf, info.name);
- case Integer:
- match {
- case ti == type_info(int): bprint_string(buf, "int");
- case ti == type_info(uint): bprint_string(buf, "uint");
- default:
- bprint_string(buf, if info.signed { give "i" } else { give "u"});
- bprint_u64(buf, 8*info.size as u64);
- }
- case Float:
- match info.size {
- case 4: bprint_string(buf, "f32");
- case 8: bprint_string(buf, "f64");
- }
- case String: bprint_string(buf, "string");
- case Boolean: bprint_string(buf, "bool");
- case Pointer:
- if info.elem == nil {
- bprint_string(buf, "rawptr");
- } else {
- bprint_string(buf, "^");
- bprint_type(buf, info.elem);
- }
- case Maybe:
- bprint_string(buf, "?");
- bprint_type(buf, info.elem);
- case Procedure:
- bprint_string(buf, "proc");
- if info.params == nil {
- bprint_string(buf, "()");
- } else {
- count := (info.params as ^Tuple).fields.count;
- if count == 1 { bprint_string(buf, "("); }
- bprint_type(buf, info.params);
- if count == 1 { bprint_string(buf, ")"); }
- }
- if info.results != nil {
- bprint_string(buf, " -> ");
- bprint_type(buf, info.results);
- }
- case Tuple:
- count := info.fields.count;
- if count != 1 { bprint_string(buf, "("); }
- for i : 0..<count {
- if i > 0 { bprint_string(buf, ", "); }
- f := info.fields[i];
- if f.name.count > 0 {
- bprint_string(buf, f.name);
- bprint_string(buf, ": ");
- }
- bprint_type(buf, f.type_info);
- }
- if count != 1 { bprint_string(buf, ")"); }
- case Array:
- bprint_string(buf, "[");
- bprint_i64(buf, info.count as i64);
- bprint_string(buf, "]");
- bprint_type(buf, info.elem);
- case Slice:
- bprint_string(buf, "[");
- bprint_string(buf, "]");
- bprint_type(buf, info.elem);
- case Vector:
- bprint_string(buf, "[vector ");
- bprint_i64(buf, info.count as i64);
- bprint_string(buf, "]");
- bprint_type(buf, info.elem);
- case Struct:
- bprint_string(buf, "struct ");
- if info.packed { bprint_string(buf, "#packed "); }
- if info.ordered { bprint_string(buf, "#ordered "); }
- bprint_string(buf, "{");
- for field, i : info.fields {
- if i > 0 {
- bprint_string(buf, ", ");
- }
- bprint_any(buf, field.name);
- bprint_string(buf, ": ");
- bprint_type(buf, field.type_info);
- }
- bprint_string(buf, "}");
- case Union:
- bprint_string(buf, "union {");
- for field, i : info.fields {
- if i > 0 {
- bprint_string(buf, ", ");
- }
- bprint_any(buf, field.name);
- bprint_string(buf, ": ");
- bprint_type(buf, field.type_info);
- }
- bprint_string(buf, "}");
- case Raw_Union:
- bprint_string(buf, "raw_union {");
- for field, i : info.fields {
- if i > 0 {
- bprint_string(buf, ", ");
- }
- bprint_any(buf, field.name);
- bprint_string(buf, ": ");
- bprint_type(buf, field.type_info);
- }
- bprint_string(buf, "}");
- case Enum:
- bprint_string(buf, "enum ");
- bprint_type(buf, info.base);
- bprint_string(buf, " {}");
- }
- }
- make_any :: proc(type_info: ^Type_Info, data: rawptr) -> any {
- a :any;
- a.type_info = type_info;
- a.data = data;
- return a;
- }
- bprint_any :: proc(buf: ^Buffer, arg: any) {
- if arg.type_info == nil {
- bprint_string(buf, "<nil>");
- return;
- }
- if arg.data == nil {
- bprint_string(buf, "<nil>");
- return;
- }
- using Type_Info;
- match type info : arg.type_info {
- case Named:
- a := make_any(info.base, arg.data);
- match type b : info.base {
- case Struct:
- bprint_string(buf, info.name);
- bprint_string(buf, "{");
- for f, i : b.fields {
- if i > 0 {
- bprint_string(buf, ", ");
- }
- bprint_string(buf, f.name);
- // bprint_any(buf, f.offset);
- bprint_string(buf, " = ");
- data := arg.data as ^byte + f.offset;
- bprint_any(buf, make_any(f.type_info, data));
- }
- bprint_string(buf, "}");
- default:
- bprint_any(buf, a);
- }
- case Integer:
- match type i : arg {
- case i8: bprint_i64(buf, i as i64);
- case u8: bprint_u64(buf, i as u64);
- case i16: bprint_i64(buf, i as i64);
- case u16: bprint_u64(buf, i as u64);
- case i32: bprint_i64(buf, i as i64);
- case u32: bprint_u64(buf, i as u64);
- case i64: bprint_i64(buf, i);
- case u64: bprint_u64(buf, i);
- // case i128: bprint_i128(buf, i);
- // case u128: bprint_u128(buf, i);
- case int: bprint_i64(buf, i as i64);
- case uint: bprint_u64(buf, i as u64);
- }
- case Float:
- match type f : arg {
- // case f16: bprint_f64(buf, f as f64);
- case f32: bprint_f32(buf, f);
- case f64: bprint_f64(buf, f);
- // case f128: bprint_f64(buf, f as f64);
- }
- case String:
- match type s : arg {
- case string: bprint_string(buf, s);
- }
- case Boolean:
- match type b : arg {
- case bool: bprint_bool(buf, b);
- }
- case Pointer:
- match type p : arg {
- case ^Type_Info: bprint_type(buf, p);
- default: bprint_pointer(buf, (arg.data as ^rawptr)^);
- }
- case Maybe:
- size := mem.size_of_type_info(info.elem);
- data := slice_ptr(arg.data as ^byte, size+1);
- if data[size] != 0 {
- bprint_any(buf, make_any(info.elem, arg.data));
- } else {
- bprint_string(buf, "nil");
- }
- case Array:
- bprintf(buf, "[%]%{", info.count, info.elem);
- defer bprint_string(buf, "}");
- for i : 0..<info.count {
- if i > 0 {
- bprint_string(buf, ", ");
- }
- data := arg.data as ^byte + i*info.elem_size;
- bprint_any(buf, make_any(info.elem, data));
- }
- case Slice:
- slice := arg.data as ^[]byte;
- bprintf(buf, "[]%{", info.elem);
- defer bprint_string(buf, "}");
- for i : 0..<slice.count {
- if i > 0 {
- bprint_string(buf, ", ");
- }
- data := slice.data + i*info.elem_size;
- bprint_any(buf, make_any(info.elem, data));
- }
- case Vector:
- is_bool :: proc(type_info: ^Type_Info) -> bool {
- match type info : type_info {
- case Named:
- return is_bool(info.base);
- case Boolean:
- return true;
- }
- return false;
- }
- bprintf(buf, "[vector %]%{", info.count, info.elem);
- defer bprint_string(buf, "}");
- if is_bool(info.elem) {
- return;
- }
- for i : 0..<info.count {
- if i > 0 {
- bprint_string(buf, ", ");
- }
- data := arg.data as ^byte + i*info.elem_size;
- bprint_any(buf, make_any(info.elem, data));
- }
- case Struct:
- bprintf(buf, "%{", arg.type_info);
- defer bprint_string(buf, "}");
- for f, i : info.fields {
- if i > 0 {
- bprint_string(buf, ", ");
- }
- bprint_string(buf, f.name);
- bprint_string(buf, " = ");
- data := arg.data as ^byte + f.offset;
- ti := f.type_info;
- bprint_any(buf, make_any(ti, data));
- }
- case Union:
- bprint_string(buf, "(union)");
- case Raw_Union:
- bprint_string(buf, "(raw_union)");
- case Enum:
- bprint_any(buf, make_any(info.base, arg.data));
- case Procedure:
- bprint_type(buf, arg.type_info);
- bprint_string(buf, " @ ");
- bprint_pointer(buf, (arg.data as ^rawptr)^);
- }
- }
- bprintf :: proc(buf: ^Buffer, fmt: string, args: ...any) -> int {
- is_digit :: proc(r: rune) -> bool #inline {
- return '0' <= r && r <= '9';
- }
- parse_int :: proc(s: string, offset: int) -> (int, int) {
- result := 0;
- for _ : offset..<s.count {
- c := s[offset] as rune;
- if !is_digit(c) {
- break;
- }
- result *= 10;
- result += (c - '0') as int;
- }
- return result, offset;
- }
- prev := 0;
- implicit_index := 0;
- while i := 0; i < fmt.count { defer i += 1;
- r := fmt[i] as rune;
- index := implicit_index;
- if r != '%' {
- continue;
- }
- bprint_string(buf, fmt[prev:i]);
- i += 1; // Skip %
- if i < fmt.count {
- next := fmt[i] as rune;
- if next == '%' {
- bprint_string(buf, "%");
- i += 1;
- prev = i;
- continue;
- }
- if is_digit(next) {
- index, i = parse_int(fmt, i);
- }
- }
- if 0 <= index && index < args.count {
- bprint_any(buf, args[index]);
- implicit_index = index+1;
- } else {
- // TODO(bill): Error check index out bounds
- bprint_string(buf, "<invalid>");
- }
- prev = i;
- }
- bprint_string(buf, fmt[prev:]);
- return buf.length;
- }
- bprint :: proc(buf: ^Buffer, args: ...any) -> int {
- is_type_string :: proc(info: ^Type_Info) -> bool {
- using Type_Info;
- if info == nil {
- return false;
- }
- match type i : type_info_base(info) {
- case String:
- return true;
- }
- return false;
- }
- prev_string := false;
- for arg, i : args {
- is_string := arg.data != nil && is_type_string(arg.type_info);
- if i > 0 && !is_string && !prev_string {
- bprint_space(buf);
- }
- bprint_any(buf, arg);
- prev_string = is_string;
- }
- return buf.length;
- }
- bprintln :: proc(buf: ^Buffer, args: ...any) -> int {
- for arg, i : args {
- if i > 0 {
- bprint_space(buf);
- }
- bprint_any(buf, arg);
- }
- bprint_nl(buf);
- return buf.length;
- }
|