// // MPTokenStream.m // MathPad // // Created by Kim Wittenburg on 20.09.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPTokenStream.h" #import "MPToken.h" @interface MPTokenStream () @property (nonatomic, copy) NSArray *tokens; @property (nonatomic) NSUInteger currentTokenIndex; @property (nonatomic) NSUInteger eofLocation; @property (nonatomic) BOOL *whitespaceStates; @property (nonatomic) NSUInteger maxWhitespaceIgnores; @property (nonatomic) NSUInteger currentWhitespaceIgnoreState; - (void)pushWhitespaceState:(BOOL)state; @end @implementation MPTokenStream - (instancetype)initWithTokens:(NSArray *)tokens { self = [super init]; if (self) { self.tokens = tokens; self.whitespaceStates = malloc(10 * sizeof(BOOL)); self.maxWhitespaceIgnores = 10; self.currentWhitespaceIgnoreState = 0; [self beginAcceptingWhitespaceTokens]; _currentTokenIndex = 0; if (tokens.count > 0) { self.eofLocation = NSMaxRange([tokens.lastObject range]); } else { self.eofLocation = 0; } } return self; } - (void)beginAcceptingWhitespaceTokens { [self pushWhitespaceState:YES]; } - (void)beginIgnoringWhitespaceTokens { [self pushWhitespaceState:NO]; } - (void)pushWhitespaceState:(BOOL)state { self.currentWhitespaceIgnoreState++; if (self.currentWhitespaceIgnoreState >= self.maxWhitespaceIgnores) { self.maxWhitespaceIgnores += 10; BOOL *reallocatedWhitespaceIgnores = realloc(self.whitespaceStates, self.maxWhitespaceIgnores); if (reallocatedWhitespaceIgnores) { self.whitespaceStates = reallocatedWhitespaceIgnores; } else { @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Realloc Failed" userInfo:nil]; } } self.whitespaceStates[self.currentWhitespaceIgnoreState] = state; } - (void)endIgnoringOrAcceptingWhitespaceTokens { self.currentWhitespaceIgnoreState--; } - (void)skipWhitespaces { if (self.whitespaceStates[self.currentWhitespaceIgnoreState]) { return; } while (_currentTokenIndex < self.tokens.count) { MPToken *token = self.tokens[_currentTokenIndex]; if (token.tokenType != MPWhitespaceToken) { return; } _currentTokenIndex++; } } - (BOOL)hasMoreTokens { [self skipWhitespaces]; return _currentTokenIndex < self.tokens.count; } - (id)currentToken { [self skipWhitespaces]; if (_currentTokenIndex >= _tokens.count) { return nil; } return _tokens[_currentTokenIndex]; } - (id)peekNextToken { NSUInteger currentTokenIndex = _currentTokenIndex; [self currentTokenConsumed]; // Pretend the current token has been consumed id token = [self currentToken]; _currentTokenIndex = currentTokenIndex; // Undo the lookahead return token; } - (void)currentTokenConsumed { [self currentToken]; ++_currentTokenIndex; } - (void)dealloc { free(self.whitespaceStates); } @end