Skip to content

Commit 87d3a37

Browse files
committed
[interpreter] Enable nesting of invocations and gets
1 parent b1fbe1a commit 87d3a37

File tree

8 files changed

+201
-65
lines changed

8 files changed

+201
-65
lines changed

interpreter/README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,14 @@ module:
391391
( module <name>? quote <string>* ) ;; module quoted in text (may be malformed)
392392
393393
action:
394-
( invoke <name>? <string> <const>* ) ;; invoke function export
394+
( invoke <name>? <string> <arg>* ) ;; invoke function export
395395
( get <name>? <string> ) ;; get global export
396396
397-
const:
397+
arg:
398+
<literal> ;; literal argument
399+
<action> ;; expression argument
400+
401+
literal:
398402
( <num_type>.const <num> ) ;; number value
399403
( <vec_type> <vec_shape> <num>+ ) ;; vector value
400404
( ref.null <ref_kind> ) ;; null reference
@@ -410,7 +414,7 @@ assertion:
410414
( assert_trap <module> <failure> ) ;; assert module traps on instantiation
411415
412416
result:
413-
<const>
417+
<literal>
414418
( <num_type>.const <num_pat> )
415419
( <vec_type>.const <vec_shape> <num_pat>+ )
416420
( ref.extern )

interpreter/script/js.ml

Lines changed: 95 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@ function assert_return(action, ...expected) {
188188
|}
189189

190190

191+
(* Errors & Tracing *)
192+
193+
module Error = Error.Make ()
194+
195+
exception Error = Error.Error
196+
197+
191198
(* Context *)
192199

193200
module NameMap = Map.Make(struct type t = Ast.name let compare = compare end)
@@ -217,12 +224,26 @@ let bind (mods : modules) x_opt m =
217224
let lookup (mods : modules) x_opt name at =
218225
let exports =
219226
try Map.find (of_var_opt mods x_opt) mods.env with Not_found ->
220-
raise (Eval.Crash (at,
221-
if x_opt = None then "no module defined within script"
222-
else "unknown module " ^ of_var_opt mods x_opt ^ " within script"))
227+
Error.error at
228+
(if x_opt = None then "no module defined within script"
229+
else "unknown module " ^ of_var_opt mods x_opt ^ " within script")
223230
in try NameMap.find name exports with Not_found ->
224-
raise (Eval.Crash (at, "unknown export \"" ^
225-
string_of_name name ^ "\" within module"))
231+
Error.error at ("unknown export \"" ^
232+
string_of_name name ^ "\" within module")
233+
234+
let lookup_func (mods : modules) x_opt name at =
235+
match lookup mods x_opt name at with
236+
| ExternFuncType ft -> ft
237+
| _ ->
238+
Error.error at ("export \"" ^
239+
string_of_name name ^ "\" is not a function")
240+
241+
let lookup_global (mods : modules) x_opt name at =
242+
match lookup mods x_opt name at with
243+
| ExternGlobalType gt -> gt
244+
| _ ->
245+
Error.error at ("export \"" ^
246+
string_of_name name ^ "\" is not a global")
226247

227248

228249
(* Wrappers *)
@@ -259,21 +280,34 @@ let abs_mask_of = function
259280
| I32Type | F32Type -> Values.I32 Int32.max_int
260281
| I64Type | F64Type -> Values.I64 Int64.max_int
261282

262-
let value v =
263-
match v.it with
264-
| Values.Num n -> [Const (n @@ v.at) @@ v.at]
265-
| Values.Vec s -> [VecConst (s @@ v.at) @@ v.at]
266-
| Values.Ref (Values.NullRef t) -> [RefNull t @@ v.at]
283+
(*
284+
let literal lit =
285+
match lit.it with
286+
| Values.Num n -> [Const (n @@ lit.at) @@ lit.at]
287+
| Values.Vec s -> [VecConst (s @@ lit.at) @@ lit.at]
288+
| Values.Ref (Values.NullRef t) -> [RefNull t @@ lit.at]
267289
| Values.Ref (ExternRef n) ->
268-
[Const (Values.I32 n @@ v.at) @@ v.at; Call (externref_idx @@ v.at) @@ v.at]
290+
[ Const (Values.I32 n @@ lit.at) @@ lit.at;
291+
Call (externref_idx @@ lit.at) @@ lit.at;
292+
]
269293
| Values.Ref _ -> assert false
270-
271-
let invoke ft vs at =
272-
[ft @@ at], FuncImport (subject_type_idx @@ at) @@ at,
273-
List.concat (List.map value vs) @ [Call (subject_idx @@ at) @@ at]
294+
*)
274295

