Skip to content

Commit 425aa61

Browse files
committed
Initial fix for ECMAScript 3 allowing named function expressions.
1 parent d7e1795 commit 425aa61

File tree

6 files changed

+21
-11
lines changed

6 files changed

+21
-11
lines changed

Diff for: README

+4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ $ cabal install --reinstall alex
4545

4646
Changes
4747

48+
0.2.0 ECMAScript 3 allows function expressions to have names, AST.JSFunctionExpression now reflects this
49+
50+
0.1.0 Simplified AST by removing JSElement and JSElementList components
51+
4852
0.0.3 Support for unicode in source. At the moment it only supports
4953
UTF8 encoding, does not recognise byte order marks or UTF-16/UTF-32
5054

Diff for: language-javascript.cabal

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Name: language-javascript
2-
Version: 0.1.0
2+
Version: 0.2.0
33
Synopsis: Parser for JavaScript
44
Description: Parses Javascript into an Abstract Syntax Tree (AST). Initially intended as frontend to hjsmin.
55
Homepage: https://github.com/alanz/language-javascript

Diff for: runtests.hs

+9-5
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ testSuite = testGroup "Parser"
104104
, testCase "Statement28" (testStmt "y--" "Right (JSExpression [JSExpressionPostfix \"--\" [JSIdentifier \"y\"]])")
105105

106106
-- Member Expressions
107-
, testCase "MemberExpression1" (testStmt "function(){}" "Right (JSExpression [JSFunctionExpression [] (JSFunctionBody [])])")
108-
, testCase "MemberExpression1" (testStmt "function(a){}" "Right (JSExpression [JSFunctionExpression [JSIdentifier \"a\"] (JSFunctionBody [])])")
109-
, testCase "MemberExpression1" (testStmt "function(a,b){}" "Right (JSExpression [JSFunctionExpression [JSIdentifier \"a\",JSIdentifier \"b\"] (JSFunctionBody [])])")
107+
, testCase "MemberExpression1" (testStmt "function(){}" "Right (JSExpression [JSFunctionExpression [] [] (JSFunctionBody [])])")
108+
, testCase "MemberExpression1" (testStmt "function(a){}" "Right (JSExpression [JSFunctionExpression [] [JSIdentifier \"a\"] (JSFunctionBody [])])")
109+
, testCase "MemberExpression1" (testStmt "function(a,b){}" "Right (JSExpression [JSFunctionExpression [] [JSIdentifier \"a\",JSIdentifier \"b\"] (JSFunctionBody [])])")
110110

111111
, testCase "MemberExpression1" (testStmt "x[y]" "Right (JSExpression [JSMemberSquare [JSIdentifier \"x\"] (JSExpression [JSIdentifier \"y\"])])")
112112
, testCase "MemberExpression1" (testStmt "x[y][z]" "Right (JSExpression [JSMemberSquare [JSMemberSquare [JSIdentifier \"x\"] (JSExpression [JSIdentifier \"y\"])] (JSExpression [JSIdentifier \"z\"])])")
@@ -201,9 +201,9 @@ testSuite = testGroup "Parser"
201201

202202
, testCase "Comment2" (testProg "/*x=1\ny=2\n*/z=2;//foo\na" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"z\",JSOperator \"=\",JSDecimal \"2\"],JSLiteral \";\",JSExpression [JSIdentifier \"a\"]])")
203203

