use quickjs_oxide::engine::api::core::{JsString, QjsHelpers, Runtime, RuntimeError, Value};
use quickjs_oxide_host::SystemHost;
fn main() -> Result<(), Box<dyn std::error::Error>> {
first_eval()?;
read_result()?;
call_function()?;
catch_exception()?;
console()?;
Ok(())
}
fn first_eval() -> Result<(), Box<dyn std::error::Error>> {
let runtime = Runtime::new_with_host_services(SystemHost::default());
let context = runtime.new_context()?;
let value = context.eval("[1, 2, 3].map((x) => x * 2).join()")?;
let Value::String(text) = value else {
panic!("expected a string, got {value:?}");
};
assert_eq!(text.to_utf8_lossy(), "2,4,6");
Ok(())
}
fn read_result() -> Result<(), Box<dyn std::error::Error>> {
let runtime = Runtime::new_with_host_services(SystemHost::default());
let context = runtime.new_context()?;
assert_eq!(context.eval("6 * 7")?, Value::Int(42));
assert_eq!(context.eval("0.5 + 0.25")?, Value::Float(0.75));
assert_eq!(context.eval("1 < 2")?, Value::Bool(true));
assert_eq!(context.eval("var unused = 1")?, Value::Undefined);
let total = context.eval("[1.5, 2, 3].reduce((a, b) => a + b)")?;
assert_eq!(total.as_number(), Some(6.5));
let point = context.eval("({ x: 3, y: 4 })")?;
let point = point.as_object().expect("an object");
let x = runtime.intern_property_key("x")?;
assert_eq!(context.get_property(point, &x)?, Value::Int(3));
Ok(())
}
fn call_function() -> Result<(), Box<dyn std::error::Error>> {
let runtime = Runtime::new_with_host_services(SystemHost::default());
let context = runtime.new_context()?;
context.eval(
"function greet(name, times) { return ('hi ' + name + ' ').repeat(times).trim(); }",
)?;
let global = context.global_object()?;
let key = runtime.intern_property_key("greet")?;
let Value::Object(object) = context.get_property(&global, &key)? else {
panic!("greet is not an object");
};
let greet = runtime.as_callable(&object)?.expect("greet is callable");
let name = Value::String(JsString::try_from_utf8("Ada")?);
let result = context.call(&greet, Value::Undefined, &[name, Value::Int(2)])?;
let text = context.to_js_string(&result)?;
assert_eq!(text.to_utf8_lossy(), "hi Ada hi Ada");
Ok(())
}
fn catch_exception() -> Result<(), Box<dyn std::error::Error>> {
let runtime = Runtime::new_with_host_services(SystemHost::default());
let context = runtime.new_context()?;
match context.eval("null.length") {
Err(RuntimeError::Exception(thrown)) => {
let message = context.to_js_string(&thrown)?;
assert_eq!(
message.to_utf8_lossy(),
"TypeError: cannot read property 'length' of null"
);
}
other => panic!("expected an exception, got {other:?}"),
}
Ok(())
}
fn console() -> Result<(), Box<dyn std::error::Error>> {
let runtime = Runtime::new_with_host_services(SystemHost::default());
let context = runtime.new_context()?;
assert_eq!(
context.eval("typeof console")?,
Value::String(JsString::from_static("undefined"))
);
context.install_qjs_helpers(&QjsHelpers::default())?;
context.eval("console.log('hello from JavaScript')")?;
Ok(())
}