275296
let get t at =
276-
[], GlobalImport t @@ at, [GlobalGet (subject_idx @@ at) @@ at]
297+
[], GlobalImport t @@ at, [], [GlobalGet (subject_idx @@ at) @@ at]
298+
299+
let invoke ft at =
300+
let FuncType (ts, _) = ft in
301+
[ft @@ at], FuncImport (subject_type_idx @@ at) @@ at,
302+
List.mapi (fun i t ->
303+
{ module_name = Utf8.decode "arg";
304+
item_name = Utf8.decode (string_of_int i);
305+
idesc = GlobalImport (GlobalType (t, Immutable)) @@ at;
306+
} @@ at
307+
) ts,
308+
List.concat
309+
(Lib.List32.mapi (fun i _ -> [GlobalGet (i @@ at) @@ at]) ts) @
310+
[Call (subject_idx @@ at) @@ at]
277311

278312
let run ts at =
279313
[], []
@@ -378,7 +412,7 @@ let assert_return ress ts at =
378412
in [], List.flatten (List.rev_map test ress)
379413

380414
let wrap item_name wrap_action wrap_assertion at =
381-
let itypes, idesc, action = wrap_action at in
415+
let itypes, idesc, iargs, action = wrap_action at in
382416
let locals, assertion = wrap_assertion at in
383417
let types =
384418
(FuncType ([], []) @@ at) ::
@@ -400,7 +434,8 @@ let wrap item_name wrap_action wrap_assertion at =
400434
{module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_externref";
401435
idesc = FuncImport (4l @@ at) @@ at} @@ at;
402436
{module_name = Utf8.decode "spectest"; item_name = Utf8.decode "eq_funcref";
403-
idesc = FuncImport (5l @@ at) @@ at} @@ at ]
437+
idesc = FuncImport (5l @@ at) @@ at} @@ at;
438+
] @ iargs
404439
in
405440
let item =
406441
List.fold_left
@@ -429,10 +464,10 @@ let is_js_value_type = function
429464
| RefType t -> true
430465

431466
let is_js_global_type = function
432-
| GlobalType (t, mut) -> is_js_value_type t && mut = Immutable
467+
| GlobalType (t, mut) -> is_js_value_type t
433468

434469
let is_js_func_type = function
435-
| FuncType (ins, out) -> List.for_all is_js_value_type (ins @ out)
470+
| FuncType (ts1, ts2) -> List.for_all is_js_value_type (ts1 @ ts2)
436471

437472

438473
(* Script conversion *)
@@ -473,14 +508,19 @@ let of_num n =
473508
let open Values in
474509
match n with
475510
| I32 i -> I32.to_string_s i
476-
| I64 i -> "int64(\"" ^ I64.to_string_s i ^ "\")"
511+
| I64 i -> I64.to_string_s i ^ "n"
477512
| F32 z -> of_float (F32.to_float z)
478513
| F64 z -> of_float (F64.to_float z)
479514

480515
let of_vec v =
481-
let open Values in
482-
match v with
483-
| V128 v -> "v128(\"" ^ V128.to_string v ^ "\")"
516+
let at = Source.no_region in
517+
let gtype = GlobalType (VecType (Values.type_of_vec v), Immutable) in
518+
let ginit = [VecConst (v @@ at) @@ at] @@ at in
519+
let globals = [{gtype; ginit} @@ at] in
520+
let edesc = GlobalExport (0l @@ at) @@ at in
521+
let exports = [{name = Utf8.decode "v128"; edesc} @@ at] in
522+
let bs = Encode.encode ({empty_module with globals; exports} @@ at) in
523+
"instance(" ^ of_bytes bs ^ ").exports.v128"
484524

485525
let of_ref r =
486526
let open Values in
@@ -489,9 +529,9 @@ let of_ref r =
489529
| ExternRef n -> "externref(" ^ Int32.to_string n ^ ")"
490530
| _ -> assert false
491531

492-
let of_value v =
532+
let of_literal lit =
493533
let open Values in
494-
match v.it with
534+
match lit.it with
495535
| Num n -> of_num n
496536
| Vec v -> of_vec v
497537
| Ref r -> of_ref r
@@ -529,43 +569,52 @@ let rec of_definition def =
529569
try of_definition (Parse.string_to_module s) with Parse.Syntax _ ->
530570
of_bytes "<malformed quote>"
531571

