Commit c8fac7b9 authored by Nigel Tao's avatar Nigel Tao

exp/html: when parsing, compare atoms (ints) instead of strings.

This is the mechanical part of the 2-part change that started with
https://golang.org/cl/6305053/

R=rsc
CC=andybalholm, golang-dev, r
https://golang.org/cl/6295055
parent cd21eff7
...@@ -54,10 +54,10 @@ func (p *parser) top() *Node { ...@@ -54,10 +54,10 @@ func (p *parser) top() *Node {
// Stop tags for use in popUntil. These come from section 12.2.3.2. // Stop tags for use in popUntil. These come from section 12.2.3.2.
var ( var (
defaultScopeStopTags = map[string][]string{ defaultScopeStopTags = map[string][]a.Atom{
"": {"applet", "caption", "html", "table", "td", "th", "marquee", "object"}, "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object},
"math": {"annotation-xml", "mi", "mn", "mo", "ms", "mtext"}, "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext},
"svg": {"desc", "foreignObject", "title"}, "svg": {a.Desc, a.ForeignObject, a.Title},
} }
) )
...@@ -90,7 +90,7 @@ const ( ...@@ -90,7 +90,7 @@ const (
// no higher element in the stack that was also in the stop tags). For example, // no higher element in the stack that was also in the stop tags). For example,
// popUntil(tableScope, "table") returns true and leaves: // popUntil(tableScope, "table") returns true and leaves:
// ["html", "body", "font"] // ["html", "body", "font"]
func (p *parser) popUntil(s scope, matchTags ...string) bool { func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool {
if i := p.indexOfElementInScope(s, matchTags...); i != -1 { if i := p.indexOfElementInScope(s, matchTags...); i != -1 {
p.oe = p.oe[:i] p.oe = p.oe[:i]
return true return true
...@@ -101,12 +101,12 @@ func (p *parser) popUntil(s scope, matchTags ...string) bool { ...@@ -101,12 +101,12 @@ func (p *parser) popUntil(s scope, matchTags ...string) bool {
// indexOfElementInScope returns the index in p.oe of the highest element whose // indexOfElementInScope returns the index in p.oe of the highest element whose
// tag is in matchTags that is in scope. If no matching element is in scope, it // tag is in matchTags that is in scope. If no matching element is in scope, it
// returns -1. // returns -1.
func (p *parser) indexOfElementInScope(s scope, matchTags ...string) int { func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
for i := len(p.oe) - 1; i >= 0; i-- { for i := len(p.oe) - 1; i >= 0; i-- {
tag := p.oe[i].Data tagAtom := p.oe[i].DataAtom
if p.oe[i].Namespace == "" { if p.oe[i].Namespace == "" {
for _, t := range matchTags { for _, t := range matchTags {
if t == tag { if t == tagAtom {
return i return i
} }
} }
...@@ -114,19 +114,19 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...string) int { ...@@ -114,19 +114,19 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...string) int {
case defaultScope: case defaultScope:
// No-op. // No-op.
case listItemScope: case listItemScope:
if tag == "ol" || tag == "ul" { if tagAtom == a.Ol || tagAtom == a.Ul {
return -1 return -1
} }
case buttonScope: case buttonScope:
if tag == "button" { if tagAtom == a.Button {
return -1 return -1
} }
case tableScope: case tableScope:
if tag == "html" || tag == "table" { if tagAtom == a.Html || tagAtom == a.Table {
return -1 return -1
} }
case selectScope: case selectScope:
if tag != "optgroup" && tag != "option" { if tagAtom != a.Optgroup && tagAtom != a.Option {
return -1 return -1
} }
default: default:
...@@ -136,7 +136,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...string) int { ...@@ -136,7 +136,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...string) int {
switch s { switch s {
case defaultScope, listItemScope, buttonScope: case defaultScope, listItemScope, buttonScope:
for _, t := range defaultScopeStopTags[p.oe[i].Namespace] { for _, t := range defaultScopeStopTags[p.oe[i].Namespace] {
if t == tag { if t == tagAtom {
return -1 return -1
} }
} }
...@@ -147,7 +147,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...string) int { ...@@ -147,7 +147,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...string) int {
// elementInScope is like popUntil, except that it doesn't modify the stack of // elementInScope is like popUntil, except that it doesn't modify the stack of
// open elements. // open elements.
func (p *parser) elementInScope(s scope, matchTags ...string) bool { func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool {
return p.indexOfElementInScope(s, matchTags...) != -1 return p.indexOfElementInScope(s, matchTags...) != -1
} }
...@@ -155,20 +155,20 @@ func (p *parser) elementInScope(s scope, matchTags ...string) bool { ...@@ -155,20 +155,20 @@ func (p *parser) elementInScope(s scope, matchTags ...string) bool {
// scope-defined element is found. // scope-defined element is found.
func (p *parser) clearStackToContext(s scope) { func (p *parser) clearStackToContext(s scope) {
for i := len(p.oe) - 1; i >= 0; i-- { for i := len(p.oe) - 1; i >= 0; i-- {
tag := p.oe[i].Data tagAtom := p.oe[i].DataAtom
switch s { switch s {
case tableScope: case tableScope:
if tag == "html" || tag == "table" { if tagAtom == a.Html || tagAtom == a.Table {
p.oe = p.oe[:i+1] p.oe = p.oe[:i+1]
return return
} }
case tableRowScope: case tableRowScope:
if tag == "html" || tag == "tr" { if tagAtom == a.Html || tagAtom == a.Tr {
p.oe = p.oe[:i+1] p.oe = p.oe[:i+1]
return return
} }
case tableBodyScope: case tableBodyScope:
if tag == "html" || tag == "tbody" || tag == "tfoot" || tag == "thead" { if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead {
p.oe = p.oe[:i+1] p.oe = p.oe[:i+1]
return return
} }
...@@ -187,8 +187,8 @@ loop: ...@@ -187,8 +187,8 @@ loop:
for i = len(p.oe) - 1; i >= 0; i-- { for i = len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i] n := p.oe[i]
if n.Type == ElementNode { if n.Type == ElementNode {
switch n.Data { switch n.DataAtom {
case "dd", "dt", "li", "option", "optgroup", "p", "rp", "rt": case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt:
for _, except := range exceptions { for _, except := range exceptions {
if n.Data == except { if n.Data == except {
break loop break loop
...@@ -224,7 +224,7 @@ func (p *parser) fosterParent(n *Node) { ...@@ -224,7 +224,7 @@ func (p *parser) fosterParent(n *Node) {
var table, parent *Node var table, parent *Node
var i int var i int
for i = len(p.oe) - 1; i >= 0; i-- { for i = len(p.oe) - 1; i >= 0; i-- {
if p.oe[i].Data == "table" { if p.oe[i].DataAtom == a.Table {
table = p.oe[i] table = p.oe[i]
break break
} }
...@@ -278,17 +278,20 @@ func (p *parser) addText(text string) { ...@@ -278,17 +278,20 @@ func (p *parser) addText(text string) {
} }
// addElement calls addChild with an element node. // addElement calls addChild with an element node.
func (p *parser) addElement(tag string, attr []Attribute) { // TODO: tagAtom, tag and attr are almost always p.tok.DataAtom, p.tok.Data, p.tok.Attr.
// The common case should be a no-arg addElement method.
func (p *parser) addElement(tagAtom a.Atom, tag string, attr []Attribute) {
p.addChild(&Node{ p.addChild(&Node{
Type: ElementNode, Type: ElementNode,
Data: tag, // TODO: also set DataAtom. DataAtom: tagAtom,
Data: tag,
Attr: attr, Attr: attr,
}) })
} }
// Section 12.2.3.3. // Section 12.2.3.3.
func (p *parser) addFormattingElement(tag string, attr []Attribute) { func (p *parser) addFormattingElement(tagAtom a.Atom, tag string, attr []Attribute) {
p.addElement(tag, attr) p.addElement(tagAtom, tag, attr)
// Implement the Noah's Ark clause, but with three per family instead of two. // Implement the Noah's Ark clause, but with three per family instead of two.
identicalElements := 0 identicalElements := 0
...@@ -410,28 +413,28 @@ func (p *parser) resetInsertionMode() { ...@@ -410,28 +413,28 @@ func (p *parser) resetInsertionMode() {
n = p.context n = p.context
} }
switch n.Data { switch n.DataAtom {
case "select": case a.Select:
p.im = inSelectIM p.im = inSelectIM
case "td", "th": case a.Td, a.Th:
p.im = inCellIM p.im = inCellIM
case "tr": case a.Tr:
p.im = inRowIM p.im = inRowIM
case "tbody", "thead", "tfoot": case a.Tbody, a.Thead, a.Tfoot:
p.im = inTableBodyIM p.im = inTableBodyIM
case "caption": case a.Caption:
p.im = inCaptionIM p.im = inCaptionIM
case "colgroup": case a.Colgroup:
p.im = inColumnGroupIM p.im = inColumnGroupIM
case "table": case a.Table:
p.im = inTableIM p.im = inTableIM
case "head": case a.Head:
p.im = inBodyIM p.im = inBodyIM
case "body": case a.Body:
p.im = inBodyIM p.im = inBodyIM
case "frameset": case a.Frameset:
p.im = inFramesetIM p.im = inFramesetIM
case "html": case a.Html:
p.im = beforeHeadIM p.im = beforeHeadIM
default: default:
continue continue
...@@ -483,15 +486,15 @@ func beforeHTMLIM(p *parser) bool { ...@@ -483,15 +486,15 @@ func beforeHTMLIM(p *parser) bool {
return true return true
} }
case StartTagToken: case StartTagToken:
if p.tok.Data == "html" { if p.tok.DataAtom == a.Html {
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.im = beforeHeadIM p.im = beforeHeadIM
return true return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "head", "body", "html", "br": case a.Head, a.Body, a.Html, a.Br:
p.parseImpliedToken(StartTagToken, "html", nil) p.parseImpliedToken(StartTagToken, a.Html, a.Html.String(), nil)
return false return false
default: default:
// Ignore the token. // Ignore the token.
...@@ -504,7 +507,7 @@ func beforeHTMLIM(p *parser) bool { ...@@ -504,7 +507,7 @@ func beforeHTMLIM(p *parser) bool {
}) })
return true return true
} }
p.parseImpliedToken(StartTagToken, "html", nil) p.parseImpliedToken(StartTagToken, a.Html, a.Html.String(), nil)
return false return false
} }
...@@ -518,19 +521,19 @@ func beforeHeadIM(p *parser) bool { ...@@ -518,19 +521,19 @@ func beforeHeadIM(p *parser) bool {
return true return true
} }
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "head": case a.Head:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.head = p.top() p.head = p.top()
p.im = inHeadIM p.im = inHeadIM
return true return true
case "html": case a.Html:
return inBodyIM(p) return inBodyIM(p)
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "head", "body", "html", "br": case a.Head, a.Body, a.Html, a.Br:
p.parseImpliedToken(StartTagToken, "head", nil) p.parseImpliedToken(StartTagToken, a.Head, a.Head.String(), nil)
return false return false
default: default:
// Ignore the token. // Ignore the token.
...@@ -547,7 +550,7 @@ func beforeHeadIM(p *parser) bool { ...@@ -547,7 +550,7 @@ func beforeHeadIM(p *parser) bool {
return true return true
} }
p.parseImpliedToken(StartTagToken, "head", nil) p.parseImpliedToken(StartTagToken, a.Head, a.Head.String(), nil)
return false return false
} }
...@@ -565,34 +568,34 @@ func inHeadIM(p *parser) bool { ...@@ -565,34 +568,34 @@ func inHeadIM(p *parser) bool {
p.tok.Data = s p.tok.Data = s
} }
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "html": case a.Html:
return inBodyIM(p) return inBodyIM(p)
case "base", "basefont", "bgsound", "command", "link", "meta": case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
return true return true
case "script", "title", "noscript", "noframes", "style": case a.Script, a.Title, a.Noscript, a.Noframes, a.Style:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.setOriginalIM() p.setOriginalIM()
p.im = textIM p.im = textIM
return true return true
case "head": case a.Head:
// Ignore the token. // Ignore the token.
return true return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "head": case a.Head:
n := p.oe.pop() n := p.oe.pop()
if n.Data != "head" { if n.DataAtom != a.Head {
panic("html: bad parser state: <head> element not found, in the in-head insertion mode") panic("html: bad parser state: <head> element not found, in the in-head insertion mode")
} }
p.im = afterHeadIM p.im = afterHeadIM
return true return true
case "body", "html", "br": case a.Body, a.Html, a.Br:
p.parseImpliedToken(EndTagToken, "head", nil) p.parseImpliedToken(EndTagToken, a.Head, a.Head.String(), nil)
return false return false
default: default:
// Ignore the token. // Ignore the token.
...@@ -609,7 +612,7 @@ func inHeadIM(p *parser) bool { ...@@ -609,7 +612,7 @@ func inHeadIM(p *parser) bool {
return true return true
} }
p.parseImpliedToken(EndTagToken, "head", nil) p.parseImpliedToken(EndTagToken, a.Head, a.Head.String(), nil)
return false return false
} }
...@@ -627,29 +630,29 @@ func afterHeadIM(p *parser) bool { ...@@ -627,29 +630,29 @@ func afterHeadIM(p *parser) bool {
p.tok.Data = s p.tok.Data = s
} }
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "html": case a.Html:
return inBodyIM(p) return inBodyIM(p)
case "body": case a.Body:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.framesetOK = false p.framesetOK = false
p.im = inBodyIM p.im = inBodyIM
return true return true
case "frameset": case a.Frameset:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.im = inFramesetIM p.im = inFramesetIM
return true return true
case "base", "basefont", "bgsound", "link", "meta", "noframes", "script", "style", "title": case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
p.oe = append(p.oe, p.head) p.oe = append(p.oe, p.head)
defer p.oe.pop() defer p.oe.pop()
return inHeadIM(p) return inHeadIM(p)
case "head": case a.Head:
// Ignore the token. // Ignore the token.
return true return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "body", "html", "br": case a.Body, a.Html, a.Br:
// Drop down to creating an implied <body> tag. // Drop down to creating an implied <body> tag.
default: default:
// Ignore the token. // Ignore the token.
...@@ -666,7 +669,7 @@ func afterHeadIM(p *parser) bool { ...@@ -666,7 +669,7 @@ func afterHeadIM(p *parser) bool {
return true return true
} }
p.parseImpliedToken(StartTagToken, "body", nil) p.parseImpliedToken(StartTagToken, a.Body, a.Body.String(), nil)
p.framesetOK = true p.framesetOK = true
return false return false
} }
...@@ -693,8 +696,8 @@ func inBodyIM(p *parser) bool { ...@@ -693,8 +696,8 @@ func inBodyIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case TextToken: case TextToken:
d := p.tok.Data d := p.tok.Data
switch n := p.oe.top(); n.Data { switch n := p.oe.top(); n.DataAtom {
case "pre", "listing": case a.Pre, a.Listing:
if len(n.Child) == 0 { if len(n.Child) == 0 {
// Ignore a newline at the start of a <pre> block. // Ignore a newline at the start of a <pre> block.
if d != "" && d[0] == '\r' { if d != "" && d[0] == '\r' {
...@@ -713,21 +716,21 @@ func inBodyIM(p *parser) bool { ...@@ -713,21 +716,21 @@ func inBodyIM(p *parser) bool {
p.addText(d) p.addText(d)
p.framesetOK = false p.framesetOK = false
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "html": case a.Html:
copyAttributes(p.oe[0], p.tok) copyAttributes(p.oe[0], p.tok)
case "base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title": case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
return inHeadIM(p) return inHeadIM(p)
case "body": case a.Body:
if len(p.oe) >= 2 { if len(p.oe) >= 2 {
body := p.oe[1] body := p.oe[1]
if body.Type == ElementNode && body.Data == "body" { if body.Type == ElementNode && body.DataAtom == a.Body {
p.framesetOK = false p.framesetOK = false
copyAttributes(body, p.tok) copyAttributes(body, p.tok)
} }
} }
case "frameset": case a.Frameset:
if !p.framesetOK || len(p.oe) < 2 || p.oe[1].Data != "body" { if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
// Ignore the token. // Ignore the token.
return true return true
} }
...@@ -736,38 +739,38 @@ func inBodyIM(p *parser) bool { ...@@ -736,38 +739,38 @@ func inBodyIM(p *parser) bool {
body.Parent.Remove(body) body.Parent.Remove(body)
} }
p.oe = p.oe[:1] p.oe = p.oe[:1]
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.im = inFramesetIM p.im = inFramesetIM
return true return true
case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul": case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "h1", "h2", "h3", "h4", "h5", "h6": case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
switch n := p.top(); n.Data { switch n := p.top(); n.DataAtom {
case "h1", "h2", "h3", "h4", "h5", "h6": case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
p.oe.pop() p.oe.pop()
} }
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "pre", "listing": case a.Pre, a.Listing:
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
// The newline, if any, will be dealt with by the TextToken case. // The newline, if any, will be dealt with by the TextToken case.
p.framesetOK = false p.framesetOK = false
case "form": case a.Form:
if p.form == nil { if p.form == nil {
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.form = p.top() p.form = p.top()
} }
case "li": case a.Li:
p.framesetOK = false p.framesetOK = false
for i := len(p.oe) - 1; i >= 0; i-- { for i := len(p.oe) - 1; i >= 0; i-- {
node := p.oe[i] node := p.oe[i]
switch node.Data { switch node.DataAtom {
case "li": case a.Li:
p.oe = p.oe[:i] p.oe = p.oe[:i]
case "address", "div", "p": case a.Address, a.Div, a.P:
continue continue
default: default:
if !isSpecialElement(node) { if !isSpecialElement(node) {
...@@ -776,16 +779,16 @@ func inBodyIM(p *parser) bool { ...@@ -776,16 +779,16 @@ func inBodyIM(p *parser) bool {
} }
break break
} }
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "dd", "dt": case a.Dd, a.Dt:
p.framesetOK = false p.framesetOK = false
for i := len(p.oe) - 1; i >= 0; i-- { for i := len(p.oe) - 1; i >= 0; i-- {
node := p.oe[i] node := p.oe[i]
switch node.Data { switch node.DataAtom {
case "dd", "dt": case a.Dd, a.Dt:
p.oe = p.oe[:i] p.oe = p.oe[:i]
case "address", "div", "p": case a.Address, a.Div, a.P:
continue continue
default: default:
if !isSpecialElement(node) { if !isSpecialElement(node) {
...@@ -794,56 +797,56 @@ func inBodyIM(p *parser) bool { ...@@ -794,56 +797,56 @@ func inBodyIM(p *parser) bool {
} }
break break
} }
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "plaintext": case a.Plaintext:
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "button": case a.Button:
p.popUntil(defaultScope, "button") p.popUntil(defaultScope, a.Button)
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.framesetOK = false p.framesetOK = false
case "a": case a.A:
for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- { for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
if n := p.afe[i]; n.Type == ElementNode && n.Data == "a" { if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
p.inBodyEndTagFormatting("a") p.inBodyEndTagFormatting(a.A)
p.oe.remove(n) p.oe.remove(n)
p.afe.remove(n) p.afe.remove(n)
break break
} }
} }
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addFormattingElement(p.tok.Data, p.tok.Attr) p.addFormattingElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u": case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addFormattingElement(p.tok.Data, p.tok.Attr) p.addFormattingElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "nobr": case a.Nobr:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
if p.elementInScope(defaultScope, "nobr") { if p.elementInScope(defaultScope, a.Nobr) {
p.inBodyEndTagFormatting("nobr") p.inBodyEndTagFormatting(a.Nobr)
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
} }
p.addFormattingElement(p.tok.Data, p.tok.Attr) p.addFormattingElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "applet", "marquee", "object": case a.Applet, a.Marquee, a.Object:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.afe = append(p.afe, &scopeMarker) p.afe = append(p.afe, &scopeMarker)
p.framesetOK = false p.framesetOK = false
case "table": case a.Table:
if !p.quirks { if !p.quirks {
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
} }
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.framesetOK = false p.framesetOK = false
p.im = inTableIM p.im = inTableIM
return true return true
case "area", "br", "embed", "img", "input", "keygen", "wbr": case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
if p.tok.Data == "input" { if p.tok.DataAtom == a.Input {
for _, t := range p.tok.Attr { for _, t := range p.tok.Attr {
if t.Key == "type" { if t.Key == "type" {
if strings.ToLower(t.Val) == "hidden" { if strings.ToLower(t.Val) == "hidden" {
...@@ -854,20 +857,21 @@ func inBodyIM(p *parser) bool { ...@@ -854,20 +857,21 @@ func inBodyIM(p *parser) bool {
} }
} }
p.framesetOK = false p.framesetOK = false
case "param", "source", "track": case a.Param, a.Source, a.Track:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
case "hr": case a.Hr:
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
p.framesetOK = false p.framesetOK = false
case "image": case a.Image:
p.tok.Data = "img" p.tok.DataAtom = a.Img
p.tok.Data = a.Img.String()
return false return false
case "isindex": case a.Isindex:
if p.form != nil { if p.form != nil {
// Ignore the token. // Ignore the token.
return true return true
...@@ -888,124 +892,124 @@ func inBodyIM(p *parser) bool { ...@@ -888,124 +892,124 @@ func inBodyIM(p *parser) bool {
} }
} }
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
p.addElement("form", nil) p.addElement(a.Form, a.Form.String(), nil)
p.form = p.top() p.form = p.top()
if action != "" { if action != "" {
p.form.Attr = []Attribute{{Key: "action", Val: action}} p.form.Attr = []Attribute{{Key: "action", Val: action}}
} }
p.addElement("hr", nil) p.addElement(a.Hr, a.Hr.String(), nil)
p.oe.pop() p.oe.pop()
p.addElement("label", nil) p.addElement(a.Label, a.Label.String(), nil)
p.addText(prompt) p.addText(prompt)
p.addElement("input", attr) p.addElement(a.Input, a.Input.String(), attr)
p.oe.pop() p.oe.pop()
p.oe.pop() p.oe.pop()
p.addElement("hr", nil) p.addElement(a.Hr, a.Hr.String(), nil)
p.oe.pop() p.oe.pop()
p.oe.pop() p.oe.pop()
p.form = nil p.form = nil
case "textarea": case a.Textarea:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.setOriginalIM() p.setOriginalIM()
p.framesetOK = false p.framesetOK = false
p.im = textIM p.im = textIM
case "xmp": case a.Xmp:
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.framesetOK = false p.framesetOK = false
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.setOriginalIM() p.setOriginalIM()
p.im = textIM p.im = textIM
case "iframe": case a.Iframe:
p.framesetOK = false p.framesetOK = false
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.setOriginalIM() p.setOriginalIM()
p.im = textIM p.im = textIM
case "noembed", "noscript": case a.Noembed, a.Noscript:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.setOriginalIM() p.setOriginalIM()
p.im = textIM p.im = textIM
case "select": case a.Select:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.framesetOK = false p.framesetOK = false
p.im = inSelectIM p.im = inSelectIM
return true return true
case "optgroup", "option": case a.Optgroup, a.Option:
if p.top().Data == "option" { if p.top().DataAtom == a.Option {
p.oe.pop() p.oe.pop()
} }
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "rp", "rt": case a.Rp, a.Rt:
if p.elementInScope(defaultScope, "ruby") { if p.elementInScope(defaultScope, a.Ruby) {
p.generateImpliedEndTags() p.generateImpliedEndTags()
} }
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "math", "svg": case a.Math, a.Svg:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
if p.tok.Data == "math" { if p.tok.DataAtom == a.Math {
adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments) adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
} else { } else {
adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments) adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
} }
adjustForeignAttributes(p.tok.Attr) adjustForeignAttributes(p.tok.Attr)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.top().Namespace = p.tok.Data p.top().Namespace = p.tok.Data
return true return true
case "caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr": case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token. // Ignore the token.
default: default:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "body": case a.Body:
if p.elementInScope(defaultScope, "body") { if p.elementInScope(defaultScope, a.Body) {
p.im = afterBodyIM p.im = afterBodyIM
} }
case "html": case a.Html:
if p.elementInScope(defaultScope, "body") { if p.elementInScope(defaultScope, a.Body) {
p.parseImpliedToken(EndTagToken, "body", nil) p.parseImpliedToken(EndTagToken, a.Body, a.Body.String(), nil)
return false return false
} }
return true return true
case "address", "article", "aside", "blockquote", "button", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "listing", "menu", "nav", "ol", "pre", "section", "summary", "ul": case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
p.popUntil(defaultScope, p.tok.Data) p.popUntil(defaultScope, p.tok.DataAtom)
case "form": case a.Form:
node := p.form node := p.form
p.form = nil p.form = nil
i := p.indexOfElementInScope(defaultScope, "form") i := p.indexOfElementInScope(defaultScope, a.Form)
if node == nil || i == -1 || p.oe[i] != node { if node == nil || i == -1 || p.oe[i] != node {
// Ignore the token. // Ignore the token.
return true return true
} }
p.generateImpliedEndTags() p.generateImpliedEndTags()
p.oe.remove(node) p.oe.remove(node)
case "p": case a.P:
if !p.elementInScope(buttonScope, "p") { if !p.elementInScope(buttonScope, a.P) {
p.addElement("p", nil) p.addElement(a.P, a.P.String(), nil)
} }
p.popUntil(buttonScope, "p") p.popUntil(buttonScope, a.P)
case "li": case a.Li:
p.popUntil(listItemScope, "li") p.popUntil(listItemScope, a.Li)
case "dd", "dt": case a.Dd, a.Dt:
p.popUntil(defaultScope, p.tok.Data) p.popUntil(defaultScope, p.tok.DataAtom)
case "h1", "h2", "h3", "h4", "h5", "h6": case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
p.popUntil(defaultScope, "h1", "h2", "h3", "h4", "h5", "h6") p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
case "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u": case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
p.inBodyEndTagFormatting(p.tok.Data) p.inBodyEndTagFormatting(p.tok.DataAtom)
case "applet", "marquee", "object": case a.Applet, a.Marquee, a.Object:
if p.popUntil(defaultScope, p.tok.Data) { if p.popUntil(defaultScope, p.tok.DataAtom) {
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
} }
case "br": case a.Br:
p.tok.Type = StartTagToken p.tok.Type = StartTagToken
return false return false
default: default:
p.inBodyEndTagOther(p.tok.Data) p.inBodyEndTagOther(p.tok.DataAtom)
} }
case CommentToken: case CommentToken:
p.addChild(&Node{ p.addChild(&Node{
...@@ -1017,7 +1021,7 @@ func inBodyIM(p *parser) bool { ...@@ -1017,7 +1021,7 @@ func inBodyIM(p *parser) bool {
return true return true
} }
func (p *parser) inBodyEndTagFormatting(tag string) { func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
// This is the "adoption agency" algorithm, described at // This is the "adoption agency" algorithm, described at
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency
...@@ -1033,13 +1037,13 @@ func (p *parser) inBodyEndTagFormatting(tag string) { ...@@ -1033,13 +1037,13 @@ func (p *parser) inBodyEndTagFormatting(tag string) {
if p.afe[j].Type == scopeMarkerNode { if p.afe[j].Type == scopeMarkerNode {
break break
} }
if p.afe[j].Data == tag { if p.afe[j].DataAtom == tagAtom {
formattingElement = p.afe[j] formattingElement = p.afe[j]
break break
} }
} }
if formattingElement == nil { if formattingElement == nil {
p.inBodyEndTagOther(tag) p.inBodyEndTagOther(tagAtom)
return return
} }
feIndex := p.oe.index(formattingElement) feIndex := p.oe.index(formattingElement)
...@@ -1047,7 +1051,7 @@ func (p *parser) inBodyEndTagFormatting(tag string) { ...@@ -1047,7 +1051,7 @@ func (p *parser) inBodyEndTagFormatting(tag string) {
p.afe.remove(formattingElement) p.afe.remove(formattingElement)
return return
} }
if !p.elementInScope(defaultScope, tag) { if !p.elementInScope(defaultScope, tagAtom) {
// Ignore the tag. // Ignore the tag.
return return
} }
...@@ -1114,8 +1118,8 @@ func (p *parser) inBodyEndTagFormatting(tag string) { ...@@ -1114,8 +1118,8 @@ func (p *parser) inBodyEndTagFormatting(tag string) {
if lastNode.Parent != nil { if lastNode.Parent != nil {
lastNode.Parent.Remove(lastNode) lastNode.Parent.Remove(lastNode)
} }
switch commonAncestor.Data { switch commonAncestor.DataAtom {
case "table", "tbody", "tfoot", "thead", "tr": case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
p.fosterParent(lastNode) p.fosterParent(lastNode)
default: default:
commonAncestor.Add(lastNode) commonAncestor.Add(lastNode)
...@@ -1142,9 +1146,9 @@ func (p *parser) inBodyEndTagFormatting(tag string) { ...@@ -1142,9 +1146,9 @@ func (p *parser) inBodyEndTagFormatting(tag string) {
} }
// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM. // inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
func (p *parser) inBodyEndTagOther(tag string) { func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
for i := len(p.oe) - 1; i >= 0; i-- { for i := len(p.oe) - 1; i >= 0; i-- {
if p.oe[i].Data == tag { if p.oe[i].DataAtom == tagAtom {
p.oe = p.oe[:i] p.oe = p.oe[:i]
break break
} }
...@@ -1161,7 +1165,7 @@ func textIM(p *parser) bool { ...@@ -1161,7 +1165,7 @@ func textIM(p *parser) bool {
p.oe.pop() p.oe.pop()
case TextToken: case TextToken:
d := p.tok.Data d := p.tok.Data
if n := p.oe.top(); n.Data == "textarea" && len(n.Child) == 0 { if n := p.oe.top(); n.DataAtom == a.Textarea && len(n.Child) == 0 {
// Ignore a newline at the start of a <textarea> block. // Ignore a newline at the start of a <textarea> block.
if d != "" && d[0] == '\r' { if d != "" && d[0] == '\r' {
d = d[1:] d = d[1:]
...@@ -1191,84 +1195,84 @@ func inTableIM(p *parser) bool { ...@@ -1191,84 +1195,84 @@ func inTableIM(p *parser) bool {
return true return true
case TextToken: case TextToken:
p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1) p.tok.Data = strings.Replace(p.tok.Data, "\x00", "", -1)
switch p.oe.top().Data { switch p.oe.top().DataAtom {
case "table", "tbody", "tfoot", "thead", "tr": case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
if strings.Trim(p.tok.Data, whitespace) == "" { if strings.Trim(p.tok.Data, whitespace) == "" {
p.addText(p.tok.Data) p.addText(p.tok.Data)
return true return true
} }
} }
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "caption": case a.Caption:
p.clearStackToContext(tableScope) p.clearStackToContext(tableScope)
p.afe = append(p.afe, &scopeMarker) p.afe = append(p.afe, &scopeMarker)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.im = inCaptionIM p.im = inCaptionIM
return true return true
case "colgroup": case a.Colgroup:
p.clearStackToContext(tableScope) p.clearStackToContext(tableScope)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.im = inColumnGroupIM p.im = inColumnGroupIM
return true return true
case "col": case a.Col:
p.parseImpliedToken(StartTagToken, "colgroup", nil) p.parseImpliedToken(StartTagToken, a.Colgroup, a.Colgroup.String(), nil)
return false return false
case "tbody", "tfoot", "thead": case a.Tbody, a.Tfoot, a.Thead:
p.clearStackToContext(tableScope) p.clearStackToContext(tableScope)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.im = inTableBodyIM p.im = inTableBodyIM
return true return true
case "td", "th", "tr": case a.Td, a.Th, a.Tr:
p.parseImpliedToken(StartTagToken, "tbody", nil) p.parseImpliedToken(StartTagToken, a.Tbody, a.Tbody.String(), nil)
return false return false
case "table": case a.Table:
if p.popUntil(tableScope, "table") { if p.popUntil(tableScope, a.Table) {
p.resetInsertionMode() p.resetInsertionMode()
return false return false
} }
// Ignore the token. // Ignore the token.
return true return true
case "style", "script": case a.Style, a.Script:
return inHeadIM(p) return inHeadIM(p)
case "input": case a.Input:
for _, t := range p.tok.Attr { for _, t := range p.tok.Attr {
if t.Key == "type" && strings.ToLower(t.Val) == "hidden" { if t.Key == "type" && strings.ToLower(t.Val) == "hidden" {
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.oe.pop() p.oe.pop()
return true return true
} }
} }
// Otherwise drop down to the default action. // Otherwise drop down to the default action.
case "form": case a.Form:
if p.form != nil { if p.form != nil {
// Ignore the token. // Ignore the token.
return true return true
} }
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.form = p.oe.pop() p.form = p.oe.pop()
case "select": case a.Select:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
switch p.top().Data { switch p.top().DataAtom {
case "table", "tbody", "tfoot", "thead", "tr": case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
p.fosterParenting = true p.fosterParenting = true
} }
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.fosterParenting = false p.fosterParenting = false
p.framesetOK = false p.framesetOK = false
p.im = inSelectInTableIM p.im = inSelectInTableIM
return true return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "table": case a.Table:
if p.popUntil(tableScope, "table") { if p.popUntil(tableScope, a.Table) {
p.resetInsertionMode() p.resetInsertionMode()
return true return true
} }
// Ignore the token. // Ignore the token.
return true return true
case "body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr": case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token. // Ignore the token.
return true return true
} }
...@@ -1283,8 +1287,8 @@ func inTableIM(p *parser) bool { ...@@ -1283,8 +1287,8 @@ func inTableIM(p *parser) bool {
return true return true
} }
switch p.top().Data { switch p.top().DataAtom {
case "table", "tbody", "tfoot", "thead", "tr": case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
p.fosterParenting = true p.fosterParenting = true
defer func() { p.fosterParenting = false }() defer func() { p.fosterParenting = false }()
} }
...@@ -1296,9 +1300,9 @@ func inTableIM(p *parser) bool { ...@@ -1296,9 +1300,9 @@ func inTableIM(p *parser) bool {
func inCaptionIM(p *parser) bool { func inCaptionIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "caption", "col", "colgroup", "tbody", "td", "tfoot", "thead", "tr": case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Thead, a.Tr:
if p.popUntil(tableScope, "caption") { if p.popUntil(tableScope, a.Caption) {
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
p.im = inTableIM p.im = inTableIM
return false return false
...@@ -1306,23 +1310,23 @@ func inCaptionIM(p *parser) bool { ...@@ -1306,23 +1310,23 @@ func inCaptionIM(p *parser) bool {
// Ignore the token. // Ignore the token.
return true return true
} }
case "select": case a.Select:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.framesetOK = false p.framesetOK = false
p.im = inSelectInTableIM p.im = inSelectInTableIM
return true return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "caption": case a.Caption:
if p.popUntil(tableScope, "caption") { if p.popUntil(tableScope, a.Caption) {
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
p.im = inTableIM p.im = inTableIM
} }
return true return true
case "table": case a.Table:
if p.popUntil(tableScope, "caption") { if p.popUntil(tableScope, a.Caption) {
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
p.im = inTableIM p.im = inTableIM
return false return false
...@@ -1330,7 +1334,7 @@ func inCaptionIM(p *parser) bool { ...@@ -1330,7 +1334,7 @@ func inCaptionIM(p *parser) bool {
// Ignore the token. // Ignore the token.
return true return true
} }
case "body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr": case a.Body, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token. // Ignore the token.
return true return true
} }
...@@ -1361,29 +1365,29 @@ func inColumnGroupIM(p *parser) bool { ...@@ -1361,29 +1365,29 @@ func inColumnGroupIM(p *parser) bool {
// Ignore the token. // Ignore the token.
return true return true
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "html": case a.Html:
return inBodyIM(p) return inBodyIM(p)
case "col": case a.Col:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
return true return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "colgroup": case a.Colgroup:
if p.oe.top().Data != "html" { if p.oe.top().DataAtom != a.Html {
p.oe.pop() p.oe.pop()
p.im = inTableIM p.im = inTableIM
} }
return true return true
case "col": case a.Col:
// Ignore the token. // Ignore the token.
return true return true
} }
} }
if p.oe.top().Data != "html" { if p.oe.top().DataAtom != a.Html {
p.oe.pop() p.oe.pop()
p.im = inTableIM p.im = inTableIM
return false return false
...@@ -1395,17 +1399,17 @@ func inColumnGroupIM(p *parser) bool { ...@@ -1395,17 +1399,17 @@ func inColumnGroupIM(p *parser) bool {
func inTableBodyIM(p *parser) bool { func inTableBodyIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "tr": case a.Tr:
p.clearStackToContext(tableBodyScope) p.clearStackToContext(tableBodyScope)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.im = inRowIM p.im = inRowIM
return true return true
case "td", "th": case a.Td, a.Th:
p.parseImpliedToken(StartTagToken, "tr", nil) p.parseImpliedToken(StartTagToken, a.Tr, a.Tr.String(), nil)
return false return false
case "caption", "col", "colgroup", "tbody", "tfoot", "thead": case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
if p.popUntil(tableScope, "tbody", "thead", "tfoot") { if p.popUntil(tableScope, a.Tbody, a.Thead, a.Tfoot) {
p.im = inTableIM p.im = inTableIM
return false return false
} }
...@@ -1413,22 +1417,22 @@ func inTableBodyIM(p *parser) bool { ...@@ -1413,22 +1417,22 @@ func inTableBodyIM(p *parser) bool {
return true return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "tbody", "tfoot", "thead": case a.Tbody, a.Tfoot, a.Thead:
if p.elementInScope(tableScope, p.tok.Data) { if p.elementInScope(tableScope, p.tok.DataAtom) {
p.clearStackToContext(tableBodyScope) p.clearStackToContext(tableBodyScope)
p.oe.pop() p.oe.pop()
p.im = inTableIM p.im = inTableIM
} }
return true return true
case "table": case a.Table:
if p.popUntil(tableScope, "tbody", "thead", "tfoot") { if p.popUntil(tableScope, a.Tbody, a.Thead, a.Tfoot) {
p.im = inTableIM p.im = inTableIM
return false return false
} }
// Ignore the token. // Ignore the token.
return true return true
case "body", "caption", "col", "colgroup", "html", "td", "th", "tr": case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Td, a.Th, a.Tr:
// Ignore the token. // Ignore the token.
return true return true
} }
...@@ -1447,15 +1451,15 @@ func inTableBodyIM(p *parser) bool { ...@@ -1447,15 +1451,15 @@ func inTableBodyIM(p *parser) bool {
func inRowIM(p *parser) bool { func inRowIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "td", "th": case a.Td, a.Th:
p.clearStackToContext(tableRowScope) p.clearStackToContext(tableRowScope)
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.afe = append(p.afe, &scopeMarker) p.afe = append(p.afe, &scopeMarker)
p.im = inCellIM p.im = inCellIM
return true return true
case "caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr": case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Tfoot, a.Thead, a.Tr:
if p.popUntil(tableScope, "tr") { if p.popUntil(tableScope, a.Tr) {
p.im = inTableBodyIM p.im = inTableBodyIM
return false return false
} }
...@@ -1463,29 +1467,29 @@ func inRowIM(p *parser) bool { ...@@ -1463,29 +1467,29 @@ func inRowIM(p *parser) bool {
return true return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "tr": case a.Tr:
if p.popUntil(tableScope, "tr") { if p.popUntil(tableScope, a.Tr) {
p.im = inTableBodyIM p.im = inTableBodyIM
return true return true
} }
// Ignore the token. // Ignore the token.
return true return true
case "table": case a.Table:
if p.popUntil(tableScope, "tr") { if p.popUntil(tableScope, a.Tr) {
p.im = inTableBodyIM p.im = inTableBodyIM
return false return false
} }
// Ignore the token. // Ignore the token.
return true return true
case "tbody", "tfoot", "thead": case a.Tbody, a.Tfoot, a.Thead:
if p.elementInScope(tableScope, p.tok.Data) { if p.elementInScope(tableScope, p.tok.DataAtom) {
p.parseImpliedToken(EndTagToken, "tr", nil) p.parseImpliedToken(EndTagToken, a.Tr, a.Tr.String(), nil)
return false return false
} }
// Ignore the token. // Ignore the token.
return true return true
case "body", "caption", "col", "colgroup", "html", "td", "th": case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Td, a.Th:
// Ignore the token. // Ignore the token.
return true return true
} }
...@@ -1498,9 +1502,9 @@ func inRowIM(p *parser) bool { ...@@ -1498,9 +1502,9 @@ func inRowIM(p *parser) bool {
func inCellIM(p *parser) bool { func inCellIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr": case a.Caption, a.Col, a.Colgroup, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
if p.popUntil(tableScope, "td", "th") { if p.popUntil(tableScope, a.Td, a.Th) {
// Close the cell and reprocess. // Close the cell and reprocess.
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
p.im = inRowIM p.im = inRowIM
...@@ -1508,33 +1512,33 @@ func inCellIM(p *parser) bool { ...@@ -1508,33 +1512,33 @@ func inCellIM(p *parser) bool {
} }
// Ignore the token. // Ignore the token.
return true return true
case "select": case a.Select:
p.reconstructActiveFormattingElements() p.reconstructActiveFormattingElements()
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.framesetOK = false p.framesetOK = false
p.im = inSelectInTableIM p.im = inSelectInTableIM
return true return true
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "td", "th": case a.Td, a.Th:
if !p.popUntil(tableScope, p.tok.Data) { if !p.popUntil(tableScope, p.tok.DataAtom) {
// Ignore the token. // Ignore the token.
return true return true
} }
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
p.im = inRowIM p.im = inRowIM
return true return true
case "body", "caption", "col", "colgroup", "html": case a.Body, a.Caption, a.Col, a.Colgroup, a.Html:
// Ignore the token. // Ignore the token.
return true return true
case "table", "tbody", "tfoot", "thead", "tr": case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
if !p.elementInScope(tableScope, p.tok.Data) { if !p.elementInScope(tableScope, p.tok.DataAtom) {
// Ignore the token. // Ignore the token.
return true return true
} }
// Close the cell and reprocess. // Close the cell and reprocess.
p.popUntil(tableScope, "td", "th") p.popUntil(tableScope, a.Td, a.Th)
p.clearActiveFormattingElements() p.clearActiveFormattingElements()
p.im = inRowIM p.im = inRowIM
return false return false
...@@ -1552,51 +1556,51 @@ func inSelectIM(p *parser) bool { ...@@ -1552,51 +1556,51 @@ func inSelectIM(p *parser) bool {
case TextToken: case TextToken:
p.addText(strings.Replace(p.tok.Data, "\x00", "", -1)) p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "html": case a.Html:
return inBodyIM(p) return inBodyIM(p)
case "option": case a.Option:
if p.top().Data == "option" { if p.top().DataAtom == a.Option {
p.oe.pop() p.oe.pop()
} }
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "optgroup": case a.Optgroup:
if p.top().Data == "option" { if p.top().DataAtom == a.Option {
p.oe.pop() p.oe.pop()
} }
if p.top().Data == "optgroup" { if p.top().DataAtom == a.Optgroup {
p.oe.pop() p.oe.pop()
} }
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "select": case a.Select:
p.tok.Type = EndTagToken p.tok.Type = EndTagToken
return false return false
case "input", "keygen", "textarea": case a.Input, a.Keygen, a.Textarea:
if p.elementInScope(selectScope, "select") { if p.elementInScope(selectScope, a.Select) {
p.parseImpliedToken(EndTagToken, "select", nil) p.parseImpliedToken(EndTagToken, a.Select, a.Select.String(), nil)
return false return false
} }
// Ignore the token. // Ignore the token.
return true return true
case "script": case a.Script:
return inHeadIM(p) return inHeadIM(p)
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "option": case a.Option:
if p.top().Data == "option" { if p.top().DataAtom == a.Option {
p.oe.pop() p.oe.pop()
} }
case "optgroup": case a.Optgroup:
i := len(p.oe) - 1 i := len(p.oe) - 1
if p.oe[i].Data == "option" { if p.oe[i].DataAtom == a.Option {
i-- i--
} }
if p.oe[i].Data == "optgroup" { if p.oe[i].DataAtom == a.Optgroup {
p.oe = p.oe[:i] p.oe = p.oe[:i]
} }
case "select": case a.Select:
if p.popUntil(selectScope, "select") { if p.popUntil(selectScope, a.Select) {
p.resetInsertionMode() p.resetInsertionMode()
} }
} }
...@@ -1617,10 +1621,10 @@ func inSelectIM(p *parser) bool { ...@@ -1617,10 +1621,10 @@ func inSelectIM(p *parser) bool {
func inSelectInTableIM(p *parser) bool { func inSelectInTableIM(p *parser) bool {
switch p.tok.Type { switch p.tok.Type {
case StartTagToken, EndTagToken: case StartTagToken, EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th": case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th:
if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.Data) { if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.DataAtom) {
p.parseImpliedToken(EndTagToken, "select", nil) p.parseImpliedToken(EndTagToken, a.Select, a.Select.String(), nil)
return false return false
} else { } else {
// Ignore the token. // Ignore the token.
...@@ -1644,17 +1648,17 @@ func afterBodyIM(p *parser) bool { ...@@ -1644,17 +1648,17 @@ func afterBodyIM(p *parser) bool {
return inBodyIM(p) return inBodyIM(p)
} }
case StartTagToken: case StartTagToken:
if p.tok.Data == "html" { if p.tok.DataAtom == a.Html {
return inBodyIM(p) return inBodyIM(p)
} }
case EndTagToken: case EndTagToken:
if p.tok.Data == "html" { if p.tok.DataAtom == a.Html {
p.im = afterAfterBodyIM p.im = afterAfterBodyIM
return true return true
} }
case CommentToken: case CommentToken:
// The comment is attached to the <html> element. // The comment is attached to the <html> element.
if len(p.oe) < 1 || p.oe[0].Data != "html" { if len(p.oe) < 1 || p.oe[0].DataAtom != a.Html {
panic("html: bad parser state: <html> element not found, in the after-body insertion mode") panic("html: bad parser state: <html> element not found, in the after-body insertion mode")
} }
p.oe[0].Add(&Node{ p.oe[0].Add(&Node{
...@@ -1688,24 +1692,24 @@ func inFramesetIM(p *parser) bool { ...@@ -1688,24 +1692,24 @@ func inFramesetIM(p *parser) bool {
p.addText(s) p.addText(s)
} }
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "html": case a.Html:
return inBodyIM(p) return inBodyIM(p)
case "frameset": case a.Frameset:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
case "frame": case a.Frame:
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.oe.pop() p.oe.pop()
p.acknowledgeSelfClosingTag() p.acknowledgeSelfClosingTag()
case "noframes": case a.Noframes:
return inHeadIM(p) return inHeadIM(p)
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "frameset": case a.Frameset:
if p.oe.top().Data != "html" { if p.oe.top().DataAtom != a.Html {
p.oe.pop() p.oe.pop()
if p.oe.top().Data != "frameset" { if p.oe.top().DataAtom != a.Frameset {
p.im = afterFramesetIM p.im = afterFramesetIM
return true return true
} }
...@@ -1738,15 +1742,15 @@ func afterFramesetIM(p *parser) bool { ...@@ -1738,15 +1742,15 @@ func afterFramesetIM(p *parser) bool {
p.addText(s) p.addText(s)
} }
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "html": case a.Html:
return inBodyIM(p) return inBodyIM(p)
case "noframes": case a.Noframes:
return inHeadIM(p) return inHeadIM(p)
} }
case EndTagToken: case EndTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "html": case a.Html:
p.im = afterAfterFramesetIM p.im = afterAfterFramesetIM
return true return true
} }
...@@ -1769,7 +1773,7 @@ func afterAfterBodyIM(p *parser) bool { ...@@ -1769,7 +1773,7 @@ func afterAfterBodyIM(p *parser) bool {
return inBodyIM(p) return inBodyIM(p)
} }
case StartTagToken: case StartTagToken:
if p.tok.Data == "html" { if p.tok.DataAtom == a.Html {
return inBodyIM(p) return inBodyIM(p)
} }
case CommentToken: case CommentToken:
...@@ -1807,10 +1811,10 @@ func afterAfterFramesetIM(p *parser) bool { ...@@ -1807,10 +1811,10 @@ func afterAfterFramesetIM(p *parser) bool {
return inBodyIM(p) return inBodyIM(p)
} }
case StartTagToken: case StartTagToken:
switch p.tok.Data { switch p.tok.DataAtom {
case "html": case a.Html:
return inBodyIM(p) return inBodyIM(p)
case "noframes": case a.Noframes:
return inHeadIM(p) return inHeadIM(p)
} }
case DoctypeToken: case DoctypeToken:
...@@ -1837,7 +1841,7 @@ func parseForeignContent(p *parser) bool { ...@@ -1837,7 +1841,7 @@ func parseForeignContent(p *parser) bool {
}) })
case StartTagToken: case StartTagToken:
b := breakout[p.tok.Data] b := breakout[p.tok.Data]
if p.tok.Data == "font" { if p.tok.DataAtom == a.Font {
loop: loop:
for _, attr := range p.tok.Attr { for _, attr := range p.tok.Attr {
switch attr.Key { switch attr.Key {
...@@ -1873,7 +1877,7 @@ func parseForeignContent(p *parser) bool { ...@@ -1873,7 +1877,7 @@ func parseForeignContent(p *parser) bool {
} }
adjustForeignAttributes(p.tok.Attr) adjustForeignAttributes(p.tok.Attr)
namespace := p.top().Namespace namespace := p.top().Namespace
p.addElement(p.tok.Data, p.tok.Attr) p.addElement(p.tok.DataAtom, p.tok.Data, p.tok.Attr)
p.top().Namespace = namespace p.top().Namespace = namespace
if p.hasSelfClosingToken { if p.hasSelfClosingToken {
p.oe.pop() p.oe.pop()
...@@ -1906,14 +1910,14 @@ func (p *parser) inForeignContent() bool { ...@@ -1906,14 +1910,14 @@ func (p *parser) inForeignContent() bool {
return false return false
} }
if mathMLTextIntegrationPoint(n) { if mathMLTextIntegrationPoint(n) {
if p.tok.Type == StartTagToken && p.tok.Data != "mglyph" && p.tok.Data != "malignmark" { if p.tok.Type == StartTagToken && p.tok.DataAtom != a.Mglyph && p.tok.DataAtom != a.Malignmark {
return false return false
} }
if p.tok.Type == TextToken { if p.tok.Type == TextToken {
return false return false
} }
} }
if n.Namespace == "math" && n.Data == "annotation-xml" && p.tok.Type == StartTagToken && p.tok.Data == "svg" { if n.Namespace == "math" && n.DataAtom == a.AnnotationXml && p.tok.Type == StartTagToken && p.tok.DataAtom == a.Svg {
return false return false
} }
if htmlIntegrationPoint(n) && (p.tok.Type == StartTagToken || p.tok.Type == TextToken) { if htmlIntegrationPoint(n) && (p.tok.Type == StartTagToken || p.tok.Type == TextToken) {
...@@ -1927,11 +1931,12 @@ func (p *parser) inForeignContent() bool { ...@@ -1927,11 +1931,12 @@ func (p *parser) inForeignContent() bool {
// parseImpliedToken parses a token as though it had appeared in the parser's // parseImpliedToken parses a token as though it had appeared in the parser's
// input. // input.
func (p *parser) parseImpliedToken(t TokenType, data string, attr []Attribute) { func (p *parser) parseImpliedToken(t TokenType, dataAtom a.Atom, data string, attr []Attribute) {
realToken, selfClosing := p.tok, p.hasSelfClosingToken realToken, selfClosing := p.tok, p.hasSelfClosingToken
p.tok = Token{ p.tok = Token{
Type: t, Type: t,
Data: data, // TODO: also set DataAtom. DataAtom: dataAtom,
Data: data,
Attr: attr, Attr: attr,
} }
p.hasSelfClosingToken = false p.hasSelfClosingToken = false
...@@ -1958,7 +1963,7 @@ func (p *parser) parseCurrentToken() { ...@@ -1958,7 +1963,7 @@ func (p *parser) parseCurrentToken() {
if p.hasSelfClosingToken { if p.hasSelfClosingToken {
p.hasSelfClosingToken = false p.hasSelfClosingToken = false
p.parseImpliedToken(EndTagToken, p.tok.Data, nil) p.parseImpliedToken(EndTagToken, p.tok.DataAtom, p.tok.Data, nil)
} }
} }
...@@ -2008,22 +2013,23 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) { ...@@ -2008,22 +2013,23 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
} }
if context != nil { if context != nil {
switch context.Data { switch context.DataAtom {
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "title", "textarea", "xmp": case a.Iframe, a.Noembed, a.Noframes, a.Noscript, a.Plaintext, a.Script, a.Style, a.Title, a.Textarea, a.Xmp:
p.tokenizer.rawTag = context.Data p.tokenizer.rawTag = context.DataAtom.String()
} }
} }
root := &Node{ root := &Node{
Type: ElementNode, Type: ElementNode,
Data: "html", // TODO: also set DataAtom. DataAtom: a.Html,
Data: a.Html.String(),
} }
p.doc.Add(root) p.doc.Add(root)
p.oe = nodeStack{root} p.oe = nodeStack{root}
p.resetInsertionMode() p.resetInsertionMode()
for n := context; n != nil; n = n.Parent { for n := context; n != nil; n = n.Parent {
if n.Type == ElementNode && n.Data == "form" { if n.Type == ElementNode && n.DataAtom == a.Form {
p.form = n p.form = n
break break
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment