Skip to content

Commit f8bfa31

Browse files
rhendricerikd
authored andcommitted
Add support for method definitions
1 parent 54fecb9 commit f8bfa31

File tree

7 files changed

+57
-14
lines changed

7 files changed

+57
-14
lines changed

src/Language/JavaScript/Parser/AST.hs

+15-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module Language.JavaScript.Parser.AST
1717
, JSPropertyName (..)
1818
, JSObjectPropertyList
1919
, JSAccessor (..)
20+
, JSMethodDefinition (..)
2021
, JSIdent (..)
2122
, JSVarInitializer (..)
2223
, JSArrayElement (..)
@@ -287,9 +288,15 @@ data JSVarInitializer
287288
deriving (Data, Eq, Show, Typeable)
288289

289290
data JSObjectProperty
290-
= JSPropertyAccessor !JSAccessor !JSPropertyName !JSAnnot ![JSExpression] !JSAnnot !JSBlock -- ^(get|set), name, lb, params, rb, block
291-
| JSPropertyNameandValue !JSPropertyName !JSAnnot ![JSExpression] -- ^name, colon, value
291+
= JSPropertyNameandValue !JSPropertyName !JSAnnot ![JSExpression] -- ^name, colon, value
292292
| JSPropertyIdentRef !JSAnnot !String
293+
| JSObjectMethod !JSMethodDefinition
294+
deriving (Data, Eq, Show, Typeable)
295+
296+
data JSMethodDefinition
297+
= JSMethodDefinition !JSPropertyName !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- name, lb, params, rb, block
298+
| JSGeneratorMethodDefinition !JSAnnot !JSPropertyName !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- ^*, name, lb, params, rb, block
299+
| JSPropertyAccessor !JSAccessor !JSPropertyName !JSAnnot !(JSCommaList JSExpression) !JSAnnot !JSBlock -- ^get/set, name, lb, params, rb, block
293300
deriving (Data, Eq, Show, Typeable)
294301

295302
data JSPropertyName
@@ -482,8 +489,13 @@ instance ShowStripped JSIdent where
482489

483490
instance ShowStripped JSObjectProperty where
484491
ss (JSPropertyNameandValue x1 _colon x2s) = "JSPropertyNameandValue (" ++ ss x1 ++ ") " ++ ss x2s
485-
ss (JSPropertyAccessor s x1 _lb1 x2s _rb1 x3) = "JSPropertyAccessor " ++ ss s ++ " (" ++ ss x1 ++ ") " ++ ss x2s ++ " (" ++ ss x3 ++ ")"
486492
ss (JSPropertyIdentRef _ s) = "JSPropertyIdentRef " ++ singleQuote s
493+
ss (JSObjectMethod m) = ss m
494+
495+
instance ShowStripped JSMethodDefinition where
496+
ss (JSMethodDefinition x1 _lb1 x2s _rb1 x3) = "JSMethodDefinition (" ++ ss x1 ++ ") " ++ ss x2s ++ " (" ++ ss x3 ++ ")"
497+
ss (JSPropertyAccessor s x1 _lb1 x2s _rb1 x3) = "JSPropertyAccessor " ++ ss s ++ " (" ++ ss x1 ++ ") " ++ ss x2s ++ " (" ++ ss x3 ++ ")"
498+
ss (JSGeneratorMethodDefinition _ x1 _lb1 x2s _rb1 x3) = "JSGeneratorMethodDefinition (" ++ ss x1 ++ ") " ++ ss x2s ++ " (" ++ ss x3 ++ ")"
487499

488500
instance ShowStripped JSPropertyName where
489501
ss (JSPropertyIdent _ s) = "JSIdentifier " ++ singleQuote s

src/Language/JavaScript/Parser/Grammar7.y