532-
let of_wrapper mods x_opt name wrap_action wrap_assertion at =
572+
let of_arg_import i opd =
573+
"arg" ^ string_of_int i ^ ": " ^ opd
574+
575+
let of_wrapper mods x_opt name wrap_action opds wrap_assertion at =
533576
let x = of_var_opt mods x_opt in
534577
let bs = wrap name wrap_action wrap_assertion at in
535-
"call(instance(" ^ of_bytes bs ^ ", " ^
536-
"exports(" ^ x ^ ")), " ^ " \"run\", [])"
578+
let exs = if opds = [] then "exports(" ^ x ^ ")" else
579+
"{...exports(" ^ x ^ "), " ^
580+
"args: [" ^ String.concat ", " (List.mapi of_arg_import opds) ^ "]}"
581+
in "call(instance(" ^ of_bytes bs ^ ", " ^ exs ^ "), \"run\", [])"
537582

538-
let of_action mods act =
583+
let rec of_action mods act =
539584
match act.it with
540-
| Invoke (x_opt, name, vs) ->
585+
| Invoke (x_opt, name, args) ->
541586
"call(" ^ of_var_opt mods x_opt ^ ", " ^ of_name name ^ ", " ^
542-
"[" ^ String.concat ", " (List.map of_value vs) ^ "])",
543-
(match lookup mods x_opt name act.at with
544-
| ExternFuncType ft when not (is_js_func_type ft) ->
545-
let FuncType (_, out) = ft in
546-
Some (of_wrapper mods x_opt name (invoke ft vs), out)
547-
| _ -> None
548-
)
587+
"[" ^ String.concat ", " (List.map (of_arg mods) args) ^ "].flat())",
588+
let FuncType (_, ts2) as ft = lookup_func mods x_opt name act.at in
589+
if is_js_func_type ft then None else
590+
let opds = List.map (of_arg mods) args in
591+
Some (of_wrapper mods x_opt name (invoke ft) opds, ts2)
549592
| Get (x_opt, name) ->
550593
"get(" ^ of_var_opt mods x_opt ^ ", " ^ of_name name ^ ")",
551-
(match lookup mods x_opt name act.at with
552-
| ExternGlobalType gt when not (is_js_global_type gt) ->
553-
let GlobalType (t, _) = gt in
554-
Some (of_wrapper mods x_opt name (get gt), [t])
555-
| _ -> None
556-
)
594+
let GlobalType (t, _) as gt = lookup_global mods x_opt name act.at in
595+
if is_js_global_type gt then None else
596+
Some (of_wrapper mods x_opt name (get gt) [], [t])
597+
598+
and of_arg mods arg =
599+
match arg.it with
600+
| LiteralArg lit -> of_literal lit
601+
| ActionArg act ->
602+
let act_js, act_wrapper_opt = of_action mods act in
603+
match act_wrapper_opt with
604+
| None -> act_js
605+
| Some (act_wrapper, ts) -> act_wrapper (run ts) act.at
557606

558607
let of_assertion' mods act name args wrapper_opt =
559608
let act_js, act_wrapper_opt = of_action mods act in
560609
let js = name ^ "(() => " ^ act_js ^ String.concat ", " ("" :: args) ^ ")" in
561610
match act_wrapper_opt with
562611
| None -> js ^ ";"
563-
| Some (act_wrapper, out) ->
612+
| Some (act_wrapper, ts) ->
564613
let run_name, wrapper =
565614
match wrapper_opt with
566615
| None -> name, run
567616
| Some wrapper -> "run", wrapper
568-
in run_name ^ "(() => " ^ act_wrapper (wrapper out) act.at ^ "); // " ^ js
617+
in run_name ^ "(() => " ^ act_wrapper (wrapper ts) act.at ^ "); // " ^ js
569618

570619
let of_assertion mods ass =
571620
match ass.it with

interpreter/script/js.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
exception Error of Source.region * string
2+
13
val of_script : Script.script -> string

interpreter/script/run.ml

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ let input_from get_script run =
114114
| Eval.Crash (at, msg) -> error at "runtime crash" msg
115115
| Encode.Code (at, msg) -> error at "encoding error" msg
116116
| Script.Error (at, msg) -> error at "script error" msg
117+
| Js.Error (at, msg) -> error at "script error" msg
117118
| IO (at, msg) -> error at "i/o error" msg
118119
| Assert (at, msg) -> error at "assertion failure" msg
119120
| Abort _ -> false
@@ -340,21 +341,22 @@ let rec run_definition def : Ast.module_ =
340341
let def' = Parse.string_to_module s in
341342
run_definition def'
342343

