fix(compiler): fix handling of escaped characters in the lexer - #28978
petebacondarwin wants to merge 5 commits into
Conversation
28db305 to
0321bcf
Compare
cexbrayat
left a comment
There was a problem hiding this comment.
As I spent a few hours lately trying to fix this bug, I can only agree that the cursor abstraction makes the whole section much easier to understand, and feels less hacky than our initial ideas. 馃憤
There was a problem hiding this comment.
(unrelated) nit: the param is not correct anymore, should be options.
There was a problem hiding this comment.
Nor the _tokenizeIcu param either!
There was a problem hiding this comment.
in case this is unvolontary: it used to be forced to lowercase (the parameter of _consumeRawTextWithTagClose is still named lowercaseTagName).
There was a problem hiding this comment.
I shall add a test to check :-)
There was a problem hiding this comment.
Actually the original code was a bit weird. It used the raw tag name in the opening tag token but then a lower-cased version in the closing tag token. For matching the opening tag to the closing tag it is using the _attemptStrCaseInsensitive() function anyway so it doesn't matter.
As the code is now, the closing tag token is using the same casing as the opening tag token - which I think is more consistent and correct.
There was a problem hiding this comment.
I changed the other occurrence of lowercaseTagName instead.
c1bcf89 to
1c00170
Compare
alxhub
left a comment
There was a problem hiding this comment.
Very nice work, I love the new CharacterCursor abstraction. Just a couple typings nits and a question about performance.
There was a problem hiding this comment.
| clone(): CharacterCursor; | |
| clone(): this; |
There was a problem hiding this comment.
I tried that too :-)
Unfortunately if you make the interface use this then the return value actually does have to be this (and not new SomeClass()). I.E. the following code is node invalid:
clone(): this { return new PlainCharacterCursor(this); }You get the error:
Type 'PlainCharacterCursor' is not assignable to type 'this'.
There was a problem hiding this comment.
This seems expensive (allocating on every advance). Can we avoid having two copies of the same state, or the need to copy between them?
There was a problem hiding this comment.
I wondered about this but without testing it we don't really know if it is a performance hit. These objects are small and always have the same shape, so I wouldn't be surprised if the memory could be used efficiently.
I could definitely move the file, input and end properties out of the CursorState object, which would halve the number of properties that need copying.
Also I could move the copy of the object into the processEscapeSequence so that we only make a copy if we hit an escape. Otherwise the two object stay the same.
1c00170 to
960381d
Compare
The parts of a token are supposed to be an array of not-null strings, but we were using `null` for tags that had no prefix. This has been fixed to use the empty string in such cases, which allows the `null !` hack to be removed.
Previously the start of a character indicated by an escape sequence was being incorrectly computed by the lexer, which caused tokens to include the start of the escaped character sequence in the preceding token. In particular this affected the name extracted from opening tags if the name was terminated by an escape sequence. For example, `<t\n>` would have the name `t\` rather than `t`. This fix refactors the lexer to use a "cursor" object to iterate over the characters in the template source. There are two cursor implementations, one expects a simple string, the other expects a string that contains JavaScript escape sequences that need to be unescaped.
960381d to
a094903
Compare
| super(fileOrCursor); | ||
| this.internalState = {...fileOrCursor.internalState}; | ||
| } else { | ||
| super(fileOrCursor, range !); |
There was a problem hiding this comment.
TS was not clever enough to know that we must have come via the second signature.
|
merge-assistance: g3 is good http://test/OCL:236077460:BASE:236077487:1551346219091:61b6ddf8 |
Previously the start of a character indicated by an escape sequence was being incorrectly computed by the lexer, which caused tokens to include the start of the escaped character sequence in the preceding token. In particular this affected the name extracted from opening tags if the name was terminated by an escape sequence. For example, `<t\n>` would have the name `t\` rather than `t`. This fix refactors the lexer to use a "cursor" object to iterate over the characters in the template source. There are two cursor implementations, one expects a simple string, the other expects a string that contains JavaScript escape sequences that need to be unescaped. PR Close #28978
|
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: #28843
Previously the start of a character indicated by an escape sequence
was being incorrectly computed by the lexer, which caused tokens
to include the start of the escaped character sequence in the
preceding token. In particular this affected the name extracted
from opening tags if the name was terminated by an escape sequence.
For example,
<t\n>would have the namet\rather thant.What is the new behavior?
This fix refactors the lexer to use a "cursor" object to iterate over
the characters in the template source. There are two cursor implementations,
one expects a simple string, the other expects a string that contains
JavaScript escape sequences that need to be unescaped.
Does this PR introduce a breaking change?
Other information
Alternative to #28844