Add raw text elements and doctypes
Co-Authored-By: Ashi Krishnan <queerviolet@github.com>
This commit is contained in:
parent
d9a504136e
commit
21b5fad6f0
|
@ -87,3 +87,50 @@ Comments
|
|||
(start_tag)
|
||||
(comment)
|
||||
(end_tag)))
|
||||
|
||||
==================================
|
||||
Raw text elements
|
||||
==================================
|
||||
|
||||
<script>
|
||||
</s
|
||||
</sc
|
||||
</scr
|
||||
</scri
|
||||
</scrip
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</ </s </st </sty </styl
|
||||
</style>
|
||||
|
||||
---
|
||||
|
||||
(fragment
|
||||
(raw_element
|
||||
(start_tag)
|
||||
(end_tag))
|
||||
(raw_element
|
||||
(start_tag)
|
||||
(end_tag))
|
||||
(text))
|
||||
|
||||
==================================
|
||||
All-caps doctype
|
||||
==================================
|
||||
<!DOCTYPE html PUBLIC
|
||||
"-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
---
|
||||
|
||||
(fragment
|
||||
(doctype))
|
||||
|
||||
==================================
|
||||
Lowercase doctype
|
||||
==================================
|
||||
<!doctype html>
|
||||
---
|
||||
|
||||
(fragment
|
||||
(doctype))
|
||||
|
|
25
grammar.js
25
grammar.js
|
@ -8,21 +8,32 @@ module.exports = grammar({
|
|||
|
||||
externals: $ => [
|
||||
$._open_start_tag,
|
||||
$._open_raw_start_tag,
|
||||
$._close_start_tag,
|
||||
$._self_close_start_tag,
|
||||
$.end_tag,
|
||||
$._implicit_end_tag,
|
||||
$._erroneous_end_tag,
|
||||
$._raw_text,
|
||||
$.comment,
|
||||
],
|
||||
|
||||
rules: {
|
||||
fragment: $ => repeat($._node),
|
||||
|
||||
doctype: $ => seq(
|
||||
'<!',
|
||||
/[Dd][Oo][Cc][Tt][Yy][Pp][Ee]/,
|
||||
/[^>]+/,
|
||||
'>'
|
||||
),
|
||||
|
||||
_node: $ => choice(
|
||||
$.doctype,
|
||||
$.text,
|
||||
$._erroneous_end_tag,
|
||||
$.element
|
||||
$.element,
|
||||
$.raw_element
|
||||
),
|
||||
|
||||
element: $ => choice(
|
||||
|
@ -34,12 +45,24 @@ module.exports = grammar({
|
|||
$.self_closing_tag
|
||||
),
|
||||
|
||||
raw_element: $ => seq(
|
||||
alias($._raw_start_tag, $.start_tag),
|
||||
optional($._raw_text),
|
||||
$.end_tag
|
||||
),
|
||||
|
||||
start_tag: $ => seq(
|
||||
$._open_start_tag,
|
||||
repeat($.attribute),
|
||||
$._close_start_tag
|
||||
),
|
||||
|
||||
_raw_start_tag: $ => seq(
|
||||
$._open_raw_start_tag,
|
||||
repeat($.attribute),
|
||||
$._close_start_tag
|
||||
),
|
||||
|
||||
self_closing_tag: $ => seq(
|
||||
$._open_start_tag,
|
||||
repeat($.attribute),
|
||||
|
|
|
@ -8,9 +8,34 @@
|
|||
"name": "_node"
|
||||
}
|
||||
},
|
||||
"doctype": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "<!"
|
||||
},
|
||||
{
|
||||
"type": "PATTERN",
|
||||
"value": "[Dd][Oo][Cc][Tt][Yy][Pp][Ee]"
|
||||
},
|
||||
{
|
||||
"type": "PATTERN",
|
||||
"value": "[^>]+"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ">"
|
||||
}
|
||||
]
|
||||
},
|
||||
"_node": {
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "doctype"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "text"
|
||||
|
@ -22,6 +47,10 @@
|
|||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "element"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "raw_element"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -63,6 +92,36 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"raw_element": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "ALIAS",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "_raw_start_tag"
|
||||
},
|
||||
"named": true,
|
||||
"value": "start_tag"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_raw_text"
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "end_tag"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start_tag": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
|
@ -83,6 +142,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"_raw_start_tag": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_open_raw_start_tag"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "attribute"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_close_start_tag"
|
||||
}
|
||||
]
|
||||
},
|
||||
"self_closing_tag": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
|
@ -236,6 +315,10 @@
|
|||
"type": "SYMBOL",
|
||||
"name": "_open_start_tag"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_open_raw_start_tag"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_close_start_tag"
|
||||
|
@ -256,6 +339,10 @@
|
|||
"type": "SYMBOL",
|
||||
"name": "_erroneous_end_tag"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "_raw_text"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "comment"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,7 +3,6 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include <locale>
|
||||
|
||||
#include "tag.h"
|
||||
|
||||
namespace {
|
||||
|
@ -13,12 +12,14 @@ using std::string;
|
|||
|
||||
enum TokenType {
|
||||
OPEN_START_TAG,
|
||||
OPEN_RAW_START_TAG,
|
||||
CLOSE_START_TAG,
|
||||
SELF_CLOSE_START_TAG,
|
||||
END_TAG,
|
||||
IMPLICIT_END_TAG,
|
||||
ERRONEOUS_END_TAG,
|
||||
COMMENT,
|
||||
RAW_TEXT,
|
||||
COMMENT
|
||||
};
|
||||
|
||||
struct Scanner {
|
||||
|
@ -97,6 +98,31 @@ struct Scanner {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool raw_text(TSLexer *lexer) {
|
||||
if (!tags.size()) return false;
|
||||
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
const string &end_delimiter = tags.back().type == SCRIPT
|
||||
? "</script"
|
||||
: "</style";
|
||||
|
||||
unsigned delimiter_index = 0;
|
||||
while (lexer->lookahead) {
|
||||
if (lexer->lookahead == end_delimiter[delimiter_index]) {
|
||||
delimiter_index++;
|
||||
if (delimiter_index == end_delimiter.size()) break;
|
||||
} else {
|
||||
delimiter_index = 0;
|
||||
lexer->mark_end(lexer);
|
||||
}
|
||||
lexer->advance(lexer, false);
|
||||
}
|
||||
|
||||
lexer->result_symbol = RAW_TEXT;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_tag(TSLexer *lexer) {
|
||||
if (!tags.empty() && tags.back().is_void()) {
|
||||
tags.pop_back();
|
||||
|
@ -111,7 +137,7 @@ struct Scanner {
|
|||
tags.push_back(tag);
|
||||
|
||||
lexer->mark_end(lexer);
|
||||
lexer->result_symbol = OPEN_START_TAG;
|
||||
lexer->result_symbol = tag.is_raw() ? OPEN_RAW_START_TAG : OPEN_START_TAG;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -150,6 +176,10 @@ struct Scanner {
|
|||
lexer->advance(lexer, true);
|
||||
}
|
||||
|
||||
if (valid_symbols[RAW_TEXT] && !valid_symbols[OPEN_START_TAG] && !valid_symbols[CLOSE_START_TAG]) {
|
||||
return raw_text(lexer);
|
||||
}
|
||||
|
||||
switch (lexer->lookahead) {
|
||||
case '<':
|
||||
lexer->mark_end(lexer);
|
||||
|
|
Loading…
Reference in New Issue