parseElement method
Implementation
Element? parseElement() {
if (!next(TokenType.lt)) return null;
var lt = _current;
if (next(TokenType.slash)) {
// We entered a closing tag, don't keep reading...
_index -= 2;
return null;
}
var tagName = parseIdentifier();
if (tagName == null) {
errors.add(
JaelError(JaelErrorSeverity.error, 'Missing tag name.', lt.span));
return null;
}
var attributes = <Attribute>[];
var attribute = parseAttribute();
while (attribute != null) {
attributes.add(attribute);
attribute = parseAttribute();
}
if (next(TokenType.slash)) {
// Try for self-closing...
var slash = _current;
if (!next(TokenType.gt)) {
errors.add(JaelError(JaelErrorSeverity.error,
'Missing ">" in self-closing "${tagName.name}" tag.', slash.span));
return null;
}
return SelfClosingElement(lt, tagName, attributes, slash, _current);
}
if (!next(TokenType.gt)) {
errors.add(JaelError(
JaelErrorSeverity.error,
'Missing ">" in "${tagName.name}" tag.',
attributes.isEmpty ? tagName.span : attributes.last.span));
return null;
}
var gt = _current;
// Implicit self-closing
if (Element.selfClosing.contains(tagName.name)) {
return SelfClosingElement(lt, tagName, attributes, null, gt);
}
var children = <ElementChild>[];
var child = parseElementChild();
while (child != null) {
// if (child is! HtmlComment) children.add(child);
children.add(child);
child = parseElementChild();
}
// Parse closing tag
if (!next(TokenType.lt)) {
errors.add(JaelError(
JaelErrorSeverity.error,
'Missing closing tag for "${tagName.name}" tag.',
children.isEmpty ? tagName.span : children.last.span));
return null;
}
var lt2 = _current;
if (!next(TokenType.slash)) {
errors.add(JaelError(JaelErrorSeverity.error,
'Missing "/" in "${tagName.name}" closing tag.', lt2.span));
return null;
}
var slash = _current;
var tagName2 = parseIdentifier();
if (tagName2 == null) {
errors.add(JaelError(
JaelErrorSeverity.error,
'Missing "${tagName.name}" in "${tagName.name}" closing tag.',
slash.span));
return null;
}
if (tagName2.name != tagName.name) {
errors.add(JaelError(
JaelErrorSeverity.error,
'Mismatched closing tags. Expected "${tagName.span.text}"; got "${tagName2.name}" instead.',
lt2.span));
return null;
}
if (!next(TokenType.gt)) {
errors.add(JaelError(JaelErrorSeverity.error,
'Missing ">" in "${tagName.name}" closing tag.', tagName2.span));
return null;
}
return RegularElement(
lt, tagName, attributes, gt, children, lt2, slash, tagName2, _current);
}