Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOJSMissionVariables.m
Go to the documentation of this file.
1/*
2
3OOJSMissionVariables.h
4
5JavaScript mission variables object.
6
7
8Oolite
9Copyright (C) 2004-2013 Giles C Williams and contributors
10
11This program is free software; you can redistribute it and/or
12modify it under the terms of the GNU General Public License
13as published by the Free Software Foundation; either version 2
14of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24MA 02110-1301, USA.
25
26*/
27
30#import "OOIsNumberLiteral.h"
31
32#import "OOJSPlayer.h"
33
34
35static NSString *KeyForPropertyID(JSContext *context, jsid propID)
36{
37 NSCParameterAssert(JSID_IS_STRING(propID));
38
39 NSString *key = OOStringFromJSString(context, JSID_TO_STRING(propID));
40 if ([key hasPrefix:@"_"]) return nil;
41 return [@"mission_" stringByAppendingString:key];
42}
43
44
45static JSBool MissionVariablesDeleteProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
46static JSBool MissionVariablesGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
47static JSBool MissionVariablesSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
48static JSBool MissionVariablesEnumerate(JSContext *context, JSObject *object, JSIterateOp enumOp, jsval *state, jsid *idp);
49
50#ifndef NDEBUG
51static id MissionVariablesConverter(JSContext *context, JSObject *object);
52#endif
53
54
55static JSClass sMissionVariablesClass =
56{
57 "MissionVariables",
58 JSCLASS_NEW_ENUMERATE,
59
60 JS_PropertyStub,
64 (JSEnumerateOp)MissionVariablesEnumerate,
65 JS_ResolveStub,
66 JS_ConvertStub,
67 JS_FinalizeStub
68};
69
70
71void InitOOJSMissionVariables(JSContext *context, JSObject *global)
72{
73 JS_DefineObject(context, global, "missionVariables", &sMissionVariablesClass, NULL, OOJS_PROP_READONLY);
74
75#ifndef NDEBUG
76 // Allow callObjC() on missionVariables to call methods on the mission variables dictionary.
78#endif
79}
80
81
82#ifndef NDEBUG
83static id MissionVariablesConverter(JSContext *context, JSObject *object)
84{
85 return [PLAYER missionVariables];
86}
87#endif
88
89
90static JSBool MissionVariablesDeleteProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
91{
92 OOJS_NATIVE_ENTER(context)
93
95
96 if (JSID_IS_STRING(propID))
97 {
98 NSString *key = KeyForPropertyID(context, propID);
99 [player setMissionVariable:nil forKey:key];
100 }
101 return YES;
102
104}
105
106
107static JSBool MissionVariablesGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
108{
109 OOJS_NATIVE_ENTER(context)
110
112
113 if (JSID_IS_STRING(propID))
114 {
115 NSString *key = KeyForPropertyID(context, propID);
116 if (key == nil) return YES;
117
118 id mvar = [player missionVariableForKey:key];
119
120 if ([mvar isKindOfClass:[NSString class]]) // Currently there should only be strings, but we may want to change this.
121 {
122 if (OOIsNumberLiteral(mvar, YES))
123 {
124 return JS_NewNumberValue(context, [mvar doubleValue], value);
125 }
126 }
127
128 *value = OOJSValueFromNativeObject(context, mvar);
129 }
130 return YES;
131
133}
134
135
136static JSBool MissionVariablesSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
137{
138 OOJS_NATIVE_ENTER(context)
139
141
142 if (JSID_IS_STRING(propID))
143 {
144 NSString *key = KeyForPropertyID(context, propID);
145 if (key == nil)
146 {
147 OOJSReportError(context, @"Invalid mission variable name \"%@\".", [OOStringFromJSID(propID) escapedForJavaScriptLiteral]);
148 return NO;
149 }
150
151 NSString *objValue = OOStringFromJSValue(context, *value);
152
153 if ([objValue isKindOfClass:[NSNull class]]) objValue = nil;
154 [player setMissionVariable:objValue forKey:key];
155 }
156 return YES;
157
159}
160
161
162static JSBool MissionVariablesEnumerate(JSContext *context, JSObject *object, JSIterateOp enumOp, jsval *state, jsid *idp)
163{
164 OOJS_NATIVE_ENTER(context)
165
166 NSEnumerator *enumerator = nil;
167
168 switch (enumOp)
169 {
170 case JSENUMERATE_INIT:
171 case JSENUMERATE_INIT_ALL: // For ES5 Object.getOwnPropertyNames(). Since we have no non-enumerable properties, this is the same as _INIT.
172 {
173 // -allKeys implicitly makes a copy, which is good since the enumerating code might mutate.
174 NSArray *mvars = [[PLAYER missionVariables] allKeys];
175 enumerator = [[mvars objectEnumerator] retain];
176 *state = PRIVATE_TO_JSVAL(enumerator);
177
178 NSUInteger count = [mvars count];
179 assert(count <= INT32_MAX);
180 if (idp != NULL) *idp = INT_TO_JSID((uint32_t)count);
181 return YES;
182 }
183
184 case JSENUMERATE_NEXT:
185 {
186 enumerator = JSVAL_TO_PRIVATE(*state);
187 for (;;)
188 {
189 NSString *next = [enumerator nextObject];
190 if (next == nil) break;
191 if (![next hasPrefix:@"mission_"]) continue; // Skip mission instructions, which aren't visible through missionVariables.
192
193 next = [next substringFromIndex:8]; // Cut off "mission_".
194
195 jsval val = [next oo_jsValueInContext:context];
196 return JS_ValueToId(context, val, idp);
197 }
198
199 // If we got here, we've hit the end of the enumerator.
200 *state = JSVAL_NULL;
201 // Fall through.
202 }
203
204 case JSENUMERATE_DESTROY:
205 {
206 if (enumerator == nil && JSVAL_IS_DOUBLE(*state))
207 {
208 enumerator = JSVAL_TO_PRIVATE(*state);
209 }
210 [enumerator release];
211
212 if (idp != NULL) *idp = JSID_VOID;
213 return YES;
214 }
215 }
216
218}
BOOL OOIsNumberLiteral(NSString *string, BOOL allowSpaces)
#define OOJS_NATIVE_ENTER(cx)
#define OOJS_NATIVE_EXIT
void InitOOJSMissionVariables(JSContext *context, JSObject *global)
static NSString * KeyForPropertyID(JSContext *context, jsid propID)
static JSBool MissionVariablesGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
static JSBool MissionVariablesSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
static JSBool MissionVariablesEnumerate(JSContext *context, JSObject *object, JSIterateOp enumOp, jsval *state, jsid *idp)
static id MissionVariablesConverter(JSContext *context, JSObject *object)
static JSBool MissionVariablesDeleteProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
static JSClass sMissionVariablesClass
PlayerEntity * OOPlayerForScripting(void)
Definition OOJSPlayer.m:191
NSString * OOStringFromJSID(jsid propID)
void OOJSRegisterObjectConverter(JSClass *theClass, OOJSClassConverterCallback converter)
OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)
NSString * OOStringFromJSValue(JSContext *context, jsval value)
#define OOJS_PROP_READONLY
void OOJSReportError(JSContext *context, NSString *format,...)
NSString * OOStringFromJSString(JSContext *context, JSString *string)
unsigned count
return nil
NSString * missionVariableForKey:(NSString *key)
void setMissionVariable:forKey:(NSString *value,[forKey] NSString *key)