///| Interpreter-specific error handling helpers
///|
///| Re-exports JsError from shared errors package and provides
///| Value conversion helpers for JavaScript try-catch handling.
///|
/// Create a JavaScript Error object Value with the given name and message
fn make_error_value(name : String, msg : String) -> Value {
make_error_value_with_env(name, msg, None)
}
///|
/// Create a JavaScript Error object Value with proper prototype chain
fn make_error_value_with_env(
name : String,
msg : String,
env : Environment?,
) -> Value {
let err_props : Map[String, Value] = {}
err_props["message"] = String_(msg)
err_props["name"] = String_(name)
err_props["stack"] = String_(name + ": " + msg)
// Try to look up the proper prototype from the environment
let proto : Value = match env {
Some(e) => {
let ctor : Value = try { e.get(name) } catch { _ => Null }
match ctor {
Object(ctor_data) =>
match ctor_data.properties.get("prototype") {
Some(p) => p
None => Null
}
_ => Null
}
}
None => Null
}
Object({
properties: err_props,
symbol_properties: {},
prototype: proto,
callable: None,
class_name: name,
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
}
///|
/// Create an AggregateError with the errors array property
fn make_aggregate_error_value(
msg : String,
errors : Array[Error],
env : Environment?,
) -> Value {
let err_props : Map[String, Value] = {}
err_props["message"] = String_(msg)
err_props["name"] = String_("AggregateError")
err_props["stack"] = String_("AggregateError: " + msg)
// Convert errors array to JavaScript array
let js_errors : Array[Value] = errors.map(fn(e) {
js_error_to_value_with_env(e, env)
})
err_props["errors"] = Array({ elements: js_errors })
// Try to look up the proper prototype from the environment
let proto : Value = match env {
Some(e) => {
let ctor : Value = try { e.get("AggregateError") } catch { _ => Null }
match ctor {
Object(ctor_data) =>
match ctor_data.properties.get("prototype") {
Some(p) => p
None => Null
}
_ => Null
}
}
None => Null
}
Object({
properties: err_props,
symbol_properties: {},
prototype: proto,
callable: None,
class_name: "AggregateError",
descriptors: {},
symbol_descriptors: {},
extensible: true,
})
}
///|
/// Convert any catchable error to a JavaScript Error object Value
pub fn js_error_to_value(err : Error) -> Value {
js_error_to_value_with_env(err, None)
}
///|
/// Convert any catchable error to a JavaScript Error object Value with proper prototype
pub fn js_error_to_value_with_env(err : Error, env : Environment?) -> Value {
match err {
@errors.TypeError(message~) =>
make_error_value_with_env("TypeError", message, env)
@errors.ReferenceError(message~) =>
make_error_value_with_env("ReferenceError", message, env)
@errors.SyntaxError(message~) =>
make_error_value_with_env("SyntaxError", message, env)
@errors.RangeError(message~) =>
make_error_value_with_env("RangeError", message, env)
@errors.URIError(message~) =>
make_error_value_with_env("URIError", message, env)
@errors.EvalError(message~) =>
make_error_value_with_env("EvalError", message, env)
@errors.InternalError(message~) =>
make_error_value_with_env("InternalError", message, env)
@errors.AggregateError(message~, errors~) =>
make_aggregate_error_value(message, errors, env)
JsException(val) => val // JavaScript throw statement value
_ => make_error_value_with_env("Error", err.to_string(), env)
}
}
///|
/// Convert a catchable error to the JS throw value used by this interpreter.
/// Runtime engine errors are surfaced as strings like "TypeError: ...".
pub fn js_error_to_throw_value(err : Error) -> Value {
match err {
@errors.TypeError(message~) => String_("TypeError: " + message)
@errors.ReferenceError(message~) => String_("ReferenceError: " + message)
@errors.SyntaxError(message~) => String_("SyntaxError: " + message)
@errors.RangeError(message~) => String_("RangeError: " + message)
@errors.URIError(message~) => String_("URIError: " + message)
@errors.EvalError(message~) => String_("EvalError: " + message)
@errors.InternalError(message~) => String_("InternalError: " + message)
@errors.AggregateError(message~, errors~) => {
let error_texts = errors.map(fn(e) {
js_error_to_throw_value(e).to_string()
})
let errors_str = error_texts.join(", ")
String_("AggregateError: " + message + " (errors: " + errors_str + ")")
}
JsException(val) => val
_ => String_("Error: " + err.to_string())
}
}
///|
/// Check if an error is a JavaScript catchable error
pub fn is_js_catchable_error(err : Error) -> Bool {
match err {
@errors.TypeError(_)
| @errors.ReferenceError(_)
| @errors.SyntaxError(_)
| @errors.RangeError(_)
| @errors.URIError(_)
| @errors.EvalError(_)
| @errors.InternalError(_)
| @errors.AggregateError(_)
| JsException(_) => true
_ => false
}
}