mirror of
https://github.com/RGBCube/serenity
synced 2025-05-28 11:35:10 +00:00
LibJS: Add raw strings to tagged template literals
When calling a function with a tagged template, the first array that is passed in now contains a "raw" property with the raw, escaped strings.
This commit is contained in:
parent
9d0c6a32bd
commit
b5f1df57ed
5 changed files with 52 additions and 9 deletions
|
@ -1347,6 +1347,16 @@ Value TaggedTemplateLiteral::execute(Interpreter& interpreter) const
|
||||||
else
|
else
|
||||||
arguments.append(value);
|
arguments.append(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* raw_strings = Array::create(interpreter.global_object());
|
||||||
|
for (auto& raw_string : m_template_literal->raw_strings()) {
|
||||||
|
auto value = raw_string.execute(interpreter);
|
||||||
|
if (interpreter.exception())
|
||||||
|
return {};
|
||||||
|
raw_strings->elements().append(value);
|
||||||
|
}
|
||||||
|
strings->put("raw", raw_strings, 0);
|
||||||
|
|
||||||
return interpreter.call(tag_function, js_undefined(), move(arguments));
|
return interpreter.call(tag_function, js_undefined(), move(arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -779,7 +779,13 @@ private:
|
||||||
class TemplateLiteral final : public Expression {
|
class TemplateLiteral final : public Expression {
|
||||||
public:
|
public:
|
||||||
TemplateLiteral(NonnullRefPtrVector<Expression> expressions)
|
TemplateLiteral(NonnullRefPtrVector<Expression> expressions)
|
||||||
: m_expressions(expressions)
|
: m_expressions(move(expressions))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplateLiteral(NonnullRefPtrVector<Expression> expressions, NonnullRefPtrVector<Expression> raw_strings)
|
||||||
|
: m_expressions(move(expressions))
|
||||||
|
, m_raw_strings(move(raw_strings))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,11 +793,13 @@ public:
|
||||||
virtual void dump(int indent) const override;
|
virtual void dump(int indent) const override;
|
||||||
|
|
||||||
const NonnullRefPtrVector<Expression>& expressions() const { return m_expressions; }
|
const NonnullRefPtrVector<Expression>& expressions() const { return m_expressions; }
|
||||||
|
const NonnullRefPtrVector<Expression>& raw_strings() const { return m_raw_strings; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual const char* class_name() const override { return "TemplateLiteral"; }
|
virtual const char* class_name() const override { return "TemplateLiteral"; }
|
||||||
|
|
||||||
const NonnullRefPtrVector<Expression> m_expressions;
|
const NonnullRefPtrVector<Expression> m_expressions;
|
||||||
|
const NonnullRefPtrVector<Expression> m_raw_strings;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TaggedTemplateLiteral final : public Expression {
|
class TaggedTemplateLiteral final : public Expression {
|
||||||
|
|
|
@ -417,7 +417,7 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
|
||||||
case TokenType::BracketOpen:
|
case TokenType::BracketOpen:
|
||||||
return parse_array_expression();
|
return parse_array_expression();
|
||||||
case TokenType::TemplateLiteralStart:
|
case TokenType::TemplateLiteralStart:
|
||||||
return parse_template_literal();
|
return parse_template_literal(false);
|
||||||
case TokenType::New:
|
case TokenType::New:
|
||||||
return parse_new_expression();
|
return parse_new_expression();
|
||||||
default:
|
default:
|
||||||
|
@ -560,18 +560,29 @@ NonnullRefPtr<ArrayExpression> Parser::parse_array_expression()
|
||||||
return create_ast_node<ArrayExpression>(move(elements));
|
return create_ast_node<ArrayExpression>(move(elements));
|
||||||
}
|
}
|
||||||
|
|
||||||
NonnullRefPtr<TemplateLiteral> Parser::parse_template_literal()
|
NonnullRefPtr<TemplateLiteral> Parser::parse_template_literal(bool is_tagged)
|
||||||
{
|
{
|
||||||
consume(TokenType::TemplateLiteralStart);
|
consume(TokenType::TemplateLiteralStart);
|
||||||
|
|
||||||
NonnullRefPtrVector<Expression> expressions;
|
NonnullRefPtrVector<Expression> expressions;
|
||||||
|
NonnullRefPtrVector<Expression> raw_strings;
|
||||||
|
|
||||||
|
auto append_empty_string = [&expressions, &raw_strings, is_tagged]() {
|
||||||
|
auto string_literal = create_ast_node<StringLiteral>("");
|
||||||
|
expressions.append(string_literal);
|
||||||
|
if (is_tagged)
|
||||||
|
raw_strings.append(string_literal);
|
||||||
|
};
|
||||||
|
|
||||||
if (!match(TokenType::TemplateLiteralString))
|
if (!match(TokenType::TemplateLiteralString))
|
||||||
expressions.append(create_ast_node<StringLiteral>(""));
|
append_empty_string();
|
||||||
|
|
||||||
while (!match(TokenType::TemplateLiteralEnd) && !match(TokenType::UnterminatedTemplateLiteral)) {
|
while (!match(TokenType::TemplateLiteralEnd) && !match(TokenType::UnterminatedTemplateLiteral)) {
|
||||||
if (match(TokenType::TemplateLiteralString)) {
|
if (match(TokenType::TemplateLiteralString)) {
|
||||||
expressions.append(create_ast_node<StringLiteral>(consume().string_value()));
|
auto token = consume();
|
||||||
|
expressions.append(create_ast_node<StringLiteral>(token.string_value()));
|
||||||
|
if (is_tagged)
|
||||||
|
raw_strings.append(create_ast_node<StringLiteral>(token.value()));
|
||||||
} else if (match(TokenType::TemplateLiteralExprStart)) {
|
} else if (match(TokenType::TemplateLiteralExprStart)) {
|
||||||
consume(TokenType::TemplateLiteralExprStart);
|
consume(TokenType::TemplateLiteralExprStart);
|
||||||
if (match(TokenType::TemplateLiteralExprEnd)) {
|
if (match(TokenType::TemplateLiteralExprEnd)) {
|
||||||
|
@ -587,7 +598,7 @@ NonnullRefPtr<TemplateLiteral> Parser::parse_template_literal()
|
||||||
consume(TokenType::TemplateLiteralExprEnd);
|
consume(TokenType::TemplateLiteralExprEnd);
|
||||||
|
|
||||||
if (!match(TokenType::TemplateLiteralString))
|
if (!match(TokenType::TemplateLiteralString))
|
||||||
expressions.append(create_ast_node<StringLiteral>(""));
|
append_empty_string();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,6 +608,8 @@ NonnullRefPtr<TemplateLiteral> Parser::parse_template_literal()
|
||||||
consume(TokenType::TemplateLiteralEnd);
|
consume(TokenType::TemplateLiteralEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_tagged)
|
||||||
|
return create_ast_node<TemplateLiteral>(expressions, raw_strings);
|
||||||
return create_ast_node<TemplateLiteral>(expressions);
|
return create_ast_node<TemplateLiteral>(expressions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,7 +617,7 @@ NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associati
|
||||||
{
|
{
|
||||||
auto expression = parse_primary_expression();
|
auto expression = parse_primary_expression();
|
||||||
while (match(TokenType::TemplateLiteralStart)) {
|
while (match(TokenType::TemplateLiteralStart)) {
|
||||||
auto template_literal = parse_template_literal();
|
auto template_literal = parse_template_literal(true);
|
||||||
expression = create_ast_node<TaggedTemplateLiteral>(move(expression), move(template_literal));
|
expression = create_ast_node<TaggedTemplateLiteral>(move(expression), move(template_literal));
|
||||||
}
|
}
|
||||||
while (match_secondary_expression()) {
|
while (match_secondary_expression()) {
|
||||||
|
@ -617,7 +630,7 @@ NonnullRefPtr<Expression> Parser::parse_expression(int min_precedence, Associati
|
||||||
Associativity new_associativity = operator_associativity(m_parser_state.m_current_token.type());
|
Associativity new_associativity = operator_associativity(m_parser_state.m_current_token.type());
|
||||||
expression = parse_secondary_expression(move(expression), new_precedence, new_associativity);
|
expression = parse_secondary_expression(move(expression), new_precedence, new_associativity);
|
||||||
while (match(TokenType::TemplateLiteralStart)) {
|
while (match(TokenType::TemplateLiteralStart)) {
|
||||||
auto template_literal = parse_template_literal();
|
auto template_literal = parse_template_literal(true);
|
||||||
expression = create_ast_node<TaggedTemplateLiteral>(move(expression), move(template_literal));
|
expression = create_ast_node<TaggedTemplateLiteral>(move(expression), move(template_literal));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
NonnullRefPtr<Expression> parse_unary_prefixed_expression();
|
NonnullRefPtr<Expression> parse_unary_prefixed_expression();
|
||||||
NonnullRefPtr<ObjectExpression> parse_object_expression();
|
NonnullRefPtr<ObjectExpression> parse_object_expression();
|
||||||
NonnullRefPtr<ArrayExpression> parse_array_expression();
|
NonnullRefPtr<ArrayExpression> parse_array_expression();
|
||||||
NonnullRefPtr<TemplateLiteral> parse_template_literal();
|
NonnullRefPtr<TemplateLiteral> parse_template_literal(bool is_tagged);
|
||||||
NonnullRefPtr<Expression> parse_secondary_expression(NonnullRefPtr<Expression>, int min_precedence, Associativity associate = Associativity::Right);
|
NonnullRefPtr<Expression> parse_secondary_expression(NonnullRefPtr<Expression>, int min_precedence, Associativity associate = Associativity::Right);
|
||||||
NonnullRefPtr<CallExpression> parse_call_expression(NonnullRefPtr<Expression>);
|
NonnullRefPtr<CallExpression> parse_call_expression(NonnullRefPtr<Expression>);
|
||||||
NonnullRefPtr<NewExpression> parse_new_expression();
|
NonnullRefPtr<NewExpression> parse_new_expression();
|
||||||
|
|
|
@ -82,6 +82,18 @@ try {
|
||||||
var rating = "great";
|
var rating = "great";
|
||||||
assert(review`${name} is a ${rating} project!` === "**SerenityOS** is a _great_ project!");
|
assert(review`${name} is a ${rating} project!` === "**SerenityOS** is a _great_ project!");
|
||||||
|
|
||||||
|
const getTemplateObject = (...rest) => rest;
|
||||||
|
const getRawTemplateStrings = arr => arr.raw;
|
||||||
|
|
||||||
|
let o = getTemplateObject`foo\nbar`;
|
||||||
|
assert(Object.getOwnPropertyNames(o[0]).includes('raw'));
|
||||||
|
|
||||||
|
let raw = getRawTemplateStrings`foo${1 + 3}\nbar`;
|
||||||
|
assert(!Object.getOwnPropertyNames(raw).includes('raw'));
|
||||||
|
assert(raw.length === 2);
|
||||||
|
assert(raw[0] === 'foo');
|
||||||
|
assert(raw[1].length === 5 && raw[1] === '\\nbar');
|
||||||
|
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("FAIL: " + e);
|
console.log("FAIL: " + e);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue