Skip to content

Commit

Permalink
feat: Add bindings for exception handling (try/catch/throw/rethrow)
Browse files Browse the repository at this point in the history
  • Loading branch information
peblair committed Oct 15, 2023
1 parent 74c8ce4 commit e6014fa
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 0 deletions.
112 changes: 112 additions & 0 deletions src/expression.c
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,118 @@ caml_binaryen_ref_eq(value _module, value _left, value _right) {
CAMLreturn(alloc_BinaryenExpressionRef(exp));
}

// Exception handling operations
CAMLprim value
caml_binaryen_try(value _module, value _name, value _body, value _catchTags, value _catchBodies, value _delegateTarget) {
CAMLparam6(_module, _name, _body, _catchTags, _catchBodies, _delegateTarget);
BinaryenModuleRef module = BinaryenModuleRef_val(_module);
char *name;
if (Is_None(_name)) {
name = NULL;
} else {
name = Safe_String_val(_name);
}
char* name = Safe_String_val(_name);
BinaryenExpressionRef body = BinaryenExpressionRef_val(_body);
_catchTags = array_of_list(_catchTags);
int catchTagsLen = array_length(_catchTags);
char* catchTags[catchTagsLen];
for (int i = 0; i < catchTagsLen; i++) {
catchTags[i] = Safe_String_val(Field(_catchTags, i));
}
_catchBodies = array_of_list(_catchBodies);
int catchBodiesLen = array_length(_catchBodies);
BinaryenExpressionRef catchBodies[catchBodiesLen];
for (int i = 0; i < catchBodiesLen; i++) {
catchBodies[i] = BinaryenExpressionRef_val(Field(_catchBodies, i));
}
char *delegateTarget;
if (Is_none(_delegateTarget)) {
delegateTarget = NULL;
} else {
delegateTarget = Safe_String_val(Some_val(_delegateTarget));
}
BinaryenExportRef exp = BinaryenTry(module, name, body, catchTags, catchTagsLen, catchBodies, catchBodiesLen, delegateTarget);
CAMLreturn(alloc_BinaryenExpressionRef(exp));
}

CAMLprim value
caml_binaryen_trycatch(value _module, value _name, value _body, value _catchTags, value _catchBodies) {
CAMLparam6(_module, _name, _body, _catchTags, _catchBodies, _delegateTarget);
BinaryenModuleRef module = BinaryenModuleRef_val(_module);
char *name;
if (Is_None(_name)) {
name = NULL;
} else {
name = Safe_String_val(_name);
}
BinaryenExpressionRef body = BinaryenExpressionRef_val(_body);
_catchTags = array_of_list(_catchTags);
int catchTagsLen = array_length(_catchTags);
char* catchTags[catchTagsLen];
for (int i = 0; i < catchTagsLen; i++) {
catchTags[i] = Safe_String_val(Field(_catchTags, i));
}
_catchBodies = array_of_list(_catchBodies);
int catchBodiesLen = array_length(_catchBodies);
BinaryenExpressionRef catchBodies[catchBodiesLen];
for (int i = 0; i < catchBodiesLen; i++) {
catchBodies[i] = BinaryenExpressionRef_val(Field(_catchBodies, i));
}
char *delegateTarget = NULL;
BinaryenExportRef exp = BinaryenTry(module, name, body, catchTags, catchTagsLen, catchBodies, catchBodiesLen, delegateTarget);
CAMLreturn(alloc_BinaryenExpressionRef(exp));
}

CAMLprim value
caml_binaryen_trydelegate(value _module, value _name, value _body, value _delegateTarget) {
CAMLparam6(_module, _name, _body, _catchTags, _catchBodies, _delegateTarget);
BinaryenModuleRef module = BinaryenModuleRef_val(_module);
char *name;
if (Is_None(_name)) {
name = NULL;
} else {
name = Safe_String_val(_name);
}
BinaryenExpressionRef body = BinaryenExpressionRef_val(_body);
char *delegateTarget;
if (Is_none(_delegateTarget)) {
delegateTarget = NULL;
} else {
delegateTarget = Safe_String_val(Some_val(_delegateTarget));
}
int catchTagsLen = 0;
int catchBodiesLen = 0;
char **catchTags = NULL;
BinaryExpressionRef *catchBodies = NULL;
BinaryenExportRef exp = BinaryenTry(module, name, body, catchTags, catchTagsLen, catchBodies, catchBodiesLen, delegateTarget);
CAMLreturn(alloc_BinaryenExpressionRef(exp));
}

CAMLprim value
caml_binaryen_throw(value _module, value _tag, value _operands) {
CAMLparam3(_module, _tag, _operands);
BinaryenModuleRef module = BinaryenModuleRef_val(_module);
char *tag = Safe_String_val(_tag);
_operands = array_of_list(_operands);
int operandsLen = array_length(_operands);
char* operands[operandsLen];
for (int i = 0; i < operandsLen; i++) {
operands[i] = Safe_String_val(Field(_operands, i));
}
BinaryenExportRef exp = BinaryenThrow(module, tag, operands);
CAMLreturn(alloc_BinaryenExpressionRef(exp));
}

