Add "insertion mode" state machine stub
https://html.spec.whatwg.org/multipage/syntax.html#the-insertion-mode
This commit is contained in:
+308
-2
@@ -7,23 +7,200 @@
|
||||
//
|
||||
|
||||
#import "HTMLParser.h"
|
||||
#import "HTMLTokenizer.h"
|
||||
#import "HTMLTokens.h"
|
||||
#import "HTMLParserInsertionModes.h"
|
||||
#import "HTMLElement.h"
|
||||
#import "HTMLElementTypes.h"
|
||||
|
||||
@interface HTMLParser ()
|
||||
{
|
||||
HTMLTokenizer *_tokenizer;
|
||||
|
||||
NSMutableDictionary *_insertionModes;
|
||||
HTMLInsertionMode _insertionMode;
|
||||
HTMLInsertionMode _originalInsertionMode;
|
||||
|
||||
NSMutableArray *_stackOfOpenElements;
|
||||
|
||||
HTMLElement *_context;
|
||||
HTMLElement *_contextElement;
|
||||
HTMLElement *_currentElement;
|
||||
|
||||
HTMLElement *_headElementPointer;
|
||||
HTMLElement *_formElementPointer;
|
||||
|
||||
BOOL _scriptingFlag;
|
||||
BOOL _fragmentParsingAlgorithm;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HTMLParser
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWithString:(NSString *)string
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_insertionModes = [NSMutableDictionary new];
|
||||
_insertionMode = HTMLInsertionModeInitial;
|
||||
[self setupStateMachine];
|
||||
|
||||
_stackOfOpenElements = [NSMutableArray new];
|
||||
_tokenizer = [[HTMLTokenizer alloc] initWithString:string];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setupStateMachine
|
||||
{
|
||||
for (NSUInteger i = 0; i < HTMLInsertionModesCount; i++) {
|
||||
NSString *selectorName = HTMLInsertionModesTable[i];
|
||||
SEL selector = NSSelectorFromString(selectorName);
|
||||
[_insertionModes setObject:[NSValue valueWithPointer:selector] forKey:@(i)];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Nodes
|
||||
|
||||
- (HTMLElement *)currentNode
|
||||
{
|
||||
return _stackOfOpenElements.lastObject;
|
||||
}
|
||||
|
||||
- (HTMLElement *)adjustedCurrentNode
|
||||
{
|
||||
if (_stackOfOpenElements.count == 1 && _fragmentParsingAlgorithm) {
|
||||
return _contextElement;
|
||||
}
|
||||
return [self currentNode];
|
||||
}
|
||||
|
||||
#pragma mark - State Machine
|
||||
|
||||
- (void)switchInsertionMode:(HTMLInsertionMode)mode
|
||||
{
|
||||
if (mode == HTMLInsertionModeText || mode == HTMLInsertionModeInTableText) {
|
||||
_originalInsertionMode = _insertionMode;
|
||||
}
|
||||
_insertionMode = mode;
|
||||
}
|
||||
|
||||
- (void)resetInsertionModeAppropriately
|
||||
{
|
||||
BOOL last = NO;
|
||||
HTMLElement *node = _stackOfOpenElements.lastObject;
|
||||
NSUInteger nodeIndex = _stackOfOpenElements.count - 1;
|
||||
|
||||
while (YES) {
|
||||
|
||||
if ([_stackOfOpenElements.firstObject isEqual:node]) {
|
||||
last = YES;
|
||||
if (_fragmentParsingAlgorithm) {
|
||||
node = _contextElement;
|
||||
}
|
||||
}
|
||||
|
||||
if ([node.tagName isEqualToString:@"select"]) {
|
||||
if (last == NO) {
|
||||
HTMLElement *ancestor = node;
|
||||
NSUInteger ancestorIndex = nodeIndex;
|
||||
|
||||
while (YES) {
|
||||
if ([ancestor isEqual:_stackOfOpenElements.firstObject]) {
|
||||
break;
|
||||
}
|
||||
|
||||
ancestorIndex--;
|
||||
ancestor = [_stackOfOpenElements objectAtIndex:ancestorIndex];
|
||||
|
||||
if ([ancestor.tagName isEqualToString:@"template"]) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ([ancestor.tagName isEqualToString:@"table"]) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInTable];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
[self switchInsertionMode:HTMLInsertionModeInSelect];
|
||||
return;
|
||||
}
|
||||
|
||||
if (last == NO) {
|
||||
if (matches(node.tagName, @"td", @"th")) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInCell];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ([node.tagName isEqualToString:@"tr"]) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInRow];
|
||||
return;
|
||||
}
|
||||
|
||||
if (matches(node.tagName, @"tbody", @"thead", @"tfoot")) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInTableBody];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([node.tagName isEqualToString:@"caption"]) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInCaption];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([node.tagName isEqualToString:@"colgroup"]) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInColumnGroup];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([node.tagName isEqualToString:@"template"]) {
|
||||
[self switchInsertionMode:HTMLInsertionModeCurrentTemplate];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([node.tagName isEqualToString:@"table"]) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInTable];
|
||||
return;
|
||||
}
|
||||
|
||||
if (last == NO) {
|
||||
if ([node.tagName isEqualToString:@"head"]) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInHead];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ([node.tagName isEqualToString:@"body"]) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInBody];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([node.tagName isEqualToString:@"frameset"]) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInFrameset];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([node.tagName isEqualToString:@"html"]) {
|
||||
if (_headElementPointer == nil) {
|
||||
[self switchInsertionMode:HTMLInsertionModeBeforeHead];
|
||||
} else {
|
||||
[self switchInsertionMode:HTMLInsertionModeAfterHead];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (last) {
|
||||
[self switchInsertionMode:HTMLInsertionModeInBody];
|
||||
return;
|
||||
}
|
||||
|
||||
nodeIndex--;
|
||||
node = [_stackOfOpenElements objectAtIndex:nodeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Parse
|
||||
|
||||
- (id)parse
|
||||
@@ -76,12 +253,141 @@
|
||||
|
||||
- (void)handleToken:(HTMLToken *)token byApplyingRulesForInsertionMode:(HTMLInsertionMode)insertionMode
|
||||
{
|
||||
|
||||
SEL selector = [[_insertionModes objectForKey:@(_insertionMode)] pointerValue];
|
||||
if ([self respondsToSelector:selector]) {
|
||||
/* ObjC-Runtime-style performSelector for ARC to shut up the
|
||||
compiler, since it can't figure out the type of the return
|
||||
value on its own */
|
||||
IMP method = [self methodForSelector:selector];
|
||||
((void (*)(id, SEL, id))method)(self, selector, token);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleTokenByApplyingRulesForParsingTokensInForeignContent:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - Insertion Modes
|
||||
|
||||
- (void)HTMLInsertionModeInitial:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeBeforeHTML:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeBeforeHead:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInHead:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInHeadNoscript:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeAfterHead:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInBody:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeText:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInTable:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInTableText:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInCaption:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInColumnGroup:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInTableBody:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInRow:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInCell:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInSelect:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInSelectInTable:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInTemplate:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeAfterBody:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeInFrameset:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeAfterFrameset:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeAfterAfterBody:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeAfterAfterFrameset:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)HTMLInsertionModeCurrentTemplate:(HTMLToken *)token
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user