Bladeren bron

LibJS: Fix that windows style line endings were not ignored or converted

These are tested by test262 but the current test262-runner reads the
files in python which automatically converts \r\n to \n.
This meant that we passed the tests while we should not have.
davidot 3 jaren geleden
bovenliggende
commit
3fee7b0d0b

+ 1 - 1
Userland/Libraries/LibJS/Parser.cpp

@@ -1271,7 +1271,7 @@ NonnullRefPtr<TemplateLiteral> Parser::parse_template_literal(bool is_tagged)
             auto token = consume();
             expressions.append(parse_string_literal(token, true));
             if (is_tagged)
-                raw_strings.append(create_ast_node<StringLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, token.value()));
+                raw_strings.append(create_ast_node<StringLiteral>({ m_state.current_token.filename(), rule_start.position(), position() }, token.raw_template_value()));
         } else if (match(TokenType::TemplateLiteralExprStart)) {
             consume(TokenType::TemplateLiteralExprStart);
             if (match(TokenType::TemplateLiteralExprEnd)) {

+ 28 - 0
Userland/Libraries/LibJS/Tests/parser-line-terminators.js

@@ -61,6 +61,34 @@ test("line terminators can be mixed (but please don't)", () => {
 test("all line terminators are valid for line continuations", () => {
     expect(Function('return "a\\\nb"')()).toBe("ab");
     expect(Function('return "a\\\rb"')()).toBe("ab");
+    expect(Function('return "a\\\r\nb"')()).toBe("ab");
     expect(Function('return "a\\
b"')()).toBe("ab");
     expect(Function('return "a\\
b"')()).toBe("ab");
 });
+
+test("template-literals raw and real value", () => {
+    let lastTemplate;
+    let lastRaw;
+
+    function tag(cs) {
+        lastTemplate = cs[0];
+        lastRaw = cs.raw[0];
+    }
+
+    function checkTemplate(string_value, expected_template, expected_raw) {
+        eval("tag`" + string_value + "`");
+        expect(lastTemplate).toBe(expected_template);
+        expect(lastRaw).toBe(expected_raw);
+    }
+
+    checkTemplate("", "", "");
+    checkTemplate("\n", "\n", "\n");
+    checkTemplate("\r", "\n", "\n");
+    checkTemplate("\r\n", "\n", "\n");
+    checkTemplate("\n\r\n", "\n\n", "\n\n");
+
+    checkTemplate("a\\\nb", "ab", "a\\\nb");
+    checkTemplate("a\\\rb", "ab", "a\\\nb");
+    checkTemplate("a\\
b", "ab", "a\\
b");
+    checkTemplate("a\\
b", "ab", "a\\
b");
+});

+ 21 - 0
Userland/Libraries/LibJS/Token.cpp

@@ -106,6 +106,16 @@ String Token::string_value(StringValueStatus& status) const
     while (!lexer.is_eof()) {
         // No escape, consume one char and continue
         if (!lexer.next_is('\\')) {
+
+            if (is_template && lexer.next_is('\r')) {
+                lexer.ignore();
+                if (lexer.next_is('\n'))
+                    lexer.ignore();
+
+                builder.append('\n');
+                continue;
+            }
+
             builder.append(lexer.consume());
             continue;
         }
@@ -132,6 +142,8 @@ String Token::string_value(StringValueStatus& status) const
 
         // Line continuation
         if (lexer.next_is('\n') || lexer.next_is('\r')) {
+            if (lexer.next_is("\r\n"))
+                lexer.ignore();
             lexer.ignore();
             continue;
         }
@@ -192,6 +204,15 @@ String Token::string_value(StringValueStatus& status) const
     return builder.to_string();
 }
 
+// 12.8.6.2 Static Semantics: TRV, https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#sec-static-semantics-trv
+String Token::raw_template_value() const
+{
+    String base = value().to_string();
+    base.replace("\r\n", "\n", true);
+    base.replace("\r", "\n", true);
+    return base;
+}
+
 bool Token::bool_value() const
 {
     VERIFY(type() == TokenType::BoolLiteral);

+ 1 - 0
Userland/Libraries/LibJS/Token.h

@@ -237,6 +237,7 @@ public:
         LegacyOctalEscapeSequence,
     };
     String string_value(StringValueStatus& status) const;
+    String raw_template_value() const;
 
     bool is_identifier_name() const;
     bool trivia_contains_line_terminator() const;