Refactor and organize code in the HTML Parser

This commit is contained in:
iska
2015-03-25 22:39:35 +01:00
parent 78fac7527b
commit 22e6aff5e9
2 changed files with 89 additions and 50 deletions
+2
View File
@@ -12,4 +12,6 @@
@interface HTMLParser : NSObject
- (instancetype)initWithString:(NSString *)string context:(HTMLElement *)context;
@end
+87 -50
View File
@@ -60,10 +60,13 @@
#pragma mark - Lifecycle
- (instancetype)initWithString:(NSString *)string
- (instancetype)initWithString:(NSString *)string context:(HTMLElement *)context
{
self = [super init];
if (self) {
_contextElement = context;
_fragmentParsingAlgorithm = (context != nil);
_errors = [NSMutableArray new];
_insertionModes = [NSMutableDictionary new];
@@ -78,6 +81,9 @@
_pendingTableCharacterTokens = [[HTMLCharacterToken alloc] initWithString:@""];
_headElementPointer = nil;
_formElementPointer = nil;
_framesetOkFlag = YES;
_fragmentParsingAlgorithm = NO;
_fosterParenting = NO;
@@ -95,68 +101,75 @@
}
}
#pragma mark - Nodes
#pragma mark - Properties
- (HTMLElement *)currentNode
- (NSArray *)parseErrors
{
return _stackOfOpenElements.currentNode;
return _errors;
}
- (HTMLElement *)adjustedCurrentNode
- (HTMLDocument *)document
{
if (_stackOfOpenElements.count == 1 && _fragmentParsingAlgorithm) {
return _contextElement;
if (_document == nil) {
[self parse];
}
return [self currentNode];
}
#pragma mark - Emits
- (void)emitParseError:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2)
{
va_list args;
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
[_errors addObject:message];
va_end(args);
return _document;
}
#pragma mark - Parse
- (id)parse
- (void)parse
{
_document = [HTMLDocument new];
if (_fragmentParsingAlgorithm) {
if (_contextElement != nil) {
if ([_contextElement.tagName isEqualToAny:@"title", @"textarea", nil]) {
_tokenizer.state = HTMLTokenizerStateRCDATA;
} else if ([_contextElement.tagName isEqualToAny:@"style", @"xmp", @"iframe", @"noembed", @"noframes", nil]) {
_tokenizer.state = HTMLTokenizerStateRAWTEXT;
} else if ([_contextElement.tagName isEqualToString:@"script"]) {
_tokenizer.state = HTMLTokenizerStateScriptData;
} else if ([_contextElement.tagName isEqualToString:@"noscript"]) {
_tokenizer.state = HTMLTokenizerStateRAWTEXT;
} else if ([_contextElement.tagName isEqualToString:@"plaintext"]) {
_tokenizer.state = HTMLTokenizerStatePLAINTEXT;
} else {
_tokenizer.state = HTMLTokenizerStateData;
}
}
HTMLElement *root = [[HTMLElement alloc] initWithTagName:@"html"];
[_document appendNode:root];
[_stackOfOpenElements pushElement:root];
if ([_contextElement.tagName isEqualToString:@"template"]) {
#warning Implement HTML Template
}
[self resetInsertionModeAppropriately];
_formElementPointer = _contextElement;
while (_formElementPointer != nil && ![_formElementPointer.tagName isEqualToString:@"form"]) {
_formElementPointer = _formElementPointer.parentElement;
}
}
for (HTMLToken *token in _tokenizer) {
if (_document.readyState == HTMLDocumentComplete) {
break;
}
[self processToken:token];
}
return nil;
}
- (id)parseFragment
- (void)stopParsing
{
if (_contextElement != nil) {
if ([_contextElement.tagName isEqualToAny:@"title", @"textarea", nil]) {
_tokenizer.state = HTMLTokenizerStateRCDATA;
} else if ([_contextElement.tagName isEqualToAny:@"style", @"xmp", @"iframe", @"noembed", @"noframes", nil]) {
_tokenizer.state = HTMLTokenizerStateRAWTEXT;
} else if ([_contextElement.tagName isEqualToString:@"script"]) {
_tokenizer.state = HTMLTokenizerStateScriptData;
} else if ([_contextElement.tagName isEqualToString:@"noscript"]) {
if (_scriptingFlag) {
_tokenizer.state = HTMLTokenizerStateRAWTEXT;
}
} else if ([_contextElement.tagName isEqualToString:@"plaintext"]) {
_tokenizer.state = HTMLTokenizerStatePLAINTEXT;
} else {
_tokenizer.state = HTMLTokenizerStateData;
}
}
return nil;
[_stackOfOpenElements popAll];
_document.readyState = HTMLDocumentComplete;
}
#pragma mark - Processing
- (void)processToken:(HTMLToken *)token
{
BOOL (^ treeConstructionDispatcher)(HTMLElement *node) = ^BOOL(HTMLElement *node){
@@ -229,10 +242,30 @@
}
}
- (void)stopParsing
#pragma mark - Nodes
- (HTMLElement *)currentNode
{
[_stackOfOpenElements popAll];
_document.readyState =HTMLDocumentComplete;
return _stackOfOpenElements.currentNode;
}
- (HTMLElement *)adjustedCurrentNode
{
if (_stackOfOpenElements.count == 1 && _fragmentParsingAlgorithm) {
return _contextElement;
}
return [self currentNode];
}
#pragma mark - Emits
- (void)emitParseError:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2)
{
va_list args;
va_start(args, format);
NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
[_errors addObject:message];
va_end(args);
}
#pragma mark - Insertions & Manipulations
@@ -446,10 +479,9 @@
HTMLElement *lastNode = furthestBlock;
for (int innerLoopCounter = 0; innerLoopCounter < 3; innerLoopCounter ++) {
NSUInteger nodeStackIndex = [_stackOfOpenElements indexOfElement:node];
NSUInteger stackIndex = [_stackOfOpenElements indexOfElement:node];
node = _stackOfOpenElements[nodeStackIndex - 1];
node = _stackOfOpenElements[stackIndex - 1];
if (![_listOfActiveFormattingElements containsElement:node]) {
[_stackOfOpenElements removeElement:node];
continue;
@@ -459,13 +491,16 @@
break;
}
stackIndex = [_stackOfOpenElements indexOfElement:node];
NSUInteger listIndex = [_listOfActiveFormattingElements indexOfElement:node];
HTMLElement *newElement = [node copy];
[_listOfActiveFormattingElements replaceElementAtIndex:listIndex withElement:newElement];
[_stackOfOpenElements replaceElementAtIndex:stackIndex withElement:newElement];
node = newElement;
if ([lastNode isEqual:furthestBlock]) {
bookmark = nodeListIndex + 1;
bookmark = listIndex + 1;
}
[node appendNode:lastNode];
@@ -484,7 +519,8 @@
[furthestBlock appendNode:newElement];
[_listOfActiveFormattingElements removeElement:formattingElement];
[_listOfActiveFormattingElements insertElement:newElement atIndex:bookmark-1];
bookmark = bookmark == 0 ?: bookmark -1;
[_listOfActiveFormattingElements insertElement:newElement atIndex:bookmark];
[_stackOfOpenElements removeElement:formattingElement];
NSUInteger furthestBlockIndex = [_stackOfOpenElements indexOfElement:furthestBlock];
[_stackOfOpenElements insertElement:newElement atIndex:furthestBlockIndex];
@@ -1126,8 +1162,8 @@
} else if ([tagName isEqualToString:@"a"]) {
HTMLElement *element = ^ HTMLElement * {
for (HTMLElement *element in _listOfActiveFormattingElements.reverseObjectEnumerator) {
if ([element isEqualTo:[HTMLMarker marker]]) return nil;
if ([element.tagName isEqualTo:@"a"]) {
if ([element isEqual:[HTMLMarker marker]]) return nil;
if ([element.tagName isEqualToString:@"a"]) {
return element;
}
}
@@ -1509,6 +1545,7 @@
[self reprocessToken:token];
} else if ([token.asTagToken.tagName isEqualToAny:@"tbody", @"tfoot", @"thead", nil]) {
[_stackOfOpenElements clearBackToTableContext];
[self insertElementForToken:token.asTagToken];
[self switchInsertionMode:HTMLInsertionModeInTableBody];
} else if ([token.asTagToken.tagName isEqualToAny:@"td", @"th", @"tr", nil]) {
[_stackOfOpenElements clearBackToTableContext];