code: function readOpenTag() {
  		// Read tag name
  		let start = getSourcePoint(),
  			match = tagNameRegex.exec(source.substr(pos))
  		if (!match) {
  			throwSyntaxError('Invalid open tag')
  		}
  		let tagName = match[0].toLowerCase(),
  			isVoid = voidElementsRegex.test(tagName)
  		advanceTo(pos + tagName.length)
  
  		// Keep reading content
  		let selfClose = false,
  			attributes = [],
  			// Used to detect repeated attributes
  			foundAttributeNames = []
  		while (true) {
  			// Match using anchored regex
  			let match = tagOpenContentStartRegex.exec(source.substr(pos))
  			if (!match) {
  				throwSyntaxError('Invalid open tag')
  			}
  
  			advanceTo(pos + match[0].length)
  			if (match[1] === '<%-') {
  				throwSyntaxError('EJS unescaped tags are not allowed inside open tags')
  			} else if (match[1] === '<%=') {
  				throwSyntaxError('EJS escaped tags are not allowed inside open tags')
  			} else if (match[1] === '<%') {
  				throwSyntaxError('EJS eval tags are not allowed inside open tags')
  			} else if (match[1] === '>') {
  				break
  			} else if (match[1] === '/>') {
  				selfClose = true
  				break
  			} else {
  				// Attribute start
  				let lowerName = match[1].toLowerCase()
  				if (foundAttributeNames.indexOf(lowerName) !== -1) {
  					throwSyntaxError(`Repeated attribute ${match[1]} in open tag ${tagName}`)
  				}
  				foundAttributeNames.push(lowerName)
  				attributes.push(readAttribute(lowerName))
  			}
  		}
  
  		if (!isVoid && selfClose) {
  			throwSyntaxError('Self-closed tags for non-void elements are not allowed')
  		}
  
  		return {
  			type: 'element',
  			start,
  			end: getSourcePoint(),
  			name: tagName,
  			isVoid,
  			attributes,
  			children: []
  		}
  	}
docs: Read an open tag token
  @returns {Token}