Skip to content

Commit 9089e8c

Browse files
committed
Only missing: evalInExpression()
1 parent 45e75bd commit 9089e8c

File tree

2 files changed

+200
-13
lines changed

2 files changed

+200
-13
lines changed

JawaScriptExecutive-iOS/JawaExecutor.m

Lines changed: 178 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,171 @@ -(NSMutableDictionary*)invoke:(NSString *)funcName with:(NSMutableDictionary*)as
119119
return retJSON;
120120
}
121121

122+
-(int)toInteger:(JawaObjectRef*)o {
123+
if ([o.object isMemberOfClass:[NSDecimalNumber class]]) {
124+
double d = ((NSDecimalNumber*)o.object).doubleValue;
125+
int magnitude = (int)(long)floor(fabs(d));
126+
int sign = d >= 0 ? 1 : -1;
127+
return magnitude * sign;
128+
}
129+
[NSException raise:@"JawaScript Runtime Exception" format:@"Not yet implemented conversion"];
130+
return -1;
131+
}
132+
133+
-(JawaObjectRef*)evalInExpression:(NSDictionary*)ast {
134+
return nil;
135+
}
136+
137+
-(JawaObjectRef*)evalUnaryExpression:(NSDictionary*)ast {
138+
NSString* op = [[((NSString*)[ast objectForKey:PR_op]) componentsSeparatedByString:@","]objectAtIndex:1];
139+
JawaObjectRef* subExpression = [self evaluate:[ast objectForKey:PR_subExpression]];
140+
if (subExpression == nil)
141+
[NSException raise:@"JawaScript Runtime Exception" format:@"Unary op cannot be applied to null"];
142+
if ([op isEqualToString:@"++"] || [op isEqualToString:@"--"]) {
143+
if (![subExpression.object isMemberOfClass:[NSDecimalNumber class]])
144+
[NSException raise:@"JawaScript Runtime Exception" format:@"++ and -- only apply to numbers"];
145+
double d = ((NSDecimalNumber*)subExpression.object).doubleValue;
146+
subExpression.object = [NSDecimalNumber numberWithDouble:d + (([op isEqualToString:@"++"]) ? 1 : -1)];
147+
return subExpression;
148+
} else if([op isEqualToString:@"-"]) {
149+
if (![subExpression.object isMemberOfClass:[NSDecimalNumber class]])
150+
[NSException raise:@"JawaScript Runtime Exception" format:@"- only applies to numbers"];
151+
double d = ((NSDecimalNumber*)subExpression.object).doubleValue;
152+
return [JawaObjectRef RefWithNumber:-d in:self];
153+
} else if([op isEqualToString:@"~"]) {
154+
if (![subExpression.object isMemberOfClass:[NSDecimalNumber class]])
155+
[NSException raise:@"JawaScript Runtime Exception" format:@"- only applies to numbers"];
156+
int truncated = [self toInteger:subExpression];
157+
return [JawaObjectRef RefWithNumber:~truncated in:self];
158+
} else if([op isEqualToString:@"!"]) {
159+
if (![subExpression.object isMemberOfClass:[NSDecimalNumber class]])
160+
[NSException raise:@"JawaScript Runtime Exception" format:@"- only applies to numbers"];
161+
bool b = ((NSDecimalNumber*)subExpression.object).boolValue;
162+
return [JawaObjectRef RefWithBoolean:!b in:self];
163+
}
164+
return nil;
165+
}
166+
167+
-(JawaObjectRef*)evalAndExpression:(NSDictionary*)ast {
168+
NSArray* oprnds = [ast objectForKey:PR_subExpressions];
169+
170+
JawaObjectRef* firstOprnd = [self evaluate:[oprnds objectAtIndex:0]];
171+
for (NSUInteger i = 1 ; i < oprnds.count ; i++) {
172+
JawaObjectRef* secondOprnd = [self evaluate:[oprnds objectAtIndex:i]];
173+
if (firstOprnd == nil || secondOprnd == nil ||
174+
![firstOprnd.object isMemberOfClass:[NSDecimalNumber class]] ||
175+
![secondOprnd.object isMemberOfClass:[NSDecimalNumber class] ])
176+
[NSException raise:@"JawaScript Runtime Exception" format:@"& applies to only numbers"];
177+
int l = [self toInteger:firstOprnd];
178+
int r = [self toInteger:secondOprnd];
179+
firstOprnd = [JawaObjectRef RefWithNumber:l & r in:self];
180+
}
181+
return firstOprnd;
182+
}
183+
184+
-(JawaObjectRef*)evalExclusiveOrExpression:(NSDictionary*)ast {
185+
NSArray* oprnds = [ast objectForKey:PR_subExpressions];
186+
187+
JawaObjectRef* firstOprnd = [self evaluate:[oprnds objectAtIndex:0]];
188+
for (NSUInteger i = 1 ; i < oprnds.count ; i++) {
189+
JawaObjectRef* secondOprnd = [self evaluate:[oprnds objectAtIndex:i]];
190+
if (firstOprnd == nil || secondOprnd == nil ||
191+
![firstOprnd.object isMemberOfClass:[NSDecimalNumber class]] ||
192+
![secondOprnd.object isMemberOfClass:[NSDecimalNumber class] ])
193+
[NSException raise:@"JawaScript Runtime Exception" format:@"^ applies to only numbers"];
194+
int l = [self toInteger:firstOprnd];
195+
int r = [self toInteger:secondOprnd];
196+
firstOprnd = [JawaObjectRef RefWithNumber:l ^ r in:self];
197+
}
198+
return firstOprnd;
199+
}
200+
201+
-(JawaObjectRef*)evalInclusiveOrExpression:(NSDictionary*)ast {
202+
NSArray* oprnds = [ast objectForKey:PR_subExpressions];
203+
204+
JawaObjectRef* firstOprnd = [self evaluate:[oprnds objectAtIndex:0]];
205+
for (NSUInteger i = 1 ; i < oprnds.count ; i++) {
206+
JawaObjectRef* secondOprnd = [self evaluate:[oprnds objectAtIndex:i]];
207+
if (firstOprnd == nil || secondOprnd == nil ||
208+
![firstOprnd.object isMemberOfClass:[NSDecimalNumber class]] ||
209+
![secondOprnd.object isMemberOfClass:[NSDecimalNumber class] ])
210+
[NSException raise:@"JawaScript Runtime Exception" format:@"| applies to only numbers"];
211+
int l = [self toInteger:firstOprnd];
212+
int r = [self toInteger:secondOprnd];
213+
firstOprnd = [JawaObjectRef RefWithNumber:l | r in:self];
214+
}
215+
return firstOprnd;
216+
}
217+
218+
-(JawaObjectRef*)execContinueStatement:(NSDictionary*)ast {
219+
[self.currentIterationScope setObject:NULL_CONSTANT forKey:@"continue"];
220+
return nil;
221+
}
222+
223+
-(JawaObjectRef*)execBreakStatement:(NSDictionary*)ast {
224+
[self.currentIterationScope setObject:NULL_CONSTANT forKey:@"break"];
225+
return nil;
226+
}
227+
228+
-(JawaObjectRef*)execWhileStatement:(NSDictionary*)ast {
229+
NSDictionary* body = [ast objectForKey:PR_body];
230+
NSDictionary* test = [ast objectForKey:PR_test];
231+
NSMutableDictionary* scope = [[NSMutableDictionary alloc]init];
232+
[self.currentActivation addObject:scope];
233+
NSMutableDictionary* outerIterationScope = self.currentIterationScope;
234+
self.currentIterationScope = scope;
235+
236+
while (true) {
237+
JawaObjectRef* cond = [self evaluate:test];
238+
if (!(cond != nil && [cond.object isKindOfClass:[NSNumber class]] && ((NSNumber*)cond.object).boolValue))
239+
break;
240+
[self evaluate:body];
241+
if ([[self.currentActivation objectAtIndex:0]objectForKey:@"return"] != nil)
242+
break;
243+
if ([self.currentIterationScope objectForKey:@"break"] != nil)
244+
break;
245+
if ([self.currentIterationScope objectForKey:@"continue"] != nil)
246+
[self.currentIterationScope removeObjectForKey:@"continue"];
247+
}
248+
249+
self.currentIterationScope = outerIterationScope;
250+
[self.currentActivation removeLastObject];
251+
return nil;
252+
}
253+
254+
-(JawaObjectRef*)execDoWhileStatement:(NSDictionary*)ast {
255+
NSDictionary* body = [ast objectForKey:PR_body];
256+
NSDictionary* test = [ast objectForKey:PR_test];
257+
NSMutableDictionary* scope = [[NSMutableDictionary alloc]init];
258+
[self.currentActivation addObject:scope];
259+
NSMutableDictionary* outerIterationScope = self.currentIterationScope;
260+
self.currentIterationScope = scope;
261+
262+
JawaObjectRef* cond;
263+
do {
264+
[self evaluate:body];
265+
if ([[self.currentActivation objectAtIndex:0]objectForKey:@"return"] != nil)
266+
break;
267+
if ([self.currentIterationScope objectForKey:@"break"] != nil)
268+
break;
269+
if ([self.currentIterationScope objectForKey:@"continue"] != nil)
270+
[self.currentIterationScope removeObjectForKey:@"continue"];
271+
cond = [self evaluate:test];
272+
} while (cond != nil && [cond.object isKindOfClass:[NSNumber class]] && ((NSNumber*)cond.object).boolValue);
273+
self.currentIterationScope = outerIterationScope;
274+
[self.currentActivation removeLastObject];
275+
return nil;
276+
}
277+
278+
-(JawaObjectRef*)evalSequenceExpression:(NSDictionary*)ast {
279+
NSArray* expressions = [ast objectForKey:PR_expressions];
280+
JawaObjectRef* ret = nil;
281+
for(NSDictionary *expr in expressions) {
282+
ret = [self evaluate:expr];
283+
}
284+
return ret;
285+
}
286+
122287
-(JawaObjectRef*)evalConditionalExpression:(NSDictionary*)ast {
123288
JawaObjectRef* test = [self evaluate:[ast objectForKey:PR_condition]];
124289
if (test == nil)
@@ -480,7 +645,7 @@ -(JawaObjectRef*)evalComputedMemberExpression:(NSDictionary*)ast {
480645
} else {
481646
return [((JawaArray*)object.object) getProp:[property description]];
482647
}
483-
} else if ([object.object isMemberOfClass:[NSMutableString class]]) {
648+
} else if ([object.object isKindOfClass:[NSString class]]) {
484649
if ([property.object isMemberOfClass:[NSDecimalNumber class]]) {
485650
double v = ((NSDecimalNumber*)property.object).doubleValue;
486651
if (fabs(v-round(v)) < QUANTUM) {
@@ -780,7 +945,7 @@ -(JawaObjectRef*)execForStatement:(NSDictionary*)ast {
780945

781946
if (iterable == nil)
782947
[NSException raise:@"JawaScript Runtime Exception" format:@"Null is not iterable"];
783-
if ([iterable.object isMemberOfClass:[NSMutableString class]]) {
948+
if ([iterable.object isKindOfClass:[NSString class]]) {
784949
NSUInteger len = ((NSString*)iterable.object).length;
785950
for (NSUInteger i = 0 ; i < len ; i++) {
786951
[scope setObject:[JawaObjectRef RefWithNumber:i in:self] forKey:iterator];
@@ -914,9 +1079,9 @@ -(JawaObjectRef*)evaluate:(NSDictionary *)tree {
9141079
case BLOCK_STATEMENT:
9151080
return [self evalBlockStatement:tree];
9161081
case EMPTY_STATEMENT:
917-
break;
1082+
return nil;
9181083
case SEQUENCE_EXPRESSION:
919-
break;
1084+
return [self evalSequenceExpression:tree];
9201085
case ASSIGNMENT_EXPRESSION:
9211086
return [self evalAssignmentExpression:tree];
9221087
case CONDITIONAL_EXPRESSION:
@@ -926,25 +1091,25 @@ -(JawaObjectRef*)evaluate:(NSDictionary *)tree {
9261091
case LOGICAL_AND_EXPRESSION:
9271092
return [self evalLogicalAndExpression:tree];
9281093
case INCLUSIVE_OR_EXPRESSION:
929-
break;
1094+
return [self evalInclusiveOrExpression:tree];
9301095
case EXCLUSIVE_OR_EXPRESSION:
931-
break;
1096+
return [self evalExclusiveOrExpression:tree];
9321097
case AND_EXPRESSION:
933-
break;
1098+
return [self evalAndExpression:tree];
9341099
case EQUALITY_EXPRESSION:
9351100
return [self evalEqualityExpression:tree];
9361101
case RELATIONAL_EXPRESSION:
9371102
return [self evalRelationalExpression:tree];
9381103
case IN_EXPRESSION:
939-
break;
1104+
return [self evalInExpression:tree];
9401105
case SHIFT_EXPRESSION:
9411106
return [self evalShiftExpression:tree];
9421107
case ADDITIVE_EXPRESSION:
9431108
return [self evalAdditiveExpression:tree];
9441109
case MULTIPLICATIVE_EXPRESSION:
9451110
return [self evalMultiplicativeExpression:tree];
9461111
case UNARY_EXPRESSION:
947-
break;
1112+
return [self evalUnaryExpression:tree];
9481113
case POSTFIX_EXPRESSION:
9491114
return [self evalPostfixExpression:tree];
9501115
case STATIC_MEMBER_EXPRESSION:
@@ -966,13 +1131,13 @@ -(JawaObjectRef*)evaluate:(NSDictionary *)tree {
9661131
case VAR_STATEMENT:
9671132
return [self execVarStatement:tree];
9681133
case WHILE_STATEMENT:
969-
break;
1134+
return [self execWhileStatement:tree];
9701135
case CONTINUE_STATEMENT:
971-
break;
1136+
return [self execContinueStatement:tree];
9721137
case BREAK_STATEMENT:
973-
break;
1138+
return [self execBreakStatement:tree];
9741139
case DO_WHILE_STATEMENT:
975-
break;
1140+
return [self execDoWhileStatement:tree];
9761141
case FOR_STATEMENT:
9771142
return [self execForStatement:tree];
9781143
case VARIABLE_DECLARATION:

JawaScriptExecutive-iOS/test.m

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,27 @@ BOOL test6() {
115115
return true;
116116
}
117117

118+
BOOL test7() {
119+
JawaExecutor* ex = [[JawaExecutor alloc]init];
120+
NSString *parsed = @"{\"t\":0,\"0\":[{\"t\":1,\"3\":\"test\",\"23\":[],\"24\":{\"t\":2,\"0\":[{\"t\":37,\"33\":[{\"t\":34,\"26\":\"ret\",\"27\":{\"t\":25,\"8\":\"STRING_LITERAL,\"}}]},{\"t\":37,\"33\":[{\"t\":34,\"26\":\"i\",\"27\":{\"t\":25,\"8\":\"NUMERIC_LITERAL,0.0\"}}]},{\"t\":31,\"24\":{\"t\":2,\"0\":[{\"t\":5,\"14\":\"PUNCTUATOR,+=\",\"20\":{\"t\":24,\"3\":\"i\"},\"21\":{\"t\":25,\"8\":\"NUMERIC_LITERAL,1.0\"}},{\"t\":5,\"14\":\"PUNCTUATOR,+=\",\"20\":{\"t\":24,\"3\":\"ret\"},\"21\":{\"t\":16,\"15\":[{\"t\":5,\"v\":\"+\"}],\"16\":[{\"t\":25,\"8\":\"STRING_LITERAL, \"},{\"t\":24,\"3\":\"i\"}]}}]},\"25\":{\"t\":13,\"15\":[{\"t\":5,\"v\":\"<\"}],\"16\":[{\"t\":24,\"3\":\"i\"},{\"t\":25,\"8\":\"NUMERIC_LITERAL,5.0\"}]}},{\"t\":35,\"18\":{\"t\":2,\"0\":[{\"t\":5,\"14\":\"PUNCTUATOR,+=\",\"20\":{\"t\":24,\"3\":\"ret\"},\"21\":{\"t\":25,\"8\":\"STRING_LITERAL, Even\"}}]},\"19\":{\"t\":2,\"0\":[{\"t\":5,\"14\":\"PUNCTUATOR,+=\",\"20\":{\"t\":24,\"3\":\"ret\"},\"21\":{\"t\":25,\"8\":\"STRING_LITERAL, Odd\"}}]},\"25\":{\"t\":12,\"15\":[{\"t\":5,\"v\":\"==\"}],\"16\":[{\"t\":17,\"15\":[{\"t\":5,\"v\":\"%\"}],\"16\":[{\"t\":24,\"3\":\"i\"},{\"t\":25,\"8\":\"NUMERIC_LITERAL,2.0\"}]},{\"t\":25,\"8\":\"NUMERIC_LITERAL,0.0\"}]}},{\"t\":37,\"33\":[{\"t\":34,\"26\":\"str\",\"27\":{\"t\":25,\"8\":\"STRING_LITERAL,ABCDE\"}}]},{\"t\":33,\"24\":{\"t\":2,\"0\":[{\"t\":5,\"14\":\"PUNCTUATOR,+=\",\"20\":{\"t\":24,\"3\":\"ret\"},\"21\":{\"t\":16,\"15\":[{\"t\":5,\"v\":\"+\"}],\"16\":[{\"t\":25,\"8\":\"STRING_LITERAL, \"},{\"t\":22,\"10\":{\"t\":24,\"3\":\"str\"},\"11\":{\"t\":24,\"3\":\"c\"}}]}}]},\"29\":{\"t\":32,\"26\":\"c\",\"28\":{\"t\":24,\"3\":\"str\"}}},{\"t\":38,\"24\":{\"t\":2,\"0\":[{\"t\":35,\"18\":{\"t\":2,\"0\":[{\"t\":5,\"14\":\"PUNCTUATOR,+=\",\"20\":{\"t\":24,\"3\":\"i\"},\"21\":{\"t\":25,\"8\":\"NUMERIC_LITERAL,1.0\"}},{\"t\":30}]},\"25\":{\"t\":12,\"15\":[{\"t\":5,\"v\":\"==\"}],\"16\":[{\"t\":17,\"15\":[{\"t\":5,\"v\":\"%\"}],\"16\":[{\"t\":24,\"3\":\"i\"},{\"t\":25,\"8\":\"NUMERIC_LITERAL,20.0\"}]},{\"t\":25,\"8\":\"NUMERIC_LITERAL,0.0\"}]}},{\"t\":35,\"18\":{\"t\":5,\"14\":\"PUNCTUATOR,+=\",\"20\":{\"t\":24,\"3\":\"ret\"},\"21\":{\"t\":16,\"15\":[{\"t\":5,\"v\":\"+\"}],\"16\":[{\"t\":25,\"8\":\"STRING_LITERAL, \"},{\"t\":24,\"3\":\"i\"}]}},\"25\":{\"t\":12,\"15\":[{\"t\":5,\"v\":\"==\"}],\"16\":[{\"t\":17,\"15\":[{\"t\":5,\"v\":\"%\"}],\"16\":[{\"t\":24,\"3\":\"i\"},{\"t\":25,\"8\":\"NUMERIC_LITERAL,5.0\"}]},{\"t\":25,\"8\":\"NUMERIC_LITERAL,0.0\"}]}},{\"t\":35,\"18\":{\"t\":29},\"25\":{\"t\":12,\"15\":[{\"t\":5,\"v\":\"==\"}],\"16\":[{\"t\":24,\"3\":\"i\"},{\"t\":25,\"8\":\"NUMERIC_LITERAL,79.0\"}]}},{\"t\":5,\"14\":\"PUNCTUATOR,+=\",\"20\":{\"t\":24,\"3\":\"i\"},\"21\":{\"t\":25,\"8\":\"NUMERIC_LITERAL,1.0\"}}]},\"25\":{\"t\":13,\"15\":[{\"t\":5,\"v\":\"<\"}],\"16\":[{\"t\":24,\"3\":\"i\"},{\"t\":25,\"8\":\"NUMERIC_LITERAL,100.0\"}]}},{\"t\":5,\"14\":\"PUNCTUATOR,+=\",\"20\":{\"t\":24,\"3\":\"ret\"},\"21\":{\"t\":16,\"15\":[{\"t\":5,\"v\":\"+\"}],\"16\":[{\"t\":25,\"8\":\"STRING_LITERAL, \"},{\"t\":24,\"3\":\"i\"}]}},{\"t\":36,\"32\":{\"t\":24,\"3\":\"ret\"}}]}}]}";
121+
122+
NSDictionary* prog = jsonToDictionary(parsed);
123+
NSString *answer = @"{\"retType\":\"string\",\"retValue\":\" 1 2 3 4 5 Odd A B C D E 5 10 15 25 30 35 45 50 55 65 70 75 79\"}";
124+
125+
[ex execute:prog];
126+
NSMutableDictionary* result = [ex invoke:@"test" with:nil];
127+
NSString *actual = dictionaryToJSON(result);
128+
129+
if (![actual isEqualToString:answer]) {
130+
printf("Test 7 failed!\n");
131+
printf("Expected : %s\n", [answer UTF8String]);
132+
printf("Actual : %s\n", [actual UTF8String]);
133+
return false;
134+
}
135+
printf("Test 7 passed.\n");
136+
return true;
137+
}
138+
118139
int main(int argc, char *argv[]) {
119140
@autoreleasepool {
120141
if (!test1()) return -1;
@@ -123,6 +144,7 @@ int main(int argc, char *argv[]) {
123144
if (!test4()) return -1;
124145
if (!test5()) return -1;
125146
if (!test6()) return -1;
147+
if (!test7()) return -1;
126148
}
127149
return 0;
128150
}

0 commit comments

Comments
 (0)