Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Wasm text syntax #87

Open
vouillon opened this issue Oct 4, 2024 · 0 comments
Open

Improved Wasm text syntax #87

vouillon opened this issue Oct 4, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@vouillon
Copy link
Collaborator

vouillon commented Oct 4, 2024

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:

  • Introduce local variables when they are first used rather than at the beginning of functions.
  • Use a single namespace for globals, locals, and functions, so that one can just write x instead of (local.get $x), (global.get $x) or (ref.func $x).
  • Recover missing type information through type inference: write e1 + e2 instead of (in32.add e1 e2), write e.m instead of (struct.get $t $m e).

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
@vouillon vouillon added the enhancement New feature or request label Oct 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant