1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-19 17:47:53 +03:00
mal/wasm/printf.wam
2018-12-08 17:02:13 -06:00

227 lines
7.1 KiB
Plaintext

(module $printf
(global $printf_buf (mut i32) 0)
(func $init_printf_mem
;; sprintf static buffer
(set_global $printf_buf (STATIC_ARRAY 256))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(func $printf_1 (param $fmt i32) (param $v0 i32)
(drop ($sprintf_6 (get_global $printf_buf) $fmt $v0 0 0 0 0 0))
($print (get_global $printf_buf))
)
(func $printf_2 (param $fmt i32 $v0 i32 $v1 i32)
(drop ($sprintf_6 (get_global $printf_buf) $fmt $v0 $v1 0 0 0 0))
($print (get_global $printf_buf))
)
(func $printf_3 (param $fmt i32)
(param $v0 i32) (param $v1 i32) (param $v2 i32)
(drop ($sprintf_6 (get_global $printf_buf) $fmt $v0 $v1 $v2 0 0 0))
($print (get_global $printf_buf))
)
(func $printf_4 (param $fmt i32)
(param $v0 i32) (param $v1 i32) (param $v2 i32)
(param $v3 i32)
(drop ($sprintf_6 (get_global $printf_buf) $fmt $v0 $v1 $v2 $v3 0 0))
($print (get_global $printf_buf))
)
(func $printf_5 (param $fmt i32)
(param $v0 i32) (param $v1 i32) (param $v2 i32)
(param $v3 i32) (param $v4 i32)
(drop ($sprintf_6 (get_global $printf_buf) $fmt $v0 $v1 $v2 $v3 $v4 0))
($print (get_global $printf_buf))
)
(func $printf_6 (param $fmt i32)
(param $v0 i32) (param $v1 i32) (param $v2 i32)
(param $v3 i32) (param $v4 i32) (param $v5 i32)
(drop ($sprintf_6 (get_global $printf_buf) $fmt $v0 $v1 $v2 $v3 $v4 $v5))
($print (get_global $printf_buf))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(func $_sprintdigit (param $str i32) (param $num i32) (param $base i32)
(LET $n (i32.rem_u $num $base)
$ch (if (result i32) (i32.lt_u $n 10) 48 55))
(i32.store8 $str (i32.add $n $ch))
)
;; TODO: add max buf length (i.e. snprintnum)
(func $_sprintnum (param $buf i32) (param $val i32) (param $radix i32)
(param $pad_cnt i32) (param $pad_char i32) (result i32)
(LET $pbuf $buf
$neg 0 $i 0 $j 0 $k 0 $len 0 $digit 0)
(if (AND (i32.lt_s $val 0) (i32.eq $radix 10))
(then
(set_local $neg 1)
(set_local $val (i32.sub 0 $val))))
;; Calculate smallest to most significant digit
(loop $loop
(set_local $digit (i32.rem_u $val $radix))
(i32.store8 $pbuf (if (result i32) (i32.lt_u $digit 10)
(i32.add (CHR "0") $digit)
(i32.sub (i32.add (CHR "A") $digit) 10)))
(set_local $pbuf (i32.add $pbuf 1))
(set_local $val (i32.div_u $val $radix))
(br_if $loop (i32.gt_u $val 0))
)
(set_local $i (i32.sub $pbuf $buf))
(block $done
(loop $loop
(br_if $done (i32.ge_u $i $pad_cnt))
(i32.store8 $pbuf $pad_char)
(set_local $pbuf (i32.add $pbuf 1))
(set_local $i (i32.add $i 1))
(br $loop)
)
)
(if $neg
(then
(i32.store8 $pbuf (CHR "-"))
(set_local $pbuf (i32.add $pbuf 1))))
(i32.store8 $pbuf (CHR "\x00"))
;; now reverse it
(set_local $len (i32.sub $pbuf $buf))
(set_local $i 0)
(block $done
(loop $loop
(br_if $done (i32.ge_u $i (i32.div_u $len 2)))
(set_local $j (i32.load8_u (i32.add $buf $i)))
(set_local $k (i32.add $buf (i32.sub (i32.sub $len $i) 1)))
(i32.store8 (i32.add $buf $i) (i32.load8_u $k))
(i32.store8 $k $j)
(set_local $i (i32.add $i 1))
(br $loop)
)
)
(i32.add $buf $len)
)
;; TODO: switch to snprint* (add buffer len)
(func $sprintf_1 (param $str i32) (param $fmt i32)
(param $v0 i32) (result i32)
($sprintf_6 $str $fmt $v0 0 0 0 0 0)
)
(func $sprintf_6 (param $str i32) (param $fmt i32)
(param $v0 i32) (param $v1 i32) (param $v2 i32)
(param $v3 i32) (param $v4 i32) (param $v5 i32)
(result i32)
(LET $pstr $str
$vidx 0 $ch 0 $v 0 $len 0 $pad_cnt 0 $pad_char 0)
(block $done
(loop $loop
(block $after_v
;; set $v to the current parameter
(block (block (block (block (block (block
(br_table 0 1 2 3 4 5 0 $vidx))
(; 0 ;) (set_local $v $v0) (br $after_v))
(; 1 ;) (set_local $v $v1) (br $after_v))
(; 2 ;) (set_local $v $v2) (br $after_v))
(; 3 ;) (set_local $v $v3) (br $after_v))
(; 4 ;) (set_local $v $v4) (br $after_v))
(; 5 ;) (set_local $v $v5) (br $after_v)
)
;;; while ((ch=*(fmt++)))
(set_local $ch (i32.load8_u $fmt))
(set_local $fmt (i32.add 1 $fmt))
(br_if $done (i32.eqz $ch))
;; TODO: check buffer length
(if (i32.ne $ch (CHR "%"))
(then
;; TODO: check buffer length
(i32.store8 $pstr $ch)
(set_local $pstr (i32.add 1 $pstr))
(br $loop)))
;;; ch=*(fmt++)
(set_local $ch (i32.load8_u $fmt))
(set_local $fmt (i32.add 1 $fmt))
(br_if $done (i32.eqz $ch))
(set_local $pad_cnt 0)
(set_local $pad_char (CHR " "))
(if (AND (i32.ge_s $ch (CHR "0")) (i32.le_s $ch (CHR "9")))
(then
;; padding requested
(if (i32.eq $ch (CHR "0"))
(then
;; zero padding requested
(set_local $pad_char (CHR "0"))
;;; ch=*(fmt++)
(set_local $ch (i32.load8_u $fmt))
(set_local $fmt (i32.add 1 $fmt))
(br_if $done (i32.eqz $ch))))
(loop $loop
(set_local $pad_cnt (i32.mul $pad_cnt 10))
(set_local $pad_cnt (i32.add $pad_cnt
(i32.sub $ch (CHR "0"))))
(set_local $ch (i32.load8_u $fmt))
(set_local $fmt (i32.add 1 $fmt))
(br_if $loop (AND (i32.ge_s $ch (CHR "0"))
(i32.le_s $ch (CHR "9"))))
)))
(if (i32.eq (CHR "d") $ch)
(then
(set_local $pstr ($_sprintnum $pstr $v 10 $pad_cnt $pad_char)))
(else (if (i32.eq (CHR "x") $ch)
(then
(set_local $pstr ($_sprintnum $pstr $v 16 $pad_cnt $pad_char)))
(else (if (i32.eq (CHR "s") $ch)
(then
(set_local $len ($strlen $v))
(block $done
(loop $loop
(br_if $done (i32.le_s $pad_cnt $len))
(i32.store8 $pstr (CHR " "))
(set_local $pstr (i32.add $pstr 1))
(set_local $pad_cnt (i32.sub $pad_cnt 1))
(br $loop)
)
)
($memmove $pstr $v $len)
(set_local $pstr (i32.add $pstr $len)))
(else (if (i32.eq (CHR "c") $ch)
(then
(i32.store8 $pstr $v)
(set_local $pstr (i32.add $pstr 1)))
(else (if (i32.eq (CHR "%") $ch)
(then
(i32.store8 $pstr (CHR "%"))
(set_local $pstr (i32.add $pstr 1))
(br $loop)) ;; don't increase vidx
(else
($printf_1 "Illegal format character: '%c'\n" $ch)
($fatal 3 "")))))))))))
(set_local $vidx (i32.add 1 $vidx))
(br $loop)
)
)
(i32.store8 $pstr (CHR "\x00"))
$pstr
)
)