(FYI i'm using ' as a backtick in in-line code blocks for convenience, whenever i use single-quote, i mean backtick)
Tagged templates have operator precedence ~16 according to MDN (src)
The tag does not have to be a plain identifier. You can use any expression with precedence greater than 16, which includes property access, function call, new expression, or even another tagged template literal.
new without its (..) args is level 16
so new foo'hi' should result in foo'hi' being evaluated first
then new is applied as if the result of foo'hi' is a classname
So the correct parse tree should be something like this
but new() with its args list is level 17
so new foo()'hi' should result in new foo() being evaluated first
then 'hi' being applied as it 'calls' the resulting class instance
So the correct parse tree should be something like this
This occurs for two reasons, call_expressions require an expression, but new_expressions only allow primary_expressions so when the identifierfoo is processed into a primary_expression it gets consumed by new_expression without conflict.
This diff changes call_expressions to be constructed with choice(primary_expression, new_expression) in the case where a tagged-template is used. This is sane because of the precedence rules discussed earlier, ie primary_expression allows for call_expressionmember_expression (level 17), parenthesized_expression (level 18), and direct identifiers.
The only other allowed expression is new_expression (level 17) so I added it to the choice block
With this change, we still don't get the desired result because 'new' primary_expression gets resolved as new_expression before we can make a call expression. So I add a new template_call precedence for this case.
Note that regular call precedences should still come after 'new' so that new foo() continues to parse correctly
Closes #334
Background understanding
(FYI i'm using
'
as a backtick in in-line code blocks for convenience, whenever i use single-quote, i mean backtick)Tagged templates have operator precedence ~16 according to MDN (src)
new
without its(..)
args is level 16so
new foo'hi'
should result infoo'hi'
being evaluated first thennew
is applied as if the result offoo'hi'
is a classnameSo the correct parse tree should be something like this
but
new()
with its args list is level 17 sonew foo()'hi'
should result innew foo()
being evaluated first then'hi'
being applied as it 'calls' the resulting class instanceSo the correct parse tree should be something like this
Current Problem and fix
new foo()'hi'
is currently correct butnew foo'hi'
results inThis occurs for two reasons,
call_expressions
require anexpression
, butnew_expressions
only allowprimary_expressions
so when theidentifier
foo
is processed into aprimary_expression
it gets consumed bynew_expression
without conflict.This diff changes
call_expressions
to be constructed withchoice(primary_expression, new_expression)
in the case where a tagged-template is used. This is sane because of the precedence rules discussed earlier, ieprimary_expression
allows forcall_expression
member_expression
(level 17),parenthesized_expression
(level 18), and direct identifiers.The only other allowed expression is
new_expression
(level 17) so I added it to the choice blockWith this change, we still don't get the desired result because 'new' primary_expression gets resolved as new_expression before we can make a call expression. So I add a new
template_call
precedence for this case.Note that regular
call
precedences should still come after 'new' so thatnew foo()
continues to parse correctlycc @amaanq