mirror of
https://github.com/kanaka/mal.git
synced 2024-11-11 00:52:44 +03:00
0a19c2f1c7
wasm: update to wat syntax as of Jan 2019. Examples: - get_local -> local.get - i32.wrap/i64 -> i32.warp_i64 - etc The distinction between wat and wast has been clarified: - wat: textual format for web assembly modules - wast: superset of wat used in the specification to define tests.
216 lines
7.0 KiB
Plaintext
216 lines
7.0 KiB
Plaintext
(module $string
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; Copy len bytes from src to dst
|
|
;; Returns len
|
|
(func $memmove (param $dst i32 $src i32 $len i32)
|
|
(LET $idx 0)
|
|
(loop $copy
|
|
(i32.store8 (i32.add $idx $dst)
|
|
(i32.load8_u (i32.add $idx $src)))
|
|
(local.set $idx (i32.add 1 $idx))
|
|
(br_if $copy (i32.lt_u $idx $len))
|
|
)
|
|
)
|
|
|
|
(func $strlen (param $str i32) (result i32)
|
|
(LET $cur $str)
|
|
(loop $count
|
|
(if (i32.ne 0 (i32.load8_u $cur))
|
|
(then
|
|
(local.set $cur (i32.add $cur 1))
|
|
(br $count)))
|
|
)
|
|
(i32.sub $cur $str)
|
|
)
|
|
|
|
;; Based on https://stackoverflow.com/a/25705264/471795
|
|
;; This could be made much more efficient
|
|
(func $strstr (param $haystack i32 $needle i32) (result i32)
|
|
(LET $i 0
|
|
$needle_len ($strlen $needle)
|
|
$len ($strlen $haystack))
|
|
|
|
(if (i32.eq $needle_len 0) (return $haystack))
|
|
|
|
(local.set $i 0)
|
|
(block $done
|
|
(loop $loop
|
|
(if (i32.gt_s $i (i32.sub $len $needle_len)) (br $done))
|
|
|
|
(if (AND (i32.eq (i32.load8_u $haystack)
|
|
(i32.load8_u $needle))
|
|
(i32.eqz ($strncmp $haystack $needle $needle_len)))
|
|
(return $haystack))
|
|
(local.set $haystack (i32.add $haystack 1))
|
|
(local.set $i (i32.add $i 1))
|
|
(br $loop)
|
|
)
|
|
)
|
|
0
|
|
)
|
|
|
|
(func $atoi (param $str i32) (result i32)
|
|
(LET $acc 0
|
|
$i 0
|
|
$neg 0
|
|
$ch 0)
|
|
(block $done
|
|
(loop $loop
|
|
(local.set $ch (i32.load8_u (i32.add $str $i)))
|
|
(if (AND (i32.ne $ch (CHR "-"))
|
|
(OR (i32.lt_u $ch (CHR "0"))
|
|
(i32.gt_u $ch (CHR "9"))))
|
|
(br $done))
|
|
(local.set $i (i32.add $i 1))
|
|
(if (i32.eq $ch (CHR "-"))
|
|
(then
|
|
(local.set $neg 1))
|
|
(else
|
|
(local.set $acc (i32.add (i32.mul $acc 10)
|
|
(i32.sub $ch (CHR "0"))))))
|
|
(br $loop)
|
|
)
|
|
)
|
|
(if (result i32) $neg
|
|
(then (i32.sub 0 $acc))
|
|
(else $acc))
|
|
)
|
|
|
|
(func $strcmp (param $s1 i32 $s2 i32) (result i32)
|
|
(block $done
|
|
(loop $loop
|
|
(if (OR (i32.eqz (i32.load8_u $s1)) (i32.eqz (i32.load8_u $s2)))
|
|
(br $done))
|
|
(if (i32.ne (i32.load8_u $s1) (i32.load8_u $s2))
|
|
(br $done))
|
|
(local.set $s1 (i32.add $s1 1))
|
|
(local.set $s2 (i32.add $s2 1))
|
|
(br $loop)
|
|
)
|
|
)
|
|
(if (result i32) (i32.eq (i32.load8_u $s1) (i32.load8_u $s2))
|
|
(then 0)
|
|
(else
|
|
(if (result i32) (i32.lt_u (i32.load8_u $s1) (i32.load8_u $s2))
|
|
(then -1)
|
|
(else 1))))
|
|
)
|
|
|
|
(func $strncmp (param $s1 i32 $s2 i32 $len i32) (result i32)
|
|
(LET $i 0)
|
|
(if (i32.eq $len 0) (return 0))
|
|
(block $done
|
|
(loop $loop
|
|
(if (i32.ge_u $i $len) (br $done))
|
|
(if (i32.eqz (i32.load8_u (i32.add $i $s1))) (br $done))
|
|
(if (i32.ne (i32.load8_u (i32.add $i $s1))
|
|
(i32.load8_u (i32.add $i $s2))) (br $done))
|
|
(local.set $i (i32.add $i 1))
|
|
(br $loop)
|
|
)
|
|
)
|
|
(if (OR (i32.eq $i $len)
|
|
(i32.eq (i32.load8_u (i32.add $i $s1))
|
|
(i32.load8_u (i32.add $i $s2))))
|
|
(return 0))
|
|
(if (result i32) (i32.lt_u (i32.load8_u (i32.add $i $s1))
|
|
(i32.load8_u (i32.add $i $s2)))
|
|
(then -1)
|
|
(else 1))
|
|
)
|
|
|
|
;; Writes new string to grass with all needles in haystack replaced.
|
|
;; If the length of replace is equal to of less than needle then
|
|
;; grass can be NULL.
|
|
;; Returns length of grass.
|
|
(func $REPLACE3 (param $grass i32 $haystack i32
|
|
$needle0 i32 $replace0 i32
|
|
$needle1 i32 $replace1 i32
|
|
$needle2 i32 $replace2 i32) (result i32)
|
|
(LET $haystack_len ($strlen $haystack)
|
|
$src_str $haystack
|
|
$dst_str $grass
|
|
$s 0 $found_tmp 0 $found 0
|
|
$needle 0 $replace 0 $needle_len 0 $replace_len 0
|
|
$replace_s 0 $replace_len_s 0 $needle_len_s 0)
|
|
|
|
;; in-place
|
|
(if (i32.eqz $grass)
|
|
(then
|
|
;; check that we aren't expanding in place
|
|
(local.set $s 0)
|
|
(block $done
|
|
(loop $loop
|
|
(if (i32.ge_u $s 3) (br $done))
|
|
(local.set $needle (if (result i32) (i32.eq $s 0) $needle0
|
|
(if (result i32) (i32.eq $s 1) $needle1
|
|
$needle2)))
|
|
(local.set $replace (if (result i32) (i32.eq $s 0) $replace0
|
|
(if (result i32) (i32.eq $s 1) $replace1
|
|
$replace2)))
|
|
(local.set $needle_len ($strlen $needle))
|
|
(local.set $replace_len ($strlen $replace))
|
|
(if (i32.gt_u $replace_len $needle_len)
|
|
($fatal 7 "REPLACE: invalid expanding in-place call\n"))
|
|
(local.set $s (i32.add $s 1))
|
|
(br $loop)
|
|
)
|
|
)
|
|
(local.set $grass $haystack)
|
|
(local.set $dst_str $grass)))
|
|
|
|
(block $done1
|
|
(loop $loop1
|
|
(if (i32.ge_s (i32.sub $src_str $haystack) $haystack_len)
|
|
(br $done1))
|
|
|
|
;; Find the earliest match
|
|
(local.set $found 0)
|
|
(local.set $s 0)
|
|
(block $done2
|
|
(loop $loop2
|
|
(if (i32.ge_u $s 3) (br $done2))
|
|
(local.set $needle (if (result i32) (i32.eq $s 0) $needle0
|
|
(if (result i32) (i32.eq $s 1) $needle1
|
|
$needle2)))
|
|
(local.set $replace (if (result i32) (i32.eq $s 0) $replace0
|
|
(if (result i32) (i32.eq $s 1) $replace1
|
|
$replace2)))
|
|
(local.set $s (i32.add $s 1))
|
|
(local.set $found_tmp ($strstr $src_str $needle))
|
|
(if (i32.eqz $found_tmp) (br $loop2))
|
|
(if (OR (i32.eqz $found) (i32.lt_s $found_tmp $found))
|
|
(then
|
|
(local.set $found $found_tmp)
|
|
(local.set $needle_len_s ($strlen $needle))
|
|
(local.set $replace_s $replace)
|
|
(local.set $replace_len_s ($strlen $replace))))
|
|
(br $loop2)
|
|
)
|
|
)
|
|
(if (i32.eqz $found) (br $done1))
|
|
;; copy before the match
|
|
($memmove $dst_str $src_str (i32.add (i32.sub $found $src_str) 1))
|
|
(local.set $dst_str (i32.add $dst_str (i32.sub $found $src_str)))
|
|
;; add the replace string
|
|
($memmove $dst_str $replace_s (i32.add $replace_len_s 1))
|
|
(local.set $dst_str (i32.add $dst_str $replace_len_s))
|
|
;; Move to after the match
|
|
(local.set $src_str (i32.add $found $needle_len_s))
|
|
(br $loop1)
|
|
)
|
|
)
|
|
|
|
;; Copy the left-over
|
|
($memmove $dst_str $src_str ($strlen $src_str))
|
|
(local.set $dst_str (i32.add $dst_str ($strlen $src_str)))
|
|
(i32.store8 $dst_str (CHR "\x00"))
|
|
|
|
(i32.sub $dst_str $grass)
|
|
)
|
|
|
|
)
|
|
|