From 0c8367d29f980b51f35d01967c0982b4cc7aea33 Mon Sep 17 00:00:00 2001 From: John Doty Date: Mon, 19 Jun 2023 12:51:35 -0700 Subject: [PATCH 1/3] [oden-js-sys] Add functions to get more information of modules Adopt https://github.com/bellard/quickjs/pull/35 --- oden-js-sys/quickjs/quickjs.c | 33 ++++++++++++++++++++++++++++++++- oden-js-sys/quickjs/quickjs.h | 5 +++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/oden-js-sys/quickjs/quickjs.c b/oden-js-sys/quickjs/quickjs.c index 48aeffc6..94ed0e54 100644 --- a/oden-js-sys/quickjs/quickjs.c +++ b/oden-js-sys/quickjs/quickjs.c @@ -27125,7 +27125,7 @@ static int add_req_module_entry(JSContext *ctx, JSModuleDef *m, return i; } -static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m, +static JSExportEntry *find_export_entry(JSContext *ctx, const JSModuleDef *m, JSAtom export_name) { JSExportEntry *me; @@ -27241,6 +27241,37 @@ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, return -1; } +JSValueConst JS_GetModuleExport(JSContext *ctx, const JSModuleDef *m, const char *export_name) { + JSExportEntry *me; + JSAtom name; + name = JS_NewAtom(ctx, export_name); + if (name == JS_ATOM_NULL) + goto fail; + me = find_export_entry(ctx, m, name); + JS_FreeAtom(ctx, name); + if (!me) + goto fail; + return JS_DupValue(ctx, me->u.local.var_ref->value); + fail: + return JS_UNDEFINED; +} + +int JS_CountModuleExport(JSContext *ctx, const JSModuleDef *m) { + return m->export_entries_count; +} + +JSAtom JS_GetModuleExportName(JSContext *ctx, const JSModuleDef *m, int idx) { + if (idx >= m->export_entries_count || idx < 0) + return JS_ATOM_NULL; + return JS_DupAtom(ctx, m->export_entries[idx].export_name); +} + +JSValueConst JS_GetModuleExportValue(JSContext *ctx, const JSModuleDef *m, int idx) { + if (idx >= m->export_entries_count || idx < 0) + return JS_UNDEFINED; + return JS_DupValue(ctx, m->export_entries[idx].u.local.var_ref->value); +} + void JS_SetModuleLoaderFunc(JSRuntime *rt, JSModuleNormalizeFunc *module_normalize, JSModuleLoaderFunc *module_loader, void *opaque) diff --git a/oden-js-sys/quickjs/quickjs.h b/oden-js-sys/quickjs/quickjs.h index d4a5cd31..2b3b6205 100644 --- a/oden-js-sys/quickjs/quickjs.h +++ b/oden-js-sys/quickjs/quickjs.h @@ -1038,6 +1038,11 @@ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, JSValue val); int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, const JSCFunctionListEntry *tab, int len); +/* can only be called after the module is initialized */ +JSValueConst JS_GetModuleExport(JSContext *ctx, const JSModuleDef *m, const char *export_name); +int JS_CountModuleExport(JSContext *ctx, const JSModuleDef *m); +JSAtom JS_GetModuleExportName(JSContext *ctx, const JSModuleDef *m, int idx); +JSValueConst JS_GetModuleExportValue(JSContext *ctx, const JSModuleDef *m, int idx); #undef js_unlikely #undef js_force_inline From 16e6f1304ce4328d455ac17c1ede1e61bbe5e095 Mon Sep 17 00:00:00 2001 From: John Doty Date: Mon, 19 Jun 2023 13:24:35 -0700 Subject: [PATCH 2/3] [oden-js] Get module exports --- oden-js-sys/src/static-functions.rs | 6 +++++- oden-js-sys/static-functions.c | 4 ++++ oden-js/src/context.rs | 27 +++++++++++++++++++++++++++ oden-js/src/value.rs | 21 ++++++++++++++++++++- 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/oden-js-sys/src/static-functions.rs b/oden-js-sys/src/static-functions.rs index 21a7f957..da619269 100644 --- a/oden-js-sys/src/static-functions.rs +++ b/oden-js-sys/src/static-functions.rs @@ -50,7 +50,7 @@ extern "C" { magic: ::std::os::raw::c_int, ) -> JSValue; fn JS_MakeException_real() -> JSValue; - + fn JS_ValueGetPtr_real(v: JSValue) -> *mut ::std::os::raw::c_void; } pub unsafe fn JS_ValueGetTag(v: JSValue) -> i32 { @@ -217,3 +217,7 @@ pub unsafe fn JS_NewCFunctionMagic( pub unsafe fn JS_MakeException() -> JSValue { JS_MakeException_real() } + +pub unsafe fn JS_ValueGetPtr(v: JSValue) -> *mut ::std::os::raw::c_void { + JS_ValueGetPtr_real(v) +} diff --git a/oden-js-sys/static-functions.c b/oden-js-sys/static-functions.c index 5185ecb1..4aec6a10 100644 --- a/oden-js-sys/static-functions.c +++ b/oden-js-sys/static-functions.c @@ -128,3 +128,7 @@ JSValue JS_NewCFunctionMagic_real(JSContext *ctx, JSCFunctionMagic *func, const JSValue JS_MakeException_real() { return JS_EXCEPTION; } + +void *JS_ValueGetPtr_real(JSValue val) { + return JS_VALUE_GET_PTR(val); +} diff --git a/oden-js/src/context.rs b/oden-js/src/context.rs index 00aa6247..8a748755 100644 --- a/oden-js/src/context.rs +++ b/oden-js/src/context.rs @@ -106,6 +106,14 @@ impl ContextRef { unsafe { sys::JS_EnableBignumExt(self.ctx, if enable { 1 } else { 0 }) } } + pub fn load_module(&self, input: &str, filename: &str) -> Result { + let val = self.eval(input, filename, EvalType::Module, EvalFlags::COMPILE_ONLY)?; + assert!(val.is_module()); + val.eval_function(self)?; + + Ok(val) + } + /// Evaluate the specified JavaScript code. pub fn eval( &self, @@ -482,4 +490,23 @@ mod tests { .unwrap(); assert_eq!(String::from("UNSAFE"), result.to_string(&ctx).unwrap()); } + + #[test] + fn modules_with_exports() { + let ctx = Context::new(Runtime::new()); + let module = ctx + .load_module("const foo = 123; export { foo };", "main.js") + .expect("Could not load!"); + assert_eq!(module.value_type(), ValueType::Module); + + let foo = module + .get_module_export(&ctx, "foo") + .expect("Could not get export"); + assert_eq!(String::from("123"), foo.to_string(&ctx).unwrap()); + + let bar = module + .get_module_export(&ctx, "bar") + .expect("Could not get export"); + assert!(bar.is_undefined()); + } } diff --git a/oden-js/src/value.rs b/oden-js/src/value.rs index 90257483..dbebce06 100644 --- a/oden-js/src/value.rs +++ b/oden-js/src/value.rs @@ -1,6 +1,6 @@ use crate::{AtomRef, ContextRef, Error, Result, Runtime, RustFunction}; use oden_js_sys as sys; -use std::ffi::CStr; +use std::ffi::{CStr, CString}; use std::fmt; use std::ops::{Deref, DerefMut}; @@ -309,6 +309,25 @@ impl ValueRef { Ok(result) } + + pub fn get_module_export(&self, ctx: &ContextRef, export: &str) -> Result { + if self.value_type() != ValueType::Module { + return Err(Error::InvalidType { + expected: ValueType::Bool, + found: self.value_type(), + }); + } + + let c_value = match CString::new(export) { + Ok(cs) => Ok(cs), + Err(_) => Err(Error::UnexpectedNul), + }?; + + unsafe { + let module = sys::JS_ValueGetPtr(self.val) as *mut sys::JSModuleDef; + ctx.check_exception(sys::JS_GetModuleExport(ctx.ctx, module, c_value.into_raw())) + } + } } impl<'ctx> fmt::Debug for ValueRef { From 8d7dd789ed834a270056d551754870047bb40d82 Mon Sep 17 00:00:00 2001 From: John Doty Date: Mon, 19 Jun 2023 13:46:09 -0700 Subject: [PATCH 3/3] [oden] JavaScript, god help me --- oden-js-sys/src/static-functions.rs | 10 +++++++ oden-js-sys/static-functions.c | 8 ++++++ oden-js/src/value.rs | 26 ++++++++++++++++++ src/lib.rs | 2 ++ src/main.js | 9 +++++++ src/script.rs | 41 ++++++++++++++++++++++++++--- 6 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 src/main.js diff --git a/oden-js-sys/src/static-functions.rs b/oden-js-sys/src/static-functions.rs index da619269..6419d46e 100644 --- a/oden-js-sys/src/static-functions.rs +++ b/oden-js-sys/src/static-functions.rs @@ -50,6 +50,8 @@ extern "C" { magic: ::std::os::raw::c_int, ) -> JSValue; fn JS_MakeException_real() -> JSValue; + fn JS_MakeNull_real() -> JSValue; + fn JS_MakeUndefined_real() -> JSValue; fn JS_ValueGetPtr_real(v: JSValue) -> *mut ::std::os::raw::c_void; } @@ -218,6 +220,14 @@ pub unsafe fn JS_MakeException() -> JSValue { JS_MakeException_real() } +pub unsafe fn JS_MakeNull() -> JSValue { + JS_MakeNull_real() +} + +pub unsafe fn JS_MakeUndefined() -> JSValue { + JS_MakeUndefined_real() +} + pub unsafe fn JS_ValueGetPtr(v: JSValue) -> *mut ::std::os::raw::c_void { JS_ValueGetPtr_real(v) } diff --git a/oden-js-sys/static-functions.c b/oden-js-sys/static-functions.c index 4aec6a10..26922beb 100644 --- a/oden-js-sys/static-functions.c +++ b/oden-js-sys/static-functions.c @@ -129,6 +129,14 @@ JSValue JS_MakeException_real() { return JS_EXCEPTION; } +JSValue JS_MakeNull_real() { + return JS_NULL; +} + +JSValue JS_MakeUndefined_real() { + return JS_UNDEFINED; +} + void *JS_ValueGetPtr_real(JSValue val) { return JS_VALUE_GET_PTR(val); } diff --git a/oden-js/src/value.rs b/oden-js/src/value.rs index dbebce06..b6d88405 100644 --- a/oden-js/src/value.rs +++ b/oden-js/src/value.rs @@ -328,6 +328,18 @@ impl ValueRef { ctx.check_exception(sys::JS_GetModuleExport(ctx.ctx, module, c_value.into_raw())) } } + + pub fn call(&self, ctx: &ContextRef) -> Result { + unsafe { + ctx.check_exception(sys::JS_Call( + ctx.ctx, + self.val, + sys::JS_MakeUndefined(), + 0, + std::ptr::null_mut(), + )) + } + } } impl<'ctx> fmt::Debug for ValueRef { @@ -357,6 +369,20 @@ impl Value { rt: Runtime::from_raw(unsafe { sys::JS_GetRuntime(ctx.ctx) }), } } + + pub fn null(ctx: &ContextRef) -> Self { + Value { + value: ValueRef::from_raw(unsafe { sys::JS_MakeNull() }), + rt: Runtime::from_raw(unsafe { sys::JS_GetRuntime(ctx.ctx) }), + } + } + + pub fn undefined(ctx: &ContextRef) -> Self { + Value { + value: ValueRef::from_raw(unsafe { sys::JS_MakeUndefined() }), + rt: Runtime::from_raw(unsafe { sys::JS_GetRuntime(ctx.ctx) }), + } + } } impl Deref for Value { diff --git a/src/lib.rs b/src/lib.rs index 5314c44b..562f9e35 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -356,6 +356,8 @@ pub async fn run() { let mut state = State::new(window).await; let context = script::ScriptContext::new(); + context.init(); + event_loop.run(move |event, _, control_flow| { control_flow.set_poll(); diff --git a/src/main.js b/src/main.js new file mode 100644 index 00000000..7b985b1f --- /dev/null +++ b/src/main.js @@ -0,0 +1,9 @@ +function init() { + // console.log("Hello world!"); +} + +function update() {} + +function draw() {} + +export { init, update, draw } diff --git a/src/script.rs b/src/script.rs index 2ed49e87..4391e0d2 100644 --- a/src/script.rs +++ b/src/script.rs @@ -1,7 +1,10 @@ use oden_js as js; pub struct ScriptContext { - _context: js::Context, + context: js::Context, + init: js::Value, + update: js::Value, + draw: js::Value, } impl ScriptContext { @@ -13,10 +16,40 @@ impl ScriptContext { context.add_intrinsic_bigdecimal(); context.add_intrinsic_operators(); - ScriptContext { _context: context } + let js = include_str!("main.js"); + let module = context + .load_module(js, "main.js") + .expect("Unable to load main"); + + let init = module + .get_module_export(&context, "init") + .expect("Unable to fetch init"); + let update = module + .get_module_export(&context, "update") + .expect("Unable to fetch update"); + let draw = module + .get_module_export(&context, "draw") + .expect("Unable to fetch draw"); + + ScriptContext { + context, + init, + update, + draw, + } } - pub fn update(&self) {} + pub fn init(&self) { + self.init.call(&self.context).expect("Exception in init"); + } - pub fn render(&self) {} + pub fn update(&self) { + self.update + .call(&self.context) + .expect("Exception in update"); + } + + pub fn render(&self) { + self.draw.call(&self.context).expect("Exception in draw"); + } }