@@ -165,7 +165,7 @@ pub const Env = struct {
165165 }
166166
167167 // start a Javascript context
168- pub fn start (self : * Env , alloc : std.mem.Allocator ) anyerror ! void {
168+ pub fn start (self : * Env ) anyerror ! void {
169169
170170 // context
171171 self .js_ctx = v8 .Context .init (self .isolate , self .globals .getInstanceTemplate (), null );
@@ -197,13 +197,10 @@ pub const Env = struct {
197197 // TODO: this is an horrible hack
198198 if (comptime T_refl .isException ()) {
199199 const script = T_refl .name ++ ".prototype.__proto__ = Error.prototype" ;
200- const res = try self .execTryCatch (
201- alloc ,
202- script ,
203- "errorSubclass" ,
204- );
205- defer res .deinit (alloc );
206- if (! res .success ) return error .errorSubClass ;
200+ _ = self .exec (script , "errorSubclass" ) catch {
201+ // TODO: is there a reason to override the error?
202+ return error .errorSubClass ;
203+ };
207204 }
208205 }
209206 }
@@ -293,119 +290,48 @@ pub const Env = struct {
293290 }
294291 }
295292
296- // compile and run a Javascript script
297- // if no error you need to call deinit on the returned result
293+ // compile and run a JS script
294+ // It doesn't wait for callbacks execution
298295 pub fn exec (
299296 self : Env ,
300- alloc : std.mem.Allocator ,
301297 script : []const u8 ,
302298 name : ? []const u8 ,
303- try_catch : TryCatch ,
304- ) ! JSResult {
299+ ) anyerror ! JSValue {
305300 if (self .js_ctx == null ) {
306301 return error .EnvNotStarted ;
307302 }
308-
309- var res = JSResult .init ();
310- try res .exec (alloc , script , name , self .isolate , self .js_ctx .? , try_catch .try_catch .* );
311- return res ;
303+ return try jsExec (script , name , self .isolate , self .js_ctx .? );
312304 }
313305
314- // compile and run a Javascript script with try/catch
315- // if no error you need to call deinit on the returned result
316- pub fn execTryCatch (
317- self : Env ,
318- alloc : std.mem.Allocator ,
319- script : []const u8 ,
320- name : ? []const u8 ,
321- ) anyerror ! JSResult {
322-
323- // JS try cache
324- var try_catch = TryCatch .init (self );
325- defer try_catch .deinit ();
326-
327- return self .exec (alloc , script , name , try_catch );
328- }
329-
330- // wait I/O loop until all JS callbacks are executed
306+ // wait I/O Loop until all JS callbacks are executed
331307 // This is a blocking operation.
332- pub fn wait (
333- self : Env ,
334- alloc : std.mem.Allocator ,
335- try_catch : v8.TryCatch ,
336- cbk_res : ? * JSResult ,
337- ) ! void {
308+ // Errors can be either:
309+ // - an error of the Loop (eg. IO kernel)
310+ // - an error of one of the JS callbacks
311+ // NOTE: the Loop does not stop when a JS callback throw an error
312+ // ie. all JS callbacks are executed
313+ // TODO: return at first error on a JS callback and let the caller
314+ // decide whether going forward or not
315+ pub fn wait (self : Env ) anyerror ! void {
338316 if (self .js_ctx == null ) {
339317 return error .EnvNotStarted ;
340318 }
341319
342320 // run loop
343- self .nat_ctx .loop .run () catch | err | {
344- if (try_catch .hasCaught ()) {
345- if (cbk_res ) | res | {
346- res .success = false ;
347- return res .setError (alloc , self .isolate , self .js_ctx .? , try_catch );
348- }
349- // otherwise ignore JS errors
350- } else {
351- // IO kernel error
352- return err ;
353- }
354- };
355-
356- if (cbk_res ) | res | res .success = true ;
321+ return self .nat_ctx .loop .run ();
357322 }
358323
359- pub fn waitTryCatch (
360- self : Env ,
361- alloc : std.mem.Allocator ,
362- ) anyerror ! JSResult {
363-
364- // JS try cache
365- var try_catch : v8.TryCatch = undefined ;
366- try_catch .init (self .isolate );
367- defer try_catch .deinit ();
368-
369- var res = JSResult {};
370- try self .wait (alloc , try_catch , & res );
371- return res ;
372- }
373-
374- // run a JS script and wait for all callbacks
375- // try_catch + exec + wait
376- pub fn run (
377- self : Env ,
378- alloc : std.mem.Allocator ,
379- script : []const u8 ,
380- name : ? []const u8 ,
381- res : * JSResult ,
382- cbk_res : ? * JSResult ,
383- ) anyerror ! void {
384- if (self .js_ctx == null ) {
385- return error .EnvNotStarted ;
386- }
387-
388- // JS try cache
389- var try_catch : v8.TryCatch = undefined ;
390- try_catch .init (self .isolate );
391- defer try_catch .deinit ();
324+ // compile and run a JS script and wait for all callbacks (exec + wait)
325+ // This is a blocking operation.
326+ pub fn execWait (self : Env , script : []const u8 , name : ? []const u8 ) anyerror ! JSValue {
392327
393328 // exec script
394- try res . exec ( alloc , script , name , self .isolate , self . js_ctx .? , try_catch );
329+ const res = try self .exec ( script , name );
395330
396- // run loop
397- self .nat_ctx .loop .run () catch | err | {
398- if (try_catch .hasCaught ()) {
399- if (cbk_res ) | r | {
400- r .success = false ;
401- return r .setError (alloc , self .isolate , self .js_ctx .? , try_catch );
402- }
403- // otherwise ignore JS errors
404- } else {
405- // IO kernel error
406- return err ;
407- }
408- };
331+ // wait
332+ try self .wait ();
333+
334+ return res ;
409335 }
410336};
411337
@@ -493,91 +419,82 @@ pub const JSObject = struct {
493419 }
494420};
495421
496- pub const TryCatch = struct {
497- try_catch : * v8.TryCatch ,
422+ pub const JSValue = struct {
423+ value : v8.Value ,
498424
499- pub inline fn init (env : Env ) TryCatch {
500- var try_catch : v8.TryCatch = undefined ;
501- try_catch .init (env .isolate );
502- return .{ .try_catch = & try_catch };
425+ // the caller needs to deinit the string returned
426+ pub fn toString (self : JSValue , alloc : std.mem.Allocator , env : Env ) anyerror ! []const u8 {
427+ return valueToUtf8 (alloc , self .value , env .isolate , env .js_ctx .? );
503428 }
504429
505- pub inline fn exception (self : TryCatch , alloc : std.mem.Allocator , env : Env ) anyerror ! ? []const u8 {
506- if (self .try_catch .getException ()) | msg | {
507- return try valueToUtf8 (alloc , msg , env .isolate , env .js_ctx .? );
508- }
509- return null ;
510- }
511-
512- pub inline fn deinit (self : * TryCatch ) void {
513- self .try_catch .deinit ();
430+ pub fn typeOf (self : JSValue , env : Env ) anyerror ! public.JSTypes {
431+ var buf : [20 ]u8 = undefined ;
432+ const str = try self .value .typeOf (env .isolate );
433+ const len = str .lenUtf8 (env .isolate );
434+ const s = buf [0.. len ];
435+ _ = str .writeUtf8 (env .isolate , s );
436+ return std .meta .stringToEnum (public .JSTypes , s ) orelse {
437+ std .log .err ("JSValueTypeNotHandled: {s}" , .{s });
438+ return error .JSValueTypeNotHandled ;
439+ };
514440 }
515441};
516442
517- pub const JSResult = struct {
518- success : bool = false ,
519- result : []const u8 = undefined ,
520- stack : ? []const u8 = null ,
443+ pub const TryCatch = struct {
444+ inner : v8.TryCatch ,
521445
522- pub fn init () JSResult {
523- return .{} ;
446+ pub fn init (self : * TryCatch , env : Env ) void {
447+ self . inner . init ( env . isolate ) ;
524448 }
525449
526- pub fn deinit (self : JSResult , alloc : std.mem.Allocator ) void {
527- alloc .free (self .result );
528- if (self .stack ) | stack | {
529- alloc .free (stack );
530- }
450+ pub fn hasCaught (self : TryCatch ) bool {
451+ return self .inner .hasCaught ();
531452 }
532453
533- pub fn exec (
534- self : * JSResult ,
535- alloc : std.mem.Allocator ,
536- script : []const u8 ,
537- name : ? []const u8 ,
538- isolate : v8.Isolate ,
539- js_ctx : v8.Context ,
540- try_catch : v8.TryCatch ,
541- ) ! void {
542-
543- // compile
544- var origin : ? v8.ScriptOrigin = undefined ;
545- if (name ) | n | {
546- const scr_name = v8 .String .initUtf8 (isolate , n );
547- origin = v8 .ScriptOrigin .initDefault (isolate , scr_name .toValue ());
454+ // the caller needs to deinit the string returned
455+ pub fn exception (self : TryCatch , alloc : std.mem.Allocator , env : Env ) anyerror ! ? []const u8 {
456+ if (self .inner .getException ()) | msg | {
457+ return try valueToUtf8 (alloc , msg , env .isolate , env .js_ctx .? );
548458 }
549- const scr_js = v8 .String .initUtf8 (isolate , script );
550- const scr = v8 .Script .compile (js_ctx , scr_js , origin ) catch {
551- return self .setError (alloc , isolate , js_ctx , try_catch );
552- };
459+ return null ;
460+ }
553461
554- // run
555- const res = scr .run (js_ctx ) catch {
556- return self .setError (alloc , isolate , js_ctx , try_catch );
557- };
558- self .success = true ;
559- self .result = try valueToUtf8 (alloc , res , isolate , js_ctx );
462+ // the caller needs to deinit the string returned
463+ pub fn stack (self : TryCatch , alloc : std.mem.Allocator , env : Env ) anyerror ! ? []const u8 {
464+ const stck = self .inner .getStackTrace (env .js_ctx .? );
465+ if (stck ) | s | return try valueToUtf8 (alloc , s , env .isolate , env .js_ctx .? );
466+ return null ;
560467 }
561468
562- pub fn setError (
563- self : * JSResult ,
564- alloc : std.mem.Allocator ,
565- isolate : v8.Isolate ,
566- js_ctx : v8.Context ,
567- try_catch : v8.TryCatch ,
568- ) ! void {
569-
570- // exception
571- const except = try_catch .getException ().? ;
572- self .success = false ;
573- self .result = try valueToUtf8 (alloc , except , isolate , js_ctx );
574-
575- // stack
576- if (self .stack != null ) {
577- return ;
578- }
579- if (try_catch .getStackTrace (js_ctx )) | stack | {
580- self .stack = try valueToUtf8 (alloc , stack , isolate , js_ctx );
469+ // a shorthand method to return either the entire stack message
470+ // or just the exception message
471+ // - in Debug mode return the stack if available
472+ // - otherwhise return the exception if available
473+ // the caller needs to deinit the string returned
474+ pub fn err (self : TryCatch , alloc : std.mem.Allocator , env : Env ) anyerror ! ? []const u8 {
475+ if (builtin .mode == .Debug ) {
476+ if (try self .stack (alloc , env )) | msg | return msg ;
581477 }
478+ return try self .exception (alloc , env );
479+ }
480+
481+ pub fn deinit (self : * TryCatch ) void {
482+ self .inner .deinit ();
582483 }
583484};
485+
486+ pub fn jsExec (script : []const u8 , name : ? []const u8 , isolate : v8.Isolate , js_ctx : v8.Context ) ! JSValue {
487+
488+ // compile
489+ var origin : ? v8.ScriptOrigin = undefined ;
490+ if (name ) | n | {
491+ const scr_name = v8 .String .initUtf8 (isolate , n );
492+ origin = v8 .ScriptOrigin .initDefault (isolate , scr_name .toValue ());
493+ }
494+ const scr_js = v8 .String .initUtf8 (isolate , script );
495+ const scr = v8 .Script .compile (js_ctx , scr_js , origin ) catch return error .JSCompile ;
496+
497+ // run
498+ const value = scr .run (js_ctx ) catch return error .JSExec ;
499+ return .{ .value = value };
500+ }
0 commit comments