fmt.odin 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. #import "os.odin"
  2. #import "mem.odin"
  3. #import "utf8.odin"
  4. PRINT_BUF_SIZE :: 1<<12
  5. fprint :: proc(f: ^os.File, args: ..any) -> int {
  6. data: [PRINT_BUF_SIZE]byte
  7. buf := data[:0]
  8. bprint(^buf, ..args)
  9. os.write(f, buf)
  10. return buf.count
  11. }
  12. fprintln :: proc(f: ^os.File, args: ..any) -> int {
  13. data: [PRINT_BUF_SIZE]byte
  14. buf := data[:0]
  15. bprintln(^buf, ..args)
  16. os.write(f, buf)
  17. return buf.count
  18. }
  19. fprintf :: proc(f: ^os.File, fmt: string, args: ..any) -> int {
  20. data: [PRINT_BUF_SIZE]byte
  21. buf := data[:0]
  22. bprintf(^buf, fmt, ..args)
  23. os.write(f, buf)
  24. return buf.count
  25. }
  26. print :: proc(args: ..any) -> int {
  27. return fprint(os.stdout, ..args)
  28. }
  29. println :: proc(args: ..any) -> int {
  30. return fprintln(os.stdout, ..args)
  31. }
  32. printf :: proc(fmt: string, args: ..any) -> int {
  33. return fprintf(os.stdout, fmt, ..args)
  34. }
  35. fprint_type :: proc(f: ^os.File, info: ^Type_Info) {
  36. data: [PRINT_BUF_SIZE]byte
  37. buf := data[:0]
  38. bprint_type(^buf, info)
  39. os.write(f, buf)
  40. }
  41. print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
  42. if buf.count < buf.capacity {
  43. n := min(buf.capacity-buf.count, b.count)
  44. if n > 0 {
  45. mem.copy(buf.data + buf.count, b.data, n)
  46. buf.count += n
  47. }
  48. }
  49. }
  50. bprint_string :: proc(buf: ^[]byte, s: string) {
  51. print_byte_buffer(buf, s as []byte)
  52. }
  53. byte_reverse :: proc(b: []byte) {
  54. n := b.count
  55. for i := 0; i < n/2; i++ {
  56. b[i], b[n-1-i] = b[n-1-i], b[i]
  57. }
  58. }
  59. bprint_rune :: proc(buf: ^[]byte, r: rune) {
  60. b, n := utf8.encode_rune(r)
  61. bprint_string(buf, b[:n] as string)
  62. }
  63. bprint_space :: proc(buf: ^[]byte) { bprint_rune(buf, ' '); }
  64. bprint_nl :: proc(buf: ^[]byte) { bprint_rune(buf, '\n'); }
  65. __NUM_TO_CHAR_TABLE := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
  66. bprint_bool :: proc(buffer: ^[]byte, b : bool) {
  67. if b {
  68. bprint_string(buffer, "true")
  69. } else {
  70. bprint_string(buffer, "false")
  71. }
  72. }
  73. bprint_pointer :: proc(buffer: ^[]byte, p: rawptr) #inline {
  74. bprint_string(buffer, "0x")
  75. bprint_u64(buffer, p as uint as u64)
  76. }
  77. bprint_f16 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 4); }
  78. bprint_f32 :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7); }
  79. bprint_f64 :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f as f64, 16); }
  80. bprint_u64 :: proc(buffer: ^[]byte, value: u64) {
  81. i := value
  82. buf: [20]byte
  83. len := 0
  84. if i == 0 {
  85. buf[len] = '0'
  86. len++
  87. }
  88. for i > 0 {
  89. buf[len] = __NUM_TO_CHAR_TABLE[i % 10]
  90. len++
  91. i /= 10
  92. }
  93. byte_reverse(buf[:len])
  94. bprint_string(buffer, buf[:len] as string)
  95. }
  96. bprint_i64 :: proc(buffer: ^[]byte, value: i64) {
  97. // TODO(bill): Cleanup printing
  98. i := value
  99. if i < 0 {
  100. i = -i
  101. bprint_rune(buffer, '-')
  102. }
  103. bprint_u64(buffer, i as u64)
  104. }
  105. /*
  106. bprint_u128 :: proc(buffer: ^[]byte, value: u128) {
  107. a := value transmute [2]u64
  108. if a[1] != 0 {
  109. bprint_u64(buffer, a[1])
  110. }
  111. bprint_u64(buffer, a[0])
  112. }
  113. bprint_i128 :: proc(buffer: ^[]byte, value: i128) {
  114. i := value
  115. if i < 0 {
  116. i = -i
  117. bprint_rune(buffer, '-')
  118. }
  119. bprint_u128(buffer, i as u128)
  120. }
  121. */
  122. print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) {
  123. f := value
  124. if f == 0 {
  125. bprint_rune(buffer, '0')
  126. return
  127. }
  128. if f < 0 {
  129. bprint_rune(buffer, '-')
  130. f = -f
  131. }
  132. i := f as u64
  133. bprint_u64(buffer, i)
  134. f -= i as f64
  135. bprint_rune(buffer, '.')
  136. mult: f64 = 10.0
  137. for ; decimal_places >= 0; decimal_places-- {
  138. i = (f * mult) as u64
  139. bprint_u64(buffer, i as u64)
  140. f -= i as f64 / mult
  141. mult *= 10
  142. }
  143. }
  144. bprint_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
  145. if ti == nil {
  146. return
  147. }
  148. using Type_Info
  149. match type info : ti {
  150. case Named:
  151. bprint_string(buf, info.name)
  152. case Integer:
  153. match {
  154. case ti == type_info(int):
  155. bprint_string(buf, "int")
  156. case ti == type_info(uint):
  157. bprint_string(buf, "uint")
  158. default:
  159. if info.signed {
  160. bprint_string(buf, "i")
  161. } else {
  162. bprint_string(buf, "u")
  163. }
  164. bprint_u64(buf, 8*info.size as u64)
  165. }
  166. case Float:
  167. match info.size {
  168. case 4: bprint_string(buf, "f32")
  169. case 8: bprint_string(buf, "f64")
  170. }
  171. case String: bprint_string(buf, "string")
  172. case Boolean: bprint_string(buf, "bool")
  173. case Pointer:
  174. if info.elem == nil {
  175. bprint_string(buf, "rawptr")
  176. } else {
  177. bprint_string(buf, "^")
  178. bprint_type(buf, info.elem)
  179. }
  180. case Maybe:
  181. bprint_string(buf, "?")
  182. bprint_type(buf, info.elem)
  183. case Procedure:
  184. bprint_string(buf, "proc")
  185. if info.params == nil {
  186. bprint_string(buf, "()")
  187. } else {
  188. count := (info.params as ^Tuple).fields.count
  189. if count == 1 { bprint_string(buf, "("); }
  190. bprint_type(buf, info.params)
  191. if count == 1 { bprint_string(buf, ")"); }
  192. }
  193. if info.results != nil {
  194. bprint_string(buf, " -> ")
  195. bprint_type(buf, info.results)
  196. }
  197. case Tuple:
  198. count := info.fields.count
  199. if count != 1 { bprint_string(buf, "("); }
  200. for i := 0; i < count; i++ {
  201. if i > 0 { bprint_string(buf, ", "); }
  202. f := info.fields[i]
  203. if f.name.count > 0 {
  204. bprint_string(buf, f.name)
  205. bprint_string(buf, ": ")
  206. }
  207. bprint_type(buf, f.type_info)
  208. }
  209. if count != 1 { bprint_string(buf, ")"); }
  210. case Array:
  211. bprint_string(buf, "[")
  212. bprint_i64(buf, info.count as i64)
  213. bprint_string(buf, "]")
  214. bprint_type(buf, info.elem)
  215. case Slice:
  216. bprint_string(buf, "[")
  217. bprint_string(buf, "]")
  218. bprint_type(buf, info.elem)
  219. case Vector:
  220. bprint_string(buf, "[vector ")
  221. bprint_i64(buf, info.count as i64)
  222. bprint_string(buf, "]")
  223. bprint_type(buf, info.elem)
  224. case Struct:
  225. bprint_string(buf, "struct ")
  226. if info.packed { bprint_string(buf, "#packed "); }
  227. if info.ordered { bprint_string(buf, "#ordered "); }
  228. bprint_string(buf, "{")
  229. for i := 0; i < info.fields.count; i++ {
  230. if i > 0 {
  231. bprint_string(buf, ", ")
  232. }
  233. bprint_any(buf, info.fields[i].name)
  234. bprint_string(buf, ": ")
  235. bprint_type(buf, info.fields[i].type_info)
  236. }
  237. bprint_string(buf, "}")
  238. case Union:
  239. bprint_string(buf, "union {")
  240. for i := 0; i < info.fields.count; i++ {
  241. if i > 0 {
  242. bprint_string(buf, ", ")
  243. }
  244. bprint_any(buf, info.fields[i].name)
  245. bprint_string(buf, ": ")
  246. bprint_type(buf, info.fields[i].type_info)
  247. }
  248. bprint_string(buf, "}")
  249. case Raw_Union:
  250. bprint_string(buf, "raw_union {")
  251. for i := 0; i < info.fields.count; i++ {
  252. if i > 0 {
  253. bprint_string(buf, ", ")
  254. }
  255. bprint_any(buf, info.fields[i].name)
  256. bprint_string(buf, ": ")
  257. bprint_type(buf, info.fields[i].type_info)
  258. }
  259. bprint_string(buf, "}")
  260. case Enum:
  261. bprint_string(buf, "enum ")
  262. bprint_type(buf, info.base)
  263. bprint_string(buf, "{}")
  264. }
  265. }
  266. make_any :: proc(type_info: ^Type_Info, data: rawptr) -> any {
  267. a: any
  268. a.type_info = type_info
  269. a.data = data
  270. return a
  271. }
  272. bprint_any :: proc(buf: ^[]byte, arg: any) {
  273. if arg.type_info == nil {
  274. bprint_string(buf, "<nil>")
  275. return
  276. }
  277. if arg.data == nil {
  278. bprint_string(buf, "<nil>")
  279. return
  280. }
  281. using Type_Info
  282. match type info : arg.type_info {
  283. case Named:
  284. a := make_any(info.base, arg.data)
  285. match type b : info.base {
  286. case Struct:
  287. bprint_string(buf, info.name)
  288. bprint_string(buf, "{")
  289. for i := 0; i < b.fields.count; i++ {
  290. f := b.fields[i]
  291. if i > 0 {
  292. bprint_string(buf, ", ")
  293. }
  294. bprint_string(buf, f.name)
  295. // bprint_any(buf, f.offset)
  296. bprint_string(buf, " = ")
  297. data := arg.data as ^byte + f.offset
  298. bprint_any(buf, make_any(f.type_info, data))
  299. }
  300. bprint_string(buf, "}")
  301. default:
  302. bprint_any(buf, a)
  303. }
  304. case Integer:
  305. match type i : arg {
  306. case i8: bprint_i64(buf, i as i64)
  307. case u8: bprint_u64(buf, i as u64)
  308. case i16: bprint_i64(buf, i as i64)
  309. case u16: bprint_u64(buf, i as u64)
  310. case i32: bprint_i64(buf, i as i64)
  311. case u32: bprint_u64(buf, i as u64)
  312. case i64: bprint_i64(buf, i)
  313. case u64: bprint_u64(buf, i)
  314. // case i128: bprint_i128(buf, i)
  315. // case u128: bprint_u128(buf, i)
  316. case int: bprint_i64(buf, i as i64)
  317. case uint: bprint_u64(buf, i as u64)
  318. }
  319. case Float:
  320. match type f : arg {
  321. // case f16: bprint_f64(buf, f as f64)
  322. case f32: bprint_f32(buf, f)
  323. case f64: bprint_f64(buf, f)
  324. // case f128: bprint_f64(buf, f as f64)
  325. }
  326. case String:
  327. match type s : arg {
  328. case string: bprint_string(buf, s)
  329. }
  330. case Boolean:
  331. match type b : arg {
  332. case bool: bprint_bool(buf, b)
  333. }
  334. case Pointer:
  335. match type p : arg {
  336. case ^Type_Info: bprint_type(buf, p)
  337. default: bprint_pointer(buf, (arg.data as ^rawptr)^)
  338. }
  339. case Maybe:
  340. size := mem.size_of_type_info(info.elem)
  341. data := slice_ptr(arg.data as ^byte, size+1)
  342. if data[size] != 0 {
  343. bprint_any(buf, make_any(info.elem, arg.data))
  344. } else {
  345. bprint_string(buf, "nil")
  346. }
  347. case Enum:
  348. value: i64 = 0
  349. match type i : make_any(info.base, arg.data) {
  350. case i8: value = i as i64
  351. case i16: value = i as i64
  352. case i32: value = i as i64
  353. case i64: value = i as i64
  354. case u8: value = i as i64
  355. case u16: value = i as i64
  356. case u32: value = i as i64
  357. case u64: value = i as i64
  358. }
  359. bprint_string(buf, __enum_to_string(arg.type_info, value))
  360. case Array:
  361. bprintf(buf, "[%]%{", info.count, info.elem)
  362. defer bprint_string(buf, "}")
  363. for i := 0; i < info.count; i++ {
  364. if i > 0 {
  365. bprint_string(buf, ", ")
  366. }
  367. data := arg.data as ^byte + i*info.elem_size
  368. bprint_any(buf, make_any(info.elem, data))
  369. }
  370. case Slice:
  371. slice := arg.data as ^[]byte
  372. bprintf(buf, "[]%{", info.elem)
  373. defer bprint_string(buf, "}")
  374. for i := 0; i < slice.count; i++ {
  375. if i > 0 {
  376. bprint_string(buf, ", ")
  377. }
  378. data := slice.data + i*info.elem_size
  379. bprint_any(buf, make_any(info.elem, data))
  380. }
  381. case Vector:
  382. is_bool :: proc(type_info: ^Type_Info) -> bool {
  383. match type info : type_info {
  384. case Named:
  385. return is_bool(info.base)
  386. case Boolean:
  387. return true
  388. }
  389. return false
  390. }
  391. bprintf(buf, "[vector %]%{", info.count, info.elem)
  392. defer bprint_string(buf, "}")
  393. if is_bool(info.elem) {
  394. return
  395. }
  396. for i := 0; i < info.count; i++ {
  397. if i > 0 {
  398. bprint_string(buf, ", ")
  399. }
  400. data := arg.data as ^byte + i*info.elem_size
  401. bprint_any(buf, make_any(info.elem, data))
  402. }
  403. case Struct:
  404. bprintf(buf, "%{", arg.type_info)
  405. defer bprint_string(buf, "}")
  406. for i := 0; i < info.fields.count; i++ {
  407. if i > 0 {
  408. bprint_string(buf, ", ")
  409. }
  410. bprint_string(buf, info.fields[i].name)
  411. bprint_string(buf, " = ")
  412. data := arg.data as ^byte + info.fields[i].offset
  413. ti := info.fields[i].type_info
  414. bprint_any(buf, make_any(ti, data))
  415. }
  416. case Union:
  417. bprint_string(buf, "(union)")
  418. case Raw_Union:
  419. bprint_string(buf, "(raw_union)")
  420. case Procedure:
  421. bprint_type(buf, arg.type_info)
  422. bprint_string(buf, " @ ")
  423. bprint_pointer(buf, (arg.data as ^rawptr)^)
  424. }
  425. }
  426. bprintf :: proc(buf: ^[]byte, fmt: string, args: ..any) -> int {
  427. is_digit :: proc(r: rune) -> bool #inline {
  428. return '0' <= r && r <= '9'
  429. }
  430. parse_int :: proc(s: string, offset: int) -> (int, int) {
  431. result := 0
  432. for ; offset < s.count; offset++ {
  433. c := s[offset] as rune
  434. if !is_digit(c) {
  435. break
  436. }
  437. result *= 10
  438. result += (c - '0') as int
  439. }
  440. return result, offset
  441. }
  442. prev := 0
  443. implicit_index := 0
  444. for i := 0; i < fmt.count; i++ {
  445. r := fmt[i] as rune
  446. index := implicit_index
  447. if r != '%' {
  448. continue
  449. }
  450. bprint_string(buf, fmt[prev:i])
  451. i++; // Skip %
  452. if i < fmt.count {
  453. next := fmt[i] as rune
  454. if next == '%' {
  455. bprint_string(buf, "%")
  456. i++
  457. prev = i
  458. continue
  459. }
  460. if is_digit(next) {
  461. index, i = parse_int(fmt, i)
  462. }
  463. }
  464. if 0 <= index && index < args.count {
  465. bprint_any(buf, args[index])
  466. implicit_index = index+1
  467. } else {
  468. // TODO(bill): Error check index out bounds
  469. bprint_string(buf, "<invalid>")
  470. }
  471. prev = i
  472. }
  473. bprint_string(buf, fmt[prev:])
  474. return buf.count
  475. }
  476. bprint :: proc(buf: ^[]byte, args: ..any) -> int {
  477. is_type_string :: proc(info: ^Type_Info) -> bool {
  478. using Type_Info
  479. if info == nil {
  480. return false
  481. }
  482. match type i : type_info_base(info) {
  483. case String:
  484. return true
  485. }
  486. return false
  487. }
  488. prev_string := false
  489. for i := 0; i < args.count; i++ {
  490. arg := args[i]
  491. is_string := arg.data != nil && is_type_string(arg.type_info)
  492. if i > 0 && !is_string && !prev_string {
  493. bprint_space(buf)
  494. }
  495. bprint_any(buf, arg)
  496. prev_string = is_string
  497. }
  498. return buf.count
  499. }
  500. bprintln :: proc(buf: ^[]byte, args: ..any) -> int {
  501. for i := 0; i < args.count; i++ {
  502. if i > 0 {
  503. append(buf, ' ')
  504. }
  505. bprint_any(buf, args[i])
  506. }
  507. bprint_nl(buf)
  508. return buf.count
  509. }