+18-7
Original file line numberDiff line numberDiff line change
@@ -576,16 +576,27 @@ PropertyNameandValueList : PropertyAssignment { A
576576
-- PropertyName : AssignmentExpression
577577
-- get PropertyName() { FunctionBody }
578578
-- set PropertyName( PropertySetParameterList ) { FunctionBody }
579-
-- TODO: not clear if get/set are keywords, or just used in a specific context. Puzzling.
580579
PropertyAssignment :: { AST.JSObjectProperty }
581580
PropertyAssignment : PropertyName Colon AssignmentExpression { AST.JSPropertyNameandValue $1 $2 [$3] }
582581
| IdentifierName { identifierToProperty $1 }
583-
-- Should be "get" in next, but is not a Token
584-
| 'get' PropertyName LParen RParen FunctionBody
585-
{ AST.JSPropertyAccessor (AST.JSAccessorGet (mkJSAnnot $1)) $2 $3 [] $4 $5 }
586-
-- Should be "set" in next, but is not a Token
587-
| 'set' PropertyName LParen PropertySetParameterList RParen FunctionBody
588-
{ AST.JSPropertyAccessor (AST.JSAccessorSet (mkJSAnnot $1)) $2 $3 [$4] $5 $6 }
582+
| MethodDefinition { AST.JSObjectMethod $1 }
583+
584+
-- TODO: not clear if get/set are keywords, or just used in a specific context. Puzzling.
585+
MethodDefinition :: { AST.JSMethodDefinition }
586+
MethodDefinition : PropertyName LParen RParen FunctionBody
587+
{ AST.JSMethodDefinition $1 $2 AST.JSLNil $3 $4 }
588+
| PropertyName LParen FormalParameterList RParen FunctionBody
589+
{ AST.JSMethodDefinition $1 $2 $3 $4 $5 }
590+
| '*' PropertyName LParen RParen FunctionBody
591+
{ AST.JSGeneratorMethodDefinition (mkJSAnnot $1) $2 $3 AST.JSLNil $4 $5 }
592+
| '*' PropertyName LParen FormalParameterList RParen FunctionBody
593+
{ AST.JSGeneratorMethodDefinition (mkJSAnnot $1) $2 $3 $4 $5 $6 }
594+
-- Should be "get" in next, but is not a Token
595+
| 'get' PropertyName LParen RParen FunctionBody
596+
{ AST.JSPropertyAccessor (AST.JSAccessorGet (mkJSAnnot $1)) $2 $3 AST.JSLNil $4 $5 }
597+
-- Should be "set" in next, but is not a Token
598+
| 'set' PropertyName LParen PropertySetParameterList RParen FunctionBody
599+
{ AST.JSPropertyAccessor (AST.JSAccessorSet (mkJSAnnot $1)) $2 $3 (AST.JSLOne $4) $5 $6 }
589600

590601
-- PropertyName : See 11.1.5
591602
-- IdentifierName

src/Language/JavaScript/Pretty/Printer.hs

+6-1
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,14 @@ instance RenderJS JSBlock where
272272
(|>) pacc (JSBlock alb ss arb) = pacc |> alb |> "{" |> ss |> arb |> "}"
273273

274274
instance RenderJS JSObjectProperty where
275-
(|>) pacc (JSPropertyAccessor s n alp ps arp b) = pacc |> s |> n |> alp |> "(" |> ps |> arp |> ")" |> b
276275
(|>) pacc (JSPropertyNameandValue n c vs) = pacc |> n |> c |> ":" |> vs
277276
(|>) pacc (JSPropertyIdentRef a s) = pacc |> a |> s
277+
(|>) pacc (JSObjectMethod m) = pacc |> m
278+
279+
instance RenderJS JSMethodDefinition where
280+
(|>) pacc (JSMethodDefinition n alp ps arp b) = pacc |> n |> alp |> "(" |> ps |> arp |> ")" |> b
281+
(|>) pacc (JSGeneratorMethodDefinition s n alp ps arp b) = pacc |> s |> "*" |> n |> alp |> "(" |> ps |> arp |> ")" |> b
282+
(|>) pacc (JSPropertyAccessor s n alp ps arp b) = pacc |> s |> n |> alp |> "(" |> ps |> arp |> ")" |> b
278283

279284
instance RenderJS JSPropertyName where
280285
(|>) pacc (JSPropertyIdent a s) = pacc |> a |> s

src/Language/JavaScript/Process/Minify.hs

+6-1
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,14 @@ instance MinifyJS JSBlock where
361361

362362

363363
instance MinifyJS JSObjectProperty where
364-
fix a (JSPropertyAccessor s n _ ps _ b) = JSPropertyAccessor (fix a s) (fixSpace n) emptyAnnot (map fixEmpty ps) emptyAnnot (fixEmpty b)
365364
fix a (JSPropertyNameandValue n _ vs) = JSPropertyNameandValue (fix a n) emptyAnnot (map fixEmpty vs)
366365
fix a (JSPropertyIdentRef _ s) = JSPropertyIdentRef a s
366+
fix a (JSObjectMethod m) = JSObjectMethod (fix a m)
367+
368+
instance MinifyJS JSMethodDefinition where
369+
fix a (JSMethodDefinition n _ ps _ b) = JSMethodDefinition (fix a n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty b)
370+
fix _ (JSGeneratorMethodDefinition _ n _ ps _ b) = JSGeneratorMethodDefinition emptyAnnot (fixEmpty n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty b)
371+
fix a (JSPropertyAccessor s n _ ps _ b) = JSPropertyAccessor (fix a s) (fixSpace n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty b)
367372

368373
instance MinifyJS JSPropertyName where
369374
fix a (JSPropertyIdent _ s) = JSPropertyIdent a s

test/Test/Language/Javascript/ExpressionParser.hs

+6-2
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,17 @@ testExpressionParser = describe "Parse expressions:" $ do
5454
testExpr "{yield:1}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'yield') [JSDecimal '1']]))"
5555
testExpr "{x}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyIdentRef 'x']))"
5656
testExpr "{x,}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyIdentRef 'x',JSComma]))"
57-
testExpr "{set x([a,b]=y) {this.a=a;this.b=b}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyAccessor JSAccessorSet (JSIdentifier 'x') [JSOpAssign ('=',JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b'],JSIdentifier 'y')] (JSBlock [JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'a'),JSIdentifier 'a'),JSSemicolon,JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'b'),JSIdentifier 'b')])]))"
57+
testExpr "{set x([a,b]=y) {this.a=a;this.b=b}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyAccessor JSAccessorSet (JSIdentifier 'x') (JSOpAssign ('=',JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b'],JSIdentifier 'y')) (JSBlock [JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'a'),JSIdentifier 'a'),JSSemicolon,JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'b'),JSIdentifier 'b')])]))"
5858
testExpr "a={if:1,interface:2}" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'a',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'if') [JSDecimal '1'],JSPropertyNameandValue (JSIdentifier 'interface') [JSDecimal '2']])))"
5959
testExpr "a={\n values: 7,\n}\n" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'a',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'values') [JSDecimal '7'],JSComma])))"
60-
testExpr "x={get foo() {return 1},set foo(a) {x=a}}" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'x',JSObjectLiteral [JSPropertyAccessor JSAccessorGet (JSIdentifier 'foo') [] (JSBlock [JSReturn JSDecimal '1' ]),JSPropertyAccessor JSAccessorSet (JSIdentifier 'foo') [JSIdentifier 'a'] (JSBlock [JSOpAssign ('=',JSIdentifier 'x',JSIdentifier 'a')])])))"
60+
testExpr "x={get foo() {return 1},set foo(a) {x=a}}" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'x',JSObjectLiteral [JSPropertyAccessor JSAccessorGet (JSIdentifier 'foo') () (JSBlock [JSReturn JSDecimal '1' ]),JSPropertyAccessor JSAccessorSet (JSIdentifier 'foo') (JSIdentifier 'a') (JSBlock [JSOpAssign ('=',JSIdentifier 'x',JSIdentifier 'a')])])))"
6161
testExpr "{evaluate:evaluate,load:function load(s){if(x)return s;1}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'evaluate') [JSIdentifier 'evaluate'],JSPropertyNameandValue (JSIdentifier 'load') [JSFunctionExpression 'load' (JSIdentifier 's') (JSBlock [JSIf (JSIdentifier 'x') (JSReturn JSIdentifier 's' JSSemicolon),JSDecimal '1'])]]))"
6262
testExpr "obj = { name : 'A', 'str' : 'B', 123 : 'C', }" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'obj',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'name') [JSStringLiteral 'A'],JSPropertyNameandValue (JSIdentifier ''str'') [JSStringLiteral 'B'],JSPropertyNameandValue (JSIdentifier '123') [JSStringLiteral 'C'],JSComma])))"
6363
testExpr "{[x]:1}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSPropertyComputed (JSIdentifier 'x')) [JSDecimal '1']]))"
64+
testExpr "{ a(x,y) {}, 'blah blah'() {} }" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock []),JSMethodDefinition (JSIdentifier ''blah blah'') () (JSBlock [])]))"
65+
testExpr "{[x]() {}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSMethodDefinition (JSPropertyComputed (JSIdentifier 'x')) () (JSBlock [])]))"
66+
testExpr "{*a(x,y) {yield y;}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSGeneratorMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock [JSYieldExpression (JSIdentifier 'y'),JSSemicolon])]))"
67+
testExpr "{*[x]({y},...z) {}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSGeneratorMethodDefinition (JSPropertyComputed (JSIdentifier 'x')) (JSObjectLiteral [JSPropertyIdentRef 'y'],JSSpreadExpression (JSIdentifier 'z')) (JSBlock [])]))"
6468