204-
, testCase "min_100_animals1" (testProg "function Animal(name){if(!name)throw new Error('Must specify an animal name');this.name=name};Animal.prototype.toString=function(){return this.name};o=new Animal(\"bob\");o.toString()==\"bob\"" "Right (JSSourceElementsTop [JSFunction (JSIdentifier \"Animal\") [JSIdentifier \"name\"] (JSFunctionBody [JSSourceElements [JSIf (JSExpression [JSUnary \"!\",JSIdentifier \"name\"]) (JSBlock (JSStatementList [JSThrow (JSExpression [JSLiteral \"new \",JSIdentifier \"Error\",JSArguments [[JSStringLiteral '\\'' \"Must specify an animal name\"]]])])),JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\"),JSOperator \"=\",JSIdentifier \"name\"]]]),JSLiteral \";\",JSExpression [JSMemberDot [JSMemberDot [JSIdentifier \"Animal\"] (JSIdentifier \"prototype\")] (JSIdentifier \"toString\"),JSOperator \"=\",JSFunctionExpression [] (JSFunctionBody [JSSourceElements [JSReturn [JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\")],JSLiteral \"\"]]])],JSLiteral \";\",JSExpression [JSIdentifier \"o\",JSOperator \"=\",JSLiteral \"new \",JSIdentifier \"Animal\",JSArguments [[JSStringLiteral '\"' \"bob\"]]],JSLiteral \";\",JSExpression [JSExpressionBinary \"==\" [JSMemberDot [JSIdentifier \"o\"] (JSIdentifier \"toString\"),JSArguments []] [JSStringLiteral '\"' \"bob\"]]])")
204+
, testCase "min_100_animals1" (testProg "function Animal(name){if(!name)throw new Error('Must specify an animal name');this.name=name};Animal.prototype.toString=function(){return this.name};o=new Animal(\"bob\");o.toString()==\"bob\"" "Right (JSSourceElementsTop [JSFunction (JSIdentifier \"Animal\") [JSIdentifier \"name\"] (JSFunctionBody [JSSourceElements [JSIf (JSExpression [JSUnary \"!\",JSIdentifier \"name\"]) (JSBlock (JSStatementList [JSThrow (JSExpression [JSLiteral \"new \",JSIdentifier \"Error\",JSArguments [[JSStringLiteral '\\'' \"Must specify an animal name\"]]])])),JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\"),JSOperator \"=\",JSIdentifier \"name\"]]]),JSLiteral \";\",JSExpression [JSMemberDot [JSMemberDot [JSIdentifier \"Animal\"] (JSIdentifier \"prototype\")] (JSIdentifier \"toString\"),JSOperator \"=\",JSFunctionExpression [] [] (JSFunctionBody [JSSourceElements [JSReturn [JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\")],JSLiteral \"\"]]])],JSLiteral \";\",JSExpression [JSIdentifier \"o\",JSOperator \"=\",JSLiteral \"new \",JSIdentifier \"Animal\",JSArguments [[JSStringLiteral '\"' \"bob\"]]],JSLiteral \";\",JSExpression [JSExpressionBinary \"==\" [JSMemberDot [JSIdentifier \"o\"] (JSIdentifier \"toString\"),JSArguments []] [JSStringLiteral '\"' \"bob\"]]])")
205205

206-
, testCase "min_100_animals2" (testProg "Animal=function(){return this.name};" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"Animal\",JSOperator \"=\",JSFunctionExpression [] (JSFunctionBody [JSSourceElements [JSReturn [JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\")],JSLiteral \"\"]]])],JSLiteral \";\"])")
206+
, testCase "min_100_animals2" (testProg "Animal=function(){return this.name};" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"Animal\",JSOperator \"=\",JSFunctionExpression [] [] (JSFunctionBody [JSSourceElements [JSReturn [JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\")],JSLiteral \"\"]]])],JSLiteral \";\"])")
207207

208208
, testCase "min_100_animals3" (testProg "if(a)x=1;y=2" "Right (JSSourceElementsTop [JSIf (JSExpression [JSIdentifier \"a\"]) (JSBlock (JSStatementList [JSExpression [JSIdentifier \"x\",JSOperator \"=\",JSDecimal \"1\"]])),JSExpression [JSIdentifier \"y\",JSOperator \"=\",JSDecimal \"2\"]])")
209209

@@ -243,6 +243,10 @@ testSuite = testGroup "Parser"
243243

244244
, testCase "unicode5" (testFile "./test/Unicode.js" "JSSourceElementsTop [JSExpression [JSIdentifier \"\\224\\225\\226\\227\\228\\229\",JSOperator \"=\",JSDecimal \"1\"],JSLiteral \";\"]")
245245

