Source

Silver / Classes / Core / SVBlock.m

//
//  SVBlock.m
//  SV
//
//  Created by Michael Tindal on 7/4/10.
//  Copyright 2010 Michael Tindal. All rights reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

#import "SVBlock.h"
#import "SVControlOperations.h"
#import "SVFunction.h" // for SV_IN_FUNCTION_KEY
#import "NSMutableDictionary+SVExtensions.h"

@implementation SVBlock

+ (SVBlock *) blockWithStatements:(NSArray *)statements
{
    return [[SVBlock alloc] initWithStatements:statements];
}


- (id) initWithStatements:(NSArray *)state
{
    self = [super init];
    if (self) {
        statements_ = state;

    }
    return self;
}


- (id) evaluateWithContext:(NSMutableDictionary *)context
{
    NSMutableDictionary * _context;
    if([self class] == [SVBlock class]) {
        _context = context;
        [_context setObject:BL(YES) forKey:@"__SET_CONTEXT"];
    } else {
        _context= [NSMutableDictionary dictionary];

        [_context setObject:[SVSymbolTable table] forKey:SV_SYMBOL_TABLE_KEY];
        [_context setObject:(context ? context:[NSMutableDictionary dictionary]) forKey:SV_PARENT_CONTEXT_KEY];
    }

    id result;

    for (SVNode * statement in self.statements) {
        @try {
            result = [statement evaluateWithContext:_context];
        } @catch (SVReturnException * ex) {
            if ([context objectForKey:SV_IN_FUNCTION_KEY]) {
                return [[ex userInfo] objectForKey:@"__SV_FUNCTION_RETURN_VALUE"];
            } else {
                @throw;
            }
        }
    }

    if([self class] == [SVBlock class])
        return result != __sv_nil ? result : nil;
    else
        return result;
}


- (BOOL) isEqual:(SVNode *)object
{
    if (object == self) {
        return YES;
    }
    if (![object isKindOfClass:[SVBlock class]]) {
        return NO;
    }

    if ([[(SVBlock *) object statements] count] != self.statements.count) {
        return NO;
    }

    BOOL equal = YES;
    for (NSUInteger i = 0; i < self.statements.count; i++) {
        if (![[[(SVBlock *) object statements] objectAtIndex:i] isEqual:[self.statements objectAtIndex:i]]) {
            equal = NO;
            break;
        }
    }
    return equal;
}


- (NSComparisonResult) compare:(SVNode *)object
{
    return ![self isEqual:object];
}


- (id) copyWithZone:(NSZone *)zone
{
    NSMutableArray * array = [NSMutableArray array];
    for (SVNode * statement in self.statements) {
        [array addObject:[statement copyWithZone:zone]];
    }
    return [SVBlock blockWithStatements:array];
}


- (NSString *) stringValueWithDepth:(NSInteger)d
{
    return [self stringValueWithDepth:d isFunctionArgument:NO];
}


- (NSString *) stringValueWithDepth:(NSInteger)d isFunctionArgument:(BOOL)f
{
    NSMutableString * string =
        [NSMutableString stringWithFormat:@"%@%@%@", [self class] == [SVBlock class] ? generateDepth(d):@"", d > 0 ? @"{":@"", d >
    0 ? @"\n\r":@""];
    for (SVNode * statement in self.statements) {
        [string appendFormat:@"%@;\n\r", [statement stringValueWithDepth:d + 1]];
    }
    [string appendFormat:@"%@%@%@\n\r", generateDepth(d), d > 0 ? @"}":@"", f ? @"":d > 0 ? @"":@""];
    return string;
}


- (NSString *) description
{
    NSMutableString * descString = [NSMutableString string];
    [descString appendString:@"{\n"];
    for (SVNode * node in self.statements) {
        [descString appendFormat:@"  %@\n", [node description]];
    }
    [descString appendString:@"}\n"];
    return descString;
}


@synthesize statements = statements_;

@end