Line data Source code
1 0 : /*
2 :
3 : OOJavaScriptEngine.h
4 :
5 : JavaScript support for Oolite
6 : Copyright (C) 2007-2013 David Taylor and Jens Ayton.
7 :
8 : This program is free software; you can redistribute it and/or
9 : modify it under the terms of the GNU General Public License
10 : as published by the Free Software Foundation; either version 2
11 : of the License, or (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program; if not, write to the Free Software
20 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 : MA 02110-1301, USA.
22 :
23 : */
24 :
25 :
26 : #import "OOCocoa.h"
27 : #import "Universe.h"
28 : #import "PlayerEntity.h"
29 : #import "PlayerEntityLegacyScriptEngine.h"
30 : #include <jsapi.h>
31 :
32 :
33 0 : #define OOJSENGINE_MONITOR_SUPPORT OOLITE_DEBUG
34 :
35 :
36 : #import "OOJSPropID.h"
37 :
38 :
39 : @protocol OOJavaScriptEngineMonitor;
40 :
41 :
42 0 : @interface OOJavaScriptEngine: NSObject
43 : {
44 : @private
45 0 : JSRuntime *_runtime;
46 0 : JSObject *_globalObject;
47 0 : BOOL _showErrorLocations;
48 :
49 0 : JSClass *_objectClass;
50 0 : JSClass *_stringClass;
51 0 : JSClass *_arrayClass;
52 0 : JSClass *_numberClass;
53 0 : JSClass *_booleanClass;
54 :
55 : #ifndef NDEBUG
56 0 : BOOL _dumpStackForErrors;
57 0 : BOOL _dumpStackForWarnings;
58 : #endif
59 : #if OOJSENGINE_MONITOR_SUPPORT
60 : id<OOJavaScriptEngineMonitor> _monitor;
61 : #endif
62 : }
63 :
64 0 : + (OOJavaScriptEngine *) sharedEngine;
65 :
66 0 : - (JSObject *) globalObject;
67 :
68 0 : - (void) runMissionCallback;
69 :
70 : /* Tear down context and global object and rebuild them from scratch. This
71 : invalidates -globalObject and the main thread context.
72 : */
73 0 : - (BOOL) reset;
74 :
75 : // Call a JS function, setting up new contexts as necessary. Caller is responsible for ensuring the jsval passed really is a function.
76 0 : - (BOOL) callJSFunction:(jsval)function
77 : forObject:(JSObject *)jsThis
78 : argc:(uintN)argc
79 : argv:(jsval *)argv
80 : result:(jsval *)outResult;
81 :
82 0 : - (void) removeGCObjectRoot:(JSObject **)rootPtr;
83 0 : - (void) removeGCValueRoot:(jsval *)rootPtr;
84 :
85 0 : - (void) garbageCollectionOpportunity:(BOOL)force;
86 :
87 0 : - (BOOL) showErrorLocations;
88 0 : - (void) setShowErrorLocations:(BOOL)value;
89 :
90 0 : - (JSClass *) objectClass;
91 0 : - (JSClass *) stringClass;
92 0 : - (JSClass *) arrayClass;
93 0 : - (JSClass *) numberClass;
94 0 : - (JSClass *) booleanClass;
95 :
96 : #ifndef NDEBUG
97 0 : - (BOOL) dumpStackForErrors;
98 0 : - (void) setDumpStackForErrors:(BOOL)value;
99 :
100 0 : - (BOOL) dumpStackForWarnings;
101 0 : - (void) setDumpStackForWarnings:(BOOL)value;
102 :
103 : // Install handler for JS "debugger" statment.
104 0 : - (void) enableDebuggerStatement;
105 : #endif
106 :
107 : @end
108 :
109 :
110 : #if !JS_THREADSAFE
111 0 : #define JS_IsInRequest(context) (((void)(context)), YES)
112 0 : #define JS_BeginRequest(context) do {} while (0)
113 0 : #define JS_EndRequest(context) do {} while (0)
114 : #endif
115 :
116 :
117 : // Get the main thread's JS context, and begin a request on it.
118 0 : OOINLINE JSContext *OOJSAcquireContext(void)
119 : {
120 : extern JSContext *gOOJSMainThreadContext;
121 : NSCAssert(gOOJSMainThreadContext != NULL, @"Attempt to use JavaScript context before JavaScript engine is initialized.");
122 : JS_BeginRequest(gOOJSMainThreadContext);
123 : return gOOJSMainThreadContext;
124 : }
125 :
126 :
127 : // End a request on the main thread's context.
128 0 : OOINLINE void OOJSRelinquishContext(JSContext *context)
129 : {
130 : #ifndef NDEBUG
131 : extern JSContext *gOOJSMainThreadContext;
132 : NSCParameterAssert(context == gOOJSMainThreadContext && JS_IsInRequest(context));
133 : #endif
134 : JS_EndRequest(context);
135 : }
136 :
137 :
138 : // Notifications sent when JavaScript engine is reset.
139 0 : extern NSString * const kOOJavaScriptEngineWillResetNotification;
140 0 : extern NSString * const kOOJavaScriptEngineDidResetNotification;
141 :
142 :
143 : /* Error and warning reporters.
144 :
145 : Note that after reporting an error in a JavaScript callback, the caller
146 : must return NO to signal an error.
147 : */
148 0 : void OOJSReportError(JSContext *context, NSString *format, ...);
149 0 : void OOJSReportErrorWithArguments(JSContext *context, NSString *format, va_list args);
150 0 : void OOJSReportErrorForCaller(JSContext *context, NSString *scriptClass, NSString *function, NSString *format, ...);
151 :
152 0 : void OOJSReportWarning(JSContext *context, NSString *format, ...);
153 0 : void OOJSReportWarningWithArguments(JSContext *context, NSString *format, va_list args);
154 0 : void OOJSReportWarningForCaller(JSContext *context, NSString *scriptClass, NSString *function, NSString *format, ...);
155 :
156 0 : void OOJSReportBadPropertySelector(JSContext *context, JSObject *thisObj, jsid propID, JSPropertySpec *propertySpec);
157 0 : void OOJSReportBadPropertyValue(JSContext *context, JSObject *thisObj, jsid propID, JSPropertySpec *propertySpec, jsval value);
158 0 : void OOJSReportBadArguments(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, NSString *message, NSString *expectedArgsDescription);
159 :
160 : /* OOJSSetWarningOrErrorStackSkip()
161 :
162 : Indicate that the direct call site is not relevant for error handler.
163 : Currently, if non-zero, no call site information is provided.
164 : Ideally, we'd stack crawl instead.
165 : */
166 0 : void OOJSSetWarningOrErrorStackSkip(unsigned skip);
167 :
168 :
169 : /* OOJSArgumentListGetNumber()
170 :
171 : Get a single number from an argument list. The optional outConsumed
172 : argument can be used to find out how many parameters were used (currently,
173 : this will be 0 on failure, otherwise 1).
174 :
175 : On failure, it will return NO and raise an error. If the caller is a JS
176 : callback, it must return NO to signal an error.
177 : */
178 0 : BOOL OOJSArgumentListGetNumber(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, double *outNumber, uintN *outConsumed);
179 :
180 : /* OOJSArgumentListGetNumberNoError()
181 :
182 : Like OOJSArgumentListGetNumber(), but does not report an error on failure.
183 : */
184 0 : BOOL OOJSArgumentListGetNumberNoError(JSContext *context, uintN argc, jsval *argv, double *outNumber, uintN *outConsumed);
185 :
186 :
187 : // Typed as int rather than BOOL to work with more general expressions such as bitfield tests.
188 : OOINLINE jsval OOJSValueFromBOOL(int b) INLINE_CONST_FUNC;
189 0 : OOINLINE jsval OOJSValueFromBOOL(int b)
190 : {
191 : return BOOLEAN_TO_JSVAL(b != NO);
192 : }
193 :
194 :
195 : @interface NSObject (OOJavaScript)
196 :
197 : /* -oo_jsValueInContext:
198 :
199 : Return the JavaScript value representation of an object. The default
200 : implementation returns JSVAL_VOID.
201 :
202 : SAFETY NOTE: if this message is sent to nil, the return value depends on
203 : the platform and whether JS_USE_JSVAL_JSID_STRUCT_TYPES is set. If the
204 : receiver may be nil, use OOJSValueFromNativeObject() instead.
205 :
206 : One case where it is safe to use oo_jsValueInContext: is with objects
207 : retrieved from Foundation collections, as they can never be nil.
208 :
209 : Requires a request on context.
210 : */
211 0 : - (jsval) oo_jsValueInContext:(JSContext *)context;
212 :
213 : /* -oo_jsDescription
214 : -oo_jsDescriptionWithClassName:
215 : -oo_jsClassName
216 :
217 : See comments for -descriptionComponents in OOCocoa.h.
218 : */
219 0 : - (NSString *) oo_jsDescription;
220 0 : - (NSString *) oo_jsDescriptionWithClassName:(NSString *)className;
221 0 : - (NSString *) oo_jsClassName;
222 :
223 : /* oo_clearJSSelf:
224 : This is called by OOJSObjectWrapperFinalize() when a JS object wrapper is
225 : collected. The default implementation does nothing.
226 : */
227 0 : - (void) oo_clearJSSelf:(JSObject *)selfVal;
228 :
229 : @end
230 :
231 :
232 : /* OOJSValueFromNativeObject()
233 : Return a JavaScript value representation of an object, or null if passed
234 : nil.
235 :
236 : Requires a request on context.
237 : */
238 0 : OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)
239 : {
240 : if (object != nil) return [object oo_jsValueInContext:context];
241 : return JSVAL_NULL;
242 : }
243 :
244 :
245 : /* OOJSObjectFromNativeObject()
246 : Return a JavaScript object representation of an object, or null if passed
247 : nil. The value is boxed if necessary.
248 :
249 : Requires a request on context.
250 : */
251 0 : JSObject *OOJSObjectFromNativeObject(JSContext *context, id object);
252 :
253 :
254 : /* OOJSValue: an object whose purpose in life is to hold a JavaScript value.
255 : This is somewhat useful for putting JavaScript objects in ObjC collections,
256 : for instance to pass as properties to script loaders. The value is
257 : GC rooted for the lifetime of the OOJSValue.
258 :
259 : All methods take a context parameter, which must either be nil or a context
260 : in a request.
261 : */
262 0 : @interface OOJSValue: NSObject
263 : {
264 0 : jsval _val;
265 : }
266 :
267 0 : + (id) valueWithJSValue:(jsval)value inContext:(JSContext *)context;
268 0 : + (id) valueWithJSObject:(JSObject *)object inContext:(JSContext *)context;
269 :
270 0 : - (id) initWithJSValue:(jsval)value inContext:(JSContext *)context;
271 0 : - (id) initWithJSObject:(JSObject *)object inContext:(JSContext *)context;
272 :
273 : @end
274 :
275 :
276 :
277 : /**** String utilities ****/
278 :
279 : /* OOJSSTR(const char * [literal])
280 :
281 : Create and cache a jsval referring to an interned string literal.
282 : */
283 0 : #define OOJSSTR(str) ({ static jsval strCache; static BOOL inited; if (EXPECT_NOT(!inited)) OOJSStrLiteralCachePRIVATE(""str, &strCache, &inited); strCache; })
284 0 : void OOJSStrLiteralCachePRIVATE(const char *string, jsval *strCache, BOOL *inited);
285 :
286 :
287 : // Convert a JSString to an NSString.
288 0 : NSString *OOStringFromJSString(JSContext *context, JSString *string);
289 :
290 : /* Convert an arbitrary JS object to an NSString, calling JS_ValueToString.
291 : OOStringFromJSValue() returns nil if value is null or undefined,
292 : OOStringFromJSValueEvenIfNull() returns "null" or "undefined".
293 : */
294 0 : NSString *OOStringFromJSValue(JSContext *context, jsval value);
295 0 : NSString *OOStringFromJSValueEvenIfNull(JSContext *context, jsval value);
296 :
297 :
298 : /* OOStringFromJSPropertyIDAndSpec(context, propID, propertySpec)
299 :
300 : Returns the name of a property given either a name or a tinyid. (Intended
301 : for error reporting inside JSPropertyOps.)
302 : */
303 0 : NSString *OOStringFromJSPropertyIDAndSpec(JSContext *context, jsid propID, JSPropertySpec *propertySpec);
304 :
305 :
306 : /* Describe a value for debugging or error reporting. Strings are quoted,
307 : escaped and limited in length. Functions are described as "function foo"
308 : (or just "function" if they're anonymous). Up to four elements of arrays
309 : are included, followed by total count of there are more than four.
310 : If abbreviateObjects, the description "[object Object]" is replaced with
311 : "{...}", which may or may not be clearer depending on context.
312 : */
313 0 : NSString *OOJSDescribeValue(JSContext *context, jsval value, BOOL abbreviateObjects);
314 :
315 :
316 : // Convert a jsid to an NSString.
317 0 : NSString *OOStringFromJSID(jsid propID);
318 :
319 : // Convert an NSString to a jsid.
320 0 : jsid OOJSIDFromString(NSString *string);
321 :
322 :
323 : @interface NSString (OOJavaScriptExtensions)
324 :
325 : // For diagnostic messages; produces things like @"(42, true, "a string", an object description)".
326 0 : + (NSString *) stringWithJavaScriptParameters:(jsval *)params count:(uintN)count inContext:(JSContext *)context;
327 :
328 : // Concatenate sequence of arbitrary JS objects into string.
329 0 : + (NSString *) concatenationOfStringsFromJavaScriptValues:(jsval *)values count:(size_t)count separator:(NSString *)separator inContext:(JSContext *)context;
330 :
331 : // Add escape codes for string so that it's a valid JavaScript literal (if you put "" or '' around it).
332 0 : - (NSString *) escapedForJavaScriptLiteral;
333 :
334 : @end
335 :
336 :
337 : // OOEntityFilterPredicate wrapping a JavaScript function.
338 0 : typedef struct
339 : {
340 0 : JSContext *context;
341 0 : jsval function; // Caller is responsible for ensuring this is a function object (using OOJSValueIsFunction()).
342 0 : JSObject *jsThis;
343 0 : BOOL errorFlag; // Set if a JS exception occurs. The
344 : // exception will have been reported.
345 : // This also supresses further filtering.
346 : } JSFunctionPredicateParameter;
347 0 : BOOL JSFunctionPredicate(Entity *entity, void *parameter);
348 :
349 : // YES for ships and (normal) planets. Parameter: ignored.
350 0 : BOOL JSEntityIsJavaScriptVisiblePredicate(Entity *entity, void *parameter);
351 :
352 : // YES for ships other than sub-entities and menu-display ships, and planets other than atmospheres and menu miniatures. Parameter: ignored.
353 0 : BOOL JSEntityIsJavaScriptSearchablePredicate(Entity *entity, void *parameter);
354 :
355 : // YES for menu-display ships. Parameter: ignored
356 0 : BOOL JSEntityIsDemoShipPredicate(Entity *entity, void *parameter);
357 :
358 :
359 : // These require a request on context.
360 0 : id OOJSNativeObjectFromJSValue(JSContext *context, jsval value);
361 0 : id OOJSNativeObjectFromJSObject(JSContext *context, JSObject *object);
362 0 : id OOJSNativeObjectOfClassFromJSValue(JSContext *context, jsval value, Class requiredClass);
363 0 : id OOJSNativeObjectOfClassFromJSObject(JSContext *context, JSObject *object, Class requiredClass);
364 :
365 :
366 : OOINLINE JSClass *OOJSGetClass(JSContext *cx, JSObject *obj) ALWAYS_INLINE_FUNC;
367 0 : OOINLINE JSClass *OOJSGetClass(JSContext *cx, JSObject *obj)
368 : {
369 : #if JS_THREADSAFE
370 : return JS_GetClass(cx, obj);
371 : #else
372 : return JS_GetClass(obj);
373 : #endif
374 : }
375 :
376 :
377 : /* OOJSValueIsFunction(context, value)
378 :
379 : Test whether a jsval is a function object. The main tripping point here
380 : is that JSVAL_IS_OBJECT() is true for JSVAL_NULL, but JS_ObjectIsFunction()
381 : crashes if passed null.
382 : */
383 0 : OOINLINE BOOL OOJSValueIsFunction(JSContext *context, jsval value)
384 : {
385 : return JSVAL_IS_OBJECT(value) && !JSVAL_IS_NULL(value) && JS_ObjectIsFunction(context, JSVAL_TO_OBJECT(value));
386 : }
387 :
388 :
389 : /* OOJSValueIsArray(context, value)
390 :
391 : Test whether a jsval is an array object. The main tripping point here
392 : is that JSVAL_IS_OBJECT() is true for JSVAL_NULL, but JS_IsArrayObject()
393 : crashes if passed null.
394 :
395 : Also, it should be called JS_ObjectIsArray() for consistency.
396 : */
397 0 : OOINLINE BOOL OOJSValueIsArray(JSContext *context, jsval value)
398 : {
399 : return JSVAL_IS_OBJECT(value) && !JSVAL_IS_NULL(value) && JS_IsArrayObject(context, JSVAL_TO_OBJECT(value));
400 : }
401 :
402 :
403 : /* OOJSDictionaryFromJSValue(context, value)
404 : OOJSDictionaryFromJSObject(context, object)
405 :
406 : Converts a JavaScript value to a dictionary by calling
407 : OOJSNativeObjectFromJSValue() on each of its values.
408 :
409 : Only enumerable own (i.e., not inherited) properties with string keys are
410 : included.
411 :
412 : Requires a request on context.
413 : */
414 0 : NSDictionary *OOJSDictionaryFromJSValue(JSContext *context, jsval value);
415 0 : NSDictionary *OOJSDictionaryFromJSObject(JSContext *context, JSObject *object);
416 :
417 :
418 : /* OOJSDictionaryFromStringTable(context, value)
419 :
420 : Treat an arbitrary JavaScript object as a dictionary mapping strings to
421 : strings, and convert to a corresponding NSDictionary. The values are
422 : converted to strings using JS_ValueToString().
423 :
424 : Only enumerable own (i.e., not inherited) properties with string keys are
425 : included.
426 :
427 : Requires a request on context.
428 : */
429 0 : NSDictionary *OOJSDictionaryFromStringTable(JSContext *context, jsval value);
430 :
431 :
432 : /*
433 : DEFINE_JS_OBJECT_GETTER()
434 : Defines a helper to extract Objective-C objects from the private field of
435 : JS objects, with runtime type checking. The generated accessor requires
436 : a request on context. Weakrefs are automatically unpacked.
437 :
438 : Types which extend other types, such as entity subtypes, must register
439 : their relationships with OOJSRegisterSubclass() below.
440 :
441 : The signature of the generator is:
442 : BOOL <name>(JSContext *context, JSObject *inObject, <class>** outObject)
443 : If it returns NO, inObject is of the wrong class and an error has been
444 : raised. Otherwise, outObject is either a native object of the specified
445 : class (or a subclass) or nil.
446 : */
447 : #ifndef NDEBUG
448 0 : #define DEFINE_JS_OBJECT_GETTER(NAME, JSCLASS, JSPROTO, OBJCCLASSNAME) \
449 : static BOOL NAME(JSContext *context, JSObject *inObject, OBJCCLASSNAME **outObject) GCC_ATTR((unused)); \
450 : static BOOL NAME(JSContext *context, JSObject *inObject, OBJCCLASSNAME **outObject) \
451 : { \
452 : NSCParameterAssert(outObject != NULL); \
453 : static Class cls = Nil; \
454 : if (EXPECT_NOT(cls == Nil)) cls = [OBJCCLASSNAME class]; \
455 : return OOJSObjectGetterImplPRIVATE(context, inObject, JSCLASS, cls, #NAME, (id *)outObject); \
456 : }
457 : #else
458 : #define DEFINE_JS_OBJECT_GETTER(NAME, JSCLASS, JSPROTO, OBJCCLASSNAME) \
459 : OOINLINE BOOL NAME(JSContext *context, JSObject *inObject, OBJCCLASSNAME **outObject) \
460 : { \
461 : return OOJSObjectGetterImplPRIVATE(context, inObject, JSCLASS, (id *)outObject); \
462 : }
463 : #endif
464 :
465 : // For DEFINE_JS_OBJECT_GETTER()'s use.
466 : #ifndef NDEBUG
467 0 : BOOL OOJSObjectGetterImplPRIVATE(JSContext *context, JSObject *object, JSClass *requiredJSClass, Class requiredObjCClass, const char *name, id *outObject);
468 : #else
469 : BOOL OOJSObjectGetterImplPRIVATE(JSContext *context, JSObject *object, JSClass *requiredJSClass, id *outObject);
470 : #endif
471 :
472 :
473 : /*
474 : Subclass relationships.
475 :
476 : JSAPI doesn't have a concept of subclassing, as JavaScript doesn't have a
477 : concept of classes, but Oolite reflects part of its class hierarchy as
478 : related JSClasses whose prototypes inherit each other. For instance,
479 : JS Entity methods work on JS Ships. In order for this to work,
480 : OOJSEntityGetEntity() must be able to know that Ship is a subclass of
481 : Entity. This is done using OOJSIsSubclass().
482 :
483 : void OOJSRegisterSubclass(JSClass *subclass, JSClass *superclass)
484 : Register subclass as a subclass of superclass. Subclass must not previously
485 : have been registered as a subclass of any class (i.e., single inheritance
486 : is required).
487 :
488 : BOOL OOJSIsSubclass(JSClass *putativeSubclass, JSClass *superclass)
489 : Test whether putativeSubclass is a equal to superclass or a registered
490 : subclass of superclass, recursively.
491 : */
492 0 : void OOJSRegisterSubclass(JSClass *subclass, JSClass *superclass);
493 0 : BOOL OOJSIsSubclass(JSClass *putativeSubclass, JSClass *superclass);
494 0 : OOINLINE BOOL OOJSIsMemberOfSubclass(JSContext *context, JSObject *object, JSClass *superclass)
495 : {
496 : return OOJSIsSubclass(OOJSGetClass(context, object), superclass);
497 : }
498 :
499 :
500 : /* Support for OOJSNativeObjectFromJSValue() family
501 :
502 : OOJSClassConverterCallback specifies the prototype for a callback function
503 : which converts a JavaScript object to an Objective-C object.
504 :
505 : OOJSBasicPrivateObjectConverter() is a OOJSClassConverterCallback which
506 : returns the JS object's private storage value. It automatically unpacks
507 : OOWeakReferences if relevant.
508 :
509 : OOJSRegisterObjectConverter() registers a callback for a specific JS class.
510 : It is not automatically propagated to subclasses.
511 : */
512 0 : typedef id (*OOJSClassConverterCallback)(JSContext *context, JSObject *object);
513 0 : id OOJSBasicPrivateObjectConverter(JSContext *context, JSObject *object);
514 :
515 0 : void OOJSRegisterObjectConverter(JSClass *theClass, OOJSClassConverterCallback converter);
516 :
517 :
518 : /* JS root handling
519 :
520 : The name parameter to JS_AddNamed*Root is assigned with no overhead, not
521 : copied, but the strings serve no purpose in a release build so we may as
522 : well strip them out.
523 :
524 : In debug builds, this will deliberately cause an error if name is not a
525 : string literal.
526 : */
527 : #ifdef NDEBUG
528 : #define OOJSAddGCValueRoot(context, root, name) JS_AddValueRoot((context), (root))
529 : #define OOJSAddGCStringRoot(context, root, name) JS_AddStringRoot((context), (root))
530 : #define OOJSAddGCObjectRoot(context, root, name) JS_AddObjectRoot((context), (root))
531 : #define OOJSAddGCThingRoot(context, root, name) JS_AddGCThingRoot((context), (root))
532 : #else
533 0 : #define OOJSAddGCValueRoot(context, root, name) JS_AddNamedValueRoot((context), (root), "" name)
534 0 : #define OOJSAddGCStringRoot(context, root, name) JS_AddNamedStringRoot((context), (root), "" name)
535 0 : #define OOJSAddGCObjectRoot(context, root, name) JS_AddNamedObjectRoot((context), (root), "" name)
536 0 : #define OOJSAddGCThingRoot(context, root, name) JS_AddNamedGCThingRoot((context), (root), "" name)
537 : #endif
538 :
539 :
540 : #if OOJSENGINE_MONITOR_SUPPORT
541 :
542 : /* Protocol for debugging "monitor" object.
543 : The monitor is an object -- in Oolite, or via Distributed Objects -- which
544 : is provided with debugging information by the OOJavaScriptEngine.
545 : */
546 :
547 : @protocol OOJavaScriptEngineMonitor <NSObject>
548 :
549 : // Sent for JS errors or warnings.
550 : - (oneway void)jsEngine:(in byref OOJavaScriptEngine *)engine
551 : context:(in JSContext *)context
552 : error:(in JSErrorReport *)errorReport
553 : stackSkip:(in unsigned)stackSkip
554 : showingLocation:(in BOOL)showLocation
555 : withMessage:(in NSString *)message;
556 :
557 : // Sent for JS log messages. Note: messageClass will be nil if Log() is used rather than LogWithClass().
558 : - (oneway void)jsEngine:(in byref OOJavaScriptEngine *)engine
559 : context:(in JSContext *)context
560 : logMessage:(in NSString *)message
561 : ofClass:(in NSString *)messageClass;
562 :
563 : @end
564 :
565 :
566 : @interface OOJavaScriptEngine (OOMonitorSupport)
567 :
568 : - (void)setMonitor:(id<OOJavaScriptEngineMonitor>)monitor;
569 :
570 : @end
571 :
572 : #endif
573 :
574 :
575 : #import "OOJSEngineNativeWrappers.h"
576 :
577 : /* See comments on time limiter in OOJSEngineTimeManagement.h.
578 : */
579 0 : void OOJSPauseTimeLimiter(void);
580 0 : void OOJSResumeTimeLimiter(void);
581 :
582 :
583 : /* OOJSDumpStack()
584 : Write JavaScript stack to log.
585 :
586 : OOJSDescribeLocation()
587 : Get script and line number for a stack frame.
588 :
589 : OOJSMarkConsoleEvalLocation()
590 : Specify that a given stack frame identifies eval()ed code from the debug
591 : console, so that matching locations can be described specially by
592 : OOJSDescribeLocation().
593 : */
594 : #ifndef NDEBUG
595 0 : void OOJSDumpStack(JSContext *context);
596 :
597 0 : NSString *OOJSDescribeLocation(JSContext *context, JSStackFrame *stackFrame);
598 0 : void OOJSMarkConsoleEvalLocation(JSContext *context, JSStackFrame *stackFrame);
599 : #else
600 : #define OOJSDumpStack(cx) do {} while (0)
601 : #define OOJSDescribeLocation(cx, frame) do {} while (0)
602 : #define OOJSMarkConsoleEvalLocation(cx, frame) do {} while (0)
603 : #endif
604 :
605 :
606 :
607 :
608 : /***** Reusable JS callbacks ****/
609 :
610 : /* OOJSUnconstructableConstruct
611 :
612 : Constructor callback for pseudo-classes which can't be constructed.
613 : */
614 0 : JSBool OOJSUnconstructableConstruct(JSContext *context, uintN argc, jsval *vp);
615 :
616 :
617 : /* OOJSObjectWrapperFinalize
618 :
619 : Finalizer for JS classes whose private storage is a retained object
620 : reference (generally an OOWeakReference, but doesn't have to be).
621 : */
622 0 : void OOJSObjectWrapperFinalize(JSContext *context, JSObject *this);
623 :
624 :
625 : /* OOJSObjectWrapperToString
626 :
627 : Implementation of toString() for JS classes whose private storage is an
628 : Objective-C object reference (generally an OOWeakReference).
629 :
630 : Calls -oo_jsDescription and, if that fails, -description.
631 : */
632 0 : JSBool OOJSObjectWrapperToString(JSContext *context, uintN argc, jsval *vp);
633 :
634 :
635 :
636 : /***** Appropriate flags for host-defined read/write and read-only properties *****/
637 :
638 : // Slot-based (defined with JS_Define{Property/Object/Function}() and no callbacks)
639 0 : #define OOJS_PROP_READWRITE (JSPROP_PERMANENT | JSPROP_ENUMERATE)
640 0 : #define OOJS_PROP_READONLY (JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY)
641 :
642 : // Non-enumerable properties
643 0 : #define OOJS_PROP_HIDDEN_READWRITE (JSPROP_PERMANENT)
644 0 : #define OOJS_PROP_HIDDEN_READONLY (JSPROP_PERMANENT | JSPROP_READONLY)
645 :
646 : // Methods should be non-enumerable
647 0 : #define OOJS_METHOD_READONLY OOJS_PROP_HIDDEN_READONLY
648 :
649 : // Callback-based (includes all properties specified in JSPropertySpecs)
650 0 : #define OOJS_PROP_READWRITE_CB (OOJS_PROP_READWRITE | JSPROP_SHARED)
651 0 : #define OOJS_PROP_READONLY_CB (OOJS_PROP_READONLY | JSPROP_SHARED)
652 :
653 0 : #define OOJS_PROP_HIDDEN_READWRITE_CB (OOJS_PROP_HIDDEN_READWRITE | JSPROP_SHARED)
654 0 : #define OOJS_PROP_HIDDEN_READONLY_CB (OOJS_PROP_HIDDEN_READONLY | JSPROP_SHARED)
655 :
656 :
657 :
658 :
659 : /***** Helpers for native callbacks. *****/
660 0 : #define OOJS_THIS JS_THIS_OBJECT(context, vp)
661 0 : #define OOJS_ARGV JS_ARGV(context, vp)
662 0 : #define OOJS_RVAL JS_RVAL(context, vp)
663 0 : #define OOJS_SET_RVAL(v) JS_SET_RVAL(context, vp, v)
664 :
665 0 : #define OOJS_RETURN(v) do { OOJS_SET_RVAL(v); return YES; } while (0)
666 0 : #define OOJS_RETURN_JSOBJECT(o) OOJS_RETURN(OBJECT_TO_JSVAL(o))
667 0 : #define OOJS_RETURN_VOID OOJS_RETURN(JSVAL_VOID)
668 0 : #define OOJS_RETURN_NULL OOJS_RETURN(JSVAL_NULL)
669 0 : #define OOJS_RETURN_BOOL(v) OOJS_RETURN(OOJSValueFromBOOL(v))
670 0 : #define OOJS_RETURN_INT(v) OOJS_RETURN(INT_TO_JSVAL(v))
671 0 : #define OOJS_RETURN_OBJECT(o) OOJS_RETURN(OOJSValueFromNativeObject(context, o))
672 :
673 0 : #define OOJS_RETURN_WITH_HELPER(helper, value) \
674 : do { \
675 : jsval jsresult; \
676 : BOOL OK = helper(context, value, &jsresult); \
677 : JS_SET_RVAL(context, vp, jsresult); return OK; \
678 : } while (0)
679 :
680 0 : #define OOJS_RETURN_VECTOR(value) OOJS_RETURN_WITH_HELPER(VectorToJSValue, value)
681 0 : #define OOJS_RETURN_HPVECTOR(value) OOJS_RETURN_WITH_HELPER(HPVectorToJSValue, value)
682 0 : #define OOJS_RETURN_QUATERNION(value) OOJS_RETURN_WITH_HELPER(QuaternionToJSValue, value)
683 0 : #define OOJS_RETURN_DOUBLE(value) OOJS_RETURN_WITH_HELPER(JS_NewNumberValue, value)
|