246+
, testCase "bug2.a" (testProg "function() {\nz = function /*z*/(o) {\nreturn r;\n};}" "Right (JSSourceElementsTop [JSExpression [JSFunctionExpression [] [] (JSFunctionBody [JSSourceElements [JSExpression [JSIdentifier \"z\",JSOperator \"=\",JSFunctionExpression [] [JSIdentifier \"o\"] (JSFunctionBody [JSSourceElements [JSReturn [JSExpression [JSIdentifier \"r\"],JSLiteral \";\"]]])],JSLiteral \";\"]])]])")
247+
248+
, testCase "bug2.b" (testProg "function() {\nz = function z(o) {\nreturn r;\n};}" "Right (JSSourceElementsTop [JSExpression [JSFunctionExpression [] [] (JSFunctionBody [JSSourceElements [JSExpression [JSIdentifier \"z\",JSOperator \"=\",JSFunctionExpression [JSIdentifier \"z\"] [JSIdentifier \"o\"] (JSFunctionBody [JSSourceElements [JSReturn [JSExpression [JSIdentifier \"r\"],JSLiteral \";\"]]])],JSLiteral \";\"]])]])")
249+
246250
]
247251

248252
srcHelloWorld = "Hello"

Diff for: src/Language/JavaScript/Parser/AST.hs

+1-3
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ data JSNode = JSArguments [[JSNode]]
1616
| JSDecimal String -- Was Integer
1717
| JSDefault JSNode
1818
| JSDoWhile JSNode JSNode JSNode
19-
-- | JSElement String [JSNode]
20-
-- | JSElementList [JSNode]
2119
| JSElision [JSNode]
2220
| JSEmpty JSNode
2321
| JSExpression [JSNode]
@@ -32,7 +30,7 @@ data JSNode = JSArguments [[JSNode]]
3230
| JSForVarIn JSNode JSNode JSNode
3331
| JSFunction JSNode [JSNode] JSNode -- name, parameter list, body
3432
| JSFunctionBody [JSNode]
35-
| JSFunctionExpression [JSNode] JSNode -- name, parameter list, body
33+
| JSFunctionExpression [JSNode] [JSNode] JSNode -- name, parameter list, body
3634
| JSHexInteger String -- Was Integer
3735
| JSIdentifier String
3836
| JSIf JSNode JSNode

Diff for: src/Language/JavaScript/Parser/Grammar.y

+5-2
Original file line numberDiff line numberDiff line change
@@ -666,9 +666,12 @@ FunctionDeclaration : 'function' Identifier '(' FormalParameterList ')' '{' Func
666666
-- <Function Expression> ::= 'function' '(' ')' '{' <Function Body> '}'
667667
-- | 'function' '(' <Formal Parameter List> ')' '{' <Function Body> '}'
668668
FunctionExpression :: { AST.JSNode }
669-
FunctionExpression : 'function' '(' ')' '{' FunctionBody '}' { (AST.JSFunctionExpression [] $5) }
670-
| 'function' '(' FormalParameterList ')' '{' FunctionBody '}' { (AST.JSFunctionExpression $3 $6) }
669+
FunctionExpression : 'function' IdentifierOpt '(' ')' '{' FunctionBody '}' { (AST.JSFunctionExpression $2 [] $6) }
670+
| 'function' IdentifierOpt '(' FormalParameterList ')' '{' FunctionBody '}' { (AST.JSFunctionExpression $2 $4 $7) }
671671

672+
IdentifierOpt :: { [AST.JSNode] }
673+
IdentifierOpt : Identifier { [$1] {- IdentifierOpt -}}
674+
| { [] {- IdentifierOpt -}}
672675

673676
-- <Formal Parameter List> ::= Identifier
674677
-- | <Formal Parameter List> ',' Identifier

Diff for: test/k.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
function f() {}

0 commit comments

Comments
 (0)