Update x/net (#5169)
This commit is contained in:
parent
f887085ee0
commit
2af57c7820
|
@ -746,7 +746,8 @@
|
||||||
revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e"
|
revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:47ea747d07fae720d749d06ac5dc5ded0df70c57e328b6549cf2d9c64698757e"
|
branch = "master"
|
||||||
|
digest = "1:6d5ed712653ea5321fe3e3475ab2188cf362a4e0d31e9fd3acbd4dfbbca0d680"
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
packages = [
|
packages = [
|
||||||
"context",
|
"context",
|
||||||
|
@ -755,7 +756,7 @@
|
||||||
"html/charset",
|
"html/charset",
|
||||||
]
|
]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
revision = "9b4f9f5ad5197c79fd623a3638e70d8b26cef344"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:8159a9cda4b8810aaaeb0d60e2fa68e2fd86d8af4ec8f5059830839e3c8d93d5"
|
digest = "1:8159a9cda4b8810aaaeb0d60e2fa68e2fd86d8af4ec8f5059830839e3c8d93d5"
|
||||||
|
|
|
@ -27,7 +27,7 @@ ignored = ["google.golang.org/appengine*"]
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
revision = "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
branch = "master"
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
// Package context defines the Context type, which carries deadlines,
|
// Package context defines the Context type, which carries deadlines,
|
||||||
// cancelation signals, and other request-scoped values across API boundaries
|
// cancelation signals, and other request-scoped values across API boundaries
|
||||||
// and between processes.
|
// and between processes.
|
||||||
|
// As of Go 1.7 this package is available in the standard library under the
|
||||||
|
// name context. https://golang.org/pkg/context.
|
||||||
//
|
//
|
||||||
// Incoming requests to a server should create a Context, and outgoing calls to
|
// Incoming requests to a server should create a Context, and outgoing calls to
|
||||||
// servers should accept a Context. The chain of function calls between must
|
// servers should accept a Context. The chain of function calls between must
|
||||||
// propagate the Context, optionally replacing it with a modified copy created
|
// propagate the Context, optionally replacing it with a modified copy created
|
||||||
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
|
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
|
||||||
//
|
//
|
||||||
|
@ -16,14 +18,14 @@
|
||||||
// propagation:
|
// propagation:
|
||||||
//
|
//
|
||||||
// Do not store Contexts inside a struct type; instead, pass a Context
|
// Do not store Contexts inside a struct type; instead, pass a Context
|
||||||
// explicitly to each function that needs it. The Context should be the first
|
// explicitly to each function that needs it. The Context should be the first
|
||||||
// parameter, typically named ctx:
|
// parameter, typically named ctx:
|
||||||
//
|
//
|
||||||
// func DoSomething(ctx context.Context, arg Arg) error {
|
// func DoSomething(ctx context.Context, arg Arg) error {
|
||||||
// // ... use ctx ...
|
// // ... use ctx ...
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
||||||
// if you are unsure about which Context to use.
|
// if you are unsure about which Context to use.
|
||||||
//
|
//
|
||||||
// Use context Values only for request-scoped data that transits processes and
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
@ -36,112 +38,15 @@
|
||||||
// Contexts.
|
// Contexts.
|
||||||
package context // import "golang.org/x/net/context"
|
package context // import "golang.org/x/net/context"
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
// A Context carries a deadline, a cancelation signal, and other values across
|
|
||||||
// API boundaries.
|
|
||||||
//
|
|
||||||
// Context's methods may be called by multiple goroutines simultaneously.
|
|
||||||
type Context interface {
|
|
||||||
// Deadline returns the time when work done on behalf of this context
|
|
||||||
// should be canceled. Deadline returns ok==false when no deadline is
|
|
||||||
// set. Successive calls to Deadline return the same results.
|
|
||||||
Deadline() (deadline time.Time, ok bool)
|
|
||||||
|
|
||||||
// Done returns a channel that's closed when work done on behalf of this
|
|
||||||
// context should be canceled. Done may return nil if this context can
|
|
||||||
// never be canceled. Successive calls to Done return the same value.
|
|
||||||
//
|
|
||||||
// WithCancel arranges for Done to be closed when cancel is called;
|
|
||||||
// WithDeadline arranges for Done to be closed when the deadline
|
|
||||||
// expires; WithTimeout arranges for Done to be closed when the timeout
|
|
||||||
// elapses.
|
|
||||||
//
|
|
||||||
// Done is provided for use in select statements:
|
|
||||||
//
|
|
||||||
// // Stream generates values with DoSomething and sends them to out
|
|
||||||
// // until DoSomething returns an error or ctx.Done is closed.
|
|
||||||
// func Stream(ctx context.Context, out chan<- Value) error {
|
|
||||||
// for {
|
|
||||||
// v, err := DoSomething(ctx)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// select {
|
|
||||||
// case <-ctx.Done():
|
|
||||||
// return ctx.Err()
|
|
||||||
// case out <- v:
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// See http://blog.golang.org/pipelines for more examples of how to use
|
|
||||||
// a Done channel for cancelation.
|
|
||||||
Done() <-chan struct{}
|
|
||||||
|
|
||||||
// Err returns a non-nil error value after Done is closed. Err returns
|
|
||||||
// Canceled if the context was canceled or DeadlineExceeded if the
|
|
||||||
// context's deadline passed. No other values for Err are defined.
|
|
||||||
// After Done is closed, successive calls to Err return the same value.
|
|
||||||
Err() error
|
|
||||||
|
|
||||||
// Value returns the value associated with this context for key, or nil
|
|
||||||
// if no value is associated with key. Successive calls to Value with
|
|
||||||
// the same key returns the same result.
|
|
||||||
//
|
|
||||||
// Use context values only for request-scoped data that transits
|
|
||||||
// processes and API boundaries, not for passing optional parameters to
|
|
||||||
// functions.
|
|
||||||
//
|
|
||||||
// A key identifies a specific value in a Context. Functions that wish
|
|
||||||
// to store values in Context typically allocate a key in a global
|
|
||||||
// variable then use that key as the argument to context.WithValue and
|
|
||||||
// Context.Value. A key can be any type that supports equality;
|
|
||||||
// packages should define keys as an unexported type to avoid
|
|
||||||
// collisions.
|
|
||||||
//
|
|
||||||
// Packages that define a Context key should provide type-safe accessors
|
|
||||||
// for the values stores using that key:
|
|
||||||
//
|
|
||||||
// // Package user defines a User type that's stored in Contexts.
|
|
||||||
// package user
|
|
||||||
//
|
|
||||||
// import "golang.org/x/net/context"
|
|
||||||
//
|
|
||||||
// // User is the type of value stored in the Contexts.
|
|
||||||
// type User struct {...}
|
|
||||||
//
|
|
||||||
// // key is an unexported type for keys defined in this package.
|
|
||||||
// // This prevents collisions with keys defined in other packages.
|
|
||||||
// type key int
|
|
||||||
//
|
|
||||||
// // userKey is the key for user.User values in Contexts. It is
|
|
||||||
// // unexported; clients use user.NewContext and user.FromContext
|
|
||||||
// // instead of using this key directly.
|
|
||||||
// var userKey key = 0
|
|
||||||
//
|
|
||||||
// // NewContext returns a new Context that carries value u.
|
|
||||||
// func NewContext(ctx context.Context, u *User) context.Context {
|
|
||||||
// return context.WithValue(ctx, userKey, u)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // FromContext returns the User value stored in ctx, if any.
|
|
||||||
// func FromContext(ctx context.Context) (*User, bool) {
|
|
||||||
// u, ok := ctx.Value(userKey).(*User)
|
|
||||||
// return u, ok
|
|
||||||
// }
|
|
||||||
Value(key interface{}) interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Background returns a non-nil, empty Context. It is never canceled, has no
|
// Background returns a non-nil, empty Context. It is never canceled, has no
|
||||||
// values, and has no deadline. It is typically used by the main function,
|
// values, and has no deadline. It is typically used by the main function,
|
||||||
// initialization, and tests, and as the top-level Context for incoming
|
// initialization, and tests, and as the top-level Context for incoming
|
||||||
// requests.
|
// requests.
|
||||||
func Background() Context {
|
func Background() Context {
|
||||||
return background
|
return background
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||||
// it's unclear which Context to use or it is not yet available (because the
|
// it's unclear which Context to use or it is not yet available (because the
|
||||||
// surrounding function has not yet been extended to accept a Context
|
// surrounding function has not yet been extended to accept a Context
|
||||||
// parameter). TODO is recognized by static analysis tools that determine
|
// parameter). TODO is recognized by static analysis tools that determine
|
||||||
|
@ -149,8 +54,3 @@ func Background() Context {
|
||||||
func TODO() Context {
|
func TODO() Context {
|
||||||
return todo
|
return todo
|
||||||
}
|
}
|
||||||
|
|
||||||
// A CancelFunc tells an operation to abandon its work.
|
|
||||||
// A CancelFunc does not wait for the work to stop.
|
|
||||||
// After the first call, subsequent calls to a CancelFunc do nothing.
|
|
||||||
type CancelFunc func()
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
// context's Done channel is closed when the deadline expires, when the returned
|
// context's Done channel is closed when the deadline expires, when the returned
|
||||||
// cancel function is called, or when the parent context's Done channel is
|
// cancel function is called, or when the parent context's Done channel is
|
||||||
// closed, whichever happens first.
|
// closed, whichever happens first.
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import "context" // standard library's context, as of Go 1.7
|
||||||
|
|
||||||
|
// A Context carries a deadline, a cancelation signal, and other values across
|
||||||
|
// API boundaries.
|
||||||
|
//
|
||||||
|
// Context's methods may be called by multiple goroutines simultaneously.
|
||||||
|
type Context = context.Context
|
||||||
|
|
||||||
|
// A CancelFunc tells an operation to abandon its work.
|
||||||
|
// A CancelFunc does not wait for the work to stop.
|
||||||
|
// After the first call, subsequent calls to a CancelFunc do nothing.
|
||||||
|
type CancelFunc = context.CancelFunc
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||||
// struct{}, since vars of this type must have distinct addresses.
|
// struct{}, since vars of this type must have distinct addresses.
|
||||||
type emptyCtx int
|
type emptyCtx int
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ func propagateCancel(parent Context, child canceler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parentCancelCtx follows a chain of parent references until it finds a
|
// parentCancelCtx follows a chain of parent references until it finds a
|
||||||
// *cancelCtx. This function understands how each of the concrete types in this
|
// *cancelCtx. This function understands how each of the concrete types in this
|
||||||
// package represents its parent.
|
// package represents its parent.
|
||||||
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
||||||
for {
|
for {
|
||||||
|
@ -134,14 +134,14 @@ func removeChild(parent Context, child canceler) {
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// A canceler is a context type that can be canceled directly. The
|
// A canceler is a context type that can be canceled directly. The
|
||||||
// implementations are *cancelCtx and *timerCtx.
|
// implementations are *cancelCtx and *timerCtx.
|
||||||
type canceler interface {
|
type canceler interface {
|
||||||
cancel(removeFromParent bool, err error)
|
cancel(removeFromParent bool, err error)
|
||||||
Done() <-chan struct{}
|
Done() <-chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
||||||
// that implement canceler.
|
// that implement canceler.
|
||||||
type cancelCtx struct {
|
type cancelCtx struct {
|
||||||
Context
|
Context
|
||||||
|
@ -193,8 +193,8 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
// context's Done channel is closed when the deadline expires, when the returned
|
// context's Done channel is closed when the deadline expires, when the returned
|
||||||
// cancel function is called, or when the parent context's Done channel is
|
// cancel function is called, or when the parent context's Done channel is
|
||||||
// closed, whichever happens first.
|
// closed, whichever happens first.
|
||||||
|
@ -226,8 +226,8 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||||
return c, func() { c.cancel(true, Canceled) }
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
||||||
// implement Done and Err. It implements cancel by stopping its timer then
|
// implement Done and Err. It implements cancel by stopping its timer then
|
||||||
// delegating to cancelCtx.cancel.
|
// delegating to cancelCtx.cancel.
|
||||||
type timerCtx struct {
|
type timerCtx struct {
|
||||||
*cancelCtx
|
*cancelCtx
|
||||||
|
@ -281,7 +281,7 @@ func WithValue(parent Context, key interface{}, val interface{}) Context {
|
||||||
return &valueCtx{parent, key, val}
|
return &valueCtx{parent, key, val}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A valueCtx carries a key-value pair. It implements Value for that key and
|
// A valueCtx carries a key-value pair. It implements Value for that key and
|
||||||
// delegates all other calls to the embedded Context.
|
// delegates all other calls to the embedded Context.
|
||||||
type valueCtx struct {
|
type valueCtx struct {
|
||||||
Context
|
Context
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// A Context carries a deadline, a cancelation signal, and other values across
|
||||||
|
// API boundaries.
|
||||||
|
//
|
||||||
|
// Context's methods may be called by multiple goroutines simultaneously.
|
||||||
|
type Context interface {
|
||||||
|
// Deadline returns the time when work done on behalf of this context
|
||||||
|
// should be canceled. Deadline returns ok==false when no deadline is
|
||||||
|
// set. Successive calls to Deadline return the same results.
|
||||||
|
Deadline() (deadline time.Time, ok bool)
|
||||||
|
|
||||||
|
// Done returns a channel that's closed when work done on behalf of this
|
||||||
|
// context should be canceled. Done may return nil if this context can
|
||||||
|
// never be canceled. Successive calls to Done return the same value.
|
||||||
|
//
|
||||||
|
// WithCancel arranges for Done to be closed when cancel is called;
|
||||||
|
// WithDeadline arranges for Done to be closed when the deadline
|
||||||
|
// expires; WithTimeout arranges for Done to be closed when the timeout
|
||||||
|
// elapses.
|
||||||
|
//
|
||||||
|
// Done is provided for use in select statements:
|
||||||
|
//
|
||||||
|
// // Stream generates values with DoSomething and sends them to out
|
||||||
|
// // until DoSomething returns an error or ctx.Done is closed.
|
||||||
|
// func Stream(ctx context.Context, out chan<- Value) error {
|
||||||
|
// for {
|
||||||
|
// v, err := DoSomething(ctx)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// select {
|
||||||
|
// case <-ctx.Done():
|
||||||
|
// return ctx.Err()
|
||||||
|
// case out <- v:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// See http://blog.golang.org/pipelines for more examples of how to use
|
||||||
|
// a Done channel for cancelation.
|
||||||
|
Done() <-chan struct{}
|
||||||
|
|
||||||
|
// Err returns a non-nil error value after Done is closed. Err returns
|
||||||
|
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||||
|
// context's deadline passed. No other values for Err are defined.
|
||||||
|
// After Done is closed, successive calls to Err return the same value.
|
||||||
|
Err() error
|
||||||
|
|
||||||
|
// Value returns the value associated with this context for key, or nil
|
||||||
|
// if no value is associated with key. Successive calls to Value with
|
||||||
|
// the same key returns the same result.
|
||||||
|
//
|
||||||
|
// Use context values only for request-scoped data that transits
|
||||||
|
// processes and API boundaries, not for passing optional parameters to
|
||||||
|
// functions.
|
||||||
|
//
|
||||||
|
// A key identifies a specific value in a Context. Functions that wish
|
||||||
|
// to store values in Context typically allocate a key in a global
|
||||||
|
// variable then use that key as the argument to context.WithValue and
|
||||||
|
// Context.Value. A key can be any type that supports equality;
|
||||||
|
// packages should define keys as an unexported type to avoid
|
||||||
|
// collisions.
|
||||||
|
//
|
||||||
|
// Packages that define a Context key should provide type-safe accessors
|
||||||
|
// for the values stores using that key:
|
||||||
|
//
|
||||||
|
// // Package user defines a User type that's stored in Contexts.
|
||||||
|
// package user
|
||||||
|
//
|
||||||
|
// import "golang.org/x/net/context"
|
||||||
|
//
|
||||||
|
// // User is the type of value stored in the Contexts.
|
||||||
|
// type User struct {...}
|
||||||
|
//
|
||||||
|
// // key is an unexported type for keys defined in this package.
|
||||||
|
// // This prevents collisions with keys defined in other packages.
|
||||||
|
// type key int
|
||||||
|
//
|
||||||
|
// // userKey is the key for user.User values in Contexts. It is
|
||||||
|
// // unexported; clients use user.NewContext and user.FromContext
|
||||||
|
// // instead of using this key directly.
|
||||||
|
// var userKey key = 0
|
||||||
|
//
|
||||||
|
// // NewContext returns a new Context that carries value u.
|
||||||
|
// func NewContext(ctx context.Context, u *User) context.Context {
|
||||||
|
// return context.WithValue(ctx, userKey, u)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // FromContext returns the User value stored in ctx, if any.
|
||||||
|
// func FromContext(ctx context.Context) (*User, bool) {
|
||||||
|
// u, ok := ctx.Value(userKey).(*User)
|
||||||
|
// return u, ok
|
||||||
|
// }
|
||||||
|
Value(key interface{}) interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CancelFunc tells an operation to abandon its work.
|
||||||
|
// A CancelFunc does not wait for the work to stop.
|
||||||
|
// After the first call, subsequent calls to a CancelFunc do nothing.
|
||||||
|
type CancelFunc func()
|
|
@ -4,17 +4,17 @@
|
||||||
|
|
||||||
// +build ignore
|
// +build ignore
|
||||||
|
|
||||||
|
//go:generate go run gen.go
|
||||||
|
//go:generate go run gen.go -test
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
// This program generates table.go and table_test.go.
|
|
||||||
// Invoke as
|
|
||||||
//
|
|
||||||
// go run gen.go |gofmt >table.go
|
|
||||||
// go run gen.go -test |gofmt >table_test.go
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -42,6 +42,18 @@ func identifier(s string) string {
|
||||||
|
|
||||||
var test = flag.Bool("test", false, "generate table_test.go")
|
var test = flag.Bool("test", false, "generate table_test.go")
|
||||||
|
|
||||||
|
func genFile(name string, buf *bytes.Buffer) {
|
||||||
|
b, err := format.Source(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if err := ioutil.WriteFile(name, b, 0644); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
@ -52,32 +64,31 @@ func main() {
|
||||||
all = append(all, extra...)
|
all = append(all, extra...)
|
||||||
sort.Strings(all)
|
sort.Strings(all)
|
||||||
|
|
||||||
if *test {
|
|
||||||
fmt.Printf("// generated by go run gen.go -test; DO NOT EDIT\n\n")
|
|
||||||
fmt.Printf("package atom\n\n")
|
|
||||||
fmt.Printf("var testAtomList = []string{\n")
|
|
||||||
for _, s := range all {
|
|
||||||
fmt.Printf("\t%q,\n", s)
|
|
||||||
}
|
|
||||||
fmt.Printf("}\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// uniq - lists have dups
|
// uniq - lists have dups
|
||||||
// compute max len too
|
|
||||||
maxLen := 0
|
|
||||||
w := 0
|
w := 0
|
||||||
for _, s := range all {
|
for _, s := range all {
|
||||||
if w == 0 || all[w-1] != s {
|
if w == 0 || all[w-1] != s {
|
||||||
if maxLen < len(s) {
|
|
||||||
maxLen = len(s)
|
|
||||||
}
|
|
||||||
all[w] = s
|
all[w] = s
|
||||||
w++
|
w++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
all = all[:w]
|
all = all[:w]
|
||||||
|
|
||||||
|
if *test {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fmt.Fprintln(&buf, "// Code generated by go generate gen.go; DO NOT EDIT.\n")
|
||||||
|
fmt.Fprintln(&buf, "//go:generate go run gen.go -test\n")
|
||||||
|
fmt.Fprintln(&buf, "package atom\n")
|
||||||
|
fmt.Fprintln(&buf, "var testAtomList = []string{")
|
||||||
|
for _, s := range all {
|
||||||
|
fmt.Fprintf(&buf, "\t%q,\n", s)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(&buf, "}")
|
||||||
|
|
||||||
|
genFile("table_test.go", &buf)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Find hash that minimizes table size.
|
// Find hash that minimizes table size.
|
||||||
var best *table
|
var best *table
|
||||||
for i := 0; i < 1000000; i++ {
|
for i := 0; i < 1000000; i++ {
|
||||||
|
@ -163,36 +174,46 @@ func main() {
|
||||||
atom[s] = uint32(off<<8 | len(s))
|
atom[s] = uint32(off<<8 | len(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
// Generate the Go code.
|
// Generate the Go code.
|
||||||
fmt.Printf("// generated by go run gen.go; DO NOT EDIT\n\n")
|
fmt.Fprintln(&buf, "// Code generated by go generate gen.go; DO NOT EDIT.\n")
|
||||||
fmt.Printf("package atom\n\nconst (\n")
|
fmt.Fprintln(&buf, "//go:generate go run gen.go\n")
|
||||||
|
fmt.Fprintln(&buf, "package atom\n\nconst (")
|
||||||
|
|
||||||
|
// compute max len
|
||||||
|
maxLen := 0
|
||||||
for _, s := range all {
|
for _, s := range all {
|
||||||
fmt.Printf("\t%s Atom = %#x\n", identifier(s), atom[s])
|
if maxLen < len(s) {
|
||||||
|
maxLen = len(s)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, "\t%s Atom = %#x\n", identifier(s), atom[s])
|
||||||
}
|
}
|
||||||
fmt.Printf(")\n\n")
|
fmt.Fprintln(&buf, ")\n")
|
||||||
|
|
||||||
fmt.Printf("const hash0 = %#x\n\n", best.h0)
|
fmt.Fprintf(&buf, "const hash0 = %#x\n\n", best.h0)
|
||||||
fmt.Printf("const maxAtomLen = %d\n\n", maxLen)
|
fmt.Fprintf(&buf, "const maxAtomLen = %d\n\n", maxLen)
|
||||||
|
|
||||||
fmt.Printf("var table = [1<<%d]Atom{\n", best.k)
|
fmt.Fprintf(&buf, "var table = [1<<%d]Atom{\n", best.k)
|
||||||
for i, s := range best.tab {
|
for i, s := range best.tab {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("\t%#x: %#x, // %s\n", i, atom[s], s)
|
fmt.Fprintf(&buf, "\t%#x: %#x, // %s\n", i, atom[s], s)
|
||||||
}
|
}
|
||||||
fmt.Printf("}\n")
|
fmt.Fprintf(&buf, "}\n")
|
||||||
datasize := (1 << best.k) * 4
|
datasize := (1 << best.k) * 4
|
||||||
|
|
||||||
fmt.Printf("const atomText =\n")
|
fmt.Fprintln(&buf, "const atomText =")
|
||||||
textsize := len(text)
|
textsize := len(text)
|
||||||
for len(text) > 60 {
|
for len(text) > 60 {
|
||||||
fmt.Printf("\t%q +\n", text[:60])
|
fmt.Fprintf(&buf, "\t%q +\n", text[:60])
|
||||||
text = text[60:]
|
text = text[60:]
|
||||||
}
|
}
|
||||||
fmt.Printf("\t%q\n\n", text)
|
fmt.Fprintf(&buf, "\t%q\n\n", text)
|
||||||
|
|
||||||
fmt.Fprintf(os.Stderr, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize)
|
genFile("table.go", &buf)
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stdout, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize)
|
||||||
}
|
}
|
||||||
|
|
||||||
type byLen []string
|
type byLen []string
|
||||||
|
@ -285,8 +306,10 @@ func (t *table) push(i uint32, depth int) bool {
|
||||||
|
|
||||||
// The lists of element names and attribute keys were taken from
|
// The lists of element names and attribute keys were taken from
|
||||||
// https://html.spec.whatwg.org/multipage/indices.html#index
|
// https://html.spec.whatwg.org/multipage/indices.html#index
|
||||||
// as of the "HTML Living Standard - Last Updated 21 February 2015" version.
|
// as of the "HTML Living Standard - Last Updated 16 April 2018" version.
|
||||||
|
|
||||||
|
// "command", "keygen" and "menuitem" have been removed from the spec,
|
||||||
|
// but are kept here for backwards compatibility.
|
||||||
var elements = []string{
|
var elements = []string{
|
||||||
"a",
|
"a",
|
||||||
"abbr",
|
"abbr",
|
||||||
|
@ -349,6 +372,7 @@ var elements = []string{
|
||||||
"legend",
|
"legend",
|
||||||
"li",
|
"li",
|
||||||
"link",
|
"link",
|
||||||
|
"main",
|
||||||
"map",
|
"map",
|
||||||
"mark",
|
"mark",
|
||||||
"menu",
|
"menu",
|
||||||
|
@ -364,6 +388,7 @@ var elements = []string{
|
||||||
"output",
|
"output",
|
||||||
"p",
|
"p",
|
||||||
"param",
|
"param",
|
||||||
|
"picture",
|
||||||
"pre",
|
"pre",
|
||||||
"progress",
|
"progress",
|
||||||
"q",
|
"q",
|
||||||
|
@ -375,6 +400,7 @@ var elements = []string{
|
||||||
"script",
|
"script",
|
||||||
"section",
|
"section",
|
||||||
"select",
|
"select",
|
||||||
|
"slot",
|
||||||
"small",
|
"small",
|
||||||
"source",
|
"source",
|
||||||
"span",
|
"span",
|
||||||
|
@ -403,14 +429,21 @@ var elements = []string{
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/indices.html#attributes-3
|
// https://html.spec.whatwg.org/multipage/indices.html#attributes-3
|
||||||
|
//
|
||||||
|
// "challenge", "command", "contextmenu", "dropzone", "icon", "keytype", "mediagroup",
|
||||||
|
// "radiogroup", "spellcheck", "scoped", "seamless", "sortable" and "sorted" have been removed from the spec,
|
||||||
|
// but are kept here for backwards compatibility.
|
||||||
var attributes = []string{
|
var attributes = []string{
|
||||||
"abbr",
|
"abbr",
|
||||||
"accept",
|
"accept",
|
||||||
"accept-charset",
|
"accept-charset",
|
||||||
"accesskey",
|
"accesskey",
|
||||||
"action",
|
"action",
|
||||||
|
"allowfullscreen",
|
||||||
|
"allowpaymentrequest",
|
||||||
|
"allowusermedia",
|
||||||
"alt",
|
"alt",
|
||||||
|
"as",
|
||||||
"async",
|
"async",
|
||||||
"autocomplete",
|
"autocomplete",
|
||||||
"autofocus",
|
"autofocus",
|
||||||
|
@ -420,6 +453,7 @@ var attributes = []string{
|
||||||
"checked",
|
"checked",
|
||||||
"cite",
|
"cite",
|
||||||
"class",
|
"class",
|
||||||
|
"color",
|
||||||
"cols",
|
"cols",
|
||||||
"colspan",
|
"colspan",
|
||||||
"command",
|
"command",
|
||||||
|
@ -457,6 +491,8 @@ var attributes = []string{
|
||||||
"icon",
|
"icon",
|
||||||
"id",
|
"id",
|
||||||
"inputmode",
|
"inputmode",
|
||||||
|
"integrity",
|
||||||
|
"is",
|
||||||
"ismap",
|
"ismap",
|
||||||
"itemid",
|
"itemid",
|
||||||
"itemprop",
|
"itemprop",
|
||||||
|
@ -481,16 +517,20 @@ var attributes = []string{
|
||||||
"multiple",
|
"multiple",
|
||||||
"muted",
|
"muted",
|
||||||
"name",
|
"name",
|
||||||
|
"nomodule",
|
||||||
|
"nonce",
|
||||||
"novalidate",
|
"novalidate",
|
||||||
"open",
|
"open",
|
||||||
"optimum",
|
"optimum",
|
||||||
"pattern",
|
"pattern",
|
||||||
"ping",
|
"ping",
|
||||||
"placeholder",
|
"placeholder",
|
||||||
|
"playsinline",
|
||||||
"poster",
|
"poster",
|
||||||
"preload",
|
"preload",
|
||||||
"radiogroup",
|
"radiogroup",
|
||||||
"readonly",
|
"readonly",
|
||||||
|
"referrerpolicy",
|
||||||
"rel",
|
"rel",
|
||||||
"required",
|
"required",
|
||||||
"reversed",
|
"reversed",
|
||||||
|
@ -507,10 +547,13 @@ var attributes = []string{
|
||||||
"sizes",
|
"sizes",
|
||||||
"sortable",
|
"sortable",
|
||||||
"sorted",
|
"sorted",
|
||||||
|
"slot",
|
||||||
"span",
|
"span",
|
||||||
|
"spellcheck",
|
||||||
"src",
|
"src",
|
||||||
"srcdoc",
|
"srcdoc",
|
||||||
"srclang",
|
"srclang",
|
||||||
|
"srcset",
|
||||||
"start",
|
"start",
|
||||||
"step",
|
"step",
|
||||||
"style",
|
"style",
|
||||||
|
@ -520,16 +563,22 @@ var attributes = []string{
|
||||||
"translate",
|
"translate",
|
||||||
"type",
|
"type",
|
||||||
"typemustmatch",
|
"typemustmatch",
|
||||||
|
"updateviacache",
|
||||||
"usemap",
|
"usemap",
|
||||||
"value",
|
"value",
|
||||||
"width",
|
"width",
|
||||||
|
"workertype",
|
||||||
"wrap",
|
"wrap",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "onautocomplete", "onautocompleteerror", "onmousewheel",
|
||||||
|
// "onshow" and "onsort" have been removed from the spec,
|
||||||
|
// but are kept here for backwards compatibility.
|
||||||
var eventHandlers = []string{
|
var eventHandlers = []string{
|
||||||
"onabort",
|
"onabort",
|
||||||
"onautocomplete",
|
"onautocomplete",
|
||||||
"onautocompleteerror",
|
"onautocompleteerror",
|
||||||
|
"onauxclick",
|
||||||
"onafterprint",
|
"onafterprint",
|
||||||
"onbeforeprint",
|
"onbeforeprint",
|
||||||
"onbeforeunload",
|
"onbeforeunload",
|
||||||
|
@ -541,11 +590,14 @@ var eventHandlers = []string{
|
||||||
"onclick",
|
"onclick",
|
||||||
"onclose",
|
"onclose",
|
||||||
"oncontextmenu",
|
"oncontextmenu",
|
||||||
|
"oncopy",
|
||||||
"oncuechange",
|
"oncuechange",
|
||||||
|
"oncut",
|
||||||
"ondblclick",
|
"ondblclick",
|
||||||
"ondrag",
|
"ondrag",
|
||||||
"ondragend",
|
"ondragend",
|
||||||
"ondragenter",
|
"ondragenter",
|
||||||
|
"ondragexit",
|
||||||
"ondragleave",
|
"ondragleave",
|
||||||
"ondragover",
|
"ondragover",
|
||||||
"ondragstart",
|
"ondragstart",
|
||||||
|
@ -565,18 +617,24 @@ var eventHandlers = []string{
|
||||||
"onload",
|
"onload",
|
||||||
"onloadeddata",
|
"onloadeddata",
|
||||||
"onloadedmetadata",
|
"onloadedmetadata",
|
||||||
|
"onloadend",
|
||||||
"onloadstart",
|
"onloadstart",
|
||||||
"onmessage",
|
"onmessage",
|
||||||
|
"onmessageerror",
|
||||||
"onmousedown",
|
"onmousedown",
|
||||||
|
"onmouseenter",
|
||||||
|
"onmouseleave",
|
||||||
"onmousemove",
|
"onmousemove",
|
||||||
"onmouseout",
|
"onmouseout",
|
||||||
"onmouseover",
|
"onmouseover",
|
||||||
"onmouseup",
|
"onmouseup",
|
||||||
"onmousewheel",
|
"onmousewheel",
|
||||||
|
"onwheel",
|
||||||
"onoffline",
|
"onoffline",
|
||||||
"ononline",
|
"ononline",
|
||||||
"onpagehide",
|
"onpagehide",
|
||||||
"onpageshow",
|
"onpageshow",
|
||||||
|
"onpaste",
|
||||||
"onpause",
|
"onpause",
|
||||||
"onplay",
|
"onplay",
|
||||||
"onplaying",
|
"onplaying",
|
||||||
|
@ -585,7 +643,9 @@ var eventHandlers = []string{
|
||||||
"onratechange",
|
"onratechange",
|
||||||
"onreset",
|
"onreset",
|
||||||
"onresize",
|
"onresize",
|
||||||
|
"onrejectionhandled",
|
||||||
"onscroll",
|
"onscroll",
|
||||||
|
"onsecuritypolicyviolation",
|
||||||
"onseeked",
|
"onseeked",
|
||||||
"onseeking",
|
"onseeking",
|
||||||
"onselect",
|
"onselect",
|
||||||
|
@ -597,6 +657,7 @@ var eventHandlers = []string{
|
||||||
"onsuspend",
|
"onsuspend",
|
||||||
"ontimeupdate",
|
"ontimeupdate",
|
||||||
"ontoggle",
|
"ontoggle",
|
||||||
|
"onunhandledrejection",
|
||||||
"onunload",
|
"onunload",
|
||||||
"onvolumechange",
|
"onvolumechange",
|
||||||
"onwaiting",
|
"onwaiting",
|
||||||
|
@ -604,6 +665,7 @@ var eventHandlers = []string{
|
||||||
|
|
||||||
// extra are ad-hoc values not covered by any of the lists above.
|
// extra are ad-hoc values not covered by any of the lists above.
|
||||||
var extra = []string{
|
var extra = []string{
|
||||||
|
"acronym",
|
||||||
"align",
|
"align",
|
||||||
"annotation",
|
"annotation",
|
||||||
"annotation-xml",
|
"annotation-xml",
|
||||||
|
@ -639,6 +701,8 @@ var extra = []string{
|
||||||
"plaintext",
|
"plaintext",
|
||||||
"prompt",
|
"prompt",
|
||||||
"public",
|
"public",
|
||||||
|
"rb",
|
||||||
|
"rtc",
|
||||||
"spacer",
|
"spacer",
|
||||||
"strike",
|
"strike",
|
||||||
"svg",
|
"svg",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
package html
|
package html
|
||||||
|
|
||||||
// Section 12.2.3.2 of the HTML5 specification says "The following elements
|
// Section 12.2.4.2 of the HTML5 specification says "The following elements
|
||||||
// have varying levels of special parsing rules".
|
// have varying levels of special parsing rules".
|
||||||
// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
|
// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
|
||||||
var isSpecialElementMap = map[string]bool{
|
var isSpecialElementMap = map[string]bool{
|
||||||
|
@ -52,10 +52,12 @@ var isSpecialElementMap = map[string]bool{
|
||||||
"iframe": true,
|
"iframe": true,
|
||||||
"img": true,
|
"img": true,
|
||||||
"input": true,
|
"input": true,
|
||||||
"isindex": true,
|
"isindex": true, // The 'isindex' element has been removed, but keep it for backwards compatibility.
|
||||||
|
"keygen": true,
|
||||||
"li": true,
|
"li": true,
|
||||||
"link": true,
|
"link": true,
|
||||||
"listing": true,
|
"listing": true,
|
||||||
|
"main": true,
|
||||||
"marquee": true,
|
"marquee": true,
|
||||||
"menu": true,
|
"menu": true,
|
||||||
"meta": true,
|
"meta": true,
|
||||||
|
@ -95,8 +97,16 @@ func isSpecialElement(element *Node) bool {
|
||||||
switch element.Namespace {
|
switch element.Namespace {
|
||||||
case "", "html":
|
case "", "html":
|
||||||
return isSpecialElementMap[element.Data]
|
return isSpecialElementMap[element.Data]
|
||||||
|
case "math":
|
||||||
|
switch element.Data {
|
||||||
|
case "mi", "mo", "mn", "ms", "mtext", "annotation-xml":
|
||||||
|
return true
|
||||||
|
}
|
||||||
case "svg":
|
case "svg":
|
||||||
return element.Data == "foreignObject"
|
switch element.Data {
|
||||||
|
case "foreignObject", "desc", "title":
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,18 +49,18 @@ call to Next. For example, to extract an HTML page's anchor text:
|
||||||
for {
|
for {
|
||||||
tt := z.Next()
|
tt := z.Next()
|
||||||
switch tt {
|
switch tt {
|
||||||
case ErrorToken:
|
case html.ErrorToken:
|
||||||
return z.Err()
|
return z.Err()
|
||||||
case TextToken:
|
case html.TextToken:
|
||||||
if depth > 0 {
|
if depth > 0 {
|
||||||
// emitBytes should copy the []byte it receives,
|
// emitBytes should copy the []byte it receives,
|
||||||
// if it doesn't process it immediately.
|
// if it doesn't process it immediately.
|
||||||
emitBytes(z.Text())
|
emitBytes(z.Text())
|
||||||
}
|
}
|
||||||
case StartTagToken, EndTagToken:
|
case html.StartTagToken, html.EndTagToken:
|
||||||
tn, _ := z.TagName()
|
tn, _ := z.TagName()
|
||||||
if len(tn) == 1 && tn[0] == 'a' {
|
if len(tn) == 1 && tn[0] == 'a' {
|
||||||
if tt == StartTagToken {
|
if tt == html.StartTagToken {
|
||||||
depth++
|
depth++
|
||||||
} else {
|
} else {
|
||||||
depth--
|
depth--
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -67,7 +67,7 @@ func mathMLTextIntegrationPoint(n *Node) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.5.
|
// Section 12.2.6.5.
|
||||||
var breakout = map[string]bool{
|
var breakout = map[string]bool{
|
||||||
"b": true,
|
"b": true,
|
||||||
"big": true,
|
"big": true,
|
||||||
|
@ -115,7 +115,7 @@ var breakout = map[string]bool{
|
||||||
"var": true,
|
"var": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.5.
|
// Section 12.2.6.5.
|
||||||
var svgTagNameAdjustments = map[string]string{
|
var svgTagNameAdjustments = map[string]string{
|
||||||
"altglyph": "altGlyph",
|
"altglyph": "altGlyph",
|
||||||
"altglyphdef": "altGlyphDef",
|
"altglyphdef": "altGlyphDef",
|
||||||
|
@ -155,7 +155,7 @@ var svgTagNameAdjustments = map[string]string{
|
||||||
"textpath": "textPath",
|
"textpath": "textPath",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.1
|
// Section 12.2.6.1
|
||||||
var mathMLAttributeAdjustments = map[string]string{
|
var mathMLAttributeAdjustments = map[string]string{
|
||||||
"definitionurl": "definitionURL",
|
"definitionurl": "definitionURL",
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,10 @@ const (
|
||||||
scopeMarkerNode
|
scopeMarkerNode
|
||||||
)
|
)
|
||||||
|
|
||||||
// Section 12.2.3.3 says "scope markers are inserted when entering applet
|
// Section 12.2.4.3 says "The markers are inserted when entering applet,
|
||||||
// elements, buttons, object elements, marquees, table cells, and table
|
// object, marquee, template, td, th, and caption elements, and are used
|
||||||
// captions, and are used to prevent formatting from 'leaking'".
|
// to prevent formatting from "leaking" into applet, object, marquee,
|
||||||
|
// template, td, th, and caption elements".
|
||||||
var scopeMarker = Node{Type: scopeMarkerNode}
|
var scopeMarker = Node{Type: scopeMarkerNode}
|
||||||
|
|
||||||
// A Node consists of a NodeType and some Data (tag name for element nodes,
|
// A Node consists of a NodeType and some Data (tag name for element nodes,
|
||||||
|
@ -173,6 +174,16 @@ func (s *nodeStack) index(n *Node) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// contains returns whether a is within s.
|
||||||
|
func (s *nodeStack) contains(a atom.Atom) bool {
|
||||||
|
for _, n := range *s {
|
||||||
|
if n.DataAtom == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// insert inserts a node at the given index.
|
// insert inserts a node at the given index.
|
||||||
func (s *nodeStack) insert(i int, n *Node) {
|
func (s *nodeStack) insert(i int, n *Node) {
|
||||||
(*s) = append(*s, nil)
|
(*s) = append(*s, nil)
|
||||||
|
@ -191,3 +202,19 @@ func (s *nodeStack) remove(n *Node) {
|
||||||
(*s)[j] = nil
|
(*s)[j] = nil
|
||||||
*s = (*s)[:j]
|
*s = (*s)[:j]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type insertionModeStack []insertionMode
|
||||||
|
|
||||||
|
func (s *insertionModeStack) pop() (im insertionMode) {
|
||||||
|
i := len(*s)
|
||||||
|
im = (*s)[i-1]
|
||||||
|
*s = (*s)[:i-1]
|
||||||
|
return im
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *insertionModeStack) top() insertionMode {
|
||||||
|
if i := len(*s); i > 0 {
|
||||||
|
return (*s)[i-1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -25,20 +25,22 @@ type parser struct {
|
||||||
hasSelfClosingToken bool
|
hasSelfClosingToken bool
|
||||||
// doc is the document root element.
|
// doc is the document root element.
|
||||||
doc *Node
|
doc *Node
|
||||||
// The stack of open elements (section 12.2.3.2) and active formatting
|
// The stack of open elements (section 12.2.4.2) and active formatting
|
||||||
// elements (section 12.2.3.3).
|
// elements (section 12.2.4.3).
|
||||||
oe, afe nodeStack
|
oe, afe nodeStack
|
||||||
// Element pointers (section 12.2.3.4).
|
// Element pointers (section 12.2.4.4).
|
||||||
head, form *Node
|
head, form *Node
|
||||||
// Other parsing state flags (section 12.2.3.5).
|
// Other parsing state flags (section 12.2.4.5).
|
||||||
scripting, framesetOK bool
|
scripting, framesetOK bool
|
||||||
|
// The stack of template insertion modes
|
||||||
|
templateStack insertionModeStack
|
||||||
// im is the current insertion mode.
|
// im is the current insertion mode.
|
||||||
im insertionMode
|
im insertionMode
|
||||||
// originalIM is the insertion mode to go back to after completing a text
|
// originalIM is the insertion mode to go back to after completing a text
|
||||||
// or inTableText insertion mode.
|
// or inTableText insertion mode.
|
||||||
originalIM insertionMode
|
originalIM insertionMode
|
||||||
// fosterParenting is whether new elements should be inserted according to
|
// fosterParenting is whether new elements should be inserted according to
|
||||||
// the foster parenting rules (section 12.2.5.3).
|
// the foster parenting rules (section 12.2.6.1).
|
||||||
fosterParenting bool
|
fosterParenting bool
|
||||||
// quirks is whether the parser is operating in "quirks mode."
|
// quirks is whether the parser is operating in "quirks mode."
|
||||||
quirks bool
|
quirks bool
|
||||||
|
@ -56,7 +58,7 @@ func (p *parser) top() *Node {
|
||||||
return p.doc
|
return p.doc
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.4.2.
|
||||||
var (
|
var (
|
||||||
defaultScopeStopTags = map[string][]a.Atom{
|
defaultScopeStopTags = map[string][]a.Atom{
|
||||||
"": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template},
|
"": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template},
|
||||||
|
@ -79,7 +81,7 @@ const (
|
||||||
|
|
||||||
// popUntil pops the stack of open elements at the highest element whose tag
|
// popUntil pops the stack of open elements at the highest element whose tag
|
||||||
// is in matchTags, provided there is no higher element in the scope's stop
|
// is in matchTags, provided there is no higher element in the scope's stop
|
||||||
// tags (as defined in section 12.2.3.2). It returns whether or not there was
|
// tags (as defined in section 12.2.4.2). It returns whether or not there was
|
||||||
// such an element. If there was not, popUntil leaves the stack unchanged.
|
// such an element. If there was not, popUntil leaves the stack unchanged.
|
||||||
//
|
//
|
||||||
// For example, the set of stop tags for table scope is: "html", "table". If
|
// For example, the set of stop tags for table scope is: "html", "table". If
|
||||||
|
@ -126,7 +128,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
case tableScope:
|
case tableScope:
|
||||||
if tagAtom == a.Html || tagAtom == a.Table {
|
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
case selectScope:
|
case selectScope:
|
||||||
|
@ -162,17 +164,17 @@ func (p *parser) clearStackToContext(s scope) {
|
||||||
tagAtom := p.oe[i].DataAtom
|
tagAtom := p.oe[i].DataAtom
|
||||||
switch s {
|
switch s {
|
||||||
case tableScope:
|
case tableScope:
|
||||||
if tagAtom == a.Html || tagAtom == a.Table {
|
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
|
||||||
p.oe = p.oe[:i+1]
|
p.oe = p.oe[:i+1]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case tableRowScope:
|
case tableRowScope:
|
||||||
if tagAtom == a.Html || tagAtom == a.Tr {
|
if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template {
|
||||||
p.oe = p.oe[:i+1]
|
p.oe = p.oe[:i+1]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case tableBodyScope:
|
case tableBodyScope:
|
||||||
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead {
|
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template {
|
||||||
p.oe = p.oe[:i+1]
|
p.oe = p.oe[:i+1]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -183,7 +185,7 @@ func (p *parser) clearStackToContext(s scope) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateImpliedEndTags pops nodes off the stack of open elements as long as
|
// generateImpliedEndTags pops nodes off the stack of open elements as long as
|
||||||
// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt.
|
// the top node has a tag name of dd, dt, li, optgroup, option, p, rb, rp, rt or rtc.
|
||||||
// If exceptions are specified, nodes with that name will not be popped off.
|
// If exceptions are specified, nodes with that name will not be popped off.
|
||||||
func (p *parser) generateImpliedEndTags(exceptions ...string) {
|
func (p *parser) generateImpliedEndTags(exceptions ...string) {
|
||||||
var i int
|
var i int
|
||||||
|
@ -192,7 +194,7 @@ loop:
|
||||||
n := p.oe[i]
|
n := p.oe[i]
|
||||||
if n.Type == ElementNode {
|
if n.Type == ElementNode {
|
||||||
switch n.DataAtom {
|
switch n.DataAtom {
|
||||||
case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt:
|
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc:
|
||||||
for _, except := range exceptions {
|
for _, except := range exceptions {
|
||||||
if n.Data == except {
|
if n.Data == except {
|
||||||
break loop
|
break loop
|
||||||
|
@ -234,9 +236,9 @@ func (p *parser) shouldFosterParent() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fosterParent adds a child node according to the foster parenting rules.
|
// fosterParent adds a child node according to the foster parenting rules.
|
||||||
// Section 12.2.5.3, "foster parenting".
|
// Section 12.2.6.1, "foster parenting".
|
||||||
func (p *parser) fosterParent(n *Node) {
|
func (p *parser) fosterParent(n *Node) {
|
||||||
var table, parent, prev *Node
|
var table, parent, prev, template *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].DataAtom == a.Table {
|
if p.oe[i].DataAtom == a.Table {
|
||||||
|
@ -245,6 +247,19 @@ func (p *parser) fosterParent(n *Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var j int
|
||||||
|
for j = len(p.oe) - 1; j >= 0; j-- {
|
||||||
|
if p.oe[j].DataAtom == a.Template {
|
||||||
|
template = p.oe[j]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if template != nil && (table == nil || j > i) {
|
||||||
|
template.AppendChild(n)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if table == nil {
|
if table == nil {
|
||||||
// The foster parent is the html element.
|
// The foster parent is the html element.
|
||||||
parent = p.oe[0]
|
parent = p.oe[0]
|
||||||
|
@ -304,7 +319,7 @@ func (p *parser) addElement() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.3.3.
|
// Section 12.2.4.3.
|
||||||
func (p *parser) addFormattingElement() {
|
func (p *parser) addFormattingElement() {
|
||||||
tagAtom, attr := p.tok.DataAtom, p.tok.Attr
|
tagAtom, attr := p.tok.DataAtom, p.tok.Attr
|
||||||
p.addElement()
|
p.addElement()
|
||||||
|
@ -351,7 +366,7 @@ findIdenticalElements:
|
||||||
p.afe = append(p.afe, p.top())
|
p.afe = append(p.afe, p.top())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.3.3.
|
// Section 12.2.4.3.
|
||||||
func (p *parser) clearActiveFormattingElements() {
|
func (p *parser) clearActiveFormattingElements() {
|
||||||
for {
|
for {
|
||||||
n := p.afe.pop()
|
n := p.afe.pop()
|
||||||
|
@ -361,7 +376,7 @@ func (p *parser) clearActiveFormattingElements() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.3.3.
|
// Section 12.2.4.3.
|
||||||
func (p *parser) reconstructActiveFormattingElements() {
|
func (p *parser) reconstructActiveFormattingElements() {
|
||||||
n := p.afe.top()
|
n := p.afe.top()
|
||||||
if n == nil {
|
if n == nil {
|
||||||
|
@ -390,12 +405,12 @@ func (p *parser) reconstructActiveFormattingElements() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.4.
|
// Section 12.2.5.
|
||||||
func (p *parser) acknowledgeSelfClosingTag() {
|
func (p *parser) acknowledgeSelfClosingTag() {
|
||||||
p.hasSelfClosingToken = false
|
p.hasSelfClosingToken = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// An insertion mode (section 12.2.3.1) is the state transition function from
|
// An insertion mode (section 12.2.4.1) is the state transition function from
|
||||||
// a particular state in the HTML5 parser's state machine. It updates the
|
// a particular state in the HTML5 parser's state machine. It updates the
|
||||||
// parser's fields depending on parser.tok (where ErrorToken means EOF).
|
// parser's fields depending on parser.tok (where ErrorToken means EOF).
|
||||||
// It returns whether the token was consumed.
|
// It returns whether the token was consumed.
|
||||||
|
@ -403,7 +418,7 @@ type insertionMode func(*parser) bool
|
||||||
|
|
||||||
// setOriginalIM sets the insertion mode to return to after completing a text or
|
// setOriginalIM sets the insertion mode to return to after completing a text or
|
||||||
// inTableText insertion mode.
|
// inTableText insertion mode.
|
||||||
// Section 12.2.3.1, "using the rules for".
|
// Section 12.2.4.1, "using the rules for".
|
||||||
func (p *parser) setOriginalIM() {
|
func (p *parser) setOriginalIM() {
|
||||||
if p.originalIM != nil {
|
if p.originalIM != nil {
|
||||||
panic("html: bad parser state: originalIM was set twice")
|
panic("html: bad parser state: originalIM was set twice")
|
||||||
|
@ -411,18 +426,38 @@ func (p *parser) setOriginalIM() {
|
||||||
p.originalIM = p.im
|
p.originalIM = p.im
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.3.1, "reset the insertion mode".
|
// Section 12.2.4.1, "reset the insertion mode".
|
||||||
func (p *parser) resetInsertionMode() {
|
func (p *parser) resetInsertionMode() {
|
||||||
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 i == 0 && p.context != nil {
|
last := i == 0
|
||||||
|
if last && p.context != nil {
|
||||||
n = p.context
|
n = p.context
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n.DataAtom {
|
switch n.DataAtom {
|
||||||
case a.Select:
|
case a.Select:
|
||||||
|
if !last {
|
||||||
|
for ancestor, first := n, p.oe[0]; ancestor != first; {
|
||||||
|
if ancestor == first {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ancestor = p.oe[p.oe.index(ancestor)-1]
|
||||||
|
switch ancestor.DataAtom {
|
||||||
|
case a.Template:
|
||||||
|
p.im = inSelectIM
|
||||||
|
return
|
||||||
|
case a.Table:
|
||||||
|
p.im = inSelectInTableIM
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
p.im = inSelectIM
|
p.im = inSelectIM
|
||||||
case a.Td, a.Th:
|
case a.Td, a.Th:
|
||||||
|
// TODO: remove this divergence from the HTML5 spec.
|
||||||
|
//
|
||||||
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
||||||
p.im = inCellIM
|
p.im = inCellIM
|
||||||
case a.Tr:
|
case a.Tr:
|
||||||
p.im = inRowIM
|
p.im = inRowIM
|
||||||
|
@ -434,25 +469,41 @@ func (p *parser) resetInsertionMode() {
|
||||||
p.im = inColumnGroupIM
|
p.im = inColumnGroupIM
|
||||||
case a.Table:
|
case a.Table:
|
||||||
p.im = inTableIM
|
p.im = inTableIM
|
||||||
|
case a.Template:
|
||||||
|
// TODO: remove this divergence from the HTML5 spec.
|
||||||
|
if n.Namespace != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p.im = p.templateStack.top()
|
||||||
case a.Head:
|
case a.Head:
|
||||||
p.im = inBodyIM
|
// TODO: remove this divergence from the HTML5 spec.
|
||||||
|
//
|
||||||
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
||||||
|
p.im = inHeadIM
|
||||||
case a.Body:
|
case a.Body:
|
||||||
p.im = inBodyIM
|
p.im = inBodyIM
|
||||||
case a.Frameset:
|
case a.Frameset:
|
||||||
p.im = inFramesetIM
|
p.im = inFramesetIM
|
||||||
case a.Html:
|
case a.Html:
|
||||||
p.im = beforeHeadIM
|
if p.head == nil {
|
||||||
|
p.im = beforeHeadIM
|
||||||
|
} else {
|
||||||
|
p.im = afterHeadIM
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
|
if last {
|
||||||
|
p.im = inBodyIM
|
||||||
|
return
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.im = inBodyIM
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const whitespace = " \t\r\n\f"
|
const whitespace = " \t\r\n\f"
|
||||||
|
|
||||||
// Section 12.2.5.4.1.
|
// Section 12.2.6.4.1.
|
||||||
func initialIM(p *parser) bool {
|
func initialIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case TextToken:
|
case TextToken:
|
||||||
|
@ -479,7 +530,7 @@ func initialIM(p *parser) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.2.
|
// Section 12.2.6.4.2.
|
||||||
func beforeHTMLIM(p *parser) bool {
|
func beforeHTMLIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case DoctypeToken:
|
case DoctypeToken:
|
||||||
|
@ -517,7 +568,7 @@ func beforeHTMLIM(p *parser) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.3.
|
// Section 12.2.6.4.3.
|
||||||
func beforeHeadIM(p *parser) bool {
|
func beforeHeadIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case TextToken:
|
case TextToken:
|
||||||
|
@ -560,7 +611,7 @@ func beforeHeadIM(p *parser) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.4.
|
// Section 12.2.6.4.4.
|
||||||
func inHeadIM(p *parser) bool {
|
func inHeadIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case TextToken:
|
case TextToken:
|
||||||
|
@ -590,19 +641,41 @@ func inHeadIM(p *parser) bool {
|
||||||
case a.Head:
|
case a.Head:
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
|
case a.Template:
|
||||||
|
p.addElement()
|
||||||
|
p.afe = append(p.afe, &scopeMarker)
|
||||||
|
p.framesetOK = false
|
||||||
|
p.im = inTemplateIM
|
||||||
|
p.templateStack = append(p.templateStack, inTemplateIM)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
case EndTagToken:
|
case EndTagToken:
|
||||||
switch p.tok.DataAtom {
|
switch p.tok.DataAtom {
|
||||||
case a.Head:
|
case a.Head:
|
||||||
n := p.oe.pop()
|
p.oe.pop()
|
||||||
if n.DataAtom != a.Head {
|
|
||||||
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 a.Body, a.Html, a.Br:
|
case a.Body, a.Html, a.Br:
|
||||||
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
|
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
|
||||||
return false
|
return false
|
||||||
|
case a.Template:
|
||||||
|
if !p.oe.contains(a.Template) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// TODO: remove this divergence from the HTML5 spec.
|
||||||
|
//
|
||||||
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
||||||
|
p.generateImpliedEndTags()
|
||||||
|
for i := len(p.oe) - 1; i >= 0; i-- {
|
||||||
|
if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
|
||||||
|
p.oe = p.oe[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.clearActiveFormattingElements()
|
||||||
|
p.templateStack.pop()
|
||||||
|
p.resetInsertionMode()
|
||||||
|
return true
|
||||||
default:
|
default:
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
|
@ -622,7 +695,7 @@ func inHeadIM(p *parser) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.6.
|
// Section 12.2.6.4.6.
|
||||||
func afterHeadIM(p *parser) bool {
|
func afterHeadIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case TextToken:
|
case TextToken:
|
||||||
|
@ -648,7 +721,7 @@ func afterHeadIM(p *parser) bool {
|
||||||
p.addElement()
|
p.addElement()
|
||||||
p.im = inFramesetIM
|
p.im = inFramesetIM
|
||||||
return true
|
return true
|
||||||
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
|
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
||||||
p.oe = append(p.oe, p.head)
|
p.oe = append(p.oe, p.head)
|
||||||
defer p.oe.remove(p.head)
|
defer p.oe.remove(p.head)
|
||||||
return inHeadIM(p)
|
return inHeadIM(p)
|
||||||
|
@ -660,6 +733,8 @@ func afterHeadIM(p *parser) bool {
|
||||||
switch p.tok.DataAtom {
|
switch p.tok.DataAtom {
|
||||||
case a.Body, a.Html, a.Br:
|
case a.Body, a.Html, a.Br:
|
||||||
// Drop down to creating an implied <body> tag.
|
// Drop down to creating an implied <body> tag.
|
||||||
|
case a.Template:
|
||||||
|
return inHeadIM(p)
|
||||||
default:
|
default:
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
|
@ -697,7 +772,7 @@ func copyAttributes(dst *Node, src Token) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.7.
|
// Section 12.2.6.4.7.
|
||||||
func inBodyIM(p *parser) bool {
|
func inBodyIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case TextToken:
|
case TextToken:
|
||||||
|
@ -727,10 +802,16 @@ func inBodyIM(p *parser) bool {
|
||||||
case StartTagToken:
|
case StartTagToken:
|
||||||
switch p.tok.DataAtom {
|
switch p.tok.DataAtom {
|
||||||
case a.Html:
|
case a.Html:
|
||||||
|
if p.oe.contains(a.Template) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
copyAttributes(p.oe[0], p.tok)
|
copyAttributes(p.oe[0], p.tok)
|
||||||
case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
|
case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
||||||
return inHeadIM(p)
|
return inHeadIM(p)
|
||||||
case a.Body:
|
case a.Body:
|
||||||
|
if p.oe.contains(a.Template) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if len(p.oe) >= 2 {
|
if len(p.oe) >= 2 {
|
||||||
body := p.oe[1]
|
body := p.oe[1]
|
||||||
if body.Type == ElementNode && body.DataAtom == a.Body {
|
if body.Type == ElementNode && body.DataAtom == a.Body {
|
||||||
|
@ -767,9 +848,13 @@ func inBodyIM(p *parser) bool {
|
||||||
// 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 a.Form:
|
case a.Form:
|
||||||
if p.form == nil {
|
if p.form != nil && !p.oe.contains(a.Template) {
|
||||||
p.popUntil(buttonScope, a.P)
|
// Ignore the token
|
||||||
p.addElement()
|
return true
|
||||||
|
}
|
||||||
|
p.popUntil(buttonScope, a.P)
|
||||||
|
p.addElement()
|
||||||
|
if !p.oe.contains(a.Template) {
|
||||||
p.form = p.top()
|
p.form = p.top()
|
||||||
}
|
}
|
||||||
case a.Li:
|
case a.Li:
|
||||||
|
@ -903,6 +988,14 @@ func inBodyIM(p *parser) bool {
|
||||||
p.acknowledgeSelfClosingTag()
|
p.acknowledgeSelfClosingTag()
|
||||||
p.popUntil(buttonScope, a.P)
|
p.popUntil(buttonScope, a.P)
|
||||||
p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
|
p.parseImpliedToken(StartTagToken, a.Form, a.Form.String())
|
||||||
|
if p.form == nil {
|
||||||
|
// NOTE: The 'isindex' element has been removed,
|
||||||
|
// and the 'template' element has not been designed to be
|
||||||
|
// collaborative with the index element.
|
||||||
|
//
|
||||||
|
// Ignore the token.
|
||||||
|
return true
|
||||||
|
}
|
||||||
if action != "" {
|
if action != "" {
|
||||||
p.form.Attr = []Attribute{{Key: "action", Val: action}}
|
p.form.Attr = []Attribute{{Key: "action", Val: action}}
|
||||||
}
|
}
|
||||||
|
@ -952,11 +1045,16 @@ func inBodyIM(p *parser) bool {
|
||||||
}
|
}
|
||||||
p.reconstructActiveFormattingElements()
|
p.reconstructActiveFormattingElements()
|
||||||
p.addElement()
|
p.addElement()
|
||||||
case a.Rp, a.Rt:
|
case a.Rb, a.Rtc:
|
||||||
if p.elementInScope(defaultScope, a.Ruby) {
|
if p.elementInScope(defaultScope, a.Ruby) {
|
||||||
p.generateImpliedEndTags()
|
p.generateImpliedEndTags()
|
||||||
}
|
}
|
||||||
p.addElement()
|
p.addElement()
|
||||||
|
case a.Rp, a.Rt:
|
||||||
|
if p.elementInScope(defaultScope, a.Ruby) {
|
||||||
|
p.generateImpliedEndTags("rtc")
|
||||||
|
}
|
||||||
|
p.addElement()
|
||||||
case a.Math, a.Svg:
|
case a.Math, a.Svg:
|
||||||
p.reconstructActiveFormattingElements()
|
p.reconstructActiveFormattingElements()
|
||||||
if p.tok.DataAtom == a.Math {
|
if p.tok.DataAtom == a.Math {
|
||||||
|
@ -993,15 +1091,29 @@ func inBodyIM(p *parser) bool {
|
||||||
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:
|
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.DataAtom)
|
p.popUntil(defaultScope, p.tok.DataAtom)
|
||||||
case a.Form:
|
case a.Form:
|
||||||
node := p.form
|
if p.oe.contains(a.Template) {
|
||||||
p.form = nil
|
i := p.indexOfElementInScope(defaultScope, a.Form)
|
||||||
i := p.indexOfElementInScope(defaultScope, a.Form)
|
if i == -1 {
|
||||||
if node == nil || i == -1 || p.oe[i] != node {
|
// Ignore the token.
|
||||||
// Ignore the token.
|
return true
|
||||||
return true
|
}
|
||||||
|
p.generateImpliedEndTags()
|
||||||
|
if p.oe[i].DataAtom != a.Form {
|
||||||
|
// Ignore the token.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
p.popUntil(defaultScope, a.Form)
|
||||||
|
} else {
|
||||||
|
node := p.form
|
||||||
|
p.form = nil
|
||||||
|
i := p.indexOfElementInScope(defaultScope, a.Form)
|
||||||
|
if node == nil || i == -1 || p.oe[i] != node {
|
||||||
|
// Ignore the token.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
p.generateImpliedEndTags()
|
||||||
|
p.oe.remove(node)
|
||||||
}
|
}
|
||||||
p.generateImpliedEndTags()
|
|
||||||
p.oe.remove(node)
|
|
||||||
case a.P:
|
case a.P:
|
||||||
if !p.elementInScope(buttonScope, a.P) {
|
if !p.elementInScope(buttonScope, a.P) {
|
||||||
p.parseImpliedToken(StartTagToken, a.P, a.P.String())
|
p.parseImpliedToken(StartTagToken, a.P, a.P.String())
|
||||||
|
@ -1022,6 +1134,8 @@ func inBodyIM(p *parser) bool {
|
||||||
case a.Br:
|
case a.Br:
|
||||||
p.tok.Type = StartTagToken
|
p.tok.Type = StartTagToken
|
||||||
return false
|
return false
|
||||||
|
case a.Template:
|
||||||
|
return inHeadIM(p)
|
||||||
default:
|
default:
|
||||||
p.inBodyEndTagOther(p.tok.DataAtom)
|
p.inBodyEndTagOther(p.tok.DataAtom)
|
||||||
}
|
}
|
||||||
|
@ -1030,6 +1144,21 @@ func inBodyIM(p *parser) bool {
|
||||||
Type: CommentNode,
|
Type: CommentNode,
|
||||||
Data: p.tok.Data,
|
Data: p.tok.Data,
|
||||||
})
|
})
|
||||||
|
case ErrorToken:
|
||||||
|
// TODO: remove this divergence from the HTML5 spec.
|
||||||
|
if len(p.templateStack) > 0 {
|
||||||
|
p.im = inTemplateIM
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
for _, e := range p.oe {
|
||||||
|
switch e.DataAtom {
|
||||||
|
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc, a.Tbody, a.Td, a.Tfoot, a.Th,
|
||||||
|
a.Thead, a.Tr, a.Body, a.Html:
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -1160,7 +1289,7 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
|
// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
|
||||||
// "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content
|
// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content
|
||||||
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
|
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
|
||||||
func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
|
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-- {
|
||||||
|
@ -1174,7 +1303,7 @@ func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.8.
|
// Section 12.2.6.4.8.
|
||||||
func textIM(p *parser) bool {
|
func textIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case ErrorToken:
|
case ErrorToken:
|
||||||
|
@ -1203,12 +1332,9 @@ func textIM(p *parser) bool {
|
||||||
return p.tok.Type == EndTagToken
|
return p.tok.Type == EndTagToken
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.9.
|
// Section 12.2.6.4.9.
|
||||||
func inTableIM(p *parser) bool {
|
func inTableIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case ErrorToken:
|
|
||||||
// Stop parsing.
|
|
||||||
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().DataAtom {
|
switch p.oe.top().DataAtom {
|
||||||
|
@ -1249,7 +1375,7 @@ func inTableIM(p *parser) bool {
|
||||||
}
|
}
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
case a.Style, a.Script:
|
case a.Style, a.Script, a.Template:
|
||||||
return inHeadIM(p)
|
return inHeadIM(p)
|
||||||
case a.Input:
|
case a.Input:
|
||||||
for _, t := range p.tok.Attr {
|
for _, t := range p.tok.Attr {
|
||||||
|
@ -1261,7 +1387,7 @@ func inTableIM(p *parser) bool {
|
||||||
}
|
}
|
||||||
// Otherwise drop down to the default action.
|
// Otherwise drop down to the default action.
|
||||||
case a.Form:
|
case a.Form:
|
||||||
if p.form != nil {
|
if p.oe.contains(a.Template) || p.form != nil {
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -1291,6 +1417,8 @@ func inTableIM(p *parser) bool {
|
||||||
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.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
|
||||||
|
case a.Template:
|
||||||
|
return inHeadIM(p)
|
||||||
}
|
}
|
||||||
case CommentToken:
|
case CommentToken:
|
||||||
p.addChild(&Node{
|
p.addChild(&Node{
|
||||||
|
@ -1301,6 +1429,8 @@ func inTableIM(p *parser) bool {
|
||||||
case DoctypeToken:
|
case DoctypeToken:
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
|
case ErrorToken:
|
||||||
|
return inBodyIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.fosterParenting = true
|
p.fosterParenting = true
|
||||||
|
@ -1309,7 +1439,7 @@ func inTableIM(p *parser) bool {
|
||||||
return inBodyIM(p)
|
return inBodyIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.11.
|
// Section 12.2.6.4.11.
|
||||||
func inCaptionIM(p *parser) bool {
|
func inCaptionIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case StartTagToken:
|
case StartTagToken:
|
||||||
|
@ -1355,7 +1485,7 @@ func inCaptionIM(p *parser) bool {
|
||||||
return inBodyIM(p)
|
return inBodyIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.12.
|
// Section 12.2.6.4.12.
|
||||||
func inColumnGroupIM(p *parser) bool {
|
func inColumnGroupIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case TextToken:
|
case TextToken:
|
||||||
|
@ -1386,11 +1516,13 @@ func inColumnGroupIM(p *parser) bool {
|
||||||
p.oe.pop()
|
p.oe.pop()
|
||||||
p.acknowledgeSelfClosingTag()
|
p.acknowledgeSelfClosingTag()
|
||||||
return true
|
return true
|
||||||
|
case a.Template:
|
||||||
|
return inHeadIM(p)
|
||||||
}
|
}
|
||||||
case EndTagToken:
|
case EndTagToken:
|
||||||
switch p.tok.DataAtom {
|
switch p.tok.DataAtom {
|
||||||
case a.Colgroup:
|
case a.Colgroup:
|
||||||
if p.oe.top().DataAtom != a.Html {
|
if p.oe.top().DataAtom == a.Colgroup {
|
||||||
p.oe.pop()
|
p.oe.pop()
|
||||||
p.im = inTableIM
|
p.im = inTableIM
|
||||||
}
|
}
|
||||||
|
@ -1398,17 +1530,21 @@ func inColumnGroupIM(p *parser) bool {
|
||||||
case a.Col:
|
case a.Col:
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
|
case a.Template:
|
||||||
|
return inHeadIM(p)
|
||||||
}
|
}
|
||||||
|
case ErrorToken:
|
||||||
|
return inBodyIM(p)
|
||||||
}
|
}
|
||||||
if p.oe.top().DataAtom != a.Html {
|
if p.oe.top().DataAtom != a.Colgroup {
|
||||||
p.oe.pop()
|
return true
|
||||||
p.im = inTableIM
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
return true
|
p.oe.pop()
|
||||||
|
p.im = inTableIM
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.13.
|
// Section 12.2.6.4.13.
|
||||||
func inTableBodyIM(p *parser) bool {
|
func inTableBodyIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case StartTagToken:
|
case StartTagToken:
|
||||||
|
@ -1460,7 +1596,7 @@ func inTableBodyIM(p *parser) bool {
|
||||||
return inTableIM(p)
|
return inTableIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.14.
|
// Section 12.2.6.4.14.
|
||||||
func inRowIM(p *parser) bool {
|
func inRowIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case StartTagToken:
|
case StartTagToken:
|
||||||
|
@ -1511,7 +1647,7 @@ func inRowIM(p *parser) bool {
|
||||||
return inTableIM(p)
|
return inTableIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.15.
|
// Section 12.2.6.4.15.
|
||||||
func inCellIM(p *parser) bool {
|
func inCellIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case StartTagToken:
|
case StartTagToken:
|
||||||
|
@ -1560,12 +1696,9 @@ func inCellIM(p *parser) bool {
|
||||||
return inBodyIM(p)
|
return inBodyIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.16.
|
// Section 12.2.6.4.16.
|
||||||
func inSelectIM(p *parser) bool {
|
func inSelectIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case ErrorToken:
|
|
||||||
// Stop parsing.
|
|
||||||
return true
|
|
||||||
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:
|
||||||
|
@ -1597,7 +1730,7 @@ func inSelectIM(p *parser) bool {
|
||||||
p.tokenizer.NextIsNotRawText()
|
p.tokenizer.NextIsNotRawText()
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
case a.Script:
|
case a.Script, a.Template:
|
||||||
return inHeadIM(p)
|
return inHeadIM(p)
|
||||||
}
|
}
|
||||||
case EndTagToken:
|
case EndTagToken:
|
||||||
|
@ -1618,6 +1751,8 @@ func inSelectIM(p *parser) bool {
|
||||||
if p.popUntil(selectScope, a.Select) {
|
if p.popUntil(selectScope, a.Select) {
|
||||||
p.resetInsertionMode()
|
p.resetInsertionMode()
|
||||||
}
|
}
|
||||||
|
case a.Template:
|
||||||
|
return inHeadIM(p)
|
||||||
}
|
}
|
||||||
case CommentToken:
|
case CommentToken:
|
||||||
p.addChild(&Node{
|
p.addChild(&Node{
|
||||||
|
@ -1627,12 +1762,14 @@ func inSelectIM(p *parser) bool {
|
||||||
case DoctypeToken:
|
case DoctypeToken:
|
||||||
// Ignore the token.
|
// Ignore the token.
|
||||||
return true
|
return true
|
||||||
|
case ErrorToken:
|
||||||
|
return inBodyIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.17.
|
// Section 12.2.6.4.17.
|
||||||
func inSelectInTableIM(p *parser) bool {
|
func inSelectInTableIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case StartTagToken, EndTagToken:
|
case StartTagToken, EndTagToken:
|
||||||
|
@ -1650,7 +1787,73 @@ func inSelectInTableIM(p *parser) bool {
|
||||||
return inSelectIM(p)
|
return inSelectIM(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.18.
|
// Section 12.2.6.4.18.
|
||||||
|
func inTemplateIM(p *parser) bool {
|
||||||
|
switch p.tok.Type {
|
||||||
|
case TextToken, CommentToken, DoctypeToken:
|
||||||
|
return inBodyIM(p)
|
||||||
|
case StartTagToken:
|
||||||
|
switch p.tok.DataAtom {
|
||||||
|
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
||||||
|
return inHeadIM(p)
|
||||||
|
case a.Caption, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
|
||||||
|
p.templateStack.pop()
|
||||||
|
p.templateStack = append(p.templateStack, inTableIM)
|
||||||
|
p.im = inTableIM
|
||||||
|
return false
|
||||||
|
case a.Col:
|
||||||
|
p.templateStack.pop()
|
||||||
|
p.templateStack = append(p.templateStack, inColumnGroupIM)
|
||||||
|
p.im = inColumnGroupIM
|
||||||
|
return false
|
||||||
|
case a.Tr:
|
||||||
|
p.templateStack.pop()
|
||||||
|
p.templateStack = append(p.templateStack, inTableBodyIM)
|
||||||
|
p.im = inTableBodyIM
|
||||||
|
return false
|
||||||
|
case a.Td, a.Th:
|
||||||
|
p.templateStack.pop()
|
||||||
|
p.templateStack = append(p.templateStack, inRowIM)
|
||||||
|
p.im = inRowIM
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
p.templateStack.pop()
|
||||||
|
p.templateStack = append(p.templateStack, inBodyIM)
|
||||||
|
p.im = inBodyIM
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case EndTagToken:
|
||||||
|
switch p.tok.DataAtom {
|
||||||
|
case a.Template:
|
||||||
|
return inHeadIM(p)
|
||||||
|
default:
|
||||||
|
// Ignore the token.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case ErrorToken:
|
||||||
|
if !p.oe.contains(a.Template) {
|
||||||
|
// Ignore the token.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// TODO: remove this divergence from the HTML5 spec.
|
||||||
|
//
|
||||||
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
|
||||||
|
p.generateImpliedEndTags()
|
||||||
|
for i := len(p.oe) - 1; i >= 0; i-- {
|
||||||
|
if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template {
|
||||||
|
p.oe = p.oe[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.clearActiveFormattingElements()
|
||||||
|
p.templateStack.pop()
|
||||||
|
p.resetInsertionMode()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section 12.2.6.4.19.
|
||||||
func afterBodyIM(p *parser) bool {
|
func afterBodyIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case ErrorToken:
|
case ErrorToken:
|
||||||
|
@ -1688,7 +1891,7 @@ func afterBodyIM(p *parser) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.19.
|
// Section 12.2.6.4.20.
|
||||||
func inFramesetIM(p *parser) bool {
|
func inFramesetIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case CommentToken:
|
case CommentToken:
|
||||||
|
@ -1738,7 +1941,7 @@ func inFramesetIM(p *parser) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.20.
|
// Section 12.2.6.4.21.
|
||||||
func afterFramesetIM(p *parser) bool {
|
func afterFramesetIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case CommentToken:
|
case CommentToken:
|
||||||
|
@ -1777,7 +1980,7 @@ func afterFramesetIM(p *parser) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.21.
|
// Section 12.2.6.4.22.
|
||||||
func afterAfterBodyIM(p *parser) bool {
|
func afterAfterBodyIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case ErrorToken:
|
case ErrorToken:
|
||||||
|
@ -1806,7 +2009,7 @@ func afterAfterBodyIM(p *parser) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.4.22.
|
// Section 12.2.6.4.23.
|
||||||
func afterAfterFramesetIM(p *parser) bool {
|
func afterAfterFramesetIM(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case CommentToken:
|
case CommentToken:
|
||||||
|
@ -1844,7 +2047,7 @@ func afterAfterFramesetIM(p *parser) bool {
|
||||||
|
|
||||||
const whitespaceOrNUL = whitespace + "\x00"
|
const whitespaceOrNUL = whitespace + "\x00"
|
||||||
|
|
||||||
// Section 12.2.5.5.
|
// Section 12.2.6.5
|
||||||
func parseForeignContent(p *parser) bool {
|
func parseForeignContent(p *parser) bool {
|
||||||
switch p.tok.Type {
|
switch p.tok.Type {
|
||||||
case TextToken:
|
case TextToken:
|
||||||
|
@ -1924,7 +2127,7 @@ func parseForeignContent(p *parser) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Section 12.2.5.
|
// Section 12.2.6.
|
||||||
func (p *parser) inForeignContent() bool {
|
func (p *parser) inForeignContent() bool {
|
||||||
if len(p.oe) == 0 {
|
if len(p.oe) == 0 {
|
||||||
return false
|
return false
|
||||||
|
@ -2012,6 +2215,15 @@ func (p *parser) parse() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse returns the parse tree for the HTML from the given Reader.
|
// Parse returns the parse tree for the HTML from the given Reader.
|
||||||
|
//
|
||||||
|
// It implements the HTML5 parsing algorithm
|
||||||
|
// (https://html.spec.whatwg.org/multipage/syntax.html#tree-construction),
|
||||||
|
// which is very complicated. The resultant tree can contain implicitly created
|
||||||
|
// nodes that have no explicit <tag> listed in r's data, and nodes' parents can
|
||||||
|
// differ from the nesting implied by a naive processing of start and end
|
||||||
|
// <tag>s. Conversely, explicit <tag>s in r's data can be silently dropped,
|
||||||
|
// with no corresponding node in the resulting tree.
|
||||||
|
//
|
||||||
// The input is assumed to be UTF-8 encoded.
|
// The input is assumed to be UTF-8 encoded.
|
||||||
func Parse(r io.Reader) (*Node, error) {
|
func Parse(r io.Reader) (*Node, error) {
|
||||||
p := &parser{
|
p := &parser{
|
||||||
|
@ -2033,6 +2245,8 @@ func Parse(r io.Reader) (*Node, error) {
|
||||||
// ParseFragment parses a fragment of HTML and returns the nodes that were
|
// ParseFragment parses a fragment of HTML and returns the nodes that were
|
||||||
// found. If the fragment is the InnerHTML for an existing element, pass that
|
// found. If the fragment is the InnerHTML for an existing element, pass that
|
||||||
// element in context.
|
// element in context.
|
||||||
|
//
|
||||||
|
// It has the same intricacies as Parse.
|
||||||
func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
|
func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
|
||||||
contextTag := ""
|
contextTag := ""
|
||||||
if context != nil {
|
if context != nil {
|
||||||
|
@ -2064,6 +2278,9 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
|
||||||
}
|
}
|
||||||
p.doc.AppendChild(root)
|
p.doc.AppendChild(root)
|
||||||
p.oe = nodeStack{root}
|
p.oe = nodeStack{root}
|
||||||
|
if context != nil && context.DataAtom == a.Template {
|
||||||
|
p.templateStack = append(p.templateStack, inTemplateIM)
|
||||||
|
}
|
||||||
p.resetInsertionMode()
|
p.resetInsertionMode()
|
||||||
|
|
||||||
for n := context; n != nil; n = n.Parent {
|
for n := context; n != nil; n = n.Parent {
|
||||||
|
|
|
@ -1161,8 +1161,8 @@ func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
|
||||||
return nil, nil, false
|
return nil, nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Token returns the next Token. The result's Data and Attr values remain valid
|
// Token returns the current Token. The result's Data and Attr values remain
|
||||||
// after subsequent Next calls.
|
// valid after subsequent Next calls.
|
||||||
func (z *Tokenizer) Token() Token {
|
func (z *Tokenizer) Token() Token {
|
||||||
t := Token{Type: z.tt}
|
t := Token{Type: z.tt}
|
||||||
switch z.tt {
|
switch z.tt {
|
||||||
|
|
Loading…
Reference in New Issue