blob: c24e9d3efe6d4b446e561aaa99e2ecde53388c8a [file] [log] [blame]
/**
* Copyright 2018 Alibaba Group
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <math.h>
#import "EBExpression.h"
#import "EBNativeFunction.h"
@implementation EBExpression
-(id)initWithRoot:(NSDictionary*)root {
if(self=[super init])
{
_root = root;
}
return self;
}
- (NSObject*)executeInScope:(NSDictionary *)scope {
return [self executeNodeInScope:scope node:_root];
}
- (double)toNumber:(NSObject*)value {
if([value isKindOfClass:[NSNumber class]]) {
return [(NSNumber*)value doubleValue];
}
if([value isKindOfClass:[NSString class]]) {
return [(NSString *)value doubleValue];
}
return NAN;
}
- (BOOL)toBool:(NSObject*)value {
if([value isKindOfClass:[NSNumber class]]) {
return [(NSNumber*)value boolValue] > 0;
}
if([value isKindOfClass:[NSString class]]) {
return [(NSString *)value boolValue] > 0;
}
return false;
}
- (NSNumber*)toBoolean:(NSObject*)value {
if([value isKindOfClass:[NSNumber class]]) {
return @([(NSNumber*)value boolValue]);
}
if([value isKindOfClass:[NSString class]]) {
return @([(NSString *)value boolValue]);
}
return nil;
}
- (NSObject*)executeNodeInScope:(NSDictionary *)scope node:(NSDictionary*)node {
NSString* type = [node objectForKey:@"type"];
NSArray* children = [node objectForKey:@"children"];
if([type isEqualToString:@"Identifier"]) {
return [scope objectForKey:[node objectForKey:@"value"]];
} else if([type isEqualToString:@"StringLiteral"]) {
return [node objectForKey:@"value"];
} else if([type isEqualToString:@"NumericLiteral"]) {
return [node objectForKey:@"value"];
} else if([type isEqualToString:@"BooleanLiteral"]) {
return [node objectForKey:@"value"];
} else if([type isEqualToString:@"CallExpression"]) {
NSArray* argumentNodes = [children[1] objectForKey:@"children"];
NSMutableArray* arguments = [[NSMutableArray alloc] init];
for(int i = 0; i < [argumentNodes count]; i++)
arguments[i] = [self executeNodeInScope:scope node:argumentNodes[i]];//TODO:Identifier nil check
return [(EBNativeFunction *)[self executeNodeInScope:scope node:children[0]] call:arguments];
} else if([type isEqualToString:@"?"]) {
if([self toBool:[self executeNodeInScope:scope node:children[0]]]){
return [self executeNodeInScope:scope node:children[1]];
}
else{
return [self executeNodeInScope:scope node:children[2]];
}
} else if([type isEqualToString:@"+"]) {
return [[NSNumber alloc] initWithDouble: ([self toNumber:[self executeNodeInScope:scope node:children[0]]] + [self toNumber:[self executeNodeInScope:scope node:children[1]]])];
} else if([type isEqualToString:@"-"]) {
return [[NSNumber alloc] initWithDouble: ([self toNumber:[self executeNodeInScope:scope node:children[0]]] - [self toNumber:[self executeNodeInScope:scope node:children[1]]])];
} else if([type isEqualToString:@"*"]) {
return [[NSNumber alloc] initWithDouble: ([self toNumber:[self executeNodeInScope:scope node:children[0]]] * [self toNumber:[self executeNodeInScope:scope node:children[1]]])];
} else if([type isEqualToString:@"/"]) {
return [[NSNumber alloc] initWithDouble: ([self toNumber:[self executeNodeInScope:scope node:children[0]]] / [self toNumber:[self executeNodeInScope:scope node:children[1]]])];
} else if([type isEqualToString:@"%"]) {
return [[NSNumber alloc] initWithDouble: fmod([self toNumber:[self executeNodeInScope:scope node:children[0]]], [self toNumber:[self executeNodeInScope:scope node:children[1]]])];
} else if([type isEqualToString:@"**"]) {
return [[NSNumber alloc] initWithDouble: pow([self toNumber:[self executeNodeInScope:scope node:children[0]]], [self toNumber:[self executeNodeInScope:scope node:children[1]]])];
} else if ([type isEqualToString:@">"]) {
CGFloat num1 = [self toNumber:[self executeNodeInScope:scope node:children[0]]];
CGFloat num2 = [self toNumber:[self executeNodeInScope:scope node:children[1]]];
return @(num1 > num2);
} else if ([type isEqualToString:@">="]) {
CGFloat num1 = [self toNumber:[self executeNodeInScope:scope node:children[0]]];
CGFloat num2 = [self toNumber:[self executeNodeInScope:scope node:children[1]]];
return @(num1 >= num2);
} else if ([type isEqualToString:@"<"]) {
CGFloat num1 = [self toNumber:[self executeNodeInScope:scope node:children[0]]];
CGFloat num2 = [self toNumber:[self executeNodeInScope:scope node:children[1]]];
return @(num1 < num2);
} else if ([type isEqualToString:@"<="]) {
CGFloat num1 = [self toNumber:[self executeNodeInScope:scope node:children[0]]];
CGFloat num2 = [self toNumber:[self executeNodeInScope:scope node:children[1]]];
return @(num1 <= num2);
} else if ([type isEqualToString:@"=="]) {
CGFloat num1 = [self toNumber:[self executeNodeInScope:scope node:children[0]]];
CGFloat num2 = [self toNumber:[self executeNodeInScope:scope node:children[1]]];
return @(num1 == num2);
} else if ([type isEqualToString:@"!="]) {
CGFloat num1 = [self toNumber:[self executeNodeInScope:scope node:children[0]]];
CGFloat num2 = [self toNumber:[self executeNodeInScope:scope node:children[1]]];
return @(num1 != num2);
} else if ([type isEqualToString:@"||"]) {
BOOL num1 = [self toBool:[self executeNodeInScope:scope node:children[0]]];
BOOL num2 = [self toBool:[self executeNodeInScope:scope node:children[1]]];
return @(num1 || num2);
} else if ([type isEqualToString:@"&&"]) {
BOOL num1 = [self toBool:[self executeNodeInScope:scope node:children[0]]];
BOOL num2 = [self toBool:[self executeNodeInScope:scope node:children[1]]];
return @(num1 && num2);
}
return nil;
}
@end