CAMLprim value
caml_binaryen_rethrow(value _module, value _target) {
CAMLparam3(_module, _tag, _operands);
BinaryenModuleRef module = BinaryenModuleRef_val(_module);
char *target = Safe_String_val(_target);
BinaryenExportRef exp = BinaryenRethrow(module, target);
CAMLreturn(alloc_BinaryenExpressionRef(exp));
}

// Table operations
CAMLprim value
caml_binaryen_table_get(value _module, value _name, value _index, value _ty) {
Expand Down
55 changes: 55 additions & 0 deletions src/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,61 @@ function caml_binaryen_ref_eq(wasm_mod, left, right) {
return wasm_mod.ref.func(left, right);
}

// Exception handling operations

//Provides: caml_binaryen_try
//Requires: caml_jsstring_of_string, caml_list_to_js_array
function caml_binaryen_try(wasm_mod, name, body, catch_tags, catch_bodies, delegate_target) {
return wasm_mod.try(
caml_jsstring_of_string(name),
body,
caml_list_to_js_array(catch_tags).map(caml_jsstring_of_string),
caml_list_to_js_array(catch_bodies),
delegate_target ? caml_jsstring_of_string(delegate_target[1]) : null,
)
}

//Provides: caml_binaryen_trycatch
//Requires: caml_jsstring_of_string, caml_list_to_js_array
function caml_binaryen_trycatch(wasm_mod, name, body, catch_tags, catch_bodies) {
return wasm_mod.try(
caml_jsstring_of_string(name),
body,
caml_list_to_js_array(catch_tags).map(caml_jsstring_of_string),
caml_list_to_js_array(catch_bodies),
null,
)
}

//Provides: caml_binaryen_trydelegate
//Requires: caml_jsstring_of_string, caml_list_to_js_array
function caml_binaryen_trydelegate(wasm_mod, name, body, delegate_target) {
return wasm_mod.try(
caml_jsstring_of_string(name),
body,
[],
[],
delegate_target ? caml_jsstring_of_string(delegate_target[1]) : null,
)
}

//Provides: caml_binaryen_throw
//Requires: caml_jsstring_of_string, caml_list_to_js_array
function caml_binaryen_throw(wasm_mod, tag, operands) {
return wasm_mod.throw(
caml_jsstring_of_string(tag),
caml_list_to_js_array(operands),
)
}

//Provides: caml_binaryen_rethrow
//Requires: caml_jsstring_of_string, caml_list_to_js_array
function caml_binaryen_rethrow(wasm_mod, target) {
return wasm_mod.rethrow(
caml_jsstring_of_string(target),
)
}

// Table operations

//Provides: caml_binaryen_table_get
Expand Down
26 changes: 26 additions & 0 deletions src/expression.ml
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,32 @@ module Ref = struct
(** Module, left, right *)
end

(** Bindings for `try` instruction. For better validation, use `Try_catch` or `Try_Delegate`. *)
module Try = struct
external make : Module.t -> string option -> t -> string list -> t list -> string option -> t = "caml_binaryen_try"
(** Module, name, body, catch tags, catch bodies, delegate target *)
end

module Try_Catch = struct
external make : Module.t -> string option -> t -> string list -> t list -> t = "caml_binaryen_trycatch"
(** Module, name, body, catch tags, catch bodies *)
end

module Try_Delegate = struct
external make : Module.t -> string option -> t -> string -> t = "caml_binaryen_trydelegate"
(** Module, name, body, delegate *)
end

module Throw = struct
external make : Module.t -> string -> t list -> t = "caml_binaryen_throw"
(** Module, tag, operands *)
end

module Rethrow = struct
external make : Module.t -> string -> t = "caml_binaryen_rethrow"
(** Module, target *)
end

module Table = struct
external get : Module.t -> string -> t -> Type.t -> t
= "caml_binaryen_table_get"
Expand Down
26 changes: 26 additions & 0 deletions src/expression.mli
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,32 @@ module Ref : sig
(** Module, left, right *)
end

(** Bindings for `try` instruction. For better validation, use `Try_catch` or `Try_Delegate`. *)
module Try : sig
val make : Module.t -> string option -> t -> string list -> t list -> string option -> t
(** Module, name, body, catch tags, catch bodies, delegate target *)
end

module Try_Catch : sig
val make : Module.t -> string option -> t -> string list -> t list -> t
(** Module, name, body, catch tags, catch bodies *)
end

module Try_Delegate : sig
val make : Module.t -> string option -> t -> string -> t
(** Module, name, body, delegate *)
end

module Throw : sig
val make : Module.t -> string -> t list -> t
(** Module, tag, operands *)
end

module Rethrow : sig
val make : Module.t -> string -> t
(** Module, target *)
end

module Table : sig
val get : Module.t -> string -> t -> Type.t -> t
(** Module, name, index, type *)
Expand Down

0 comments on commit e6014fa

Please sign in to comment.