343-
let run_action act : Values.value list =
344+
let rec run_action act : Values.value list =
344345
match act.it with
345-
| Invoke (x_opt, name, vs) ->
346+
| Invoke (x_opt, name, args) ->
346347
trace ("Invoking function \"" ^ Ast.string_of_name name ^ "\"...");
347348
let inst = lookup_instance x_opt act.at in
348349
(match Instance.export inst name with
349350
| Some (Instance.ExternFunc f) ->
350-
let Types.FuncType (ins, out) = Func.type_of f in
351-
if List.length vs <> List.length ins then
351+
let Types.FuncType (ts1, _) = Func.type_of f in
352+
let vs = List.concat_map run_arg args in
353+
if List.length vs <> List.length ts1 then
352354
Script.error act.at "wrong number of arguments";
353-
List.iter2 (fun v t ->
354-
if Values.type_of_value v.it <> t then
355-
Script.error v.at "wrong type of argument"
356-
) vs ins;
357-
Eval.invoke f (List.map (fun v -> v.it) vs)
355+
List.iteri (fun i (v, t) ->
356+
if Values.type_of_value v <> t then
357+
Script.error act.at ("type mismatch for argument " ^ string_of_int i)
358+
) (List.combine vs ts1);
359+
Eval.invoke f vs
358360
| Some _ -> Assert.error act.at "export is not a function"
359361
| None -> Assert.error act.at "undefined export"
360362
)
@@ -368,6 +370,10 @@ let run_action act : Values.value list =
368370
| None -> Assert.error act.at "undefined export"
369371
)
370372

373+
and run_arg arg : Values.value list =
374+
match arg.it with
375+
| LiteralArg lit -> [lit.it]
376+
| ActionArg act -> run_action act
371377

372378
let assert_nan_pat n nan =
373379
let open Values in

interpreter/script/script.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@ and definition' =
1313

1414
type action = action' Source.phrase
1515
and action' =
16-
| Invoke of var option * Ast.name * literal list
16+
| Invoke of var option * Ast.name * arg list
1717
| Get of var option * Ast.name
1818

19+
and arg = arg' Source.phrase
20+
and arg' =
21+
| LiteralArg of literal
22+
| ActionArg of action
23+
1924
type nanop = nanop' Source.phrase
2025
and nanop' = (Lib.void, Lib.void, nan, nan) Values.op
2126
and nan = CanonicalNan | ArithmeticNan

interpreter/text/arrange.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -699,13 +699,18 @@ let definition mode x_opt def =
699699
let access x_opt n =
700700
String.concat " " [var_opt x_opt; name n]
701701

702-
let action mode act =
702+
let rec action mode act =
703703
match act.it with
704-
| Invoke (x_opt, name, lits) ->
705-
Node ("invoke" ^ access x_opt name, List.map (literal mode) lits)
704+
| Invoke (x_opt, name, args) ->
705+
Node ("invoke" ^ access x_opt name, List.map (arg mode) args)
706706
| Get (x_opt, name) ->
707707
Node ("get" ^ access x_opt name, [])
708708

709+
and arg mode arg =
710+
match arg.it with
711+
| LiteralArg lit -> literal mode lit
712+
| ActionArg act -> action mode act
713+
709714
let nan = function
710715
| CanonicalNan -> "nan:canonical"
711716
| ArithmeticNan -> "nan:arithmetic"

interpreter/text/parser.mly

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,7 @@ script_module :
10151015
{ $3, Quoted ("quote:" ^ string_of_pos (at()).left, $5) @@ at() }
10161016

10171017
action :
1018-
| LPAR INVOKE module_var_opt name literal_list RPAR
1018+
| LPAR INVOKE module_var_opt name arg_list RPAR
10191019
{ Invoke ($3, $4, $5) @@ at () }
10201020
| LPAR GET module_var_opt name RPAR
10211021
{ Get ($3, $4) @@ at() }
@@ -1065,9 +1065,13 @@ literal :
10651065
| literal_vec { Values.Vec $1 @@ at () }
10661066
| literal_ref { Values.Ref $1 @@ at () }
10671067

1068-
literal_list :
1068+
arg :
1069+
| literal { LiteralArg $1 @@ at () }
1070+
| action { ActionArg $1 @@ at () }
1071+
1072+
arg_list :
10691073
| /* empty */ { [] }
1070-
| literal literal_list { $1 :: $2 }
1074+
| arg arg_list { $1 :: $2 }
10711075

10721076
numpat :
10731077
| num { fun sh -> vec_lane_lit sh $1.it $1.at }

0 commit comments

Comments
 (0)