ocaml-wasm / wasm_of_ocaml

Other
249 stars 9 forks source link

Improved Wasm text syntax #87

Open vouillon opened 1 month ago

vouillon commented 1 month ago

We have a large amount of hand-written Wasm code. It might be easier to maintain it if we could write it using a more concise syntax, with some syntactic sugar and type inference. This would involve writing a tool that can type-check the code and translate it to and from standard Wasm (possibly with source maps).

Some ideas:

For instance, consider this function:

(func $string_compare
   (param $p1 (ref eq)) (param $p2 (ref eq)) (result i32)
   (local $s1 (ref $string)) (local $s2 (ref $string))
   (local $l1 i32) (local $l2 i32) (local $len i32) (local $i i32)
   (local $c1 i32) (local $c2 i32)
   (if (ref.eq (local.get $p1) (local.get $p2))
      (then (return (i32.const 0))))
   (local.set $s1 (ref.cast (ref $string) (local.get $p1)))
   (local.set $s2 (ref.cast (ref $string) (local.get $p2)))
   (local.set $l1 (array.len (local.get $s1)))
   (local.set $l2 (array.len (local.get $s2)))
   (local.set $len (select (local.get $l1) (local.get $l2)
                       (i32.le_u (local.get $l1) (local.get $l2))))
   (local.set $i (i32.const 0))
   (loop $loop
      (if (i32.lt_s (local.get $i) (local.get $len))
         (then
            (local.set $c1
               (array.get_u $string (local.get $s1) (local.get $i)))
            (local.set $c2
               (array.get_u $string (local.get $s2) (local.get $i)))
            (if (i32.lt_u (local.get $c1) (local.get $c2))
               (then (return (i32.const -1))))
            (if (i32.gt_u (local.get $c1) (local.get $c2))
               (then (return (i32.const 1))))
            (local.set $i (i32.add (local.get $i) (i32.const 1)))
            (br $loop))))
   (if (i32.lt_u (local.get $l1) (local.get $l2))
      (then (return (i32.const -1))))
   (if (i32.gt_u (local.get $l1) (local.get $l2))
      (then (return (i32.const 1))))
   (i32.const 0))

We could write it like this using a Rust-like syntax:

fn string_compare(p1: &eq, p2: &eq) -> i32 {
  if p1 == p2 { return 0 }
  let s1 = p1 as &string;
  let s2 = p2 as &string;
  let l1 = array_len(s1);
  let l2 = array_len(s2);
  let len = l1 <=u l2?l1:l2;
  for (let i = 0; i <s len; i++) {
    let c1 = unsigned(s1[i]);
    let c2 = unsigned(s2[i]);
    if c1 <u c2 { return -1 }
    if c1 >u c2 { return 1 }
  if l1 <u l2 { return -1 }
  if l1 >u l2 { return 1 }
  0
}

Or with an OCaml-like syntax:

let string_compare (p1: eq ref) (p2: eq ref) : i32 =
  if p1 == p2 then return 0;
  let s1 :> string ref = p1 in
  let s2 :> string ref = p2 in
  let l1 = array_len s1 in
  let l2 = array_len s2 in
  let len = select l1 l2 (l1 <=u l2) in
  let i = 0 in
  while i <s len do
    let c1 = unsigned s1.[i] in
    let c2 = unsigned s2.[i] in
    if c1 <u c2 then return -1;
    if c1 >u c2 then return 1;
    i := i + 1
  done;
  if l1 <u l2 then return -1;
  if l1 >u l2 then return 1;
  0