Skip to content

Commit da727a4

Browse files
committed
Syntactic sugar for strings
1 parent 2f62327 commit da727a4

File tree

5 files changed

+109
-0
lines changed

5 files changed

+109
-0
lines changed

compiler/bin-wasmoo_util/tests/cram.t

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,38 @@ Wrong type
152152
File "-", line 1, characters 14-16:
153153
Expected a boolean but this is a string.
154154
[1]
155+
156+
Bad strings
157+
158+
$ echo '(@string)' | wasmoo_util pp
159+
File "-", line 1, characters 8-9:
160+
Expecting an id or a string.
161+
[1]
162+
163+
$ echo '(@string a "b")' | wasmoo_util pp
164+
File "-", line 1, characters 9-10:
165+
Expecting an id
166+
[1]
167+
168+
$ echo '(@string $a b)' | wasmoo_util pp
169+
File "-", line 1, characters 12-13:
170+
Expecting a string
171+
[1]
172+
173+
$ echo '(@string $good "\u{1F600}")' | wasmoo_util pp
174+
(global $good (ref eq) (array.new_fixed $bytes 4 (i32.const 240) (i32.const 159) (i32.const 152) (i32.const 128)))
175+
176+
$ echo '(@string $bad "\u{D800}")' | wasmoo_util pp
177+
File "-", line 1, characters 14-24:
178+
Invalid Unicode escape sequences.
179+
[1]
180+
181+
$ echo '(@string a)' | wasmoo_util pp
182+
File "-", line 1, characters 9-10:
183+
Expecting a string
184+
[1]
185+
186+
$ echo '(@string a b c)' | wasmoo_util pp
187+
File "-", line 1, characters 13-14:
188+
Expecting a closing parenthesis.
189+
[1]

compiler/bin-wasmoo_util/tests/tests.expected

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,10 @@
6565
(4 1 1) < (4 2 0)
6666
(4 1 1) < (5 0 1)
6767

68+
69+
;; strings
70+
(global $s (ref eq) (array.new_fixed $bytes 4 (i32.const 97) (i32.const 98) (i32.const 99) (i32.const 100)))
71+
(array.new_fixed $bytes 4 (i32.const 97) (i32.const 98) (i32.const 99) (i32.const 100))
72+
(array.new_fixed $bytes 4 (i32.const 92) (i32.const 39) (i32.const 40) (i32.const 10))
73+
(array.new_fixed $bytes 4 (i32.const 97) (i32.const 98) (i32.const 99) (i32.const 100))
74+
(array.new_fixed $bytes 4 (i32.const 97) (i32.const 98) (i32.const 99) (i32.const 100))

compiler/bin-wasmoo_util/tests/tests.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,10 @@
6565
(@if (< (4 1 1) (4 2 0)) (@then (4 1 1) < (4 2 0)))
6666
(@if (< (4 1 1) (5 0 1)) (@then (4 1 1) < (5 0 1)))
6767
(@if (< (4 1 1) (3 2 1)) (@then (4 1 1) < (3 2 1)))
68+
69+
;; strings
70+
(@string $s "abcd")
71+
(@string "abcd")
72+
(@string "\\\'\28\n")
73+
(@if (and) (@then (@string "abcd")))
74+
(@if (or) (@then) (@else (@string "abcd")))

compiler/lib-wasm/wat_preprocess.ml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,12 @@ let is_keyword s =
249249
| keyword, eof -> true
250250
| _ -> false
251251

252+
let is_id s =
253+
let lexbuf = Sedlexing.Utf8.from_string s in
254+
match%sedlex lexbuf with
255+
| id, eof -> true
256+
| _ -> false
257+
252258
(****)
253259

254260
module StringMap = Map.Make (String)
@@ -376,6 +382,14 @@ let skip st (pos' : pos) =
376382
Buffer.add_string st.buf (String.make (max 0 cols) ' ');
377383
st.pos <- pos'
378384

385+
let insert st s =
386+
Buffer.add_string st.buf s;
387+
let n = String.length s in
388+
st.pos <-
389+
{ loc = { st.pos.loc with pos_cnum = st.pos.loc.pos_cnum + n }
390+
; byte_loc = st.pos.byte_loc - 1
391+
}
392+
379393
let pred_position { loc; byte_loc } =
380394
{ loc = { loc with pos_cnum = loc.pos_cnum - 1 }; byte_loc = byte_loc - 1 }
381395

@@ -462,6 +476,50 @@ and rewrite st elt =
462476
( position_of_loc loc
463477
, Printf.sprintf "Unexpected %s clause. Maybe you forgot a parenthesis.\n" nm
464478
))
479+
| { desc =
480+
List
481+
[ { desc = Atom "@string"; _ }
482+
; { desc = Atom name; loc = loc_name }
483+
; { desc = Atom value; loc = loc_value }
484+
]
485+
; loc = pos, pos'
486+
} ->
487+
if not (is_id name) then raise (Error (position_of_loc loc_name, "Expecting an id"));
488+
if not (is_string value)
489+
then raise (Error (position_of_loc loc_value, "Expecting a string"));
490+
let s = parse_string loc_value value in
491+
write st pos;
492+
insert
493+
st
494+
(Format.asprintf
495+
"(global %s (ref eq) (array.new_fixed $bytes %d%a))"
496+
name
497+
(String.length s)
498+
(fun f s ->
499+
String.iter ~f:(fun c -> Format.fprintf f " (i32.const %d)" (Char.code c)) s)
500+
s);
501+
skip st pos'
502+
| { desc = List [ { desc = Atom "@string"; _ }; { desc = Atom value; loc = loc_value } ]
503+
; loc = pos, pos'
504+
} ->
505+
if not (is_string value)
506+
then raise (Error (position_of_loc loc_value, "Expecting a string"));
507+
let s = parse_string loc_value value in
508+
write st pos;
509+
insert
510+
st
511+
(Format.asprintf
512+
"(array.new_fixed $bytes %d%a)"
513+
(String.length s)
514+
(fun f s ->
515+
String.iter ~f:(fun c -> Format.fprintf f " (i32.const %d)" (Char.code c)) s)
516+
s);
517+
skip st pos'
518+
| { desc = List [ { desc = Atom "@string"; loc = _, pos } ]; loc = _, pos' } ->
519+
raise (Error ((pos.loc, pos'.loc), Printf.sprintf "Expecting an id or a string.\n"))
520+
| { desc = List ({ desc = Atom "@string"; _ } :: _ :: _ :: { loc; _ } :: _); _ } ->
521+
raise
522+
(Error (position_of_loc loc, Printf.sprintf "Expecting a closing parenthesis.\n"))
465523
| { desc = List l; _ } -> rewrite_list st l
466524
| _ -> ()
467525

manual/wasm_runtime.wiki

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ To form conditional expressions, the following operators are available:
6060
- comparisons: {{{=}}}, {{{>}}}, {{{>=}}}, {{{<}}}, {{{<=}}}, {{{<>}}};
6161
- boolean operators: {{{and}}}, {{{or}}}, {{{not}}}
6262

63+
It also provides some syntactic sugar to write strings. The expression{{{(@string "ab")}}} is expanded into {{{(array.new_fixed $bytes 2 (i32.const 97) (i32.const 98))}}}. The statement {{{(@string $s "ab")}}} is an abbreviation for {{{(global $s (ref eq) (@string "ab"))}}}.
64+
6365
== Implementing primitives ==
6466

6567
You define a primitive by exporting a Wasm function with parameters and return value of type {{{(ref eq)}}}.

0 commit comments

Comments
 (0)