Njs: template literal problem

Created on 18 Jun 2020  路  3Comments  路  Source: nginx/njs

$ cat lll.js 
var lines1 = `
var a = 1;
var b = 2;
if (test) {
throw new Error('one');
} else {
throw new Error('two');
}
`;

var lines2 = "\n" +
"var a = 1;\n" +
"var b = 2;\n" +
"if (test) {\n" +
"throw new Error('one');\n" +
"} else {\n" +
"throw new Error('two');\n" +
"}\n";

console.log(lines1 == lines2, lines1.length, lines2.length, lines1.codePointAt(0), lines2.codePointAt(0));
$ build/njs lll.js 
false 93 94 118 10
$ node lll.js 
true 94 94 10 10
bug

Most helpful comment

@lexborisov

works for me.
line numbers are also correct.

All 3 comments

@xeioex @lexborisov

Minimize the code.

print(`
`.length);

Expected 1, but 0.
The reason is line end should be different between normal and template parsing.

    case NJS_TOKEN_LINE_END:
        lexer->line++; 
        // should return in template parsing

        /* Fall through. */

It seems it's better to parse complete or partial (till ${) template literal in njs_lexer_make_token,
after that do the thing njs_parser_template_literal_string.
I'll try this way.

Hi @drsm @hongzhidao

It seems it's better to parse complete or partial (till ${) template literal in njs_lexer_make_token

This is not the best solution. We will have to reinvent the parser in the lexer, for example:

console.count`a${ a => {{{a}}}}b`

Please, try this patch:

# HG changeset patch
# User Alexander Borisov <[email protected]>
# Date 1592560059 -10800
#      Fri Jun 19 12:47:39 2020 +0300
# Node ID 16a3f14971a703edc46b8d0744c7932fdfdef491
# Parent  b3e4691dbcea63d6263a15fc780f54a5cf1cae4f
Parser: fixed line counting in template literals.

This closes #321 issue on GitHub.

diff -r b3e4691dbcea -r 16a3f14971a7 src/njs_parser.c
--- a/src/njs_parser.c  Fri Jun 19 11:56:48 2020 +0300
+++ b/src/njs_parser.c  Fri Jun 19 12:47:39 2020 +0300
@@ -1141,7 +1141,7 @@ njs_parser_primary_expression_test(njs_p
         parser->node = node;

         njs_parser_next(parser, njs_parser_template_literal);
-        break;
+        return NJS_OK;

     /* CoverParenthesizedExpressionAndArrowParameterList */
     case NJS_TOKEN_OPEN_PARENTHESIS:
@@ -1322,6 +1322,9 @@ njs_parser_template_literal(njs_parser_t

     parser->target = temp;

+    token->text.start++;
+    token->text.length = 0;
+
     njs_parser_next(parser, njs_parser_template_literal_string);

     return NJS_OK;
@@ -2199,8 +2202,6 @@ njs_parser_property(njs_parser_t *parser

         parser->node = node;

-        njs_lexer_consume_token(parser->lexer, 1);
-
         njs_parser_next(parser, njs_parser_template_literal);

         break;
@@ -7820,28 +7821,33 @@ njs_parser_template_string(njs_parser_t 

         c = *p++;

-        if (c == '\\') {
+        switch (c) {
+        case '\\':
             if (p == lexer->end) {
-                break;
+                return NJS_ERROR;
             }

             p++;
             escape = 1;

             continue;
-        }
-
-        if (c == '`') {
+
+        case '`':
             text->length = p - text->start - 1;
             goto done;
-        }
-
-        if (c == '$') {
+
+        case '$':
             if (p < lexer->end && *p == '{') {
                 p++;
                 text->length = p - text->start - 2;
                 goto done;
             }
+
+            break;
+
+        case '\n':
+            parser->lexer->line++;
+            break;
         }
     }

diff -r b3e4691dbcea -r 16a3f14971a7 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c  Fri Jun 19 11:56:48 2020 +0300
+++ b/src/test/njs_unit_test.c  Fri Jun 19 12:47:39 2020 +0300
@@ -6330,6 +6330,9 @@ static njs_unit_test_t  njs_test[] =
                  "foo`That ${person} is a ${age}`;"),
       njs_str("That  is a Mike21") },

+    { njs_str("`\n`.length"),
+      njs_str("1") },
+
     /* Strings. */

     { njs_str("var a = '0123456789' + '012345';"

@lexborisov

works for me.
line numbers are also correct.

Was this page helpful?
0 / 5 - 0 ratings