diff --git a/src/Language/JavaScript/Parser/Grammar7.y b/src/Language/JavaScript/Parser/Grammar7.y index f168668..fb8829e 100644 --- a/src/Language/JavaScript/Parser/Grammar7.y +++ b/src/Language/JavaScript/Parser/Grammar7.y @@ -9,6 +9,7 @@ module Language.JavaScript.Parser.Grammar7 ) where import Data.Char +import Data.Functor (($>)) import Language.JavaScript.Parser.Lexer import Language.JavaScript.Parser.ParserMonad import Language.JavaScript.Parser.SrcLocation @@ -505,8 +506,16 @@ TemplateLiteral : 'tmplnosub' { JSUntaggedTemplate (mkJSAnnot $1) ( | 'tmplhead' TemplateParts { JSUntaggedTemplate (mkJSAnnot $1) (tokenLiteral $1) $2 } TemplateParts :: { [AST.JSTemplatePart] } -TemplateParts : Expression 'tmplmiddle' TemplateParts { AST.JSTemplatePart $1 (mkJSAnnot $2) (tokenLiteral $2) : $3 } - | Expression 'tmpltail' { AST.JSTemplatePart $1 (mkJSAnnot $2) (tokenLiteral $2) : [] } +TemplateParts : TemplateExpression RBrace 'tmplmiddle' TemplateParts { AST.JSTemplatePart $1 $2 ('}' : tokenLiteral $3) : $4 } + | TemplateExpression RBrace 'tmpltail' { AST.JSTemplatePart $1 $2 ('}' : tokenLiteral $3) : [] } + +-- This production only exists to ensure that inTemplate is set to True before +-- a tmplmiddle or tmpltail token is lexed. Since the lexer is always one token +-- ahead of the parser, setInTemplate needs to be called during a reduction +-- that is *two* tokens behind tmplmiddle/tmpltail. Accordingly, +-- TemplateExpression is always followed by an RBrace, which is lexed normally. +TemplateExpression :: { AST.JSExpression } +TemplateExpression : Expression {% setInTemplate True \$> $1 } -- ArrayLiteral : See 11.1.4 -- [ Elisionopt ] diff --git a/src/Language/JavaScript/Parser/Lexer.x b/src/Language/JavaScript/Parser/Lexer.x index 69393e7..31da6f0 100644 --- a/src/Language/JavaScript/Parser/Lexer.x +++ b/src/Language/JavaScript/Parser/Lexer.x @@ -15,6 +15,7 @@ module Language.JavaScript.Parser.Lexer , alexError , runAlex , alexTestTokeniser + , setInTemplate ) where import Language.JavaScript.Parser.LexerUtils @@ -199,8 +200,9 @@ $ZWJ = [\x200d] tokens :- -- State: 0 is regex allowed, 1 is / or /= allowed +-- 2 is a special state for parsing characters inside templates -<0> () ; -- { registerStates lexToken reg divide } +<0> () ; -- { registerStates lexToken reg divide template } -- Skip Whitespace $white_char+ { adapt (mkString wsToken) } @@ -256,8 +258,8 @@ tokens :- "`" @TemplateCharacters "`" { adapt (mkString' NoSubstitutionTemplateToken) } "`" @TemplateCharacters "${" { adapt (mkString' TemplateHeadToken) } - "}" @TemplateCharacters "${" { adapt (mkString' TemplateMiddleToken) } - "}" @TemplateCharacters "`" { adapt (mkString' TemplateTailToken) } +