Skip to content

Commit d744e67

Browse files
rhendricerikd
authored andcommitted
Add support for generators and yield
1 parent b2f4cfa commit d744e67

File tree

10 files changed

+104
-2
lines changed

10 files changed

+104
-2
lines changed

src/Language/JavaScript/Parser/AST.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ data JSStatement
143143
| JSForOf !JSAnnot !JSAnnot !JSExpression !JSBinOp !JSExpression !JSAnnot !JSStatement -- ^for,lb,expr,in,expr,rb,stmt
144144
| JSForVarOf !JSAnnot !JSAnnot !JSAnnot !JSExpression !JSBinOp !JSExpression !JSAnnot !JSStatement -- ^for,lb,var,vardecl,in,expr,rb,stmt
145145
| JSFunction !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock !JSSemi -- ^fn,name, lb,parameter list,rb,block,autosemi
146+
| JSGenerator !JSAnnot !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock !JSSemi -- ^fn,*,name, lb,parameter list,rb,block,autosemi
146147
| JSIf !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSStatement -- ^if,(,expr,),stmt
147148
| JSIfElse !JSAnnot !JSAnnot !JSExpression !JSAnnot !JSStatement !JSAnnot !JSStatement -- ^if,(,expr,),stmt,else,rest
148149
| JSLabelled !JSIdent !JSAnnot !JSStatement -- ^identifier,colon,stmt
@@ -182,6 +183,7 @@ data JSExpression
182183
| JSExpressionTernary !JSExpression !JSAnnot !JSExpression !JSAnnot !JSExpression -- ^cond, ?, trueval, :, falseval
183184
| JSArrowExpression !JSArrowParameterList !JSAnnot !JSStatement -- ^parameter list,arrow,block`
184185
| JSFunctionExpression !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- ^fn,name,lb, parameter list,rb,block`
186+
| JSGeneratorExpression !JSAnnot !JSAnnot !JSIdent !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- ^fn,*,name,lb, parameter list,rb,block`
185187
| JSMemberDot !JSExpression !JSAnnot !JSExpression -- ^firstpart, dot, name
186188
| JSMemberExpression !JSExpression !JSAnnot !(JSCommaList JSExpression) !JSAnnot -- expr, lb, args, rb
187189
| JSMemberNew !JSAnnot !JSExpression !JSAnnot !(JSCommaList JSExpression) !JSAnnot -- ^new, name, lb, args, rb
@@ -192,6 +194,8 @@ data JSExpression
192194
| JSTemplateLiteral !(Maybe JSExpression) !JSAnnot !String ![JSTemplatePart] -- ^optional tag, lquot, head, parts
193195
| JSUnaryExpression !JSUnaryOp !JSExpression
194196
| JSVarInitExpression !JSExpression !JSVarInitializer -- ^identifier, initializer
197+
| JSYieldExpression !JSAnnot !(Maybe JSExpression) -- ^yield, optional expr
198+
| JSYieldFromExpression !JSAnnot !JSAnnot !JSExpression -- ^yield, *, expr
195199
deriving (Data, Eq, Show, Typeable)
196200

197201
data JSArrowParameterList
@@ -364,6 +368,7 @@ instance ShowStripped JSStatement where
364368
ss (JSForOf _ _lb x1s _i x2 _rb x3) = "JSForOf " ++ ss x1s ++ " (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")"
365369
ss (JSForVarOf _ _lb _v x1 _i x2 _rb x3) = "JSForVarOf (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")"
366370
ss (JSFunction _ n _lb pl _rb x3 _) = "JSFunction " ++ ssid n ++ " " ++ ss pl ++ " (" ++ ss x3 ++ ")"
371+
ss (JSGenerator _ _ n _lb pl _rb x3 _) = "JSGenerator " ++ ssid n ++ " " ++ ss pl ++ " (" ++ ss x3 ++ ")"
367372
ss (JSIf _ _lb x1 _rb x2) = "JSIf (" ++ ss x1 ++ ") (" ++ ss x2 ++ ")"
368373
ss (JSIfElse _ _lb x1 _rb x2 _e x3) = "JSIfElse (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")"
369374
ss (JSLabelled x1 _c x2) = "JSLabelled (" ++ ss x1 ++ ") (" ++ ss x2 ++ ")"
@@ -395,6 +400,7 @@ instance ShowStripped JSExpression where
395400
ss (JSExpressionTernary x1 _q x2 _c x3) = "JSExpressionTernary (" ++ ss x1 ++ "," ++ ss x2 ++ "," ++ ss x3 ++ ")"
396401
ss (JSArrowExpression ps _ e) = "JSArrowExpression (" ++ ss ps ++ ") => " ++ ss e
397402
ss (JSFunctionExpression _ n _lb pl _rb x3) = "JSFunctionExpression " ++ ssid n ++ " " ++ ss pl ++ " (" ++ ss x3 ++ ")"
403+
ss (JSGeneratorExpression _ _ n _lb pl _rb x3) = "JSGeneratorExpression " ++ ssid n ++ " " ++ ss pl ++ " (" ++ ss x3 ++ ")"
398404
ss (JSHexInteger _ s) = "JSHexInteger " ++ singleQuote s
399405
ss (JSOctal _ s) = "JSOctal " ++ singleQuote s
400406
ss (JSIdentifier _ s) = "JSIdentifier " ++ singleQuote s
@@ -410,6 +416,9 @@ instance ShowStripped JSExpression where
410416
ss (JSStringLiteral _ s) = "JSStringLiteral " ++ s
411417
ss (JSUnaryExpression op x) = "JSUnaryExpression (" ++ ss op ++ "," ++ ss x ++ ")"
412418
ss (JSVarInitExpression x1 x2) = "JSVarInitExpression (" ++ ss x1 ++ ") " ++ ss x2
419+
ss (JSYieldExpression _ Nothing) = "JSYieldExpression ()"
420+
ss (JSYieldExpression _ (Just x)) = "JSYieldExpression (" ++ ss x ++ ")"
421+
ss (JSYieldFromExpression _ _ x) = "JSYieldFromExpression (" ++ ss x ++ ")"
413422
ss (JSSpreadExpression _ x1) = "JSSpreadExpression (" ++ ss x1 ++ ")"
414423
ss (JSTemplateLiteral Nothing _ s ps) = "JSTemplateLiteral (()," ++ singleQuote s ++ "," ++ ss ps ++ ")"
415424
ss (JSTemplateLiteral (Just t) _ s ps) = "JSTemplateLiteral ((" ++ ss t ++ ")," ++ singleQuote s ++ "," ++ ss ps ++ ")"

src/Language/JavaScript/Parser/Grammar7.y

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ import qualified Language.JavaScript.Parser.AST as AST
123123
'void' { VoidToken {} }
124124
'while' { WhileToken {} }
125125
'with' { WithToken {} }
126+
'yield' { YieldToken {} }
126127

127128

128129
'ident' { IdentifierToken {} }
@@ -484,6 +485,7 @@ PrimaryExpression : 'this' { AST.JSLiteral (mkJSAnnot $1) "thi
484485
| Literal { $1 {- 'PrimaryExpression2' -} }
485486
| ArrayLiteral { $1 {- 'PrimaryExpression3' -} }
486487
| ObjectLiteral { $1 {- 'PrimaryExpression4' -} }
488+
| GeneratorExpression { $1 }
487489
| TemplateLiteral { mkJSTemplateLiteral Nothing $1 {- 'PrimaryExpression6' -} }
488490
| LParen Expression RParen { AST.JSExpressionParen $1 $2 $3 }
489491

@@ -495,6 +497,12 @@ Identifier : 'ident' { AST.JSIdentifier (mkJSAnnot $1) (tokenLiteral $1) }
495497
| 'get' { AST.JSIdentifier (mkJSAnnot $1) "get" }
496498
| 'set' { AST.JSIdentifier (mkJSAnnot $1) "set" }
497499
| 'from' { AST.JSIdentifier (mkJSAnnot $1) "from" }
500+
| 'yield' { AST.JSIdentifier (mkJSAnnot $1) "yield" }
501+
502+
-- Must follow Identifier; when ambiguous, `yield` as a keyword should take
503+
-- precedence over `yield` as an identifier name.
504+
Yield :: { AST.JSAnnot }
505+
Yield : 'yield' { mkJSAnnot $1 }
498506

499507

500508
SpreadExpression :: { AST.JSExpression }
@@ -858,6 +866,7 @@ ConditionalExpressionNoIn : LogicalOrExpressionNoIn { $1 {- 'ConditionalExpressi
858866
-- LeftHandSideExpression AssignmentOperator AssignmentExpression
859867
AssignmentExpression :: { AST.JSExpression }
860868
AssignmentExpression : ConditionalExpression { $1 {- 'AssignmentExpression1' -} }
869+
| YieldExpression { $1 }
861870
| LeftHandSideExpression AssignmentOperator AssignmentExpression
862871
{ AST.JSAssignExpression $1 $2 $3 {- 'AssignmentExpression2' -} }
863872
| SpreadExpression { $1 }
@@ -867,6 +876,7 @@ AssignmentExpression : ConditionalExpression { $1 {- 'AssignmentExpression1' -}
867876
-- LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn
868877
AssignmentExpressionNoIn :: { AST.JSExpression }
869878
AssignmentExpressionNoIn : ConditionalExpressionNoIn { $1 {- 'AssignmentExpressionNoIn1' -} }
879+
| YieldExpression { $1 }
870880
| LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn
871881
{ AST.JSAssignExpression $1 $2 $3 {- 'AssignmentExpressionNoIn1' -} }
872882

@@ -1193,6 +1203,38 @@ LambdaExpression : Function LParen RParen FunctionBody
11931203
| Function LParen FormalParameterList RParen FunctionBody
11941204
{ AST.JSFunctionExpression $1 AST.JSIdentNone $2 $3 $4 $5 {- 'LambdaExpression2' -} }
11951205

1206+
-- GeneratorDeclaration :
1207+
-- function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
1208+
-- function * ( FormalParameters ) { GeneratorBody }
1209+
GeneratorDeclaration :: { AST.JSStatement }
1210+
GeneratorDeclaration : NamedGeneratorExpression MaybeSemi { expressionToStatement $1 $2 }
1211+
1212+
-- GeneratorExpression :
1213+
-- function * BindingIdentifieropt ( FormalParameters ) { GeneratorBody }
1214+
-- GeneratorBody :
1215+
-- FunctionBody
1216+
GeneratorExpression :: { AST.JSExpression }
1217+
GeneratorExpression : NamedGeneratorExpression { $1 }
1218+
| Function '*' LParen RParen FunctionBody
1219+
{ AST.JSGeneratorExpression $1 (mkJSAnnot $2) AST.JSIdentNone $3 AST.JSLNil $4 $5 }
1220+
| Function '*' LParen FormalParameterList RParen FunctionBody
1221+
{ AST.JSGeneratorExpression $1 (mkJSAnnot $2) AST.JSIdentNone $3 $4 $5 $6 }
1222+
1223+
NamedGeneratorExpression :: { AST.JSExpression }
1224+
NamedGeneratorExpression : Function '*' Identifier LParen RParen FunctionBody
1225+
{ AST.JSGeneratorExpression $1 (mkJSAnnot $2) (identName $3) $4 AST.JSLNil $5 $6 }
1226+
| Function '*' Identifier LParen FormalParameterList RParen FunctionBody
1227+
{ AST.JSGeneratorExpression $1 (mkJSAnnot $2) (identName $3) $4 $5 $6 $7 }
1228+
1229+
-- YieldExpression :
1230+
-- yield
1231+
-- yield [no LineTerminator here] AssignmentExpression
1232+
-- yield [no LineTerminator here] * AssignmentExpression
1233+
YieldExpression :: { AST.JSExpression }
1234+
YieldExpression : Yield { AST.JSYieldExpression $1 Nothing }
1235+
| Yield AssignmentExpression { AST.JSYieldExpression $1 (Just $2) }
1236+
| Yield '*' AssignmentExpression { AST.JSYieldFromExpression $1 (mkJSAnnot $2) $3 }
1237+
11961238

11971239
IdentifierOpt :: { AST.JSIdent }
11981240
IdentifierOpt : Identifier { identName $1 {- 'IdentifierOpt1' -} }
@@ -1299,7 +1341,7 @@ ImportSpecifier : IdentifierName
12991341
-- [x] LexicalDeclaration
13001342
-- [ ] HoistableDeclaration :
13011343
-- [x] FunctionDeclaration
1302-
-- [ ] GeneratorDeclaration
1344+
-- [x] GeneratorDeclaration
13031345
-- [ ] AsyncFunctionDeclaration
13041346
-- [ ] AsyncGeneratorDeclaration
13051347
-- [ ] export default HoistableDeclaration[Default]
@@ -1314,6 +1356,8 @@ ExportDeclaration : ExportClause FromClause AutoSemi
13141356
{ AST.JSExport $1 $2 {- 'ExportDeclaration3' -} }
13151357
| FunctionDeclaration AutoSemi
13161358
{ AST.JSExport $1 $2 {- 'ExportDeclaration4' -} }
1359+
| GeneratorDeclaration AutoSemi
1360+
{ AST.JSExport $1 $2 {- 'ExportDeclaration5' -} }
13171361

13181362
-- ExportClause :
13191363
-- { }
@@ -1364,6 +1408,7 @@ blockToStatement (AST.JSBlock a b c) s = AST.JSStatementBlock a b c s
13641408

13651409
expressionToStatement :: AST.JSExpression -> AST.JSSemi -> AST.JSStatement
13661410
expressionToStatement (AST.JSFunctionExpression a b@(AST.JSIdentName{}) c d e f) s = AST.JSFunction a b c d e f s
1411+
expressionToStatement (AST.JSGeneratorExpression a b c@(AST.JSIdentName{}) d e f g) s = AST.JSGenerator a b c d e f g s
13671412
expressionToStatement (AST.JSAssignExpression lhs op rhs) s = AST.JSAssignStatement lhs op rhs s
13681413
expressionToStatement (AST.JSMemberExpression e l a r) s = AST.JSMethodCall e l a r s
13691414
expressionToStatement exp s = AST.JSExpressionStatement exp s

src/Language/JavaScript/Parser/Lexer.x

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ keywordNames =
561561
, ( "void", VoidToken )
562562
, ( "while", WhileToken )
563563
, ( "with", WithToken )
564+
, ( "yield", YieldToken )
564565
-- TODO: no idea if these are reserved or not, but they are needed
565566
-- handled in parser, in the Identifier rule
566567
, ( "as", AsToken ) -- not reserved
@@ -601,7 +602,7 @@ keywordNames =
601602
, ( "public", FutureToken )
602603
, ( "static", FutureToken )
603604
-- ( "strict", FutureToken ) *** not any more
604-
, ( "yield", FutureToken)
605+
-- ( "yield", FutureToken) **** an actual token, used in productions
605606
]
606607
}
607608

src/Language/JavaScript/Parser/Token.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ data Token
8989
| VarToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] }
9090
| VoidToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] }
9191
| WhileToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] }
92+
| YieldToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] }
9293
| ImportToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] }
9394
| WithToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] }
9495
| ExportToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] }

src/Language/JavaScript/Pretty/Printer.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ instance RenderJS JSExpression where
8383
(|>) pacc (JSExpressionPostfix xs op) = pacc |> xs |> op
8484
(|>) pacc (JSExpressionTernary cond h v1 c v2) = pacc |> cond |> h |> "?" |> v1 |> c |> ":" |> v2
8585
(|>) pacc (JSFunctionExpression annot n lb x2s rb x3) = pacc |> annot |> "function" |> n |> lb |> "(" |> x2s |> rb |> ")" |> x3
86+
(|>) pacc (JSGeneratorExpression annot s n lb x2s rb x3) = pacc |> annot |> "function" |> s |> "*" |> n |> lb |> "(" |> x2s |> rb |> ")" |> x3
8687
(|>) pacc (JSMemberDot xs dot n) = pacc |> xs |> "." |> dot |> n
8788
(|>) pacc (JSMemberExpression e lb a rb) = pacc |> e |> lb |> "(" |> a |> rb |> ")"
8889
(|>) pacc (JSMemberNew a lb n rb s) = pacc |> a |> "new" |> lb |> "(" |> n |> rb |> ")" |> s
@@ -92,6 +93,8 @@ instance RenderJS JSExpression where
9293
(|>) pacc (JSTemplateLiteral t a h ps) = pacc |> t |> a |> h |> ps
9394
(|>) pacc (JSUnaryExpression op x) = pacc |> op |> x
9495
(|>) pacc (JSVarInitExpression x1 x2) = pacc |> x1 |> x2
96+
(|>) pacc (JSYieldExpression y x) = pacc |> y |> "yield" |> x
97+
(|>) pacc (JSYieldFromExpression y s x) = pacc |> y |> "yield" |> s |> "*" |> x
9598
(|>) pacc (JSSpreadExpression a e) = pacc |> a |> "..." |> e
9699

97100
instance RenderJS JSArrowParameterList where
@@ -238,6 +241,7 @@ instance RenderJS JSStatement where
238241
(|>) pacc (JSForOf af alb x1s i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> x1s |> i |> x2 |> arb |> ")" |> x3
239242
(|>) pacc (JSForVarOf af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "var" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3
240243
(|>) pacc (JSFunction af n alb x2s arb x3 s) = pacc |> af |> "function" |> n |> alb |> "(" |> x2s |> arb |> ")" |> x3 |> s
244+
(|>) pacc (JSGenerator af as n alb x2s arb x3 s) = pacc |> af |> "function" |> as |> "*" |> n |> alb |> "(" |> x2s |> arb |> ")" |> x3 |> s
241245
(|>) pacc (JSIf annot alb x1 arb x2s) = pacc |> annot |> "if" |> alb |> "(" |> x1 |> arb |> ")" |> x2s
242246
(|>) pacc (JSIfElse annot alb x1 arb x2s ea x3s) = pacc |> annot |> "if" |> alb |> "(" |> x1 |> arb |> ")" |> x2s |> ea |> "else" |> x3s
243247
(|>) pacc (JSLabelled l c v) = pacc |> l |> c |> ":" |> v

src/Language/JavaScript/Process/Minify.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ fixStmt a s (JSForConstOf _ _ _ e1 op e2 _ st) = JSForConstOf a emptyAnnot space
5757
fixStmt a s (JSForOf _ _ e1 op e2 _ st) = JSForOf a emptyAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st)
5858
fixStmt a s (JSForVarOf _ _ _ e1 op e2 _ st) = JSForVarOf a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st)
5959
fixStmt a s (JSFunction _ n _ ps _ blk _) = JSFunction a (fixSpace n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty blk) s
60+
fixStmt a s (JSGenerator _ _ n _ ps _ blk _) = JSGenerator a emptyAnnot (fixEmpty n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty blk) s
6061
fixStmt a s (JSIf _ _ e _ st) = JSIf a emptyAnnot (fixEmpty e) emptyAnnot (fixIfElseBlock emptyAnnot s st)
6162
fixStmt a s (JSIfElse _ _ e _ (JSEmptyStatement _) _ sf) = JSIfElse a emptyAnnot (fixEmpty e) emptyAnnot (JSEmptyStatement emptyAnnot) emptyAnnot (fixStmt spaceAnnot s sf)
6263
fixStmt a s (JSIfElse _ _ e _ st _ sf) = JSIfElse a emptyAnnot (fixEmpty e) emptyAnnot (mkStatementBlock noSemi st) emptyAnnot (fixIfElseBlock spaceAnnot s sf)
@@ -162,6 +163,7 @@ instance MinifyJS JSExpression where
162163
fix a (JSExpressionPostfix e op) = JSExpressionPostfix (fix a e) (fixEmpty op)
163164
fix a (JSExpressionTernary cond _ v1 _ v2) = JSExpressionTernary (fix a cond) emptyAnnot (fixEmpty v1) emptyAnnot (fixEmpty v2)
164165
fix a (JSFunctionExpression _ n _ x2s _ x3) = JSFunctionExpression a (fixSpace n) emptyAnnot (fixEmpty x2s) emptyAnnot (fixEmpty x3)
166+
fix a (JSGeneratorExpression _ _ n _ x2s _ x3) = JSGeneratorExpression a emptyAnnot (fixEmpty n) emptyAnnot (fixEmpty x2s) emptyAnnot (fixEmpty x3)
165167
fix a (JSMemberDot xs _ n) = JSMemberDot (fix a xs) emptyAnnot (fixEmpty n)
166168
fix a (JSMemberExpression e _ args _) = JSMemberExpression (fix a e) emptyAnnot (fixEmpty args) emptyAnnot
167169
fix a (JSMemberNew _ n _ s _) = JSMemberNew a (fix spaceAnnot n) emptyAnnot (fixEmpty s) emptyAnnot
@@ -171,6 +173,8 @@ instance MinifyJS JSExpression where
171173
fix a (JSTemplateLiteral t _ s ps) = JSTemplateLiteral (fmap (fix a) t) emptyAnnot s (map fixEmpty ps)
172174
fix a (JSUnaryExpression op x) = let (ta, fop) = fixUnaryOp a op in JSUnaryExpression fop (fix ta x)
173175
fix a (JSVarInitExpression x1 x2) = JSVarInitExpression (fix a x1) (fixEmpty x2)
176+
fix a (JSYieldExpression _ x) = JSYieldExpression a (fixSpace x)
177+
fix a (JSYieldFromExpression _ _ x) = JSYieldFromExpression a emptyAnnot (fixEmpty x)
174178
fix a (JSSpreadExpression _ e) = JSSpreadExpression a (fixEmpty e)
175179

176180
instance MinifyJS JSArrowParameterList where

0 commit comments

Comments
 (0)