6569
it "unary expression" $ do
6670
testExpr "delete y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('delete',JSIdentifier 'y')))"

test/Test/Language/Javascript/Minify.hs

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ testMinifyExpr = describe "Minify expressions:" $ do
4343
minifyExpr " { 'str' : true , 42 : false , } " `shouldBe` "{'str':true,42:false}"
4444
minifyExpr " { x , } " `shouldBe` "{x}"
4545
minifyExpr " { [ x + y ] : 1 } " `shouldBe` "{[x+y]:1}"
46+
minifyExpr " { a ( x, y ) { } } " `shouldBe` "{a(x,y){}}"
47+
minifyExpr " { [ x + y ] ( ) { } } " `shouldBe` "{[x+y](){}}"
48+
minifyExpr " { * a ( x, y ) { } } " `shouldBe` "{*a(x,y){}}"
4649

4750
it "parentheses" $ do
4851
minifyExpr " ( 'hello' ) " `shouldBe` "('hello')"

test/Test/Language/Javascript/RoundTrip.hs

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ testRoundTrip = describe "Roundtrip:" $ do
4545
testRT "x=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/,/*j*/z/*k*/:/*l*/3/*m*/}"
4646
testRT "a=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/}"
4747
testRT "/*a*/{/*b*/[/*c*/x/*d*/+/*e*/y/*f*/]/*g*/:/*h*/1/*i*/}"
48+
testRT "/*a*/{/*b*/a/*c*/(/*d*/x/*e*/,/*f*/y/*g*/)/*h*/{/*i*/}/*j*/}"
49+
testRT "/*a*/{/*b*/[/*c*/x/*d*/+/*e*/y/*f*/]/*g*/(/*h*/)/*i*/{/*j*/}/*k*/}"
50+
testRT "/*a*/{/*b*/*/*c*/a/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/}"
4851

4952
it "miscellaneous" $ do
5053
testRT "/*a*/(/*b*/56/*c*/)"

0 commit comments

Comments
 (0)