1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-16 22:55:06 +00:00

LibJS: Add TokenType::TemplateLiteral

This is required for template literals - we're not quite there yet, but at
least the parser can now tell us when this token is encountered -
currently this yields "Unexpected token Invalid". Not really helpful.

The character is a "backtick", but as we already have
TokenType::{StringLiteral,RegexLiteral} this seemed like a fitting name.

This also enables syntax highlighting for template literals in the js
REPL and LibGUI's JSSyntaxHighlighter.
This commit is contained in:
Linus Groh 2020-04-24 00:20:02 +01:00 committed by Andreas Kling
parent 57caca3171
commit 95b51e857d
6 changed files with 13 additions and 3 deletions

View file

@ -42,6 +42,7 @@ static TextStyle style_for_token_type(Gfx::Palette palette, JS::TokenType type)
case JS::TokenType::NumericLiteral: case JS::TokenType::NumericLiteral:
return { palette.syntax_number() }; return { palette.syntax_number() };
case JS::TokenType::StringLiteral: case JS::TokenType::StringLiteral:
case JS::TokenType::TemplateLiteral:
case JS::TokenType::RegexLiteral: case JS::TokenType::RegexLiteral:
case JS::TokenType::UnterminatedStringLiteral: case JS::TokenType::UnterminatedStringLiteral:
return { palette.syntax_string() }; return { palette.syntax_string() };

View file

@ -337,7 +337,7 @@ Token Lexer::next()
} }
} }
token_type = TokenType::NumericLiteral; token_type = TokenType::NumericLiteral;
} else if (m_current_char == '"' || m_current_char == '\'') { } else if (m_current_char == '"' || m_current_char == '\'' || m_current_char == '`') {
char stop_char = m_current_char; char stop_char = m_current_char;
consume(); consume();
while (m_current_char != stop_char && m_current_char != '\n' && !is_eof()) { while (m_current_char != stop_char && m_current_char != '\n' && !is_eof()) {
@ -351,6 +351,9 @@ Token Lexer::next()
token_type = TokenType::UnterminatedStringLiteral; token_type = TokenType::UnterminatedStringLiteral;
} else { } else {
consume(); consume();
if (stop_char == '`')
token_type = TokenType::TemplateLiteral;
else
token_type = TokenType::StringLiteral; token_type = TokenType::StringLiteral;
} }
} else if (m_current_char == EOF) { } else if (m_current_char == EOF) {

View file

@ -1037,6 +1037,7 @@ bool Parser::match_expression() const
return type == TokenType::BoolLiteral return type == TokenType::BoolLiteral
|| type == TokenType::NumericLiteral || type == TokenType::NumericLiteral
|| type == TokenType::StringLiteral || type == TokenType::StringLiteral
|| type == TokenType::TemplateLiteral
|| type == TokenType::NullLiteral || type == TokenType::NullLiteral
|| type == TokenType::Identifier || type == TokenType::Identifier
|| type == TokenType::New || type == TokenType::New

View file

@ -74,7 +74,7 @@ double Token::double_value() const
String Token::string_value() const String Token::string_value() const
{ {
ASSERT(type() == TokenType::StringLiteral); ASSERT(type() == TokenType::StringLiteral || type() == TokenType::TemplateLiteral);
StringBuilder builder; StringBuilder builder;
for (size_t i = 1; i < m_value.length() - 1; ++i) { for (size_t i = 1; i < m_value.length() - 1; ++i) {
if (m_value[i] == '\\' && i + 1 < m_value.length() - 1) { if (m_value[i] == '\\' && i + 1 < m_value.length() - 1) {
@ -107,6 +107,9 @@ String Token::string_value() const
case '"': case '"':
builder.append('"'); builder.append('"');
break; break;
case '`':
builder.append('`');
break;
case '\\': case '\\':
builder.append('\\'); builder.append('\\');
break; break;

View file

@ -111,6 +111,7 @@ namespace JS {
__ENUMERATE_JS_TOKEN(SlashEquals) \ __ENUMERATE_JS_TOKEN(SlashEquals) \
__ENUMERATE_JS_TOKEN(StringLiteral) \ __ENUMERATE_JS_TOKEN(StringLiteral) \
__ENUMERATE_JS_TOKEN(Switch) \ __ENUMERATE_JS_TOKEN(Switch) \
__ENUMERATE_JS_TOKEN(TemplateLiteral) \
__ENUMERATE_JS_TOKEN(This) \ __ENUMERATE_JS_TOKEN(This) \
__ENUMERATE_JS_TOKEN(Throw) \ __ENUMERATE_JS_TOKEN(Throw) \
__ENUMERATE_JS_TOKEN(Tilde) \ __ENUMERATE_JS_TOKEN(Tilde) \

View file

@ -453,6 +453,7 @@ int main(int argc, char** argv)
stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Magenta) }); stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Magenta) });
break; break;
case JS::TokenType::StringLiteral: case JS::TokenType::StringLiteral:
case JS::TokenType::TemplateLiteral:
case JS::TokenType::RegexLiteral: case JS::TokenType::RegexLiteral:
case JS::TokenType::UnterminatedStringLiteral: case JS::TokenType::UnterminatedStringLiteral:
stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Green), Line::Style::Bold }); stylize({ start, end }, { Line::Style::Foreground(Line::Style::Color::Green), Line::Style::Bold });