Line data Source code
1 0 : /*
2 :
3 : OOJSFunction.m
4 :
5 :
6 : JavaScript support for Oolite
7 : Copyright (C) 2007-2013 David Taylor and Jens Ayton.
8 :
9 : This program is free software; you can redistribute it and/or
10 : modify it under the terms of the GNU General Public License
11 : as published by the Free Software Foundation; either version 2
12 : of the License, or (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program; if not, write to the Free Software
21 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 : MA 02110-1301, USA.
23 :
24 : */
25 :
26 : #import "OOJSFunction.h"
27 : #import "OOJSScript.h"
28 : #import "OOJSEngineTimeManagement.h"
29 :
30 :
31 : @implementation OOJSFunction
32 :
33 : - (id) initWithFunction:(JSFunction *)function context:(JSContext *)context
34 : {
35 : NSParameterAssert(context != NULL);
36 :
37 : if (function == NULL)
38 : {
39 : [self release];
40 : return nil;
41 : }
42 :
43 : if ((self = [super init]))
44 : {
45 : _function = function;
46 : OOJSAddGCObjectRoot(context, (JSObject **)&_function, "OOJSFunction._function");
47 : _name = [OOStringFromJSString(context, JS_GetFunctionId(function)) retain];
48 :
49 : [[NSNotificationCenter defaultCenter] addObserver:self
50 : selector:@selector(deleteJSValue)
51 : name:kOOJavaScriptEngineWillResetNotification
52 : object:[OOJavaScriptEngine sharedEngine]];
53 : }
54 :
55 : return self;
56 : }
57 :
58 :
59 : - (id) initWithName:(NSString *)name
60 : scope:(JSObject *)scope
61 : code:(NSString *)code
62 : argumentCount:(NSUInteger)argCount
63 : argumentNames:(const char **)argNames
64 : fileName:(NSString *)fileName
65 : lineNumber:(NSUInteger)lineNumber
66 : context:(JSContext *)context
67 : {
68 : BOOL OK = YES;
69 : BOOL releaseContext = NO;
70 : jschar *buffer = NULL;
71 : size_t length = 0;
72 : JSFunction *function;
73 :
74 : if (context == NULL)
75 : {
76 : context = OOJSAcquireContext();
77 : releaseContext = YES;
78 : }
79 : if (scope == NULL) scope = [[OOJavaScriptEngine sharedEngine] globalObject];
80 :
81 : if (code == nil || (argCount > 0 && argNames == NULL)) OK = NO;
82 :
83 : if (OK)
84 : {
85 : // jschar and unichar are both defined to be 16-bit elements.
86 : assert(sizeof(jschar) == sizeof(unichar));
87 :
88 : length = [code length];
89 : buffer = malloc(sizeof(jschar) * length);
90 : if (buffer == NULL) OK = NO;
91 : }
92 :
93 : if (OK)
94 : {
95 : assert(argCount < UINT32_MAX);
96 :
97 : [code getCharacters:buffer];
98 :
99 : function = JS_CompileUCFunction(context, scope, [name UTF8String], (uint32_t)argCount, argNames, buffer, length, [fileName UTF8String], (uint32_t)lineNumber);
100 : if (function == NULL) OK = NO;
101 :
102 : free(buffer);
103 : }
104 :
105 : if (OK)
106 : {
107 : self = [self initWithFunction:function context:context];
108 : }
109 : else
110 : {
111 : DESTROY(self);
112 : }
113 :
114 : if (releaseContext) OOJSRelinquishContext(context);
115 :
116 : return self;
117 : }
118 :
119 :
120 0 : - (void) deleteJSValue
121 : {
122 : if (_function != NULL)
123 : {
124 : JSContext *context = OOJSAcquireContext();
125 : JS_RemoveObjectRoot(context, (JSObject **)&_function);
126 : OOJSRelinquishContext(context);
127 :
128 : _function = NULL;
129 : [[NSNotificationCenter defaultCenter] removeObserver:self
130 : name:kOOJavaScriptEngineWillResetNotification
131 : object:[OOJavaScriptEngine sharedEngine]];
132 : }
133 : }
134 :
135 :
136 0 : - (void) dealloc
137 : {
138 : [self deleteJSValue];
139 : DESTROY(_name);
140 :
141 : [super dealloc];
142 : }
143 :
144 :
145 0 : - (NSString *) descriptionComponents
146 : {
147 : NSString *name = [self name];
148 : if (name == nil) name = @"<anonymous>";
149 : return [NSString stringWithFormat:@"%@()", name];
150 : }
151 :
152 :
153 : - (NSString *) name
154 : {
155 : return _name;
156 : }
157 :
158 :
159 : - (JSFunction *) function
160 : {
161 : return _function;
162 : }
163 :
164 :
165 : - (jsval) functionValue
166 : {
167 : if (EXPECT(_function != NULL))
168 : {
169 : return OBJECT_TO_JSVAL(JS_GetFunctionObject(_function));
170 : }
171 : else
172 : {
173 : return JSVAL_NULL;
174 : }
175 :
176 : }
177 :
178 :
179 : - (BOOL) evaluateWithContext:(JSContext *)context
180 : scope:(JSObject *)jsThis
181 : argc:(uintN)argc
182 : argv:(jsval *)argv
183 : result:(jsval *)result
184 : {
185 : [OOJSScript pushScript:nil];
186 : OOJSStartTimeLimiter();
187 : BOOL OK = JS_CallFunction(context, jsThis, _function, argc, argv, result);
188 : OOJSStopTimeLimiter();
189 : [OOJSScript popScript:nil];
190 :
191 : return OK;
192 : }
193 :
194 : // Semi-raw evaluation shared by convenience methods below.
195 0 : - (BOOL) evaluateWithContext:(JSContext *)context
196 : scope:(id)jsThis
197 : arguments:(NSArray *)arguments
198 : result:(jsval *)result
199 : {
200 : NSUInteger i, argc = [arguments count];
201 : assert(argc < UINT32_MAX);
202 : jsval argv[argc];
203 :
204 : for (i = 0; i < argc; i++)
205 : {
206 : argv[i] = [[arguments objectAtIndex:i] oo_jsValueInContext:context];
207 : OOJSAddGCValueRoot(context, &argv[i], "OOJSFunction argv");
208 : }
209 :
210 : JSObject *scopeObj = NULL;
211 : BOOL OK = YES;
212 : if (jsThis != nil) OK = JS_ValueToObject(context, [jsThis oo_jsValueInContext:context], &scopeObj);
213 : if (OK) OK = [self evaluateWithContext:context
214 : scope:scopeObj
215 : argc:(uint32_t)argc
216 : argv:argv
217 : result:result];
218 :
219 : for (i = 0; i < argc; i++)
220 : {
221 : JS_RemoveValueRoot(context, &argv[i]);
222 : }
223 :
224 : return OK;
225 : }
226 :
227 :
228 : - (id) evaluateWithContext:(JSContext *)context
229 : scope:(id)jsThis
230 : arguments:(NSArray *)arguments
231 : {
232 : jsval result;
233 : BOOL OK = [self evaluateWithContext:context
234 : scope:jsThis
235 : arguments:arguments
236 : result:&result];
237 : if (!OK) return nil;
238 :
239 : return OOJSNativeObjectFromJSValue(context, result);
240 : }
241 :
242 :
243 : - (BOOL) evaluatePredicateWithContext:(JSContext *)context
244 : scope:(id)jsThis
245 : arguments:(NSArray *)arguments
246 : {
247 : jsval result;
248 : BOOL OK = [self evaluateWithContext:context
249 : scope:jsThis
250 : arguments:arguments
251 : result:&result];
252 : JSBool retval = NO;
253 : if (OK) OK = JS_ValueToBoolean(context, result, &retval);
254 : return OK && retval;
255 : }
256 :
257 : @end
|