func (p *Parser) nextChar() string {
	return string(p.input[p.pos])
}
Read the current character without consuming it
package htmlPDF
import (
	"fmt"
	"regexp"
)
func ParseHtml(source string) *Node {
	p := new(Parser)
	p.input = source
	p.pos = 0
	nodes := p.parseNodes()
	if len(nodes) > 1 {
		panic("Not one root tag")
	}
	return nodes[0]
}
func (p *Parser) parseNodes() map[int]*Node {
	nodes := map[int]*Node{}
	for {
		p.consumeWhitespace()
		if p.eof() || p.startWith("</") {
			break
		}
		nodes[len(nodes)] = p.parseNode()
	}
	return nodes
}
func (p *Parser) parseNode() *Node {
	if p.nextChar() == "<" {
		return p.parseElement()
	} else {
		return p.parseText()
	}
}
func (p *Parser) parseElement() *Node {
	start := p.consumeChar()
	if start != "<" {
		panic(fmt.Sprintf("%v was not an openig tag <", start))
	}
	tagName := p.parseTagName()
	attrs := p.parseAttributes()
	end := p.consumeChar()
	if end != ">" {
		panic(fmt.Sprintf("%v was not a closing tag <", end))
	}
	children := p.parseNodes()
	start = p.consumeChar()
	if start != "<" {
		panic(fmt.Sprintf("%v was not an openig tag <", start))
	}
	slash := p.consumeChar()
	if slash != "/" {
		panic(fmt.Sprintf("%v was not a tag /", slash))
	}
	closeName := p.parseTagName()
	if closeName != tagName {
		panic(fmt.Sprintf("open tag %v and close tag %v don't equal ", tagName, closeName))
	}
	end = p.consumeChar()
	if end != ">" {
		panic(fmt.Sprintf("%v was not a closing tag <", end))
	}
	return elem(tagName, attrs, children)
}
func (p *Parser) parseText() *Node {
	return text(p.consumeWhile(func(char string) bool {
		return char != "<"
	}))
}
func (p *Parser) parseTagName() string {
	reg := regexp.MustCompile("[a-zA-Z0-9]")
	f := func(char string) bool {
		return reg.MatchString(char)
	}
	return p.consumeWhile(f)
}
func (p *Parser) parseAttributes() map[string]string {
	attr := map[string]string{}
	for {
		p.consumeWhitespace()
		if p.nextChar() == ">" {
			break
		}
		name, value := p.parseAttribute()
		attr[name] = value
	}
	return attr
}
func (p *Parser) parseAttribute() (string, string) {
	name := p.parseTagName()
	delimiter := p.consumeChar()
	if delimiter != "=" {
		panic(fmt.Sprintf("%v was not =", delimiter))
	}
	value := p.parseAttributeValue()
	return name, value
}
func (p *Parser) parseAttributeValue() string {
	q := p.consumeChar()
	if q != "\"" && q != "'" {
		panic(fmt.Sprintf("%v was not \" or '", q))
	}
	value := p.consumeWhile(func(char string) bool {
		return char != q
	})
	cq := p.consumeChar()
	if cq != q {
		panic(fmt.Sprintf("%v was not %v", cq, q))
	}
	return value
}
func (p *Parser) startWith(test string) bool {
	start := true
	for i := 0; i < len(test); i++ {
		if p.input[p.pos+i] != test[i] {
			start = false
		}
	}
	return start
}
func (p *Parser) consumeWhile(test func(char string) bool) string {
	var result string
	for {
		if p.eof() || !test(p.nextChar()) {
			break
		}
		result += p.consumeChar()
	}
	return result
}
func (p *Parser) consumeWhitespace() {
	reg := regexp.MustCompile("[\\s]")
	f := func(char string) bool {
		return reg.MatchString(char)
	}
	p.consumeWhile(f)
}
func (p *Parser) consumeChar() string {
	char := p.input[p.pos]
	p.pos++
	return string(char)
}