Import haskell-language-javascript_0.5.13.orig.tar.gz
authorClint Adams <clint@debian.org>
Sat, 7 Jun 2014 16:16:23 +0000 (17:16 +0100)
committerClint Adams <clint@debian.org>
Sat, 7 Jun 2014 16:16:23 +0000 (17:16 +0100)
[dgit import orig haskell-language-javascript_0.5.13.orig.tar.gz]

22 files changed:
.ghci [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README.md [new file with mode: 0644]
Setup.hs [new file with mode: 0644]
buildall.sh [new file with mode: 0755]
language-javascript.cabal [new file with mode: 0644]
runtests.hs [new file with mode: 0644]
src/Language/JavaScript/Parser.hs [new file with mode: 0644]
src/Language/JavaScript/Parser/AST.hs [new file with mode: 0644]
src/Language/JavaScript/Parser/Grammar5.y [new file with mode: 0644]
src/Language/JavaScript/Parser/Lexer.x [new file with mode: 0644]
src/Language/JavaScript/Parser/LexerUtils.hs [new file with mode: 0644]
src/Language/JavaScript/Parser/ParseError.hs [new file with mode: 0644]
src/Language/JavaScript/Parser/Parser.hs [new file with mode: 0644]
src/Language/JavaScript/Parser/ParserMonad.hs [new file with mode: 0644]
src/Language/JavaScript/Parser/SrcLocation.hs [new file with mode: 0644]
src/Language/JavaScript/Parser/StringEscape.hs [new file with mode: 0644]
src/Language/JavaScript/Parser/Token.hs [new file with mode: 0644]
src/Language/JavaScript/Pretty/Printer.hs [new file with mode: 0644]
test/Unicode.js [new file with mode: 0644]
test/k.js [new file with mode: 0644]
test/unicode.txt [new file with mode: 0644]

diff --git a/.ghci b/.ghci
new file mode 100644 (file)
index 0000000..14b01ea
--- /dev/null
+++ b/.ghci
@@ -0,0 +1,5 @@
+-- Startup commands for the GHC interpreter
+:set -hide-package monads-tf 
+:set -hide-package monads-fd
+:set -i./src
+:set -i./dist/build
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..0c03bcc
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c)2010, Alan Zimmerman
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Alan Zimmerman nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..3f4dad7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,142 @@
+Parser for JavaScript
+---------------------
+
+[![Build Status](https://secure.travis-ci.org/alanz/language-javascript.png?branch=master)](http://travis-ci.org/alanz/language-javascript)
+
+Based (loosely) on language-python
+
+How to build
+------------
+
+Library:
+
+    cabal clean && cabal configure && cabal build
+
+Tests:
+
+    cabal clean && cabal configure -fbuildtests && cabal build
+
+Running the tests
+
+    ./dist/build/runtests/runtests
+
+
+To debug the grammar
+
+    happy -iparse.txt -g -a  -d src/Language/JavaScript/Parser/Grammar5.y
+
+This generates src/Language/JavaScript/Parser/Grammar.hs, delete this
+when done with the debug version
+
+
+UTF8/Unicode version
+--------------------
+
+Alex 3.0 now supports unicode natively, and has been included as a
+dependency in the cabal file.
+
+Note: The generation of the lexical analyser has been separated out,
+      to remove the install-time dependency on Alex. If any changes
+      need to be made to the lexer, the Lexer.x source lies in
+      src-dev, and the runalex.sh script will invoke Alex with the
+      appropriate directories.
+
+Changes
+-------
+
+```
+0.5.13 Put GHC 7.8.x -specific alex and happy versions, thanks
+       @simonmichael
+
+0.5.12 Put dependency on alex >= 3.0.5 in the cabal file, thanks @peti
+
+0.5.11 Remove pre-generated Lexer.hs as it does not work will all
+       versions of GHC. This means a current alex will have to be
+       installed before this package can be installed.
+
+0.5.10 Bring in alex 3.1.3, allowing compatibility with GHC 7.8
+
+0.5.9 Relax array dependency for GHC 7.8.1, thanks @maoe
+
+0.5.8 Fixed compilation issue using GHC 7.6.3 on Mac OSX, thanks @albertov
+
+0.5.7 Remove the hs-source-dirs from test suite to prevent compilation
+      issues (@nomeata)
+
+      Introduce parseFileUtf8 to explicitly use utf8 for parsing a
+      file, and update tests to use it where needed. Closes #21
+
+0.5.6 Remove constraint on Alex 3.0.1, it is only required to make
+      changes to the lexer. Closes #19
+
+0.5.5 Updated version ranges for GHC 7.6.1, courtesy of @mietek
+      Note: requires alex 3.0.1 for development (not install)
+
+0.5.4 Fixed bug where lexer switches to regexp mode after a ']'
+      char, reported by @aszlig
+
+0.5.3 Merge pull requests from @aszlig to add octal support, and to
+      allow leading zeros in exponents
+
+0.5.2 Merged pull request from @markwright added some missing test
+      files to the cabal file.
+      Added runalex.sh and Lexer.x to the cabal file.
+
+0.5.1 Export CommentAnnotation(..). Simplify AST by getting rid of
+      JSFunctionBody, JSSourceElements, JSStatementBlock, JSStatementList.
+      They are replaced by JSBlock or a simple list.
+      Also fix lexer mode in presence of whitespace.
+      Changed way tests are invoked, to allow Travis integration.
+
+0.5.0 Rework AST to allow full round-trip parsing and output of
+      JavaScript. Breaks AST compatibility with prior versions
+
+0.4.10 Moved Lexer.x into a separate directory, and made a script to
+       call alex to generate Lexer.hs. This means alex is not required
+       at install time
+
+0.4.9 Make alex and happy versions more explicit. Expose the AlexSpan
+      data type, so parse error positions can be reported.
+
+0.4.8 Close issue https://github.com/alanz/language-javascript/issues/5 by
+      correcting the lexical analyser for DecimalLiteral
+
+0.4.7 Continue ECMASCRIPT update, remove incorrect future reserved words for
+      "code", "mode", "of", "one", "or" and "strict", put in by accident/stupidity.
+
+0.4.6 Update to ECMASCRIPT 5.1 by allowing continuations in string literals
+      Include build dependencies on alex >= 3.0 and happy.
+
+0.4.5 Update cabal file and docs for Alex 3.0, giving out of the box unicode support
+
+0.4.4 Allow unicode characters in comments
+
+0.4.3 correct lexer for decimalToken, only leading digit needs to be non-zero.
+
+0.4.2 Expose SrcSpan
+
+0.4.1 Expose AST.Node as well.
+
+0.4.0 Updated JSNode to include location information, and made the parse more true to the original by leaving blocks as such, not replacing with ';'.
+
+0.3.0 ECMA-262 edition 5 compliance.  Required adding JSFunctionExpression and JSPropertyAccessor to the AST.
+
+0.2.2 Heading toward compliance with edition 5. Trailing commas allowed in array literals too.
+
+0.2.1 Allow trailing comma in object literal
+
+0.2.0 ECMAScript 3 allows function expressions to have names, AST.JSFunctionExpression now reflects this
+
+0.1.0 Simplified AST by removing JSElement and JSElementList components
+
+0.0.3 Support for unicode in source. At the moment it only supports
+UTF8 encoding, does not recognise byte order marks or UTF-16/UTF-32
+
+0.0.2 Multiline comments were processed in greedy form, now end of
+comment recognised properly. Thanks to Tony Morris for reporting this.
+
+0.0.1 Initial release
+```
+
+EOF
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644 (file)
index 0000000..9a994af
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/buildall.sh b/buildall.sh
new file mode 100755 (executable)
index 0000000..6964a41
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# First run alex on Lexer.x to generate Lexer.hs
+#./runalex.sh
+
+# do a clean build of all, including the tests
+#cabal clean && cabal configure -fbuildtests && cabal build && cabal haddock
+cabal clean && cabal configure --enable-tests && cabal build && cabal test && cabal haddock
diff --git a/language-javascript.cabal b/language-javascript.cabal
new file mode 100644 (file)
index 0000000..eccf662
--- /dev/null
@@ -0,0 +1,80 @@
+Name:                language-javascript
+Version:             0.5.13
+Synopsis:            Parser for JavaScript
+Description:         Parses Javascript into an Abstract Syntax Tree (AST).  Initially intended as frontend to hjsmin.
+                     .
+                     Note: Version 0.5.0 breaks compatibility with prior versions, the AST has been reworked to allow
+                     round trip processing of JavaScript.
+Homepage:            https://github.com/alanz/language-javascript
+License:             BSD3
+License-file:        LICENSE
+Author:              Alan Zimmerman
+Maintainer:          alan.zimm@gmail.com
+Copyright:           (c) 2010,2011,2012 Alan Zimmerman
+Category:            Language
+Build-type:          Simple
+homepage:            http://github.com/alanz/language-javascript
+bug-reports:         http://github.com/alanz/language-javascript/issues
+Extra-source-files:  README.md
+                     .ghci
+                     buildall.sh
+                     test/Unicode.js
+                     test/k.js
+                     test/unicode.txt
+                     -- runalex.sh
+                     src/Language/JavaScript/Parser/Lexer.x
+
+-- Version requirement upped for test support in later Cabal
+Cabal-version:   >= 1.9.2
+
+
+Library
+  Build-depends:     base             >= 4       && < 5
+                   , array            >= 0.3     && < 0.6
+                   , mtl              >= 1.1     && < 2.9
+                   , containers       >= 0.2     && < 0.6
+                   -- For the round trip output
+                   , blaze-builder    >= 0.2     && < 1
+                   , bytestring       >= 0.9.1   && < 1
+                   , utf8-string      >= 0.3.7   && < 1
+  if impl(ghc >= 7.8)
+    build-tools:       happy >= 1.19, alex >= 3.1
+  else
+    build-tools:       happy >= 1.18.5, alex >= 3.0.5
+  hs-source-dirs: src
+  Exposed-modules:     Language.JavaScript.Parser
+                       Language.JavaScript.Parser.Parser
+                       Language.JavaScript.Parser.Lexer
+                       Language.JavaScript.Parser.Grammar5
+                       Language.JavaScript.Parser.AST
+                       Language.JavaScript.Pretty.Printer
+                       Language.JavaScript.Parser.SrcLocation
+  Other-modules:       Language.JavaScript.Parser.LexerUtils
+                       Language.JavaScript.Parser.ParseError
+                       Language.JavaScript.Parser.ParserMonad
+                       Language.JavaScript.Parser.StringEscape
+                       Language.JavaScript.Parser.Token
+  ghc-options:         -Wall
+
+Test-Suite test-language-javascript
+  Type: exitcode-stdio-1.0
+  Main-is: runtests.hs
+  build-depends: base, Cabal >= 1.9.2
+                 , QuickCheck >= 2 && < 3
+                 , HUnit
+                 , test-framework-hunit
+                 , test-framework
+                 , array            >= 0.3     && < 0.6
+                 , utf8-light       >= 0.4     && < 1.0
+                 , containers       >= 0.2     && < 0.6
+                 , mtl              >= 1.1     && < 2.9
+                 , utf8-string      >= 0.3.7   && < 1
+                 , bytestring       >= 0.9.1   && < 1
+                 , blaze-builder    >= 0.2     && < 1
+                 -- need our own library for tests
+                 , language-javascript >= 0.5.5
+
+
+source-repository head
+  type:     git
+  location: git://github.com/alanz/language-javascript.git
diff --git a/runtests.hs b/runtests.hs
new file mode 100644 (file)
index 0000000..6f87fdd
--- /dev/null
@@ -0,0 +1,793 @@
+module Main where
+
+import Test.Framework (defaultMain, testGroup, Test)
+import Test.Framework.Providers.HUnit
+import Test.HUnit hiding (Test)
+
+
+import Control.Monad (liftM)
+import Language.JavaScript.Parser.Parser
+import Language.JavaScript.Parser
+--import Language.JavaScript.Parser.Grammar
+import Language.JavaScript.Parser.Grammar5
+
+{-
+import Distribution.TestSuite
+
+instance TestOptions (String, Bool) where
+    name = fst
+    options = const []
+    defaultOptions _ = return (Options [])
+    check _ _ = []
+
+instance PureTestable (String, Bool) where
+    run (name, result) _ | result == True = Pass
+                         | result == False = Fail (name ++ " failed!")
+
+test :: (String, Bool) -> Test
+test = pure
+-}
+
+main :: IO ()
+main = defaultMain [testSuite,{- ++AZ++temporary++ commentSuite ,-}commentPrintSuite]
+
+one :: IO ()
+one = defaultMain [oneSuite]
+
+oneSuite :: Test
+oneSuite = testGroup "One"
+ [
+   testCase "ObjectLiteral7"    (testProg "x={get foo() {return 1},set foo(a) {x=a}}"  "")
+ ]
+
+testSuite :: Test
+testSuite = testGroup "Parser"
+    [
+      testCase "helloWorld"        caseHelloWorld
+    , testCase "LiteralNull"       (testLiteral "null"     "Right (JSLiteral \"null\")")
+    , testCase "LiteralFalse"      (testLiteral "false"    "Right (JSLiteral \"false\")")
+    , testCase "LiteralTrue"       (testLiteral "true"     "Right (JSLiteral \"true\")")
+    , testCase "LiteralHexInteger1" (testLiteral "0x1234fF" "Right (JSHexInteger \"0x1234fF\")")
+    , testCase "LiteralHexInteger2" (testLiteral "0X1234fF" "Right (JSHexInteger \"0X1234fF\")")
+    , testCase "LiteralDecimal1"   (testLiteral "1.0e4"    "Right (JSDecimal \"1.0e4\")")
+    , testCase "LiteralDecimal2"   (testLiteral "2.3E6"    "Right (JSDecimal \"2.3E6\")")
+    , testCase "LiteralDecimal3"   (testLiteral "4.5"      "Right (JSDecimal \"4.5\")")
+    , testCase "LiteralDecimal3"   (testLiteral "0.7e8"    "Right (JSDecimal \"0.7e8\")")
+    , testCase "LiteralDecimal4"   (testLiteral "0.7E8"    "Right (JSDecimal \"0.7E8\")")
+    , testCase "LiteralDecimal5"   (testLiteral "10"       "Right (JSDecimal \"10\")")
+    , testCase "LiteralDecimal6"   (testLiteral "0"        "Right (JSDecimal \"0\")")
+    , testCase "LiteralDecimal7"   (testLiteral "0.03"     "Right (JSDecimal \"0.03\")")
+    , testCase "LiteralDecimal9"   (testLiteral "0.7e+8"   "Right (JSDecimal \"0.7e+8\")")
+    , testCase "LiteralDecimal10"  (testLiteral "0.7e-18"  "Right (JSDecimal \"0.7e-18\")")
+    , testCase "LiteralDecimal11"  (testLiteral "1.0e+4"   "Right (JSDecimal \"1.0e+4\")")
+    , testCase "LiteralDecimal12"  (testLiteral "1.0e-4"   "Right (JSDecimal \"1.0e-4\")")
+    , testCase "LiteralDecimal13"  (testLiteral "1e18"     "Right (JSDecimal \"1e18\")")
+    , testCase "LiteralDecimal14"  (testLiteral "1e+18"    "Right (JSDecimal \"1e+18\")")
+    , testCase "LiteralDecimal15"  (testLiteral "1e-18"    "Right (JSDecimal \"1e-18\")")
+    , testCase "LiteralDecimal16"  (testLiteral "1E-01"    "Right (JSDecimal \"1E-01\")")
+
+    , testCase "LiteralOctal"      (testLiteral "010"      "Right (JSOctal \"010\")")
+
+    , testCase "LiteralString1"    (testLiteral "\"hello\\nworld\"" "Right (JSStringLiteral '\"' \"hello\\\\nworld\")")
+    , testCase "LiteralString2"    (testLiteral "'hello\\nworld'"  "Right (JSStringLiteral '\\'' \"hello\\\\nworld\")")
+
+    , testCase "LiteralThis"       (testPE "this"  "Right (JSLiteral \"this\")")
+
+    , testCase "LiteralRegex1"     (testPE "/blah/"  "Right (JSRegEx \"/blah/\")")
+    , testCase "LiteralRegex2"     (testPE "/$/g"    "Right (JSRegEx \"/$/g\")")
+    , testCase "LiteralRegex3"     (testPE "/\\n/g"  "Right (JSRegEx \"/\\\\n/g\")")
+    , testCase "LiteralRegex4"     (testPE "/^\"(?:\\.|[^\"])*\"|^'(?:[^']|\\.)*'/" "Right (JSRegEx \"/^\\\"(?:\\\\.|[^\\\"])*\\\"|^'(?:[^']|\\\\.)*'/\")")
+
+
+    , testCase "Identifier1"       (testPE "_$"      "Right (JSIdentifier \"_$\")")
+    , testCase "Identifier2"       (testPE "this_"   "Right (JSIdentifier \"this_\")")
+
+    , testCase "ArrayLiteral1"     (testPE "[]"      "Right (JSArrayLiteral [])")
+    , testCase "ArrayLiteral2"     (testPE "[,]"     "Right (JSArrayLiteral [JSElision JSLiteral \",\"])")
+    , testCase "ArrayLiteral3"     (testPE "[,,]"    "Right (JSArrayLiteral [JSElision JSLiteral \",\",JSElision JSLiteral \",\"])")
+    , testCase "ArrayLiteral4"     (testPE "[,,x]"   "Right (JSArrayLiteral [JSElision JSLiteral \",\",JSElision JSLiteral \",\",JSIdentifier \"x\"])")
+    , testCase "ArrayLiteral5"     (testPE "[,,x]"   "Right (JSArrayLiteral [JSElision JSLiteral \",\",JSElision JSLiteral \",\",JSIdentifier \"x\"])")
+    , testCase "ArrayLiteral6"     (testPE "[,x,,x]" "Right (JSArrayLiteral [JSElision JSLiteral \",\",JSIdentifier \"x\",JSElision JSLiteral \",\",JSElision JSLiteral \",\",JSIdentifier \"x\"])")
+    , testCase "ArrayLiteral7"     (testPE "[x]"     "Right (JSArrayLiteral [JSIdentifier \"x\"])")
+    , testCase "ArrayLiteral8"     (testPE "[x,]"    "Right (JSArrayLiteral [JSIdentifier \"x\",JSLiteral \",\"])")
+
+    , testCase "ObjectLiteral1"    (testPE "{}"        "Right (JSObjectLiteral [])")
+    , testCase "ObjectLiteral2"    (testPE "{x:1}"     "Right (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"x\") [JSDecimal \"1\"]])")
+    , testCase "ObjectLiteral3"    (testPE "{x:1,y:2}" "Right (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"x\") [JSDecimal \"1\"],JSLiteral \",\",JSPropertyNameandValue (JSIdentifier \"y\") [JSDecimal \"2\"]])")
+
+    , testCase "ObjectLiteral4"    (testPE "{evaluate:evaluate,load:function load(s){if(x)return s;1}}"
+                                    "Right (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"evaluate\") [JSIdentifier \"evaluate\"],JSLiteral \",\",JSPropertyNameandValue (JSIdentifier \"load\") [JSFunctionExpression [JSIdentifier \"load\"] [JSIdentifier \"s\"] (JSBlock ([JSIf (JSExpression [JSIdentifier \"x\"]) ([JSReturn [JSExpression [JSIdentifier \"s\"]] JSLiteral \";\"]) ([]),JSExpression [JSDecimal \"1\"]]))]])")
+
+    , testCase "ObjectLiteral5"    (testPE "{x:1,}"    "Right (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"x\") [JSDecimal \"1\"],JSLiteral \",\"])")
+
+    , testCase "ObjectLiteral6"    (testProg "a={\n  values: 7,\n}\n" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"a\",JSOperator JSLiteral \"=\",JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"values\") [JSDecimal \"7\"],JSLiteral \",\"]],JSLiteral \"\"])")
+
+    -- Edition 5 extensions
+    , testCase "ObjectLiteral7"    (testProg "x={get foo() {return 1},set foo(a) {x=a}}" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSObjectLiteral [JSPropertyAccessor NT (JSLiteral \"get\") (TokenPn 3 1 4) [NoComment] (JSIdentifier \"foo\") [] (JSBlock ([JSReturn [JSExpression [JSDecimal \"1\"]] JSLiteral \"\"])),JSLiteral \",\",JSPropertyAccessor NT (JSLiteral \"set\") (TokenPn 24 1 25) [NoComment] (JSIdentifier \"foo\") [JSIdentifier \"a\"] (JSBlock ([JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSIdentifier \"a\"]]))]],JSLiteral \"\"])")
+
+    , testCase "ObjectLiteral8"    (testProg "a={if:1,interface:2}" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"a\",JSOperator JSLiteral \"=\",JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"if\") [JSDecimal \"1\"],JSLiteral \",\",JSPropertyNameandValue (JSIdentifier \"interface\") [JSDecimal \"2\"]]],JSLiteral \"\"])")
+
+    , testCase "ExpressionParen"   (testPE "(56)"     "Right (JSExpressionParen (JSExpression [JSDecimal \"56\"]))")
+
+    , testCase "Statement1"        (testStmt "x"        "Right (JSExpression [JSIdentifier \"x\"])")
+    , testCase "Statement2"        (testStmt "null"     "Right (JSExpression [JSLiteral \"null\"])")
+    , testCase "Statement3"        (testStmt "true?1:2" "Right (JSExpression [JSExpressionTernary [JSLiteral \"true\"] [JSDecimal \"1\"] [JSDecimal \"2\"]])")
+
+    , testCase "Statement4"        (testStmt "x||y"     "Right (JSExpression [JSExpressionBinary \"||\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement5"        (testStmt "x&&y"     "Right (JSExpression [JSExpressionBinary \"&&\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement6"        (testStmt "x|y"     "Right (JSExpression [JSExpressionBinary \"|\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement6"        (testStmt "x^y"     "Right (JSExpression [JSExpressionBinary \"^\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement7"        (testStmt "x&y"     "Right (JSExpression [JSExpressionBinary \"&\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+
+    , testCase "Statement8"        (testStmt "x==y"     "Right (JSExpression [JSExpressionBinary \"==\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement9"        (testStmt "x!=y"     "Right (JSExpression [JSExpressionBinary \"!=\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement10"       (testStmt "x===y"     "Right (JSExpression [JSExpressionBinary \"===\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement11"       (testStmt "x!==y"     "Right (JSExpression [JSExpressionBinary \"!==\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+
+    , testCase "Statement12"       (testStmt "x<y"     "Right (JSExpression [JSExpressionBinary \"<\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement12"       (testStmt "x>y"     "Right (JSExpression [JSExpressionBinary \">\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement12"       (testStmt "x<=y"     "Right (JSExpression [JSExpressionBinary \"<=\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement12"       (testStmt "x>=y"     "Right (JSExpression [JSExpressionBinary \">=\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    -- , testCase "Statement12"       (testStmt "x instanceof y"     "") -- TODO: restore test case
+
+    , testCase "Statement13"       (testStmt "x<<y"     "Right (JSExpression [JSExpressionBinary \"<<\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement13"       (testStmt "x>>y"     "Right (JSExpression [JSExpressionBinary \">>\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement13"       (testStmt "x>>>y"     "Right (JSExpression [JSExpressionBinary \">>>\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+
+    , testCase "Statement14"       (testStmt "x+y"     "Right (JSExpression [JSExpressionBinary \"+\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement14"       (testStmt "x-y"     "Right (JSExpression [JSExpressionBinary \"-\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+
+    , testCase "Statement15"       (testStmt "x*y"     "Right (JSExpression [JSExpressionBinary \"*\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement16"       (testStmt "x/y"     "Right (JSExpression [JSExpressionBinary \"/\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+    , testCase "Statement17"       (testStmt "x%y"     "Right (JSExpression [JSExpressionBinary \"%\" [JSIdentifier \"x\"] [JSIdentifier \"y\"]])")
+
+    , testCase "Statement18"       (testStmt "delete y"  "Right (JSExpression [JSUnary \"delete \",JSIdentifier \"y\"])")
+    , testCase "Statement19"       (testStmt "void y"    "Right (JSExpression [JSUnary \"void \",JSIdentifier \"y\"])")
+    , testCase "Statement20"       (testStmt "typeof y"  "Right (JSExpression [JSUnary \"typeof \",JSIdentifier \"y\"])")
+    , testCase "Statement21"       (testStmt "++y"    "Right (JSExpression [JSUnary \"++\",JSIdentifier \"y\"])")
+    , testCase "Statement22"       (testStmt "--y"    "Right (JSExpression [JSUnary \"--\",JSIdentifier \"y\"])")
+    , testCase "Statement23"       (testStmt "+y"     "Right (JSExpression [JSUnary \"+\",JSIdentifier \"y\"])")
+    , testCase "Statement24"       (testStmt "-y"     "Right (JSExpression [JSUnary \"-\",JSIdentifier \"y\"])")
+    , testCase "Statement25"       (testStmt "~y"     "Right (JSExpression [JSUnary \"~\",JSIdentifier \"y\"])")
+    , testCase "Statement26"       (testStmt "!y"     "Right (JSExpression [JSUnary \"!\",JSIdentifier \"y\"])")
+
+    , testCase "Statement27"       (testStmt "y++"     "Right (JSExpression [JSExpressionPostfix \"++\" [JSIdentifier \"y\"]])")
+    , testCase "Statement28"       (testStmt "y--"     "Right (JSExpression [JSExpressionPostfix \"--\" [JSIdentifier \"y\"]])")
+
+      -- Member Expressions
+    , testCase "MemberExpression1a" (testStmt "function(){}"    "Right (JSExpression [JSFunctionExpression [] [] (JSBlock ([]))])")
+    , testCase "MemberExpression1b" (testStmt "function(a){}"   "Right (JSExpression [JSFunctionExpression [] [JSIdentifier \"a\"] (JSBlock ([]))])")
+    , testCase "MemberExpression1c" (testStmt "function(a,b){}" "Right (JSExpression [JSFunctionExpression [] [JSIdentifier \"a\",JSLiteral \",\",JSIdentifier \"b\"] (JSBlock ([]))])")
+
+    , testCase "MemberExpression1d" (testStmt "x[y]"     "Right (JSExpression [JSMemberSquare [JSIdentifier \"x\"] (JSExpression [JSIdentifier \"y\"])])")
+    , testCase "MemberExpression1e" (testStmt "x[y][z]"  "Right (JSExpression [JSMemberSquare [JSMemberSquare [JSIdentifier \"x\"] (JSExpression [JSIdentifier \"y\"])] (JSExpression [JSIdentifier \"z\"])])")
+    , testCase "MemberExpression1f" (testStmt "x.y"      "Right (JSExpression [JSMemberDot [JSIdentifier \"x\"] (JSIdentifier \"y\")])")
+    , testCase "MemberExpression1g" (testStmt "x.y.z"    "Right (JSExpression [JSMemberDot [JSMemberDot [JSIdentifier \"x\"] (JSIdentifier \"y\")] (JSIdentifier \"z\")])")
+
+    , testCase "MemberExpression1h" (testStmt "new x()"  "Right (JSExpression [JSLiteral \"new\",JSIdentifier \"x\",JSArguments []])")
+
+    , testCase "NewExpression1" (testStmt "new x.y"  "Right (JSExpression [JSLiteral \"new\",JSMemberDot [JSIdentifier \"x\"] (JSIdentifier \"y\")])")
+
+    , testCase "CallExpression1" (testStmt "x()"     "Right (JSExpression [JSIdentifier \"x\",JSArguments []])")
+    , testCase "CallExpression2" (testStmt "x()()"   "Right (JSExpression [JSIdentifier \"x\",JSArguments [],JSCallExpression \"()\" [JSArguments []]])")
+    , testCase "CallExpression3" (testStmt "x()[4]"  "Right (JSExpression [JSIdentifier \"x\",JSArguments [],JSCallExpression \"[]\" [JSExpression [JSDecimal \"4\"]]])")
+    , testCase "CallExpression4" (testStmt "x().x"   "Right (JSExpression [JSIdentifier \"x\",JSArguments [],JSCallExpression \".\" [JSIdentifier \"x\"]])")
+    , testCase "CallExpression5" (testStmt "x(a,b=2).x"  "Right (JSExpression [JSIdentifier \"x\",JSArguments [JSIdentifier \"a\",JSLiteral \",\",JSIdentifier \"b\",JSOperator JSLiteral \"=\",JSDecimal \"2\"],JSCallExpression \".\" [JSIdentifier \"x\"]])")
+
+    , testCase "AssignExpression1"  (testStmt "x=1"   "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression2"  (testStmt "x*=1"   "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"*=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression3"  (testStmt "x/=1"   "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"/=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression4"  (testStmt "x%=1"   "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"%=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression5"  (testStmt "x+=1"   "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"+=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression6"  (testStmt "x-=1"   "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"-=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression7"  (testStmt "x<<=1"  "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"<<=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression8"  (testStmt "x>>=1"  "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \">>=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression9"  (testStmt "x>>>=1" "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \">>>=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression10" (testStmt "x&=1"   "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"&=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression11" (testStmt "x^=1"   "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"^=\",JSDecimal \"1\"])")
+    , testCase "AssignExpression12" (testStmt "x|=1"   "Right (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"|=\",JSDecimal \"1\"])")
+
+
+    , testCase "Block1" (testStmt "{}"     "Right (JSBlock ([]))")
+    , testCase "Block2" (testStmt "{x=1}"  "Right (JSBlock ([JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"]]))")
+    , testCase "Block3" (testStmt "{x=1;y=2}" "Right (JSBlock ([JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSExpression [JSIdentifier \"y\",JSOperator JSLiteral \"=\",JSDecimal \"2\"]]))")
+    , testCase "Block4" (testStmt "{{}}"     "Right (JSBlock ([JSBlock ([])]))")
+    , testCase "Block5" (testStmt "{{{}}}"   "Right (JSBlock ([JSBlock ([JSBlock ([])])]))")
+
+    , testCase "If1" (testStmt "if (1) {}"  "Right (JSIf (JSExpression [JSDecimal \"1\"]) ([JSBlock ([])]) ([]))")
+
+    , testCase "IfElse1" (testStmt "if (1) {} else {}"  "Right (JSIf (JSExpression [JSDecimal \"1\"]) ([JSBlock ([])]) ([JSLiteral \"else\",JSBlock ([])]))")
+    , testCase "IfElse2" (testStmt "if (1) x=1; else {}" "Right (JSIf (JSExpression [JSDecimal \"1\"]) ([JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\"]) ([JSLiteral \"else\",JSBlock ([])]))")
+
+    , testCase "DoWhile1" (testStmt "do {x=1} while (true);"  "Right (JSDoWhile (JSBlock ([JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"]])) (JSExpression [JSLiteral \"true\"]) (JSLiteral \";\"))")
+    , testCase "While1"   (testStmt "while(true);"             "Right (JSWhile (JSExpression [JSLiteral \"true\"]) (JSLiteral \";\"))")
+
+    , testCase "For1"   (testStmt "for(;;);"             "Right (JSFor [] [] [] (JSLiteral \";\"))")
+    , testCase "For2"   (testStmt "for(x=1;x<10;x++);"   "Right (JSFor [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"]] [JSExpression [JSExpressionBinary \"<\" [JSIdentifier \"x\"] [JSDecimal \"10\"]]] [JSExpression [JSExpressionPostfix \"++\" [JSIdentifier \"x\"]]] (JSLiteral \";\"))")
+
+    , testCase "ForVar1"   (testStmt "for(var x;;);"            "Right (JSForVar [JSVarDecl (JSIdentifier \"x\") []] [] [] (JSLiteral \";\"))")
+    , testCase "ForVar2a"   (testStmt "for(var x=1;;);"          "Right (JSForVar [JSVarDecl (JSIdentifier \"x\") [JSLiteral \"=\",JSDecimal \"1\"]] [] [] (JSLiteral \";\"))")
+    , testCase "ForVar2b"   (testStmt "for(var x;y;z){}"         "Right (JSForVar [JSVarDecl (JSIdentifier \"x\") []] [JSExpression [JSIdentifier \"y\"]] [JSExpression [JSIdentifier \"z\"]] (JSBlock ([])))")
+
+    , testCase "ForIn1"   (testStmt "for(x in 5){}"         "Right (JSForIn [JSIdentifier \"x\"] (JSExpression [JSDecimal \"5\"]) (JSBlock ([])))")
+
+    , testCase "ForVarIn1" (testStmt "for(var x in 5){}"    "Right (JSForVarIn (JSVarDecl (JSIdentifier \"x\") []) (JSExpression [JSDecimal \"5\"]) (JSBlock ([])))")
+
+    , testCase "Var1" (testStmt "var x=1;"        "Right (JSVariables JSLiteral \"var\" [JSVarDecl (JSIdentifier \"x\") [JSLiteral \"=\",JSDecimal \"1\"]])")
+    , testCase "Var2" (testStmt "const x=1,y=2;"  "Right (JSVariables JSLiteral \"const\" [JSVarDecl (JSIdentifier \"x\") [JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \",\",JSVarDecl (JSIdentifier \"y\") [JSLiteral \"=\",JSDecimal \"2\"]])")
+
+    , testCase "Continue1" (testStmt "continue;"       "Right (JSContinue [] JSLiteral \";\")")
+    , testCase "Continue2" (testStmt "continue x;"     "Right (JSContinue [JSIdentifier \"x\"] JSLiteral \";\")")
+
+    , testCase "Break1" (testStmt "break;"       "Right (JSBreak [] JSLiteral \";\")")
+    , testCase "Break2" (testStmt "break x;"     "Right (JSBreak [JSIdentifier \"x\"] JSLiteral \";\")")
+
+    , testCase "Return1" (testStmt "return;"     "Right (JSReturn [] JSLiteral \";\")")
+    , testCase "Return2" (testStmt "return x;"   "Right (JSReturn [JSExpression [JSIdentifier \"x\"]] JSLiteral \";\")")
+
+    , testCase "With1" (testStmt "with (x) {};"   "Right (JSWith (JSExpression [JSIdentifier \"x\"]) [JSBlock ([]),JSLiteral \";\"])")
+
+    , testCase "Labelled1" (testStmt "abc:x=1"    "Right (JSLabelled (JSIdentifier \"abc\") (JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"]))")
+
+    , testCase "Switch1" (testStmt "switch (x) {}" "Right (JSSwitch (JSExpression [JSIdentifier \"x\"]) JSBlock ([JSLiteral \"\"]))")
+    , testCase "Switch2" (testStmt "switch (x) {case 1:break;}"  "Right (JSSwitch (JSExpression [JSIdentifier \"x\"]) JSBlock ([JSCase (JSExpression [JSDecimal \"1\"]) ([JSBreak [] JSLiteral \";\"])]))")
+    , testCase "Switch3" (testStmt "switch (x) {case 0:\ncase 1:break;}"  "Right (JSSwitch (JSExpression [JSIdentifier \"x\"]) JSBlock ([JSCase (JSExpression [JSDecimal \"0\"]) ([]),JSCase (JSExpression [JSDecimal \"1\"]) ([JSBreak [] JSLiteral \";\"])]))")
+    , testCase "Switch4" (testStmt "switch (x) {default:break;}"     "Right (JSSwitch (JSExpression [JSIdentifier \"x\"]) JSBlock ([JSLiteral \"\",JSDefault ([JSBreak [] JSLiteral \";\"]),JSLiteral \"\"]))")
+    , testCase "Switch5" (testStmt "switch (x) {default:\ncase 1:break;}" "Right (JSSwitch (JSExpression [JSIdentifier \"x\"]) JSBlock ([JSLiteral \"\",JSDefault ([]),JSCase (JSExpression [JSDecimal \"1\"]) ([JSBreak [] JSLiteral \";\"])]))")
+
+    , testCase "Throw1" (testStmt "throw 1"   "Right (JSThrow (JSExpression [JSDecimal \"1\"]))")
+
+    , testCase "Try1" (testStmt "try{}catch(a){}"             "Right (JSTry (JSBlock ([])) [JSCatch (JSIdentifier \"a\") [] (JSBlock ([]))])")
+    , testCase "Try2" (testStmt "try{}finally{}"              "Right (JSTry (JSBlock ([])) [JSFinally (JSBlock ([]))])")
+    , testCase "Try3" (testStmt "try{}catch(a){}finally{}"    "Right (JSTry (JSBlock ([])) [JSCatch (JSIdentifier \"a\") [] (JSBlock ([])),JSFinally (JSBlock ([]))])")
+
+    , testCase "Try4" (testStmt "try{}catch(a){}catch(b){}finally{}"   "Right (JSTry (JSBlock ([])) [JSCatch (JSIdentifier \"a\") [] (JSBlock ([])),JSCatch (JSIdentifier \"b\") [] (JSBlock ([])),JSFinally (JSBlock ([]))])")
+    , testCase "Try5" (testStmt "try{}catch(a){}catch(b){}"            "Right (JSTry (JSBlock ([])) [JSCatch (JSIdentifier \"a\") [] (JSBlock ([])),JSCatch (JSIdentifier \"b\") [] (JSBlock ([]))])")
+    , testCase "Try6" (testStmt "try{}catch(a if true){}catch(b){}"    "Right (JSTry (JSBlock ([])) [JSCatch (JSIdentifier \"a\") [JSLiteral \"if\",JSLiteral \"true\"] (JSBlock ([])),JSCatch (JSIdentifier \"b\") [] (JSBlock ([]))])")
+
+    , testCase "Function1" (testProg "function a(){}"      "Right (JSSourceElementsTop [JSFunction (JSIdentifier \"a\") [] (JSBlock ([])),JSLiteral \"\"])")
+    , testCase "Function2" (testProg "function a(b,c){}"  "Right (JSSourceElementsTop [JSFunction (JSIdentifier \"a\") [JSIdentifier \"b\",JSLiteral \",\",JSIdentifier \"c\"] (JSBlock ([])),JSLiteral \"\"])")
+
+    , testCase "Comment1" (testProg "//blah\nx=1;//foo\na"   "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSExpression [JSIdentifier \"a\"],JSLiteral \"\"])")
+
+    , testCase "Comment2" (testProg "/*x=1\ny=2\n*/z=2;//foo\na"  "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"z\",JSOperator JSLiteral \"=\",JSDecimal \"2\"],JSLiteral \";\",JSExpression [JSIdentifier \"a\"],JSLiteral \"\"])")
+
+    , 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\"] (JSBlock ([JSIf (JSExpression [JSUnary \"!\",JSIdentifier \"name\"]) ([JSThrow (JSExpression [JSLiteral \"new\",JSIdentifier \"Error\",JSArguments [JSStringLiteral '\\'' \"Must specify an animal name\"]]),JSLiteral \";\"]) ([]),JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\"),JSOperator JSLiteral \"=\",JSIdentifier \"name\"]])),JSLiteral \";\",JSExpression [JSMemberDot [JSMemberDot [JSIdentifier \"Animal\"] (JSIdentifier \"prototype\")] (JSIdentifier \"toString\"),JSOperator JSLiteral \"=\",JSFunctionExpression [] [] (JSBlock ([JSReturn [JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\")]] JSLiteral \"\"]))],JSLiteral \";\",JSExpression [JSIdentifier \"o\",JSOperator JSLiteral \"=\",JSLiteral \"new\",JSIdentifier \"Animal\",JSArguments [JSStringLiteral '\"' \"bob\"]],JSLiteral \";\",JSExpression [JSExpressionBinary \"==\" [JSMemberDot [JSIdentifier \"o\"] (JSIdentifier \"toString\"),JSArguments []] [JSStringLiteral '\"' \"bob\"]],JSLiteral \"\"])")
+
+    , testCase "min_100_animals2" (testProg "Animal=function(){return this.name};" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"Animal\",JSOperator JSLiteral \"=\",JSFunctionExpression [] [] (JSBlock ([JSReturn [JSExpression [JSMemberDot [JSLiteral \"this\"] (JSIdentifier \"name\")]] JSLiteral \"\"]))],JSLiteral \";\",JSLiteral \"\"])")
+
+    , testCase "min_100_animals3" (testProg "if(a)x=1;y=2" "Right (JSSourceElementsTop [JSIf (JSExpression [JSIdentifier \"a\"]) ([JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\"]) ([]),JSExpression [JSIdentifier \"y\",JSOperator JSLiteral \"=\",JSDecimal \"2\"],JSLiteral \"\"])")
+
+    , testCase "min_100_animals4" (testProg "if(a)x=a()y=2" "Right (JSSourceElementsTop [JSIf (JSExpression [JSIdentifier \"a\"]) ([JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSIdentifier \"a\",JSArguments []]]) ([]),JSExpression [JSIdentifier \"y\",JSOperator JSLiteral \"=\",JSDecimal \"2\"],JSLiteral \"\"])")
+
+    , testCase "05_regex"  (testProg "newlines=spaces.match(/\\n/g)" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"newlines\",JSOperator JSLiteral \"=\",JSMemberDot [JSIdentifier \"spaces\"] (JSIdentifier \"match\"),JSArguments [JSRegEx \"/\\\\n/g\"]],JSLiteral \"\"])")
+
+    , testCase "05_regex2" (testProg "x=/\\n/g" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSRegEx \"/\\\\n/g\"],JSLiteral \"\"])")
+
+    , testCase "05_regex3" (testProg "x=i(/[?|^&(){}\\[\\]+\\-*\\/\\.]/g,\"\\\\$&\")" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSIdentifier \"i\",JSArguments [JSRegEx \"/[?|^&(){}\\\\[\\\\]+\\\\-*\\\\/\\\\.]/g\",JSLiteral \",\",JSStringLiteral '\"' \"\\\\\\\\$&\"]],JSLiteral \"\"])")
+
+    , testCase "05_regex4" (testProg "x=i(/^$/g,\"\\\\$&\")" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSIdentifier \"i\",JSArguments [JSRegEx \"/^$/g\",JSLiteral \",\",JSStringLiteral '\"' \"\\\\\\\\$&\"]],JSLiteral \"\"])")
+
+   , testCase "05_regex5" (testProg "if(/^[a-z]/.test(t)){consts+=t.toUpperCase();keywords[t]=i}else consts+=(/^\\W/.test(t)?opTypeNames[t]:t);"
+                           "Right (JSSourceElementsTop [JSIf (JSExpression [JSMemberDot [JSRegEx \"/^[a-z]/\"] (JSIdentifier \"test\"),JSArguments [JSIdentifier \"t\"]]) ([JSBlock ([JSExpression [JSIdentifier \"consts\",JSOperator JSLiteral \"+=\",JSMemberDot [JSIdentifier \"t\"] (JSIdentifier \"toUpperCase\"),JSArguments []],JSLiteral \";\",JSExpression [JSMemberSquare [JSIdentifier \"keywords\"] (JSExpression [JSIdentifier \"t\"]),JSOperator JSLiteral \"=\",JSIdentifier \"i\"]])]) ([JSLiteral \"else\",JSExpression [JSIdentifier \"consts\",JSOperator JSLiteral \"+=\",JSExpressionParen (JSExpression [JSExpressionTernary [JSMemberDot [JSRegEx \"/^\\\\W/\"] (JSIdentifier \"test\"),JSArguments [JSIdentifier \"t\"]] [JSMemberSquare [JSIdentifier \"opTypeNames\"] (JSExpression [JSIdentifier \"t\"])] [JSIdentifier \"t\"]])]]),JSLiteral \";\",JSLiteral \"\"])")
+
+   , testCase "if_semi" (testProg "if(x);x=1" "Right (JSSourceElementsTop [JSIf (JSExpression [JSIdentifier \"x\"]) ([JSLiteral \";\"]) ([]),JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \"\"])")
+
+   , testCase "67_bob" (testProg "(match = /^\"(?:\\\\.|[^\"])*\"|^'(?:[^']|\\\\.)*'/(input))" "Right (JSSourceElementsTop [JSExpression [JSExpressionParen (JSExpression [JSIdentifier \"match\",JSOperator JSLiteral \"=\",JSRegEx \"/^\\\"(?:\\\\\\\\.|[^\\\"])*\\\"|^'(?:[^']|\\\\\\\\.)*'/\",JSArguments [JSIdentifier \"input\"]])],JSLiteral \"\"])")
+
+   , testCase "122_jsexec" (testProg "v = getValue(execute(n[0], x)) in getValue(execute(n[1], x));" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"v\",JSOperator JSLiteral \"=\",JSExpressionBinary \" in \" [JSIdentifier \"getValue\",JSArguments [JSIdentifier \"execute\",JSArguments [JSMemberSquare [JSIdentifier \"n\"] (JSExpression [JSDecimal \"0\"]),JSLiteral \",\",JSIdentifier \"x\"]]] [JSIdentifier \"getValue\",JSArguments [JSIdentifier \"execute\",JSArguments [JSMemberSquare [JSIdentifier \"n\"] (JSExpression [JSDecimal \"1\"]),JSLiteral \",\",JSIdentifier \"x\"]]]],JSLiteral \";\",JSLiteral \"\"])")
+
+   , testCase "bug1a" (testProg "/* */\nfunction f() {\n/*  */\n}\n" "Right (JSSourceElementsTop [JSFunction (JSIdentifier \"f\") [] (JSBlock ([])),JSLiteral \"\"])")
+   , testCase "bug1b" (testProg "/* **/\nfunction f() {\n/*  */\n}\n" "Right (JSSourceElementsTop [JSFunction (JSIdentifier \"f\") [] (JSBlock ([])),JSLiteral \"\"])")
+
+   , testCase "unicode1-ws" (testProg "a \f\v\t\r\n=\x00a0\x1680\x180e\x2000\x2001\x2002\x2003\x2004\x2005\x2006\x2007\x2008\x2009\x200a\x2028\x2029\x202f\x205f\x3000\&1;" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"a\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSLiteral \"\"])")
+
+   , testCase "unicode2-lt" (testProg "//comment\x000Ax=1;" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSLiteral \"\"])")
+   , testCase "unicode3-lt" (testProg "//comment\x000Dx=1;" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSLiteral \"\"])")
+   , testCase "unicode4-lt" (testProg "//comment\x2028x=1;" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSLiteral \"\"])")
+   , testCase "unicode5-lt" (testProg "//comment\x2029x=1;" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSLiteral \"\"])")
+
+   , testCase "unicode2" (testProg "àáâãäå = 1;" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"\\224\\225\\226\\227\\228\\229\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSLiteral \"\"])")
+
+   , testCase "unicode3" (testProg "$aà = 1;_b=2;\0065a=2"  "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"$a\\224\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSExpression [JSIdentifier \"_b\",JSOperator JSLiteral \"=\",JSDecimal \"2\"],JSLiteral \";\",JSExpression [JSIdentifier \"Aa\",JSOperator JSLiteral \"=\",JSDecimal \"2\"],JSLiteral \"\"])")
+
+   , testCase "unicode4" (testProg "x=\"àáâãäå\";y='\3012a\0068'" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSStringLiteral '\"' \"\\224\\225\\226\\227\\228\\229\"],JSLiteral \";\",JSExpression [JSIdentifier \"y\",JSOperator JSLiteral \"=\",JSStringLiteral '\\'' \"\\3012aD\"],JSLiteral \"\"])")
+
+   , testCase "unicode5f" (testFileUtf8 "./test/Unicode.js" "JSSourceElementsTop [JSExpression [JSIdentifier \"\\224\\225\\226\\227\\228\\229\",JSOperator JSLiteral \"=\",JSDecimal \"1\"],JSLiteral \";\",JSLiteral \"\"]")
+
+   , testCase "bug2.a" (testProg "function() {\nz = function /*z*/(o) {\nreturn r;\n};}" "Right (JSSourceElementsTop [JSExpression [JSFunctionExpression [] [] (JSBlock ([JSExpression [JSIdentifier \"z\",JSOperator JSLiteral \"=\",JSFunctionExpression [] [JSIdentifier \"o\"] (JSBlock ([JSReturn [JSExpression [JSIdentifier \"r\"]] JSLiteral \";\"]))],JSLiteral \";\"]))],JSLiteral \"\"])")
+
+   , testCase "bug2.b" (testProg "function() {\nz = function z(o) {\nreturn r;\n};}" "Right (JSSourceElementsTop [JSExpression [JSFunctionExpression [] [] (JSBlock ([JSExpression [JSIdentifier \"z\",JSOperator JSLiteral \"=\",JSFunctionExpression [JSIdentifier \"z\"] [JSIdentifier \"o\"] (JSBlock ([JSReturn [JSExpression [JSIdentifier \"r\"]] JSLiteral \";\"]))],JSLiteral \";\"]))],JSLiteral \"\"])")
+
+   -- https://github.com/alanz/hjsmin/issues/#issue/3
+   , testCase "bug3" (testProg "var myLatlng = new google.maps.LatLng(56.8379100, 60.5806664);" "Right (JSSourceElementsTop [JSVariables JSLiteral \"var\" [JSVarDecl (JSIdentifier \"myLatlng\") [JSLiteral \"=\",JSLiteral \"new\",JSMemberDot [JSMemberDot [JSIdentifier \"google\"] (JSIdentifier \"maps\")] (JSIdentifier \"LatLng\"),JSArguments [JSDecimal \"56.8379100\",JSLiteral \",\",JSDecimal \"60.5806664\"]]],JSLiteral \"\"])")
+
+   -- https://github.com/alanz/hjsmin/issues/#issue/4
+   , testCase "bug4" (testProg "/* * geolocation. пытаемся определить свое местоположение * если не получается то используем defaultLocation * @Param {object} map экземпляр карты * @Param {object LatLng} defaultLocation Координаты центра по умолчанию * @Param {function} callbackAfterLocation Фу-ия которая вызывается после * геолокации. Т.к запрос геолокации асинхронен */x" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\"],JSLiteral \"\"])")
+
+
+
+   , testCase "02_sm.js"   (testProg "{zero}\none1;two\n{three\nfour;five;\n{\nsix;{seven;}\n}\n}" "Right (JSSourceElementsTop [JSBlock ([JSExpression [JSIdentifier \"zero\"]]),JSExpression [JSIdentifier \"one1\"],JSLiteral \";\",JSExpression [JSIdentifier \"two\"],JSBlock ([JSExpression [JSIdentifier \"three\"],JSExpression [JSIdentifier \"four\"],JSLiteral \";\",JSExpression [JSIdentifier \"five\"],JSLiteral \";\",JSBlock ([JSExpression [JSIdentifier \"six\"],JSLiteral \";\",JSBlock ([JSExpression [JSIdentifier \"seven\"],JSLiteral \";\"])])]),JSLiteral \"\"])")
+
+   , testCase "02_sm.js.2" (testProg "{zero}\nget;two\n{three\nfour;set;\n{\nsix;{seven;}\n}\n}" "Right (JSSourceElementsTop [JSBlock ([JSExpression [JSIdentifier \"zero\"]]),JSExpression [JSIdentifier \"get\"],JSLiteral \";\",JSExpression [JSIdentifier \"two\"],JSBlock ([JSExpression [JSIdentifier \"three\"],JSExpression [JSIdentifier \"four\"],JSLiteral \";\",JSExpression [JSIdentifier \"set\"],JSLiteral \";\",JSBlock ([JSExpression [JSIdentifier \"six\"],JSLiteral \";\",JSBlock ([JSExpression [JSIdentifier \"seven\"],JSLiteral \";\"])])]),JSLiteral \"\"])")
+
+   , testCase "loc1" (testProgUn "x = 1\n  y=2;" "Right (NN (JSSourceElementsTop [NN (JSExpression [NT (JSIdentifier \"x\") (TokenPn 0 1 1) [NoComment],NN (JSOperator (NT (JSLiteral \"=\") (TokenPn 2 1 3) [WhiteSpace (TokenPn 1 1 2) \" \"])),NT (JSDecimal \"1\") (TokenPn 4 1 5) [WhiteSpace (TokenPn 3 1 4) \" \"]]),NN (JSExpression [NT (JSIdentifier \"y\") (TokenPn 8 2 3) [WhiteSpace (TokenPn 5 1 6) \"\\n  \"],NN (JSOperator (NT (JSLiteral \"=\") (TokenPn 9 2 4) [NoComment])),NT (JSDecimal \"2\") (TokenPn 10 2 5) [NoComment]]),NT (JSLiteral \";\") (TokenPn 11 2 6) [NoComment],NT (JSLiteral \"\") (TokenPn 0 0 0) [NoComment]]))")
+
+   -- https://github.com/alanz/language-javascript/issues/2
+   , testCase "issue2" (testProg "var img = document.createElement('img');\nimg.src = \"mylogo.jpg\";\n$(img).click(function() {\n   alert('clicked!');\n});" "Right (JSSourceElementsTop [JSVariables JSLiteral \"var\" [JSVarDecl (JSIdentifier \"img\") [JSLiteral \"=\",JSMemberDot [JSIdentifier \"document\"] (JSIdentifier \"createElement\"),JSArguments [JSStringLiteral '\\'' \"img\"]]],JSExpression [JSMemberDot [JSIdentifier \"img\"] (JSIdentifier \"src\"),JSOperator JSLiteral \"=\",JSStringLiteral '\"' \"mylogo.jpg\"],JSLiteral \";\",JSExpression [JSIdentifier \"$\",JSArguments [JSIdentifier \"img\"],JSCallExpression \".\" [JSIdentifier \"click\"],JSCallExpression \"()\" [JSArguments [JSFunctionExpression [] [] (JSBlock ([JSExpression [JSIdentifier \"alert\",JSArguments [JSStringLiteral '\\'' \"clicked!\"]],JSLiteral \";\"]))]]],JSLiteral \";\",JSLiteral \"\"])")
+
+
+   -- Working in ECMASCRIPT 5.1 changes
+   , testCase "lineTerminatorInString1" (testProg "x='abc\\\ndef';"   "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSStringLiteral '\\'' \"abc\\\\\\ndef\"],JSLiteral \";\",JSLiteral \"\"])")
+   , testCase "lineTerminatorInString2" (testProg "x=\"abc\\\ndef\";" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSStringLiteral '\"' \"abc\\\\\\ndef\"],JSLiteral \";\",JSLiteral \"\"])")
+   , testCase "lineTerminatorInString3" (testProg "x=\"abc\\\rdef\";" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSStringLiteral '\"' \"abc\\\\\\rdef\"],JSLiteral \";\",JSLiteral \"\"])")
+   , testCase "lineTerminatorInString4" (testProg "x=\"abc\\\x2028 def\";" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSStringLiteral '\"' \"abc\\\\\\8232 def\"],JSLiteral \";\",JSLiteral \"\"])")
+   , testCase "lineTerminatorInString5" (testProg "x=\"abc\\\x2029 def\";" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSStringLiteral '\"' \"abc\\\\\\8233 def\"],JSLiteral \";\",JSLiteral \"\"])")
+   , testCase "lineTerminatorInString6" (testProg "x=\"abc\\\r\ndef\";" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSStringLiteral '\"' \"abc\\\\\\r\\ndef\"],JSLiteral \";\",JSLiteral \"\"])")
+
+
+     -- https://github.com/alanz/language-javascript/issues/4
+   , testCase "issue4ok"   (testProg "var k = {\ny: somename\n}" "Right (JSSourceElementsTop [JSVariables JSLiteral \"var\" [JSVarDecl (JSIdentifier \"k\") [JSLiteral \"=\",JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"y\") [JSIdentifier \"somename\"]]]],JSLiteral \"\"])")
+   , testCase "issue4bug1" (testProg "var k = {\ny: code\n}" "Right (JSSourceElementsTop [JSVariables JSLiteral \"var\" [JSVarDecl (JSIdentifier \"k\") [JSLiteral \"=\",JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"y\") [JSIdentifier \"code\"]]]],JSLiteral \"\"])")
+   , testCase "issue4bug2" (testProg "var k = {\ny: mode\n}" "Right (JSSourceElementsTop [JSVariables JSLiteral \"var\" [JSVarDecl (JSIdentifier \"k\") [JSLiteral \"=\",JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"y\") [JSIdentifier \"mode\"]]]],JSLiteral \"\"])")
+
+     -- https://github.com/alanz/language-javascript/issues/5
+   , testCase "issue5bug1" (testProg "x = { y: 1e8 }" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"y\") [JSDecimal \"1e8\"]]],JSLiteral \"\"])")
+   , testCase "issue5ok2" (testProg "{ y: 1e8 }" "Right (JSSourceElementsTop [JSBlock ([JSLabelled (JSIdentifier \"y\") (JSExpression [JSDecimal \"1e8\"])]),JSLiteral \"\"])")
+   , testCase "issue5ok3" (testProg "{ y: 18 }" "Right (JSSourceElementsTop [JSBlock ([JSLabelled (JSIdentifier \"y\") (JSExpression [JSDecimal \"18\"])]),JSLiteral \"\"])")
+   , testCase "issue5ok4" (testProg "x = { y: 18 }" "Right (JSSourceElementsTop [JSExpression [JSIdentifier \"x\",JSOperator JSLiteral \"=\",JSObjectLiteral [JSPropertyNameandValue (JSIdentifier \"y\") [JSDecimal \"18\"]]],JSLiteral \"\"])")
+
+     -- https://github.com/alanz/language-javascript/issues/14
+   , testCase "issue14" (testProg "var z = x[i] / y;" "Right (JSSourceElementsTop [JSVariables JSLiteral \"var\" [JSVarDecl (JSIdentifier \"z\") [JSLiteral \"=\",JSExpressionBinary \"/\" [JSMemberSquare [JSIdentifier \"x\"] (JSExpression [JSIdentifier \"i\"])] [JSIdentifier \"y\"]]],JSLiteral \"\"])")
+
+    ]
+
+srcHelloWorld = "Hello"
+caseHelloWorld =
+  "JSSourceElementsTop [JSExpression [JSIdentifier \"Hello\"],JSLiteral \"\"]"
+  -- @=? (show $ parse srcHelloWorld "src")
+  @=? (showStripped $ readJs srcHelloWorld)
+
+
+-- ---------------------------------------------------------------------
+
+commentSuite :: Test
+commentSuite = testGroup "Comments"
+    [
+      testCase "helloWorld"        caseHelloWorld
+    , testCase "LiteralNull"       (testLiteralC "/*a*/null"     "Right (NS (JSLiteral \"null\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"])")
+    , testCase "LiteralFalse"      (testLiteralC "/*b*/false"    "Right (NS (JSLiteral \"false\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*b*/\"])")
+    , testCase "LiteralTrue"       (testLiteralC "true"          "Right (NS (JSLiteral \"true\") (TokenPn 0 1 1) [NoComment])")
+    , testCase "LiteralTrue"       (testLiteralC "/*c*/true"     "Right (NS (JSLiteral \"true\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*c*/\"])")
+
+    , testCase "LiteralHexInteger" (testLiteralC "/*d*/0x1234fF" "Right (NS (JSHexInteger \"0x1234fF\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*d*/\"])")
+    , testCase "LiteralDecimal"    (testLiteralC "/*e*/1.0e4"    "Right (NS (JSDecimal \"1.0e4\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*e*/\"])")
+    , testCase "LiteralOctal"      (testLiteralC "/*x*/011"      "Right (NS (JSOctal \"011\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*x*/\"])")
+    , testCase "LiteralString1"    (testLiteralC "/*f*/\"hello\\nworld\"" "Right (NS (JSStringLiteral '\"' \"hello\\\\nworld\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*f*/\"])")
+    , testCase "LiteralString2"    (testLiteralC "/*g*/'hello\\nworld'"   "Right (NS (JSStringLiteral '\\'' \"hello\\\\nworld\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*g*/\"])")
+
+
+    , testCase "LiteralThis"       (testPEC "/*h*/this"  "Right (NS (JSLiteral \"this\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*h*/\"])")
+
+    , testCase "LiteralRegex1"     (testPEC "/*i*//blah/"  "Right (NS (JSRegEx \"/blah/\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*i*/\"])")
+
+    , testCase "Identifier2"       (testPEC "//j\nthis_"   "Right (NS (JSIdentifier \"this_\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"//j\"])")
+
+    , testCase "ArrayLiteral1"     (testPEC "/*a*/[/*b*/]"      "Right (NS (JSArrayLiteral []) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 6 1 7) \"/*b*/\"])")
+    , testCase "ArrayLiteral2"     (testPEC "/*a*/[/*b*/,/*c*/]"     "Right (NS (JSArrayLiteral [NS (JSElision []) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 12 1 13) \"/*c*/\"])")
+    , testCase "ArrayLiteral3"     (testPEC "/*a*/[/*b*/,/*c*/,/*d*/]"    "Right (NS (JSArrayLiteral [NS (JSElision []) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"],NS (JSElision []) (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 18 1 19) \"/*d*/\"])")
+    , testCase "ArrayLiteral4"     (testPEC "/*a*/[/*b/*,/*c*/,/*d*/x/*e*/]"   "Right (NS (JSArrayLiteral [NS (JSElision []) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b/*,/*c*/\"],NS (JSIdentifier \"x\") (TokenPn 18 1 19) [CommentA (TokenPn 18 1 19) \"/*d*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 24 1 25) \"/*e*/\"])")
+    , testCase "ArrayLiteral5"     (testPEC "/*a*/[/*b*/,/*c*/,/*d*/x/*e*/]"   "Right (NS (JSArrayLiteral [NS (JSElision []) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"],NS (JSElision []) (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"],NS (JSIdentifier \"x\") (TokenPn 18 1 19) [CommentA (TokenPn 18 1 19) \"/*d*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 24 1 25) \"/*e*/\"])")
+    , testCase "ArrayLiteral6"     (testPEC "/*a*/[/*b*/,/*c*/x/*d*/,/*e*/,/*f*/x/*g*/]" "Right (NS (JSArrayLiteral [NS (JSElision []) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"],NS (JSIdentifier \"x\") (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"],NS (JSElision []) (TokenPn 18 1 19) [CommentA (TokenPn 18 1 19) \"/*d*/\"],NS (JSElision []) (TokenPn 24 1 25) [CommentA (TokenPn 24 1 25) \"/*e*/\"],NS (JSIdentifier \"x\") (TokenPn 30 1 31) [CommentA (TokenPn 30 1 31) \"/*f*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 36 1 37) \"/*g*/\"])")
+    , testCase "ArrayLiteral7"     (testPEC "/*a*/[/*b*/x/*c*/]"     "Right (NS (JSArrayLiteral [NS (JSIdentifier \"x\") (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 12 1 13) \"/*c*/\"])")
+    , testCase "ArrayLiteral8"     (testPEC "/*a*/[/*b*/x/*c*/,/*d*/]"    "Right (NS (JSArrayLiteral [NS (JSIdentifier \"x\") (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"],NS (JSLiteral \",\") (TokenPn 17 1 18) [CommentA (TokenPn 12 1 13) \"/*c*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 18 1 19) \"/*d*/\"])")
+
+    , testCase "ObjectLiteral1"    (testPEC "/*a*/{/*b*/}"       "Right (NS (JSObjectLiteral []) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 6 1 7) \"/*b*/\"])")
+    , testCase "ObjectLiteral2"    (testPEC "/*a*/{/*b*/x/*c*/:/*d*/1/*e*/}"    "Right (NS (JSObjectLiteral [NS (JSPropertyNameandValue (NS (JSIdentifier \"x\") (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]) [NS (JSDecimal \"1\") (TokenPn 18 1 19) [CommentA (TokenPn 18 1 19) \"/*d*/\"]]) (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 24 1 25) \"/*e*/\"])")
+    , testCase "ObjectLiteral3"    (testPEC "/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/}"     "Right (NS (JSObjectLiteral [NS (JSPropertyNameandValue (NS (JSIdentifier \"x\") (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]) [NS (JSDecimal \"1\") (TokenPn 18 1 19) [CommentA (TokenPn 18 1 19) \"/*d*/\"]]) (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"],NS (JSPropertyNameandValue (NS (JSIdentifier \"y\") (TokenPn 30 1 31) [CommentA (TokenPn 30 1 31) \"/*f*/\"]) [NS (JSDecimal \"2\") (TokenPn 42 1 43) [CommentA (TokenPn 42 1 43) \"/*h*/\"]]) (TokenPn 36 1 37) [CommentA (TokenPn 24 1 25) \"/*e*/\",CommentA (TokenPn 36 1 37) \"/*g*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 48 1 49) \"/*i*/\"])")
+
+    , testCase "ObjectLiteral5"    (testPEC "/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/}"    "Right (NS (JSObjectLiteral [NS (JSPropertyNameandValue (NS (JSIdentifier \"x\") (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]) [NS (JSDecimal \"1\") (TokenPn 18 1 19) [CommentA (TokenPn 18 1 19) \"/*d*/\"]]) (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"],NS (JSLiteral \",\") (TokenPn 29 1 30) [CommentA (TokenPn 24 1 25) \"/*e*/\"]]) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 30 1 31) \"/*f*/\"])")
+
+    -- Edition 5 extensions
+    , testCase "ObjectLiteral7"    (testProgC "/*a*/x/*b*/=/*c*/{/*d*/get/*e*/ foo/*f*/(/*g*/)/*h*/ {/*i*/return/*j*/ 1/*k*/}/*l*/,/*m*/set/*n*/ foo/*o*/(/*p*/a/*q*/) /*r*/{/*s*/x/*t*/=/*u*/a/*v*/}/*w*/}"  "Right (NS (JSSourceElementsTop [NS (JSExpression [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"],NS (JSOperator \"=\") (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"],NS (JSObjectLiteral [NS (JSPropertyAccessor \"get\" (NS (JSIdentifier \"foo\") (TokenPn 26 1 27) [CommentA (TokenPn 26 1 27) \"/*e*/\"]) [] (NS (JSFunctionBody [NS (JSSourceElements [NS (JSReturn [NS (JSExpression [NS (JSDecimal \"1\") (TokenPn 65 1 66) [CommentA (TokenPn 65 1 66) \"/*j*/\"]]) (TokenPn 65 1 66) [],NS (JSLiteral \"\") (TokenPn 0 0 0) []]) (TokenPn 54 1 55) [CommentA (TokenPn 54 1 55) \"/*i*/\"]]) (TokenPn 54 1 55) []]) (TokenPn 54 1 55) [])) (TokenPn 18 1 19) [CommentA (TokenPn 18 1 19) \"/*d*/\",CommentA (TokenPn 35 1 36) \"/*f*/\",CommentA (TokenPn 41 1 42) \"/*g*/\",CommentA (TokenPn 47 1 48) \"/*h*/\",CommentA (TokenPn 72 1 73) \"/*k*/\"],NS (JSPropertyAccessor \"set\" (NS (JSIdentifier \"foo\") (TokenPn 92 1 93) [CommentA (TokenPn 92 1 93) \"/*n*/\"]) [NS (JSIdentifier \"a\") (TokenPn 107 1 108) [CommentA (TokenPn 107 1 108) \"/*p*/\"]] (NS (JSFunctionBody [NS (JSSourceElements [NS (JSExpression [NS (JSIdentifier \"x\") (TokenPn 126 1 127) [CommentA (TokenPn 126 1 127) \"/*s*/\"],NS (JSOperator \"=\") (TokenPn 132 1 133) [CommentA (TokenPn 132 1 133) \"/*t*/\"],NS (JSIdentifier \"a\") (TokenPn 138 1 139) [CommentA (TokenPn 138 1 139) \"/*u*/\"]]) (TokenPn 126 1 127) []]) (TokenPn 126 1 127) []]) (TokenPn 126 1 127) [])) (TokenPn 84 1 85) [CommentA (TokenPn 78 1 79) \"/*l*/\",CommentA (TokenPn 84 1 85) \"/*m*/\",CommentA (TokenPn 101 1 102) \"/*o*/\",CommentA (TokenPn 113 1 114) \"/*q*/\",CommentA (TokenPn 120 1 121) \"/*r*/\",CommentA (TokenPn 144 1 145) \"/*v*/\"]]) (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\",CommentA (TokenPn 150 1 151) \"/*w*/\"]]) (TokenPn 0 1 1) []]) (TokenPn 0 1 1) [])")
+
+    , testCase "ExpressionParen"   (testPEC "/*a*/(/*b*/56/*c*/)"     "Right (NS (JSExpressionParen (NS (JSExpression [NS (JSDecimal \"56\") (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])) (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\",CommentA (TokenPn 13 1 14) \"/*c*/\"])")
+
+    , testCase "Statement1"        (testStmtC "/*a*/x"        "Right (NS (JSExpression [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]]) (TokenPn 0 1 1) [])")
+
+    , testCase "Statement2"        (testStmtC "/*a*/null"     "Right (NS (JSExpression [NS (JSLiteral \"null\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]]) (TokenPn 0 1 1) [])")
+
+    , testCase "Statement3"        (testStmtC "/*a*/true/*b*/?/*c*/1/*d*/:/*e*/2" "Right (NS (JSExpression [NS (JSExpressionTernary [NS (JSLiteral \"true\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSDecimal \"1\") (TokenPn 15 1 16) [CommentA (TokenPn 15 1 16) \"/*c*/\"]] [NS (JSDecimal \"2\") (TokenPn 27 1 28) [CommentA (TokenPn 27 1 28) \"/*e*/\"]]) (TokenPn 9 1 10) [CommentA (TokenPn 9 1 10) \"/*b*/\",CommentA (TokenPn 21 1 22) \"/*d*/\"]]) (TokenPn 9 1 10) [])")
+
+    , testCase "Statement4"        (testStmtC "/*a*/x/*b*/||/*c*/y"    "Right (NS (JSExpression [NS (JSExpressionBinary \"||\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 13 1 14) [CommentA (TokenPn 13 1 14) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement5"        (testStmtC "/*a*/x/*b*/&&/*c*/y"    "Right (NS (JSExpression [NS (JSExpressionBinary \"&&\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 13 1 14) [CommentA (TokenPn 13 1 14) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement6a"       (testStmtC "/*a*/x/*b*/|/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \"|\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement6b"       (testStmtC "/*a*/x/*b*/^/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \"^\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement7"        (testStmtC "/*a*/x/*b*/&/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \"&\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement8"        (testStmtC "/*a*/x/*b*/==/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \"==\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 13 1 14) [CommentA (TokenPn 13 1 14) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement9"        (testStmtC "/*a*/x/*b*/!=/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \"!=\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 13 1 14) [CommentA (TokenPn 13 1 14) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement10"       (testStmtC "/*a*/x/*b*/===/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \"===\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 14 1 15) [CommentA (TokenPn 14 1 15) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement11"       (testStmtC "/*a*/x/*b*/!==/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \"!==\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 14 1 15) [CommentA (TokenPn 14 1 15) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement12a"       (testStmtC "/*a*/x/*b*/</*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \"<\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement12b"       (testStmtC "/*a*/x/*b*/>/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \">\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 12 1 13) [CommentA (TokenPn 12 1 13) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement12c"       (testStmtC "/*a*/x/*b*/<=/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \"<=\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 13 1 14) [CommentA (TokenPn 13 1 14) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement12d"       (testStmtC "/*a*/x/*b*/>=/*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \">=\" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 13 1 14) [CommentA (TokenPn 13 1 14) \"/*c*/\"]]) (TokenPn 6 1 7) [CommentA (TokenPn 6 1 7) \"/*b*/\"]]) (TokenPn 6 1 7) [])")
+
+    , testCase "Statement12e"       (testStmtC "/*a*/x /*b*/instanceof /*c*/y"     "Right (NS (JSExpression [NS (JSExpressionBinary \" instanceof \" [NS (JSIdentifier \"x\") (TokenPn 0 1 1) [CommentA (TokenPn 0 1 1) \"/*a*/\"]] [NS (JSIdentifier \"y\") (TokenPn 23 1 24) [CommentA (TokenPn 23 1 24) \"/*c*/\"]]) (TokenPn 7 1 8) [CommentA (TokenPn 7 1 8) \"/*b*/\"]]) (TokenPn 7 1 8) [])")
+
+    ]
+
+-- ---------------------------------------------------------------------
+
+commentPrintSuite :: Test
+commentPrintSuite = testGroup "Comments"
+    [
+      testCase "Multi-comment"     (testRoundTrip "/*a*/\n//foo\nnull")
+
+
+    , testCase "LiteralNull"       (testRoundTrip "/*a*/null")
+    , testCase "LiteralFalse"      (testRoundTrip "/*b*/false")
+    , testCase "LiteralTrue"       (testRoundTrip "true")
+    , testCase "LiteralTrue"       (testRoundTrip "/*c*/true")
+
+    , testCase "LiteralHexInteger" (testRoundTrip "/*d*/0x1234fF")
+    , testCase "LiteralDecimal"    (testRoundTrip "/*e*/1.0e4")
+    , testCase "LiteralOctal"      (testRoundTrip "/*x*/011")
+    , testCase "LiteralString1"    (testRoundTrip "/*f*/\"hello\\nworld\"")
+    , testCase "LiteralString2"    (testRoundTrip "/*g*/'hello\\nworld'")
+
+
+    , testCase "LiteralThis"       (testRoundTrip "/*h*/this")
+
+    , testCase "LiteralRegex1"     (testRoundTrip "/*i*//blah/")
+
+    , testCase "Identifier2"       (testRoundTrip "//j\nthis_")
+
+    , testCase "ArrayLiteral1"     (testRoundTrip "/*a*/[/*b*/]")
+    , testCase "ArrayLiteral2"     (testRoundTrip "/*a*/[/*b*/,/*c*/]")
+    , testCase "ArrayLiteral3"     (testRoundTrip "/*a*/[/*b*/,/*c*/,/*d*/]")
+    , testCase "ArrayLiteral4"     (testRoundTrip "/*a*/[/*b/*,/*c*/,/*d*/x/*e*/]")
+    , testCase "ArrayLiteral5"     (testRoundTrip "/*a*/[/*b*/,/*c*/,/*d*/x/*e*/]")
+    , testCase "ArrayLiteral6"     (testRoundTrip "/*a*/[/*b*/,/*c*/x/*d*/,/*e*/,/*f*/x/*g*/]")
+    , testCase "ArrayLiteral7"     (testRoundTrip "/*a*/[/*b*/x/*c*/]")
+    , testCase "ArrayLiteral8"     (testRoundTrip "/*a*/[/*b*/x/*c*/,/*d*/]")
+
+    , testCase "ObjectLiteral1"    (testRoundTrip "/*a*/{/*b*/}")
+    , testCase "ObjectLiteral2"    (testRoundTrip "/*a*/{/*b*/x/*c*/:/*d*/1/*e*/}")
+    , testCase "ObjectLiteral3"    (testRoundTrip "x=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/}")
+    , testCase "ObjectLiteral3a"   (testRoundTrip "x=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/,/*j*/z/*k*/:/*l*/3/*m*/}")
+
+    , testCase "ObjectLiteral5"    (testRoundTrip "a=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/}")
+
+    -- Edition 5 extensions
+    , testCase "ObjectLiteral7"    (testRoundTrip "/*a*/x/*b*/=/*c*/{/*d*/get/*e*/ foo/*f*/(/*g*/)/*h*/ {/*i*/return/*j*/ 1/*k*/}/*l*/,/*m*/set/*n*/ foo/*o*/(/*p*/a/*q*/) /*r*/{/*s*/x/*t*/=/*u*/a/*v*/}/*w*/}")
+
+    , testCase "ExpressionParen"   (testRoundTrip "/*a*/(/*b*/56/*c*/)")
+
+    , testCase "Statement1"        (testRoundTrip "/*a*/x")
+
+    , testCase "Statement2"        (testRoundTrip "/*a*/null")
+
+    , testCase "Statement3"        (testRoundTrip "/*a*/true/*b*/?/*c*/1/*d*/:/*e*/2")
+
+    , testCase "Statement4"        (testRoundTrip "/*a*/x/*b*/||/*c*/y")
+
+    , testCase "Statement5"        (testRoundTrip "/*a*/x/*b*/&&/*c*/y")
+
+    , testCase "Statement6a"       (testRoundTrip "/*a*/x/*b*/|/*c*/y")
+
+    , testCase "Statement6b"       (testRoundTrip "/*a*/x/*b*/^/*c*/y")
+
+    , testCase "Statement7"        (testRoundTrip "/*a*/x/*b*/&/*c*/y")
+
+    , testCase "Statement8"        (testRoundTrip "/*a*/x/*b*/==/*c*/y")
+
+    , testCase "Statement9"        (testRoundTrip "/*a*/x/*b*/!=/*c*/y")
+
+    , testCase "Statement10"       (testRoundTrip "/*a*/x/*b*/===/*c*/y")
+
+    , testCase "Statement11"       (testRoundTrip "/*a*/x/*b*/!==/*c*/y")
+
+    , testCase "Statement12a"       (testRoundTrip "/*a*/x/*b*/</*c*/y")
+
+    , testCase "Statement12b"       (testRoundTrip "/*a*/x/*b*/>/*c*/y")
+
+    , testCase "Statement12c"       (testRoundTrip "/*a*/x/*b*/<=/*c*/y")
+
+    , testCase "Statement12d"       (testRoundTrip "/*a*/x/*b*/>=/*c*/y")
+
+    , testCase "Statement12e"       (testRoundTrip "/*a*/x /*b*/instanceof /*c*/y")
+
+
+
+    , testCase "Statement13"       (testRoundTrip "x<<y")
+    , testCase "Statement13"       (testRoundTrip "x>>y")
+    , testCase "Statement13"       (testRoundTrip "x>>>y")
+
+    , testCase "Statement14"       (testRoundTrip "x+y")
+    , testCase "Statement14"       (testRoundTrip "x-y")
+
+    , testCase "Statement15"       (testRoundTrip "x*y")
+    , testCase "Statement16"       (testRoundTrip "x/y")
+    , testCase "Statement17"       (testRoundTrip "x%y")
+
+    , testCase "Statement18"       (testRoundTrip "delete y")
+    , testCase "Statement19"       (testRoundTrip "void y")
+    , testCase "Statement20"       (testRoundTrip "typeof y")
+    , testCase "Statement21"       (testRoundTrip "++y")
+    , testCase "Statement22"       (testRoundTrip "--y")
+    , testCase "Statement23"       (testRoundTrip "+y")
+    , testCase "Statement24"       (testRoundTrip "-y")
+    , testCase "Statement25"       (testRoundTrip "~y")
+    , testCase "Statement26"       (testRoundTrip "!y")
+
+    , testCase "Statement27"       (testRoundTrip "y++")
+    , testCase "Statement28"       (testRoundTrip "y--")
+
+      -- Member Expressions
+    , testCase "MemberExpression1a" (testRoundTrip "function(){}")
+    , testCase "MemberExpression1b" (testRoundTrip "function(a){}")
+    , testCase "MemberExpression1c" (testRoundTrip "function(a,b){}")
+
+    , testCase "MemberExpression1d" (testRoundTrip "x[y]")
+    , testCase "MemberExpression1e" (testRoundTrip "x[y][z]")
+    , testCase "MemberExpression1f" (testRoundTrip "x.y")
+    , testCase "MemberExpression1g" (testRoundTrip "x.y.z")
+
+    , testCase "MemberExpression1h" (testRoundTrip "new x()")
+
+    , testCase "NewExpression1" (testRoundTrip "new x.y")
+
+    , testCase "CallExpression1" (testRoundTrip "x()")
+    , testCase "CallExpression2" (testRoundTrip "x()()")
+    , testCase "CallExpression3" (testRoundTrip "x()[4]")
+    , testCase "CallExpression4" (testRoundTrip "x().x")
+    , testCase "CallExpression5" (testRoundTrip "x(a,b=2).x")
+
+    , testCase "AssignExpression1" (testRoundTrip "x=1")
+    , testCase "AssignExpression1" (testRoundTrip "x*=1")
+    , testCase "AssignExpression1" (testRoundTrip "x/=1")
+    , testCase "AssignExpression1" (testRoundTrip "x%=1")
+    , testCase "AssignExpression1" (testRoundTrip "x+=1")
+    , testCase "AssignExpression1" (testRoundTrip "x-=1")
+    , testCase "AssignExpression1" (testRoundTrip "x<<=1")
+    , testCase "AssignExpression1" (testRoundTrip "x>>=1")
+    , testCase "AssignExpression1" (testRoundTrip "x>>>=1")
+    , testCase "AssignExpression1" (testRoundTrip "x&=1")
+    , testCase "AssignExpression1" (testRoundTrip "x^=1")
+    , testCase "AssignExpression1" (testRoundTrip "x|=1")
+
+
+    , testCase "Block1" (testRoundTrip "{}")
+    , testCase "Block2" (testRoundTrip "{x=1}")
+    , testCase "Block3" (testRoundTrip "{x=1;y=2}")
+    , testCase "Block4" (testRoundTrip "{{}}")
+    , testCase "Block5" (testRoundTrip "{{{}}}")
+
+
+    , testCase "If1" (testRoundTrip "if (1) {}")
+
+    , testCase "IfElse1" (testRoundTrip "if (1) {} else {}")
+    , testCase "IfElse2" (testRoundTrip "if (1) x=1; else {}")
+
+    , testCase "DoWhile1" (testRoundTrip "do {x=1} while (true);")
+    , testCase "While1"   (testRoundTrip "while(true);")
+
+    , testCase "For1"   (testRoundTrip "for(;;);")
+    , testCase "For2"   (testRoundTrip "for(x=1;x<10;x++);")
+
+    , testCase "ForVar1"   (testRoundTrip "for(var x;;);")
+    , testCase "ForVar2"   (testRoundTrip "for(var x=1;;);")
+    , testCase "ForVar2"   (testRoundTrip "for(var x;y;z){}")
+
+    , testCase "ForIn1"   (testRoundTrip "for(x in 5){}")
+
+    , testCase "ForVarIn1" (testRoundTrip "for(var x in 5){}")
+
+    , testCase "Var1" (testRoundTrip "var x=1;")
+    , testCase "Var2" (testRoundTrip "const x=1,y=2;")
+
+
+    , testCase "Continue1" (testRoundTrip "continue;")
+    , testCase "Continue2" (testRoundTrip "continue x;")
+
+    , testCase "Break1" (testRoundTrip "break;")
+    , testCase "Break2" (testRoundTrip "break x;")
+
+    , testCase "Return1" (testRoundTrip "return;")
+    , testCase "Return2" (testRoundTrip "return x;")
+
+    , testCase "With1" (testRoundTrip "with (x) {};")
+
+    , testCase "Labelled1" (testRoundTrip "abc:x=1")
+
+    , testCase "Switch1" (testRoundTrip "switch (x) {}")
+    , testCase "Switch2" (testRoundTrip "switch (x) {case 1:break;}")
+    , testCase "Switch3" (testRoundTrip "switch (x) {case 0:\ncase 1:break;}")
+    , testCase "Switch4" (testRoundTrip "switch (x) {default:break;}")
+    , testCase "Switch5" (testRoundTrip "switch (x) {default:\ncase 1:break;}")
+
+    , testCase "Throw1" (testRoundTrip "throw 1")
+
+    , testCase "Try1" (testRoundTrip "try{}catch(a){}")
+    , testCase "Try2" (testRoundTrip "try{}finally{}")
+    , testCase "Try3" (testRoundTrip "try{}catch(a){}finally{}")
+
+    , testCase "Try4" (testRoundTrip "try{}catch(a){}catch(b){}finally{}")
+    , testCase "Try5" (testRoundTrip "try{}catch(a){}catch(b){}")
+    , testCase "Try6" (testRoundTrip "try{}catch(a if true){}catch(b){}")
+
+    , testCase "Function1" (testRoundTrip "function a(){}")
+    , testCase "Function2" (testRoundTrip "function a(b,c){}")
+
+
+    , testCase "Comment1" (testRoundTrip "//blah\nx=1;//foo\na")
+
+    , testCase "Comment2" (testRoundTrip "/*x=1\ny=2\n*/z=2;//foo\na")
+
+    , testCase "min_100_animals1" (testRoundTrip "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\"")
+
+    , testCase "min_100_animals2" (testRoundTrip "Animal=function(){return this.name};")
+
+    , testCase "min_100_animals3" (testRoundTrip "if(a)x=1;y=2")
+
+    , testCase "min_100_animals4" (testRoundTrip "if(a)x=a()y=2")
+
+    , testCase "05_regex"  (testRoundTrip "newlines=spaces.match(/\\n/g)")
+
+    , testCase "05_regex2" (testRoundTrip "x=/\\n/g")
+
+    , testCase "05_regex3" (testRoundTrip "x=i(/[?|^&(){}\\[\\]+\\-*\\/\\.]/g,\"\\\\$&\")")
+
+    , testCase "05_regex4" (testRoundTrip "x=i(/^$/g,\"\\\\$&\")")
+
+   , testCase "05_regex5" (testRoundTrip "if(/^[a-z]/.test(t)){consts+=t.toUpperCase();keywords[t]=i}else consts+=(/^\\W/.test(t)?opTypeNames[t]:t);")
+
+   , testCase "if_semi" (testRoundTrip "if(x);x=1")
+
+   , testCase "67_bob" (testRoundTrip "(match = /^\"(?:\\\\.|[^\"])*\"|^'(?:[^']|\\\\.)*'/(input))")
+
+   , testCase "122_jsexec" (testRoundTrip "v = getValue(execute(n[0], x)) in getValue(execute(n[1], x));")
+
+   , testCase "bug1a" (testRoundTrip "/* */\nfunction f() {\n/*  */\n}")
+   , testCase "bug1b" (testRoundTrip "/* **/\nfunction f() {\n/*  */\n}")
+
+   , testCase "unicode1-ws" (testRoundTrip "a \f\v\t\r\n=\x00a0\x1680\x180e\x2000\x2001\x2002\x2003\x2004\x2005\x2006\x2007\x2008\x2009\x200a\x2028\x2029\x202f\x205f\x3000\&1;")
+
+   , testCase "unicode2-lt" (testRoundTrip "//comment\x000Ax=1;")
+   , testCase "unicode3-lt" (testRoundTrip "//comment\x000Dx=1;")
+   , testCase "unicode4-lt" (testRoundTrip "//comment\x2028x=1;")
+   , testCase "unicode5-lt" (testRoundTrip "//comment\x2029x=1;")
+
+   , testCase "unicode2" (testRoundTrip "àáâãäå = 1;")
+
+   , testCase "unicode3" (testRoundTrip "$aà = 1;_b=2;\0065a=2")
+
+   , testCase "unicode4" (testRoundTrip "x=\"àáâãäå\";y='\3012a\0068'")
+
+   -- , testCase "unicode5" (testFile "./test/Unicode.js")
+
+   , testCase "bug2.a" (testRoundTrip "function() {\nz = function /*z*/(o) {\nreturn r;\n};}")
+
+   , testCase "bug2.b" (testRoundTrip "function() {\nz = function z(o) {\nreturn r;\n};}")
+
+   -- https://github.com/alanz/hjsmin/issues/#issue/3
+   , testCase "bug3" (testRoundTrip "var myLatlng = new google.maps.LatLng(56.8379100, 60.5806664);")
+
+   -- https://github.com/alanz/hjsmin/issues/#issue/4
+   , testCase "bug4" (testRoundTrip "/* * geolocation. пытаемся определить свое местоположение * если не получается то используем defaultLocation * @Param {object} map экземпляр карты * @Param {object LatLng} defaultLocation Координаты центра по умолчанию * @Param {function} callbackAfterLocation Фу-ия которая вызывается после * геолокации. Т.к запрос геолокации асинхронен */x")
+
+   , testCase "02_sm.js"   (testRoundTrip "{zero}\none1;two\n{three\nfour;five;\n{\nsix;{seven;}\n}\n}")
+
+   , testCase "02_sm.js.2" (testRoundTrip "{zero}\nget;two\n{three\nfour;set;\n{\nsix;{seven;}\n}\n}")
+
+   , testCase "loc1" (testRoundTrip "x = 1\n  y=2;")
+
+   -- https://github.com/alanz/language-javascript/issues/2
+   , testCase "issue2" (testRoundTrip "var img = document.createElement('img');\nimg.src = \"mylogo.jpg\";\n$(img).click(function() {\n   alert('clicked!');\n});")
+
+
+   -- Working in ECMASCRIPT 5.1 changes
+   , testCase "lineTerminatorInString1" (testRoundTrip "x='abc\\\ndef';")
+   , testCase "lineTerminatorInString2" (testRoundTrip "x=\"abc\\\ndef\";")
+   , testCase "lineTerminatorInString3" (testRoundTrip "x=\"abc\\\rdef\";")
+   , testCase "lineTerminatorInString4" (testRoundTrip "x=\"abc\\\x2028 def\";")
+   , testCase "lineTerminatorInString5" (testRoundTrip "x=\"abc\\\x2029 def\";")
+   , testCase "lineTerminatorInString6" (testRoundTrip "x=\"abc\\\r\ndef\";")
+
+
+     -- https://github.com/alanz/language-javascript/issues/4
+   , testCase "issue4ok"   (testRoundTrip "var k = {\ny: somename\n}")
+   , testCase "issue4bug1" (testRoundTrip "var k = {\ny: code\n}")
+   , testCase "issue4bug2" (testRoundTrip "var k = {\ny: mode\n}")
+
+     -- https://github.com/alanz/language-javascript/issues/5
+   , testCase "issue5bug1" (testRoundTrip "x = { y: 1e8 }")
+   , testCase "issue5ok2" (testRoundTrip "{ y: 1e8 }")
+   , testCase "issue5ok3" (testRoundTrip "{ y: 18 }")
+   , testCase "issue5ok4" (testRoundTrip "x = { y: 18 }")
+
+   -- function body
+   , testCase "functionbody"        (testRoundTrip "function foo(a,b,c)\n{x=1;}")
+   , testCase "functionexpression" (testRoundTrip "function foo(a,b,c)\n{x=1;}")
+
+   , testCase "fn1" (testRoundTrip "function foo() { return 5; }")
+   , testCase "fn2" (testRoundTrip "var foo = function() { return 5; }")
+   , testCase "fn3" (testRoundTrip "var foo = function foo() { return 5; }")
+
+   -- Parse failure in hjsmin
+   , testCase "parsefail" (testRoundTrip "switch(t){case DIV:         v = u / v; break;}")
+
+   -- https://github.com/alanz/language-javascript/issues/14
+   , testCase "issue14" (testRoundTrip "var z = x[i] / y;")
+
+   -- https://github.com/alanz/language-javascript/issues/15
+   , testCase "issue15" (testRoundTrip "x\t=1;")
+
+   , testCase "comment-only" (testRoundTrip "// comment\n\n")
+   , testCase "empty-src" (testRoundTrip "")
+   ]
+
+-- ---------------------------------------------------------------------
+-- Test utilities
+
+testRoundTrip str = str @=? (renderToString $ readJs str)
+
+testLiteral :: String -> String -> Assertion
+testLiteral  literal expected = expected @=? (showStrippedMaybe $ parseUsing parseLiteral literal "src")
+testLiteralC :: String -> String -> Assertion
+testLiteralC literal expected = expected @=? (show              $ parseUsing parseLiteral literal "src")
+
+
+testPE :: String -> String -> Assertion
+testPE  str expected = expected @=? (showStrippedMaybe $ parseUsing parsePrimaryExpression str "src")
+testPEC :: String -> String -> Assertion
+testPEC str expected = expected @=? (show              $ parseUsing parsePrimaryExpression str "src")
+
+testStmt :: String -> String -> Assertion
+testStmt  str expected = expected @=? (showStrippedMaybe $ parseUsing parseStatement str "src")
+testStmtC :: String -> String -> Assertion
+testStmtC str expected = expected @=? (show              $ parseUsing parseStatement str "src")
+
+--testProg str expected = expected @=? (show $ parseUsing parseProgram str "src")
+testProg :: String -> String -> Assertion
+testProg  str expected = expected @=? (showStrippedMaybe $ parseUsing parseProgram str "src")
+testProgC :: String -> String -> Assertion
+testProgC str expected = expected @=? (show              $ parseUsing parseProgram str "src")
+
+testProgUn :: String -> String -> Assertion
+testProgUn str expected = expected @=? (show $ parseUsing parseProgram str "src")
+
+
+testFile :: FilePath -> String -> IO ()
+testFile fileName expected = do
+  res <- parseFile fileName
+  -- expected @=? (liftM show $ parseFile fileName)
+  (expected @=? (showStripped res))
+
+testFileUtf8 :: FilePath -> String -> IO ()
+testFileUtf8 fileName expected = do
+  res <- parseFileUtf8 fileName
+  -- expected @=? (liftM show $ parseFile fileName)
+  (expected @=? (showStripped res))
+
+
+-- Set emacs mode
+-- Local Variables:
+-- coding: utf-8
+-- End:
+
+-- EOF
diff --git a/src/Language/JavaScript/Parser.hs b/src/Language/JavaScript/Parser.hs
new file mode 100644 (file)
index 0000000..974edc1
--- /dev/null
@@ -0,0 +1,32 @@
+module Language.JavaScript.Parser
+       (
+         PA.parse
+       , PA.readJs
+       , PA.parseFile
+       , PA.parseFileUtf8
+       , PA.showStripped
+       , PA.showStrippedMaybe
+       , JSNode(..)
+       , Node(..)
+       , CommentAnnotation(..)
+       -- , ParseError(..)
+       -- Source locations
+       , TokenPosn(..)
+       , tokenPosnEmpty
+       -- * Pretty Printing
+       , renderJS
+       , renderToString
+       ) where
+
+
+import Language.JavaScript.Parser.AST
+import Language.JavaScript.Parser.ParseError
+import Language.JavaScript.Parser.Token
+import qualified Language.JavaScript.Parser.Parser as PA
+--import Language.JavaScript.Parser.ParserMonad
+import Language.JavaScript.Parser.SrcLocation
+import Language.JavaScript.Pretty.Printer
+
+-- EOF
+
+
diff --git a/src/Language/JavaScript/Parser/AST.hs b/src/Language/JavaScript/Parser/AST.hs
new file mode 100644 (file)
index 0000000..4b2a48f
--- /dev/null
@@ -0,0 +1,152 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+module Language.JavaScript.Parser.AST
+       (
+           Node (..)
+         , JSNode(..)
+         -- , TokenPosn (..)
+         , showStripped
+       ) where
+
+import Data.Data
+import Data.List
+import Language.JavaScript.Parser.SrcLocation (TokenPosn(..))
+import Language.JavaScript.Parser.Token
+
+-- ---------------------------------------------------------------------
+
+-- |The JSNode is the building block of the AST.
+-- Each has a syntactic part 'Node'. In addition, the leaf elements
+-- (terminals) have a position 'TokenPosn', as well as an array of comments
+-- and/or whitespace that was collected while parsing.
+
+data JSNode = NN Node -- ^Non Terminal node, does not have any position or comment information
+            | NT Node TokenPosn [CommentAnnotation] -- ^Terminal node, including position and comment/whitespace information
+    deriving (Show, Eq, Read, Data, Typeable)
+
+data Node =
+              -- | Terminals
+                JSIdentifier String
+              | JSDecimal String
+              | JSLiteral String
+              | JSHexInteger String
+              | JSOctal String
+              | JSStringLiteral Char [Char]
+              | JSRegEx String
+
+              -- | Non Terminals
+
+              | JSArguments JSNode [JSNode] JSNode    -- ^lb, args, rb
+              | JSArrayLiteral JSNode [JSNode] JSNode -- ^lb, contents, rb
+              | JSBlock [JSNode] [JSNode] [JSNode]      -- ^optional lb,optional block statements,optional rb
+              | JSBreak JSNode [JSNode] JSNode        -- ^break, optional identifier, autosemi
+              | JSCallExpression String [JSNode] [JSNode] [JSNode]  -- ^type : ., (), []; opening [ or ., contents, closing
+              | JSCase JSNode JSNode JSNode [JSNode]    -- ^case,expr,colon,stmtlist
+              | JSCatch JSNode JSNode JSNode [JSNode] JSNode JSNode -- ^ catch,lb,ident,[if,expr],rb,block
+              | JSContinue JSNode [JSNode] JSNode     -- ^continue,optional identifier,autosemi
+              | JSDefault JSNode JSNode [JSNode] -- ^default,colon,stmtlist
+              | JSDoWhile JSNode JSNode JSNode JSNode JSNode JSNode JSNode -- ^do,stmt,while,lb,expr,rb,autosemi
+              | JSElision JSNode               -- ^comma
+              | JSExpression [JSNode]          -- ^expression components
+              | JSExpressionBinary String [JSNode] JSNode [JSNode] -- ^what, lhs, op, rhs
+              | JSExpressionParen JSNode JSNode JSNode -- ^lb,expression,rb
+              | JSExpressionPostfix String [JSNode] JSNode -- ^type, expression, operator
+              | JSExpressionTernary [JSNode] JSNode [JSNode] JSNode [JSNode] -- ^cond, ?, trueval, :, falseval
+              | JSFinally JSNode JSNode -- ^finally,block
+              | JSFor JSNode JSNode [JSNode] JSNode [JSNode] JSNode [JSNode] JSNode JSNode -- ^for,lb,expr,semi,expr,semi,expr,rb.stmt
+              | JSForIn JSNode JSNode [JSNode] JSNode JSNode JSNode JSNode -- ^for,lb,expr,in,expr,rb,stmt
+              | JSForVar JSNode JSNode JSNode [JSNode] JSNode [JSNode] JSNode [JSNode] JSNode JSNode -- ^for,lb,var,vardecl,semi,expr,semi,expr,rb,stmt
+              | JSForVarIn JSNode JSNode JSNode JSNode JSNode JSNode JSNode JSNode -- ^for,lb,var,vardecl,in,expr,rb,stmt
+              | JSFunction JSNode JSNode JSNode [JSNode] JSNode JSNode  -- ^fn,name, lb,parameter list,rb,block
+              -- | JSFunctionBody [JSNode] -- ^body
+              | JSFunctionExpression JSNode [JSNode] JSNode [JSNode] JSNode JSNode  -- ^fn,[name],lb, parameter list,rb,block`
+              | JSIf JSNode JSNode JSNode JSNode [JSNode] [JSNode] -- ^if,(,expr,),stmt,optional rest
+              | JSLabelled JSNode JSNode JSNode -- ^identifier,colon,stmt
+              | JSMemberDot [JSNode] JSNode JSNode -- ^firstpart, dot, name
+              | JSMemberSquare [JSNode] JSNode JSNode JSNode -- ^firstpart, lb, expr, rb
+              | JSObjectLiteral JSNode [JSNode] JSNode -- ^lbrace contents rbrace
+              | JSOperator JSNode -- ^opnode
+              | JSPropertyAccessor JSNode JSNode JSNode [JSNode] JSNode JSNode -- ^(get|set), name, lb, params, rb, block
+              | JSPropertyNameandValue JSNode JSNode [JSNode] -- ^name, colon, value
+              | JSReturn JSNode [JSNode] JSNode -- ^return,optional expression,autosemi
+              -- | JSSourceElements [JSNode] -- ^source elements
+              | JSSourceElementsTop [JSNode] -- ^source elements
+              -- | JSStatementBlock JSNode JSNode JSNode -- ^lb,block,rb
+              -- | JSStatementList [JSNode] -- ^statements
+              | JSSwitch JSNode JSNode JSNode JSNode JSNode -- ^switch,lb,expr,rb,caseblock
+              | JSThrow JSNode JSNode -- ^throw val
+              | JSTry JSNode JSNode [JSNode] -- ^try,block,rest
+              | JSUnary String JSNode -- ^type, operator
+              | JSVarDecl JSNode [JSNode] -- ^identifier, optional initializer
+              | JSVariables JSNode [JSNode] JSNode -- ^var|const, decl, autosemi
+              | JSWhile JSNode JSNode JSNode JSNode JSNode -- ^while,lb,expr,rb,stmt
+              | JSWith JSNode JSNode JSNode JSNode [JSNode] -- ^with,lb,expr,rb,stmt list
+    deriving (Show, Eq, Read, Data, Typeable)
+
+-- Strip out the location info, leaving the original JSNode text representation
+showStripped :: JSNode -> String
+showStripped = ss
+
+-- Alias for internal use
+ss :: JSNode -> String
+ss (NN node    ) = showStrippedNode node
+ss (NT node _ _) = showStrippedNode node
+
+sss :: [JSNode] -> String
+--sss xs = "[" ++ (concatMap ss xs) ++ "]"
+sss xs = "[" ++ (concat (intersperse "," $ map ss xs)) ++ "]"
+
+showStrippedNode :: Node -> String
+showStrippedNode (JSArguments _lb xs _rb) = "JSArguments " ++ sss xs
+showStrippedNode (JSArrayLiteral _lb xs _rb) = "JSArrayLiteral " ++ sss xs
+showStrippedNode (JSBlock _lb xs _rb) = "JSBlock (" ++ sss xs ++ ")"
+showStrippedNode (JSBreak _b x1s as) = "JSBreak " ++ sss x1s ++ " " ++ ss as
+showStrippedNode (JSCallExpression s _os xs _cs) = "JSCallExpression " ++ show s ++ " " ++ sss xs
+showStrippedNode (JSCase _ca x1 _c x2s) = "JSCase (" ++ ss x1 ++ ") (" ++ sss x2s ++ ")"
+showStrippedNode (JSCatch _c _lb x1 x2s _rb x3) = "JSCatch (" ++ ss x1 ++ ") " ++ sss x2s ++ " (" ++ ss x3 ++ ")"
+showStrippedNode (JSContinue _c xs as) = "JSContinue " ++ sss xs ++ " " ++ ss as
+showStrippedNode (JSDecimal s) = "JSDecimal " ++ show s
+showStrippedNode (JSDefault _d _c xs) = "JSDefault (" ++ sss xs ++ ")"
+showStrippedNode (JSDoWhile _d x1 _w _lb x2 _rb x3) = "JSDoWhile (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")"
+showStrippedNode (JSElision c) = "JSElision " ++ ss c
+showStrippedNode (JSExpression xs) = "JSExpression " ++ sss xs
+showStrippedNode (JSExpressionBinary s x2s _op x3s) = "JSExpressionBinary " ++ show s ++ " " ++ sss x2s ++ " " ++ sss x3s
+showStrippedNode (JSExpressionParen _lp x _rp) = "JSExpressionParen (" ++ ss x ++ ")"
+showStrippedNode (JSExpressionPostfix s xs _op) = "JSExpressionPostfix " ++ show s ++ " " ++ sss xs
+showStrippedNode (JSExpressionTernary x1s _q x2s _c x3s) = "JSExpressionTernary " ++ sss x1s ++ " " ++ sss x2s ++ " " ++ sss x3s
+showStrippedNode (JSFinally _f x) = "JSFinally (" ++ ss x ++ ")"
+showStrippedNode (JSFor _f _lb x1s _s1 x2s _s2 x3s _rb x4) = "JSFor " ++ sss x1s ++ " " ++ sss x2s ++ " " ++ sss x3s ++ " (" ++ ss x4 ++ ")"
+showStrippedNode (JSForIn _f _lb x1s _i x2 _rb x3) = "JSForIn " ++ sss x1s ++ " (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")"
+showStrippedNode (JSForVar _f _lb _v x1s _s1 x2s _s2 x3s _rb x4) = "JSForVar " ++ sss x1s ++ " " ++ sss x2s ++ " " ++ sss x3s ++ " (" ++ ss x4 ++ ")"
+showStrippedNode (JSForVarIn _f _lb _v x1 _i x2 _rb x3) = "JSForVarIn (" ++ ss x1 ++ ") (" ++ ss x2 ++ ") (" ++ ss x3 ++ ")"
+showStrippedNode (JSFunction _f x1 _lb x2s _rb x3) = "JSFunction (" ++ ss x1 ++ ") " ++ sss x2s ++ " (" ++ ss x3 ++ ")"
+--showStrippedNode (JSFunctionBody xs) = "JSFunctionBody " ++ sss xs
+showStrippedNode (JSFunctionExpression _f x1s _lb x2s _rb x3) = "JSFunctionExpression " ++ sss x1s ++ " " ++ sss x2s ++ " (" ++ ss x3 ++ ")"
+showStrippedNode (JSHexInteger s) = "JSHexInteger " ++ show s
+showStrippedNode (JSOctal s) = "JSOctal " ++ show s
+showStrippedNode (JSIdentifier s) = "JSIdentifier " ++ show s
+showStrippedNode (JSIf _i _lb x1 _rb x2s x3s) = "JSIf (" ++ ss x1 ++ ") (" ++ sss x2s ++ ") (" ++ sss x3s ++ ")"
+showStrippedNode (JSLabelled x1 _c x2) = "JSLabelled (" ++ ss x1 ++ ") (" ++ ss x2 ++ ")"
+showStrippedNode (JSLiteral s) = "JSLiteral " ++ show s
+showStrippedNode (JSMemberDot x1s _d x2 ) = "JSMemberDot " ++ sss x1s ++ " (" ++ ss x2 ++ ")"
+showStrippedNode (JSMemberSquare x1s _lb x2 _rb) = "JSMemberSquare " ++ sss x1s ++ " (" ++ ss x2 ++ ")"
+showStrippedNode (JSObjectLiteral _lb xs _rb) = "JSObjectLiteral " ++ sss xs
+showStrippedNode (JSOperator n) = "JSOperator " ++ ss n
+showStrippedNode (JSPropertyNameandValue x1 _colon x2s) = "JSPropertyNameandValue (" ++ ss x1 ++ ") " ++ sss x2s
+showStrippedNode (JSPropertyAccessor s x1 _lb1 x2s _rb1 x3) = "JSPropertyAccessor " ++ show s ++ " (" ++ ss x1 ++ ") " ++ sss x2s ++ " (" ++ ss x3 ++ ")"
+showStrippedNode (JSRegEx s) = "JSRegEx " ++ show s
+showStrippedNode (JSReturn _r xs as) = "JSReturn " ++ sss xs ++ " " ++ ss as
+--showStrippedNode (JSSourceElements xs) = "JSSourceElements " ++ sss xs
+showStrippedNode (JSSourceElementsTop xs) = "JSSourceElementsTop " ++ sss xs
+-- showStrippedNode (JSStatementBlock _lb x _rb) = "JSStatementBlock (" ++ ss x ++ ")"
+-- showStrippedNode (JSStatementList xs) = "JSStatementList " ++ sss xs
+showStrippedNode (JSStringLiteral c s) = "JSStringLiteral " ++ show c ++ " " ++ show s
+showStrippedNode (JSSwitch _s _lb x _rb x2) = "JSSwitch (" ++ ss x ++ ") " ++ ss x2
+showStrippedNode (JSThrow _t x) = "JSThrow (" ++ ss x ++ ")"
+showStrippedNode (JSTry _t x1 x2s) = "JSTry (" ++ ss x1 ++ ") " ++ sss x2s
+showStrippedNode (JSUnary s _x) = "JSUnary " ++ show s
+showStrippedNode (JSVarDecl x1 x2s) = "JSVarDecl (" ++ ss x1 ++ ") " ++ sss x2s
+showStrippedNode (JSVariables n xs _as) = "JSVariables " ++ ss n ++ " " ++ sss xs
+showStrippedNode (JSWhile _w _lb x1 _rb x2) = "JSWhile (" ++ ss x1 ++ ") (" ++ ss x2 ++ ")"
+showStrippedNode (JSWith _w _lb x1 _rb x2s) = "JSWith (" ++ ss x1 ++ ") " ++ sss x2s
+
+-- EOF
diff --git a/src/Language/JavaScript/Parser/Grammar5.y b/src/Language/JavaScript/Parser/Grammar5.y
new file mode 100644 (file)
index 0000000..f18ba92
--- /dev/null
@@ -0,0 +1,1187 @@
+{
+{-# LANGUAGE BangPatterns #-}
+module Language.JavaScript.Parser.Grammar5 (
+    parseProgram
+  , parseLiteral
+  , parsePrimaryExpression
+  , parseStatement
+  -- debug
+  , fp
+  ) where
+
+-- import Control.Monad.Error.Class (throwError)
+import Data.Char
+import Language.JavaScript.Parser.Lexer
+import Language.JavaScript.Parser.ParseError
+import Language.JavaScript.Parser.ParserMonad
+import Language.JavaScript.Parser.SrcLocation
+import Language.JavaScript.Parser.Token
+import qualified Language.JavaScript.Parser.AST as AST
+
+}
+
+-- The name of the generated function to be exported from the module
+%name parseProgram           Program
+%name parseLiteral           LiteralMain
+%name parsePrimaryExpression PrimaryExpressionMain
+%name parseStatement         StatementMain
+
+%tokentype { Token }
+%error { parseError }
+%monad { Alex } { >>= } { return }
+%lexer { lexCont } { EOFToken {} }
+
+
+%token
+
+     ';'       { SemiColonToken {} }
+     ','       { CommaToken {} }
+     '?'       { HookToken {} }
+     ':'       { ColonToken {} }
+     '||'      { OrToken {} }
+     '&&'      { AndToken {} }
+     '|'       { BitwiseOrToken {} }
+     '^'       { BitwiseXorToken {} }
+     '&'       { BitwiseAndToken {} }
+     '==='     { StrictEqToken {} }
+     '=='      { EqToken {} }
+     '='       { SimpleAssignToken {} }
+     '!=='     { StrictNeToken {} }
+     '!='      { NeToken {} }
+     '<<'      { LshToken {} }
+     '<='      { LeToken {} }
+     '<'       { LtToken {} }
+     '>>>'     { UrshToken {} }
+     '>>'      { RshToken {} }
+     '>='      { GeToken {} }
+     '>'       { GtToken {} }
+     '++'      { IncrementToken {} }
+     '--'      { DecrementToken {} }
+     '+'       { PlusToken {} }
+     '-'       { MinusToken {} }
+     '*'       { MulToken {} }
+     '/'       { DivToken {} }
+     '%'       { ModToken {} }
+     '!'       { NotToken {} }
+     '~'       { BitwiseNotToken {} }
+     '.'       { DotToken {} }
+     '['       { LeftBracketToken {} }
+     ']'       { RightBracketToken {} }
+     '{'       { LeftCurlyToken {} }
+     '}'       { RightCurlyToken {} }
+     '('       { LeftParenToken {} }
+     ')'       { RightParenToken {} }
+     '@*/'     { CondcommentEndToken {} }
+
+     'break'      { BreakToken {} }
+     'case'       { CaseToken {} }
+     'catch'      { CatchToken {} }
+     'const'      { ConstToken {} }
+     'continue'   { ContinueToken {} }
+     'debugger'   { DebuggerToken {} }
+     'default'    { DefaultToken {} }
+     'delete'     { DeleteToken {} }
+     'do'         { DoToken {} }
+     'else'       { ElseToken {} }
+     'enum'       { EnumToken {} }
+     'false'      { FalseToken {} }
+     'finally'    { FinallyToken {} }
+     'for'        { ForToken {} }
+     'function'   { FunctionToken {} }
+     'get'        { GetToken {} }
+     'if'         { IfToken {} }
+     'in'         { InToken {} }
+     'instanceof' { InstanceofToken {} }
+     'new'        { NewToken {} }
+     'null'       { NullToken {} }
+     'return'     { ReturnToken {} }
+     'set'        { SetToken {} }
+     'switch'     { SwitchToken {} }
+     'this'       { ThisToken {} }
+     'throw'      { ThrowToken {} }
+     'true'       { TrueToken {} }
+     'try'        { TryToken {} }
+     'typeof'     { TypeofToken {} }
+     'var'        { VarToken {} }
+     'void'       { VoidToken {} }
+     'while'      { WhileToken {} }
+     'with'       { WithToken {} }
+
+
+     'ident'      { IdentifierToken {} }
+     'decimal'    { DecimalToken {} }
+     'hexinteger' { HexIntegerToken {} }
+     'octal'      { OctalToken {} }
+     'string'     { StringToken {} }
+     'regex'      { RegExToken {} }
+     'assign'     { AssignToken {} }
+
+     'future'     { FutureToken {} }
+
+     'tail'       { TailToken {} }
+     'eof'        { EOFToken {} }
+
+
+%%
+
+-- ---------------------------------------------------------------------
+-- Sort out automatically inserted semi-colons
+
+AutoSemi :: { AST.JSNode }
+AutoSemi : ';' { AST.NT (AST.JSLiteral ";") (ss $1) (gc $1)}
+         |     { AST.NT (AST.JSLiteral "") tokenPosnEmpty []}
+
+-- ---------------------------------------------------------------------
+
+-- Helpers
+
+LParen :: { AST.JSNode }
+LParen : '(' { fp (AST.NT (AST.JSLiteral "(") (ss $1) (gc $1))}
+
+RParen :: { AST.JSNode }
+RParen : ')' { fp (AST.NT (AST.JSLiteral ")") (ss $1) (gc $1))}
+
+
+LBrace :: { AST.JSNode }
+LBrace : '{' { fp (AST.NT (AST.JSLiteral "{") (ss $1) (gc $1))}
+
+RBrace :: { AST.JSNode }
+RBrace : '}' { fp (AST.NT (AST.JSLiteral "}") (ss $1) (gc $1))}
+
+
+LSquare :: { AST.JSNode }
+LSquare : '[' { fp (AST.NT (AST.JSLiteral "[") (ss $1) (gc $1))}
+
+RSquare :: { AST.JSNode }
+RSquare : ']' { fp (AST.NT (AST.JSLiteral "]") (ss $1) (gc $1))}
+
+Comma :: { AST.JSNode }
+Comma : ',' { fp (AST.NT (AST.JSLiteral ",") (ss $1) (gc $1))}
+
+Colon :: { AST.JSNode }
+Colon : ':' { fp (AST.NT (AST.JSLiteral ":") (ss $1) (gc $1))}
+
+Semi :: { AST.JSNode }
+Semi : ';' { fp (AST.NT (AST.JSLiteral ";") (ss $1) (gc $1))}
+
+Dot :: { AST.JSNode }
+Dot : '.' { fp (AST.NT (AST.JSLiteral ".") (ss $1) (gc $1))}
+
+Increment :: { AST.JSNode }
+Increment : '++' { fp (AST.NT (AST.JSLiteral "++") (ss $1) (gc $1))}
+
+Decrement :: { AST.JSNode }
+Decrement : '--' { fp (AST.NT (AST.JSLiteral "--") (ss $1) (gc $1))}
+
+Delete :: { AST.JSNode }
+Delete : 'delete' { fp (AST.NT (AST.JSLiteral "delete") (ss $1) (gc $1))}
+
+Void :: { AST.JSNode }
+Void : 'void' { fp (AST.NT (AST.JSLiteral "void") (ss $1) (gc $1))}
+
+Typeof :: { AST.JSNode }
+Typeof : 'typeof' { fp (AST.NT (AST.JSLiteral "typeof") (ss $1) (gc $1))}
+
+Plus :: { AST.JSNode }
+Plus : '+' { fp (AST.NT (AST.JSLiteral "+") (ss $1) (gc $1))}
+
+Minus :: { AST.JSNode }
+Minus : '-' { fp (AST.NT (AST.JSLiteral "-") (ss $1) (gc $1))}
+
+Tilde :: { AST.JSNode }
+Tilde : '~' { fp (AST.NT (AST.JSLiteral "~") (ss $1) (gc $1))}
+
+Not :: { AST.JSNode }
+Not : '!' { fp (AST.NT (AST.JSLiteral "!") (ss $1) (gc $1))}
+
+Mul :: { AST.JSNode }
+Mul : '*' { fp (AST.NT (AST.JSLiteral "*") (ss $1) (gc $1))}
+
+Div :: { AST.JSNode }
+Div : '/' { fp (AST.NT (AST.JSLiteral "/") (ss $1) (gc $1))}
+
+Mod :: { AST.JSNode }
+Mod : '%' { fp (AST.NT (AST.JSLiteral "%") (ss $1) (gc $1))}
+
+Lsh :: { AST.JSNode }
+Lsh : '<<' { fp (AST.NT (AST.JSLiteral "<<") (ss $1) (gc $1))}
+
+Rsh :: { AST.JSNode }
+Rsh : '>>' { fp (AST.NT (AST.JSLiteral ">>") (ss $1) (gc $1))}
+
+Ursh :: { AST.JSNode }
+Ursh : '>>>' { fp (AST.NT (AST.JSLiteral ">>>") (ss $1) (gc $1))}
+
+Le :: { AST.JSNode }
+Le : '<=' { fp (AST.NT (AST.JSLiteral "<=") (ss $1) (gc $1))}
+
+Lt :: { AST.JSNode }
+Lt : '<' { fp (AST.NT (AST.JSLiteral "<") (ss $1) (gc $1))}
+
+Ge :: { AST.JSNode }
+Ge : '>=' { fp (AST.NT (AST.JSLiteral ">=") (ss $1) (gc $1))}
+
+Gt :: { AST.JSNode }
+Gt : '>' { fp (AST.NT (AST.JSLiteral ">") (ss $1) (gc $1))}
+
+In :: { AST.JSNode }
+In : 'in' { fp (AST.NT (AST.JSLiteral "in") (ss $1) (gc $1))}
+
+Instanceof :: { AST.JSNode }
+Instanceof : 'instanceof' { fp (AST.NT (AST.JSLiteral "instanceof") (ss $1) (gc $1))}
+
+StrictEq :: { AST.JSNode }
+StrictEq : '===' { fp (AST.NT (AST.JSLiteral "===") (ss $1) (gc $1))}
+
+Equal :: { AST.JSNode }
+Equal : '==' { fp (AST.NT (AST.JSLiteral "==") (ss $1) (gc $1))}
+
+StrictNe :: { AST.JSNode }
+StrictNe : '!==' { fp (AST.NT (AST.JSLiteral "!==") (ss $1) (gc $1))}
+
+Ne :: { AST.JSNode }
+Ne : '!=' { fp (AST.NT (AST.JSLiteral "!=") (ss $1) (gc $1))}
+
+Or :: { AST.JSNode }
+Or : '||' { fp (AST.NT (AST.JSLiteral "||") (ss $1) (gc $1))}
+
+And :: { AST.JSNode }
+And : '&&' { fp (AST.NT (AST.JSLiteral "&&") (ss $1) (gc $1))}
+
+BitOr :: { AST.JSNode }
+BitOr : '|' { fp (AST.NT (AST.JSLiteral "|") (ss $1) (gc $1))}
+
+BitAnd :: { AST.JSNode }
+BitAnd : '&' { fp (AST.NT (AST.JSLiteral "&") (ss $1) (gc $1))}
+
+BitXor :: { AST.JSNode }
+BitXor : '^' { fp (AST.NT (AST.JSLiteral "^") (ss $1) (gc $1))}
+
+Hook :: { AST.JSNode }
+Hook : '?' { fp (AST.NT (AST.JSLiteral "?") (ss $1) (gc $1))}
+
+SimpleAssign :: { AST.JSNode }
+SimpleAssign : '=' { fp (AST.NT (AST.JSLiteral "=") (ss $1) (gc $1))}
+
+Assign :: { AST.JSNode }
+Assign : 'assign' { fp (AST.NT (AST.JSLiteral (token_literal $1)) (ss $1) (gc $1))}
+
+Var :: { AST.JSNode }
+Var : 'var' { fp (AST.NT (AST.JSLiteral "var") (ss $1) (gc $1))}
+
+Const :: { AST.JSNode }
+Const : 'const' { fp (AST.NT (AST.JSLiteral "const") (ss $1) (gc $1))}
+
+If :: { AST.JSNode }
+If : 'if' { fp (AST.NT (AST.JSLiteral "if") (ss $1) (gc $1))}
+
+Else :: { AST.JSNode }
+Else : 'else' { fp (AST.NT (AST.JSLiteral "else") (ss $1) (gc $1))}
+
+Do :: { AST.JSNode }
+Do : 'do' { fp (AST.NT (AST.JSLiteral "do") (ss $1) (gc $1))}
+
+While :: { AST.JSNode }
+While : 'while' { fp (AST.NT (AST.JSLiteral "while") (ss $1) (gc $1))}
+
+For :: { AST.JSNode }
+For : 'for' { fp (AST.NT (AST.JSLiteral "for") (ss $1) (gc $1))}
+
+Continue :: { AST.JSNode }
+Continue : 'continue' { fp (AST.NT (AST.JSLiteral "continue") (ss $1) (gc $1))}
+
+Break :: { AST.JSNode }
+Break : 'break' { fp (AST.NT (AST.JSLiteral "break") (ss $1) (gc $1))}
+
+Return :: { AST.JSNode }
+Return : 'return' { fp (AST.NT (AST.JSLiteral "return") (ss $1) (gc $1))}
+
+With :: { AST.JSNode }
+With : 'with' { fp (AST.NT (AST.JSLiteral "with") (ss $1) (gc $1))}
+
+Switch :: { AST.JSNode }
+Switch : 'switch' { fp (AST.NT (AST.JSLiteral "switch") (ss $1) (gc $1))}
+
+Case :: { AST.JSNode }
+Case : 'case' { fp (AST.NT (AST.JSLiteral "case") (ss $1) (gc $1))}
+
+Default :: { AST.JSNode }
+Default : 'default' { fp (AST.NT (AST.JSLiteral "default") (ss $1) (gc $1))}
+
+Throw :: { AST.JSNode }
+Throw : 'throw' { fp (AST.NT (AST.JSLiteral "throw") (ss $1) (gc $1))}
+
+Try :: { AST.JSNode }
+Try : 'try' { fp (AST.NT (AST.JSLiteral "try") (ss $1) (gc $1))}
+
+CatchL :: { AST.JSNode }
+CatchL : 'catch' { fp (AST.NT (AST.JSLiteral "catch") (ss $1) (gc $1))}
+
+FinallyL :: { AST.JSNode }
+FinallyL : 'finally' { fp (AST.NT (AST.JSLiteral "finally") (ss $1) (gc $1))}
+
+Function :: { AST.JSNode }
+Function : 'function' { fp (AST.NT (AST.JSLiteral "function") (ss $1) (gc $1))}
+
+Eof :: { AST.JSNode }
+Eof : 'tail' { fp (AST.NT (AST.JSLiteral "") (ss $1) (gc $1))}
+
+-- Literal ::                                                                See 7.8
+--         NullLiteral
+--         BooleanLiteral
+--         NumericLiteral
+--         StringLiteral
+Literal :: { AST.JSNode }
+Literal : NullLiteral     {$1}
+        | BooleanLiteral  {$1}
+        | NumericLiteral  {$1}
+        | StringLiteral   {$1}
+        | RegularExpressionLiteral {$1}
+
+NullLiteral :: { AST.JSNode }
+NullLiteral : 'null' { fp (AST.NT (AST.JSLiteral "null") (ss $1) (gc $1))}
+
+BooleanLiteral :: { AST.JSNode }
+BooleanLiteral : 'true'  { fp (AST.NT (AST.JSLiteral "true")  (ss $1) (gc $1)) }
+               | 'false' { fp (AST.NT (AST.JSLiteral "false") (ss $1) (gc $1)) }
+
+-- <Numeric Literal> ::= DecimalLiteral
+--                     | HexIntegerLiteral
+--                     | OctalLiteral
+NumericLiteral :: { AST.JSNode }
+NumericLiteral : 'decimal'    { fp (AST.NT (AST.JSDecimal (token_literal $1)) (ss $1) (gc $1))}
+               | 'hexinteger' { fp (AST.NT (AST.JSHexInteger (token_literal $1)) (ss $1) (gc $1)) }
+               | 'octal'      { fp (AST.NT (AST.JSOctal (token_literal $1)) (ss $1) (gc $1)) }
+
+StringLiteral :: { AST.JSNode }
+StringLiteral : 'string'  { fp (AST.NT (AST.JSStringLiteral (token_delimiter $1) (token_literal $1)) (ss $1) (gc $1)) }
+
+-- <Regular Expression Literal> ::= RegExp
+RegularExpressionLiteral :: { AST.JSNode }
+RegularExpressionLiteral : 'regex' { fp (AST.NT (AST.JSRegEx (token_literal $1)) (ss $1) (gc $1)) }
+
+-- PrimaryExpression :                                                   See 11.1
+--        this
+--        Identifier
+--        Literal
+--        ArrayLiteral
+--        ObjectLiteral
+--        ( Expression )
+PrimaryExpression :: { AST.JSNode }
+PrimaryExpression : 'this'                   { fp (AST.NT (AST.JSLiteral "this") (ss $1) (gc $1))}
+                  | Identifier               { $1 {- PrimaryExpression1 -}}
+                  | Literal                  { $1 {- PrimaryExpression2 -}}
+                  | ArrayLiteral             { $1 {- PrimaryExpression3 -}}
+                  | ObjectLiteral            { $1 {- PrimaryExpression4 -}}
+                  | LParen Expression RParen  { fp (AST.NN (AST.JSExpressionParen $1 $2 $3)) }
+
+-- Identifier ::                                                            See 7.6
+--         IdentifierName but not ReservedWord
+-- IdentifierName ::                                                        See 7.6
+--         IdentifierStart
+--         IdentifierName IdentifierPart
+Identifier :: { AST.JSNode }
+Identifier : 'ident' {  (AST.NT (AST.JSIdentifier (token_literal $1)) (ss $1) (gc $1))}
+           | 'get'   {  (AST.NT (AST.JSIdentifier "get") (ss $1) (gc $1))}
+           | 'set'   {  (AST.NT (AST.JSIdentifier "set") (ss $1) (gc $1))}
+
+-- TODO: make this include any reserved word too, including future ones
+IdentifierName :: { AST.JSNode }
+IdentifierName : Identifier {$1}
+             | 'break'      { fp (AST.NT (AST.JSIdentifier "break") (ss $1) (gc $1))}
+             | 'case'       { fp (AST.NT (AST.JSIdentifier "case") (ss $1) (gc $1))}
+             | 'catch'      { fp (AST.NT (AST.JSIdentifier "catch") (ss $1) (gc $1))}
+             | 'const'      { fp (AST.NT (AST.JSIdentifier "const") (ss $1) (gc $1))}
+             | 'continue'   { fp (AST.NT (AST.JSIdentifier "continue") (ss $1) (gc $1))}
+             | 'debugger'   { fp (AST.NT (AST.JSIdentifier "debugger") (ss $1) (gc $1))}
+             | 'default'    { fp (AST.NT (AST.JSIdentifier "default") (ss $1) (gc $1))}
+             | 'delete'     { fp (AST.NT (AST.JSIdentifier "delete") (ss $1) (gc $1))}
+             | 'do'         { fp (AST.NT (AST.JSIdentifier "do") (ss $1) (gc $1))}
+             | 'else'       { fp (AST.NT (AST.JSIdentifier "else") (ss $1) (gc $1))}
+             | 'enum'       { fp (AST.NT (AST.JSIdentifier "enum") (ss $1) (gc $1))}
+             | 'false'      { fp (AST.NT (AST.JSIdentifier "false") (ss $1) (gc $1))}
+             | 'finally'    { fp (AST.NT (AST.JSIdentifier "finally") (ss $1) (gc $1))}
+             | 'for'        { fp (AST.NT (AST.JSIdentifier "for")  (ss $1) (gc $1))}
+             | 'function'   { fp (AST.NT (AST.JSIdentifier "function") (ss $1) (gc $1))}
+             | 'get'        { fp (AST.NT (AST.JSIdentifier "get") (ss $1) (gc $1))}
+             | 'if'         { fp (AST.NT (AST.JSIdentifier "if") (ss $1) (gc $1))}
+             | 'in'         { fp (AST.NT (AST.JSIdentifier "in") (ss $1) (gc $1))}
+             | 'instanceof' { fp (AST.NT (AST.JSIdentifier "instanceof") (ss $1) (gc $1))}
+             | 'new'        { fp (AST.NT (AST.JSIdentifier "new") (ss $1) (gc $1))}
+             | 'null'       { fp (AST.NT (AST.JSIdentifier "null") (ss $1) (gc $1))}
+             | 'return'     { fp (AST.NT (AST.JSIdentifier "return") (ss $1) (gc $1))}
+             | 'set'        { fp (AST.NT (AST.JSIdentifier "set") (ss $1) (gc $1))}
+             | 'switch'     { fp (AST.NT (AST.JSIdentifier "switch") (ss $1) (gc $1))}
+             | 'this'       { fp (AST.NT (AST.JSIdentifier "this") (ss $1) (gc $1))}
+             | 'throw'      { fp (AST.NT (AST.JSIdentifier "throw") (ss $1) (gc $1))}
+             | 'true'       { fp (AST.NT (AST.JSIdentifier "true") (ss $1) (gc $1))}
+             | 'try'        { fp (AST.NT (AST.JSIdentifier "try") (ss $1) (gc $1))}
+             | 'typeof'     { fp (AST.NT (AST.JSIdentifier "typeof") (ss $1) (gc $1))}
+             | 'var'        { fp (AST.NT (AST.JSIdentifier "var") (ss $1) (gc $1))}
+             | 'void'       { fp (AST.NT (AST.JSIdentifier "void") (ss $1) (gc $1))}
+             | 'while'      { fp (AST.NT (AST.JSIdentifier "while") (ss $1) (gc $1))}
+             | 'with'       { fp (AST.NT (AST.JSIdentifier "with") (ss $1) (gc $1))}
+             | 'future'     { fp (AST.NT (AST.JSIdentifier (token_literal $1)) (ss $1) (gc $1))}
+
+
+
+-- ArrayLiteral :                                                        See 11.1.4
+--        [ Elisionopt ]
+--        [ ElementList ]
+--        [ ElementList , Elisionopt ]
+ArrayLiteral :: { AST.JSNode }
+ArrayLiteral : LSquare RSquare                           { fp (AST.NN (AST.JSArrayLiteral $1 [] $2))}
+             | LSquare Elision RSquare                   { fp (AST.NN (AST.JSArrayLiteral $1 $2 $3))}
+             | LSquare ElementList RSquare               { fp (AST.NN (AST.JSArrayLiteral $1 $2 $3))}
+             | LSquare ElementList Comma Elision RSquare { fp (AST.NN (AST.JSArrayLiteral $1 ($2++[$3]++$4) $5))}
+             | LSquare ElementList Comma RSquare         { fp (AST.NN (AST.JSArrayLiteral $1 ($2++[$3])     $4))}
+
+
+
+-- ElementList :                                                         See 11.1.4
+--        Elisionopt AssignmentExpression
+--        ElementList , Elisionopt AssignmentExpression
+ElementList :: { [AST.JSNode] }
+ElementList : Elision AssignmentExpression                 { (($1)++($2)) {- ElementList -}}
+            | AssignmentExpression                         { $1           {- ElementList -}}
+            | ElementList Comma Elision AssignmentExpression { (($1)++[fp (AST.NN (AST.JSElision $2))]++($3)++($4)) {- ElementList -}}
+            | ElementList Comma AssignmentExpression         { (($1)++[fp (AST.NN (AST.JSElision $2))]++($3)) {- ElementList -}}
+
+
+-- Elision :                                                             See 11.1.4
+--        ,
+--        Elision ,
+Elision :: { [AST.JSNode] }
+Elision : Comma        { [        fp (AST.NN (AST.JSElision $1))] }
+        | Elision Comma { ($1 ++ [fp (AST.NN (AST.JSElision $2))]) }
+
+-- ObjectLiteral :                                                       See 11.1.5
+--        { }
+--        { PropertyNameAndValueList }
+--        { PropertyNameAndValueList , }
+ObjectLiteral :: { AST.JSNode }
+ObjectLiteral : LBrace RBrace                                { fp (AST.NN (AST.JSObjectLiteral $1 [] $2)         )}
+              | LBrace PropertyNameandValueList RBrace       { fp (AST.NN (AST.JSObjectLiteral $1 $2 $3)         )}
+              | LBrace PropertyNameandValueList Comma RBrace { fp (AST.NN (AST.JSObjectLiteral $1 ($2++[$3]) $4) )}
+
+-- <Property Name and Value List> ::= <Property Name> ':' <Assignment Expression>
+--                                  | <Property Name and Value List> ',' <Property Name> ':' <Assignment Expression>
+
+-- Seems we can have function declarations in the value part too
+-- PropertyNameAndValueList :                                            See 11.1.5
+--        PropertyAssignment
+--        PropertyNameAndValueList , PropertyAssignment
+PropertyNameandValueList :: { [ AST.JSNode ] }
+PropertyNameandValueList : PropertyAssignment                              { [$1] {- PropertyNameandValueList1 -} }
+                         | PropertyNameandValueList Comma PropertyAssignment { ($1++[$2]++[$3]) {- PropertyNameandValueList2 -} }
+
+-- PropertyAssignment :                                                  See 11.1.5
+--        PropertyName : AssignmentExpression
+--        get PropertyName() { FunctionBody }
+--        set PropertyName( PropertySetParameterList ) { FunctionBody }
+-- TODO: not clear if get/set are keywords, or just used in a specific context. Puzzling.
+PropertyAssignment :: { AST.JSNode }
+PropertyAssignment : PropertyName Colon AssignmentExpression { fp (AST.NN (AST.JSPropertyNameandValue $1 $2 $3)) }
+                   -- Should be "get" in next, but is not a Token
+                   | 'get' PropertyName LParen RParen FunctionBody
+                       { fp (AST.NN (AST.JSPropertyAccessor (AST.NT (AST.JSLiteral "get") (ss $1) (gc $1)) $2 $3 [] $4 $5)) }
+                   -- Should be "set" in next, but is not a Token
+                   | 'set' PropertyName LParen PropertySetParameterList RParen FunctionBody
+                       { fp (AST.NN (AST.JSPropertyAccessor (AST.NT (AST.JSLiteral "set") (ss $1) (gc $1)) $2 $3 [$4] $5 $6)) }
+
+-- PropertyName :                                                        See 11.1.5
+--        IdentifierName
+--        StringLiteral
+--        NumericLiteral
+PropertyName :: { AST.JSNode }
+PropertyName : IdentifierName { $1 {- PropertyName1 -}}
+             | StringLiteral  { $1 {- PropertyName2 -}}
+             | NumericLiteral { $1 {- PropertyName3 -}}
+
+-- PropertySetParameterList :                                            See 11.1.5
+--        Identifier
+PropertySetParameterList :: { AST.JSNode }
+PropertySetParameterList : Identifier { $1 {- PropertySetParameterList -}}
+
+-- MemberExpression :                                           See 11.2
+--        PrimaryExpression
+--        FunctionExpression
+--        MemberExpression [ Expression ]
+--        MemberExpression . IdentifierName
+--        new MemberExpression Arguments
+MemberExpression :: { [AST.JSNode] }
+MemberExpression : PrimaryExpression   { [$1] {- MemberExpression -}}
+                 | FunctionExpression  { [$1] {- MemberExpression -}}
+                 | MemberExpression LSquare Expression RSquare { [fp (AST.NN (AST.JSMemberSquare $1 $2 $3 $4))] }
+                 | MemberExpression Dot IdentifierName         { [fp (AST.NN (AST.JSMemberDot $1 $2 $3))] }
+                 | 'new' MemberExpression Arguments            { (((fp (AST.NT (AST.JSLiteral "new") (ss $1) (gc $1))):$2)++[$3])}
+
+-- NewExpression :                                              See 11.2
+--        MemberExpression
+--        new NewExpression
+NewExpression :: { [AST.JSNode] }
+NewExpression : MemberExpression    { $1 {- NewExpression -}}
+              | 'new' NewExpression { (fp (AST.NT (AST.JSLiteral "new") (ss $1) (gc $1))):$2 }
+
+-- CallExpression :                                             See 11.2
+--        MemberExpression Arguments
+--        CallExpression Arguments
+--        CallExpression [ Expression ]
+--        CallExpression . IdentifierName
+CallExpression :: { [AST.JSNode] }
+CallExpression : MemberExpression Arguments        { $1++[$2] {- CallExpression -} }
+               | CallExpression Arguments          { ($1++[fp (AST.NN (AST.JSCallExpression "()" [] [$2] []))]) }
+               | CallExpression LSquare Expression RSquare { ($1++[fp (AST.NN (AST.JSCallExpression "[]" [$2] [$3] [$4]))]) }
+               | CallExpression Dot IdentifierName { ($1++[fp (AST.NN (AST.JSCallExpression "."  [$2] [$3] []))]) }
+
+-- Arguments :                                                  See 11.2
+--        ()
+--        ( ArgumentList )
+Arguments :: { AST.JSNode }
+Arguments : LParen RParen               { fp (AST.NN (AST.JSArguments $1 [] $2)) }
+          | LParen ArgumentList RParen  { fp (AST.NN (AST.JSArguments $1 $2 $3)) }
+
+-- ArgumentList :                                               See 11.2
+--        AssignmentExpression
+--        ArgumentList , AssignmentExpression
+ArgumentList :: { [AST.JSNode] }
+ArgumentList : AssignmentExpression { $1 {- ArgumentList -}}
+             | ArgumentList Comma AssignmentExpression { $1++[$2]++$3 {- ArgumentList2 -} }
+
+-- LeftHandSideExpression :                                     See 11.2
+--        NewExpression
+--        CallExpression
+LeftHandSideExpression :: { [AST.JSNode] }
+LeftHandSideExpression : NewExpression  { $1 {- LeftHandSideExpression1 -}}
+                       | CallExpression { $1 {- LeftHandSideExpression12 -}}
+
+-- PostfixExpression :                                          See 11.3
+--        LeftHandSideExpression
+--                                  [no LineTerminator here]
+--        LeftHandSideExpression                             ++
+--                                  [no LineTerminator here]
+--        LeftHandSideExpression                             --
+PostfixExpression :: { [AST.JSNode] }
+PostfixExpression : LeftHandSideExpression { $1 {- PostfixExpression -} }
+                  | PostfixExpression Increment {[fp (AST.NN (AST.JSExpressionPostfix "++" $1 $2))]}
+                  | PostfixExpression Decrement {[fp (AST.NN (AST.JSExpressionPostfix "--" $1 $2))]}
+
+-- UnaryExpression :                                            See 11.4
+--        PostfixExpression
+--        delete UnaryExpression
+--        void UnaryExpression
+--        typeof UnaryExpression
+--        ++ UnaryExpression
+--        -- UnaryExpression
+--        + UnaryExpression
+--        - UnaryExpression
+--        ~ UnaryExpression
+--        ! UnaryExpression
+UnaryExpression :: { [AST.JSNode] }
+UnaryExpression : PostfixExpression { $1 {- UnaryExpression -} }
+                | Delete    UnaryExpression { ((fp (AST.NN (AST.JSUnary "delete " $1))):$2)}
+                | Void      UnaryExpression { ((fp (AST.NN (AST.JSUnary "void "   $1))):$2)}
+                | Typeof    UnaryExpression { ((fp (AST.NN (AST.JSUnary "typeof " $1))):$2)}
+                | Increment UnaryExpression { ((fp (AST.NN (AST.JSUnary "++"      $1))):$2) }
+                | Decrement UnaryExpression { ((fp (AST.NN (AST.JSUnary "--"      $1))):$2)}
+                | Plus      UnaryExpression { ((fp (AST.NN (AST.JSUnary "+"       $1))):$2)}
+                | Minus     UnaryExpression { ((fp (AST.NN (AST.JSUnary "-"       $1))):$2)}
+                | Tilde     UnaryExpression { ((fp (AST.NN (AST.JSUnary "~"       $1))):$2)}
+                | Not       UnaryExpression { ((fp (AST.NN (AST.JSUnary "!"       $1))):$2)}
+
+-- MultiplicativeExpression :                                   See 11.5
+--        UnaryExpression
+--        MultiplicativeExpression * UnaryExpression
+--        MultiplicativeExpression / UnaryExpression
+--        MultiplicativeExpression % UnaryExpression
+MultiplicativeExpression :: { [AST.JSNode] }
+MultiplicativeExpression : UnaryExpression { $1 {- MultiplicativeExpression -}}
+                         | MultiplicativeExpression Mul UnaryExpression { [fp (AST.NN (AST.JSExpressionBinary "*" $1 $2 $3))]}
+                         | MultiplicativeExpression Div UnaryExpression { [fp (AST.NN (AST.JSExpressionBinary "/" $1 $2 $3))]}
+                         | MultiplicativeExpression Mod UnaryExpression { [fp (AST.NN (AST.JSExpressionBinary "%" $1 $2 $3))]}
+
+-- AdditiveExpression :                                        See 11.6
+--        MultiplicativeExpression
+--        AdditiveExpression + MultiplicativeExpression
+--        AdditiveExpression - MultiplicativeExpression
+AdditiveExpression :: { [AST.JSNode] }
+AdditiveExpression : AdditiveExpression Plus  MultiplicativeExpression { [fp (AST.NN (AST.JSExpressionBinary "+" $1 $2 $3))]}
+                   | AdditiveExpression Minus MultiplicativeExpression { [fp (AST.NN (AST.JSExpressionBinary "-" $1 $2 $3))]}
+                   | MultiplicativeExpression { $1 {- (goRegExp $1)-} {- AdditiveExpression -} }
+
+-- ShiftExpression :                                           See 11.7
+--        AdditiveExpression
+--        ShiftExpression << AdditiveExpression
+--        ShiftExpression >> AdditiveExpression
+--        ShiftExpression >>> AdditiveExpression
+ShiftExpression :: { [AST.JSNode] }
+ShiftExpression : ShiftExpression Lsh  AdditiveExpression { [fp (AST.NN (AST.JSExpressionBinary "<<"  $1 $2 $3))]}
+                | ShiftExpression Rsh  AdditiveExpression { [fp (AST.NN (AST.JSExpressionBinary ">>"  $1 $2 $3))]}
+                | ShiftExpression Ursh AdditiveExpression { [fp (AST.NN (AST.JSExpressionBinary ">>>" $1 $2 $3))]}
+                | AdditiveExpression { $1 {- ShiftExpression -}}
+
+-- RelationalExpression :                                      See 11.8
+--        ShiftExpression
+--        RelationalExpression < ShiftExpression
+--        RelationalExpression > ShiftExpression
+--        RelationalExpression <= ShiftExpression
+--        RelationalExpression >= ShiftExpression
+--        RelationalExpression instanceof ShiftExpression
+--        RelationalExpression in ShiftExpression
+RelationalExpression :: { [AST.JSNode] }
+RelationalExpression : ShiftExpression { $1 {- RelationalExpression -}}
+                     | RelationalExpression Lt  ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary "<"  $1 $2 $3))]}
+                     | RelationalExpression Gt  ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary ">"  $1 $2 $3))]}
+                     | RelationalExpression Le  ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary "<=" $1 $2 $3))]}
+                     | RelationalExpression Ge  ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary ">=" $1 $2 $3))]}
+                     | RelationalExpression Instanceof ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary " instanceof " $1 $2 $3))]}
+                     | RelationalExpression In         ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary " in "         $1 $2 $3))]}
+
+-- RelationalExpressionNoIn :                                  See 11.8
+--        ShiftExpression
+--        RelationalExpressionNoIn < ShiftExpression
+--        RelationalExpressionNoIn > ShiftExpression
+--        RelationalExpressionNoIn <= ShiftExpression
+--        RelationalExpressionNoIn >= ShiftExpression
+--        RelationalExpressionNoIn instanceof ShiftExpression
+RelationalExpressionNoIn :: { [AST.JSNode] }
+RelationalExpressionNoIn : ShiftExpression { $1 {- RelationalExpressionNoIn -}}
+                     | RelationalExpressionNoIn Lt  ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary "<"  $1 $2 $3))]}
+                     | RelationalExpressionNoIn Gt  ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary ">"  $1 $2 $3))]}
+                     | RelationalExpressionNoIn Le  ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary "<=" $1 $2 $3))]}
+                     | RelationalExpressionNoIn Ge  ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary ">=" $1 $2 $3))]}
+                     | RelationalExpressionNoIn Instanceof ShiftExpression { [fp (AST.NN (AST.JSExpressionBinary " instanceof " $1 $2 $3))]}
+
+-- EqualityExpression :                                        See 11.9
+--        RelationalExpression
+--        EqualityExpression == RelationalExpression
+--        EqualityExpression != RelationalExpression
+--        EqualityExpression === RelationalExpression
+--        EqualityExpression !== RelationalExpression
+EqualityExpression :: { [AST.JSNode] }
+EqualityExpression : RelationalExpression { $1 {- EqualityExpression -} }
+                   | EqualityExpression Equal    RelationalExpression { [fp (AST.NN (AST.JSExpressionBinary "=="  $1 $2 $3))]}
+                   | EqualityExpression Ne       RelationalExpression { [fp (AST.NN (AST.JSExpressionBinary "!="  $1 $2 $3))]}
+                   | EqualityExpression StrictEq RelationalExpression { [fp (AST.NN (AST.JSExpressionBinary "===" $1 $2 $3))]}
+                   | EqualityExpression StrictNe RelationalExpression { [fp (AST.NN (AST.JSExpressionBinary "!==" $1 $2 $3))]}
+
+-- EqualityExpressionNoIn :                                    See 11.9
+--        RelationalExpressionNoIn
+--        EqualityExpressionNoIn == RelationalExpressionNoIn
+--        EqualityExpressionNoIn != RelationalExpressionNoIn
+--        EqualityExpressionNoIn === RelationalExpressionNoIn
+--        EqualityExpressionNoIn !== RelationalExpressionNoIn
+EqualityExpressionNoIn :: { [AST.JSNode] }
+EqualityExpressionNoIn : RelationalExpressionNoIn { $1 {- EqualityExpressionNoIn -} }
+                       | EqualityExpressionNoIn Equal    RelationalExpression { [fp (AST.NN (AST.JSExpressionBinary "=="  $1 $2 $3))]}
+                       | EqualityExpressionNoIn Ne       RelationalExpression { [fp (AST.NN (AST.JSExpressionBinary "!="  $1 $2 $3))]}
+                       | EqualityExpressionNoIn StrictEq RelationalExpression { [fp (AST.NN (AST.JSExpressionBinary "===" $1 $2 $3))]}
+                       | EqualityExpressionNoIn StrictNe RelationalExpression { [fp (AST.NN (AST.JSExpressionBinary "!==" $1 $2 $3))]}
+
+-- BitwiseANDExpression :                                      See 11.10
+--        EqualityExpression
+--        BitwiseANDExpression & EqualityExpression
+BitwiseAndExpression :: { [AST.JSNode] }
+BitwiseAndExpression : EqualityExpression { $1 {- BitwiseAndExpression -} }
+                     | BitwiseAndExpression BitAnd EqualityExpression { [fp (AST.NN (AST.JSExpressionBinary "&" $1 $2 $3))]}
+
+-- BitwiseANDExpressionNoIn :                                  See 11.10
+--        EqualityExpressionNoIn
+--        BitwiseANDExpressionNoIn & EqualityExpressionNoIn
+BitwiseAndExpressionNoIn :: { [AST.JSNode] }
+BitwiseAndExpressionNoIn : EqualityExpressionNoIn { $1 {- BitwiseAndExpression -} }
+                     | BitwiseAndExpressionNoIn BitAnd EqualityExpressionNoIn { [fp (AST.NN (AST.JSExpressionBinary "&" $1 $2 $3))]}
+
+-- BitwiseXORExpression :                                                                See 11.10
+--        BitwiseANDExpression
+--        BitwiseXORExpression ^ BitwiseANDExpression
+BitwiseXOrExpression :: { [AST.JSNode] }
+BitwiseXOrExpression : BitwiseAndExpression { $1 {- BitwiseXOrExpression -} }
+                     | BitwiseXOrExpression BitXor BitwiseAndExpression { [fp (AST.NN (AST.JSExpressionBinary "^" $1 $2 $3))]}
+
+-- BitwiseXORExpressionNoIn :                                                            See 11.10
+--        BitwiseANDExpressionNoIn
+--        BitwiseXORExpressionNoIn ^ BitwiseANDExpressionNoIn
+BitwiseXOrExpressionNoIn :: { [AST.JSNode] }
+BitwiseXOrExpressionNoIn : BitwiseAndExpressionNoIn { $1 {- BitwiseXOrExpression -} }
+                         | BitwiseXOrExpressionNoIn BitXor BitwiseAndExpressionNoIn { [fp (AST.NN (AST.JSExpressionBinary "^" $1 $2 $3))]}
+
+-- BitwiseORExpression :                                                                 See 11.10
+--        BitwiseXORExpression
+--        BitwiseORExpression | BitwiseXORExpression
+BitwiseOrExpression :: { [AST.JSNode] }
+BitwiseOrExpression : BitwiseXOrExpression { $1 {- BitwiseOrExpression -} }
+                    | BitwiseOrExpression BitOr BitwiseXOrExpression { [fp (AST.NN (AST.JSExpressionBinary "|" $1 $2 $3))]}
+
+-- BitwiseORExpressionNoIn :                                                             See 11.10
+--        BitwiseXORExpressionNoIn
+--        BitwiseORExpressionNoIn | BitwiseXORExpressionNoIn
+BitwiseOrExpressionNoIn :: { [AST.JSNode] }
+BitwiseOrExpressionNoIn : BitwiseXOrExpressionNoIn { $1 {- BitwiseOrExpression -} }
+                        | BitwiseOrExpressionNoIn BitOr BitwiseXOrExpressionNoIn { [fp (AST.NN (AST.JSExpressionBinary "|" $1 $2 $3))]}
+
+-- LogicalANDExpression :                                                                See 11.11
+--        BitwiseORExpression
+--        LogicalANDExpression && BitwiseORExpression
+LogicalAndExpression :: { [AST.JSNode] }
+LogicalAndExpression : BitwiseOrExpression { $1 {- LogicalAndExpression -} }
+                     | LogicalAndExpression And BitwiseOrExpression { [fp (AST.NN (AST.JSExpressionBinary "&&" $1 $2 $3))]}
+
+-- LogicalANDExpressionNoIn :                                                            See 11.11
+--        BitwiseORExpressionNoIn
+--        LogicalANDExpressionNoIn && BitwiseORExpressionNoIn
+LogicalAndExpressionNoIn :: { [AST.JSNode] }
+LogicalAndExpressionNoIn : BitwiseOrExpressionNoIn { $1 {- LogicalAndExpression -} }
+                         | LogicalAndExpressionNoIn And BitwiseOrExpressionNoIn { [fp (AST.NN (AST.JSExpressionBinary "&&" $1 $2 $3))]}
+
+-- LogicalORExpression :                                                                 See 11.11
+--        LogicalANDExpression
+--        LogicalORExpression || LogicalANDExpression
+LogicalOrExpression :: { [AST.JSNode] }
+LogicalOrExpression : LogicalAndExpression { $1 {- LogicalOrExpression -} }
+                    | LogicalOrExpression Or LogicalAndExpression { [fp (AST.NN (AST.JSExpressionBinary "||" $1 $2 $3))]}
+
+-- LogicalORExpressionNoIn :                                                             See 11.11
+--        LogicalANDExpressionNoIn
+--        LogicalORExpressionNoIn || LogicalANDExpressionNoIn
+LogicalOrExpressionNoIn :: { [AST.JSNode] }
+LogicalOrExpressionNoIn : LogicalAndExpressionNoIn { $1 {- LogicalOrExpression -} }
+                        | LogicalOrExpressionNoIn Or LogicalAndExpressionNoIn { [fp (AST.NN (AST.JSExpressionBinary "||" $1 $2 $3))]}
+
+-- ConditionalExpression :                                                               See 11.12
+--        LogicalORExpression
+--        LogicalORExpression ? AssignmentExpression : AssignmentExpression
+ConditionalExpression :: { [AST.JSNode] }
+ConditionalExpression : LogicalOrExpression { $1 {- ConditionalExpression -} }
+                      | LogicalOrExpression Hook AssignmentExpression Colon AssignmentExpression
+                        { [fp (AST.NN (AST.JSExpressionTernary $1 $2 $3 $4 $5))] }
+
+-- ConditionalExpressionNoIn :                                                           See 11.12
+--        LogicalORExpressionNoIn
+--        LogicalORExpressionNoIn ? AssignmentExpressionNoIn : AssignmentExpressionNoIn
+ConditionalExpressionNoIn :: { [AST.JSNode] }
+ConditionalExpressionNoIn : LogicalOrExpressionNoIn { $1 {- ConditionalExpression -} }
+                          | LogicalOrExpressionNoIn Hook AssignmentExpressionNoIn Colon AssignmentExpressionNoIn
+                            { [fp (AST.NN (AST.JSExpressionTernary $1 $2 $3 $4 $5))] }
+
+-- AssignmentExpression :                                                                See 11.13
+--        ConditionalExpression
+--        LeftHandSideExpression AssignmentOperator AssignmentExpression
+AssignmentExpression :: { [AST.JSNode] }
+AssignmentExpression : ConditionalExpression { $1 {- AssignmentExpression -}}
+                     | LeftHandSideExpression AssignmentOperator AssignmentExpression
+                       { ($1++[$2]++$3) }
+
+-- AssignmentExpressionNoIn :                                                            See 11.13
+--        ConditionalExpressionNoIn
+--        LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn
+AssignmentExpressionNoIn :: { [AST.JSNode] }
+AssignmentExpressionNoIn : ConditionalExpressionNoIn { $1 {- AssignmentExpression -}}
+                         | LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn
+                           { ($1++[$2]++$3) }
+
+-- AssignmentOperator : one of                                                           See 11.13
+--     '=' | '*=' | '/=' | '%=' | '+=' | '-=' | '<<=' | '>>=' | '>>>=' | '&=' | '^=' | '|='
+AssignmentOperator :: { AST.JSNode }
+AssignmentOperator : Assign       { fp (AST.NN (AST.JSOperator $1))}
+                   | SimpleAssign { fp (AST.NN (AST.JSOperator $1))}
+
+-- Expression :                                                   See 11.14
+--         AssignmentExpression
+--         Expression , AssignmentExpression
+Expression :: { AST.JSNode }
+Expression : AssignmentExpression { fp (AST.NN (AST.JSExpression $1)) {- Expression -} }
+           | Expression Comma AssignmentExpression  { fp (AST.NN (AST.JSExpression ($1:[$2]++$3))) {- Expression2 -} }
+
+-- ExpressionNoIn :                                               See 11.14
+--         AssignmentExpressionNoIn
+--         ExpressionNoIn , AssignmentExpressionNoIn
+ExpressionNoIn :: { AST.JSNode }
+ExpressionNoIn : AssignmentExpressionNoIn { fp (AST.NN (AST.JSExpression $1)) {- ExpressionNoIn -} }
+               | ExpressionNoIn Comma AssignmentExpressionNoIn  { fp (AST.NN (AST.JSExpression ($1:[$2]++$3))) {- ExpressionNoIn2 -} }
+
+-- TODO: still required?
+ExpressionOpt :: { [AST.JSNode] }
+ExpressionOpt : Expression { [$1] {- ExpressionOpt -}}
+              |            { []   {- ExpressionOpt -}}
+
+ExpressionNoInOpt :: { [AST.JSNode] }
+ExpressionNoInOpt : ExpressionNoIn { [$1] {- ExpressionOpt -}}
+                  |            { []   {- ExpressionOpt -}}
+
+
+-- Statement :                                                    See clause 12
+--         Block
+--         VariableStatement
+--         EmptyStatement
+--         ExpressionStatement
+--         IfStatement
+--         IterationStatement
+--         ContinueStatement
+--         BreakStatement
+--         ReturnStatement
+--         WithStatement
+--         LabelledStatement
+--         SwitchStatement
+--         ThrowStatement
+--         TryStatement
+--         DebuggerStatement
+Statement :: { AST.JSNode }
+Statement : StatementNoEmpty   { $1 {- Statement1 -}}
+          | EmptyStatement     { $1 {- Statement3 -}}
+
+StatementNoEmpty :: { AST.JSNode }
+StatementNoEmpty : StatementBlock      { $1 {- StatementNoEmpty1 -}}
+                 | VariableStatement   { $1 {- StatementNoEmpty2 -}}
+                 | ExpressionStatement { $1 {- StatementNoEmpty4 -}}
+                 | IfStatement         { $1 {- StatementNoEmpty5 -}}
+                 | IterationStatement  { $1 {- StatementNoEmpty6 -}}
+                 | ContinueStatement   { $1 {- StatementNoEmpty7 -}}
+                 | BreakStatement      { $1 {- StatementNoEmpty8 -}}
+                 | ReturnStatement     { $1 {- StatementNoEmpty9 -}}
+                 | WithStatement       { $1 {- StatementNoEmpty10 -}}
+                 | LabelledStatement   { $1 {- StatementNoEmpty11 -}}
+                 | SwitchStatement     { $1 {- StatementNoEmpty12 -}}
+                 | ThrowStatement      { $1 {- StatementNoEmpty13 -}}
+                 | TryStatement        { $1 {- StatementNoEmpty14 -}}
+                 | DebuggerStatement   { $1 {- StatementNoEmpty15 -}}
+
+
+StatementBlock :: { AST.JSNode }
+StatementBlock : LBrace RBrace               { fp (AST.NN (AST.JSBlock [$1] [] [$2])) }
+               | LBrace StatementList RBrace { fp (AST.NN (AST.JSBlock [$1] $2 [$3])) }
+
+-- Block :                                                        See 12.1
+--         { StatementListopt }
+Block :: { AST.JSNode }
+Block : LBrace RBrace               { fp (AST.NN (AST.JSBlock [$1] [] [$2])) }
+      | LBrace StatementList RBrace { fp (AST.NN (AST.JSBlock [$1] $2 [$3])) }
+
+-- StatementList :                                                See 12.1
+--         Statement
+--         StatementList Statement
+StatementList :: { [AST.JSNode] }
+StatementList : Statement               { [$1]       {- StatementList1 -} }
+              | StatementList Statement { ($1++[$2]) {- StatementList2 -} }
+
+-- VariableStatement :                                            See 12.2
+--         var VariableDeclarationList ;
+VariableStatement :: { AST.JSNode }
+VariableStatement : Var   VariableDeclarationList AutoSemi { fp (AST.NN (AST.JSVariables $1 $2 $3))}
+                  | Const VariableDeclarationList AutoSemi { fp (AST.NN (AST.JSVariables $1 $2 $3))}
+
+-- VariableDeclarationList :                                      See 12.2
+--         VariableDeclaration
+--         VariableDeclarationList , VariableDeclaration
+VariableDeclarationList :: { [AST.JSNode] }
+VariableDeclarationList : VariableDeclaration { [$1] {- VariableDeclarationList -}}
+                        | VariableDeclarationList Comma VariableDeclaration { ($1++[$2]++[$3]) {- VariableDeclarationList -}}
+
+-- VariableDeclarationListNoIn :                                  See 12.2
+--         VariableDeclarationNoIn
+--         VariableDeclarationListNoIn , VariableDeclarationNoIn
+VariableDeclarationListNoIn :: { [AST.JSNode] }
+VariableDeclarationListNoIn : VariableDeclarationNoIn { [$1] {- VariableDeclarationList -}}
+                            | VariableDeclarationListNoIn Comma VariableDeclarationNoIn { ($1++[$2]++[$3]) {- VariableDeclarationListNoIn -}}
+
+-- VariableDeclaration :                                          See 12.2
+--         Identifier Initialiseropt
+VariableDeclaration :: { AST.JSNode }
+VariableDeclaration : Identifier              { fp (AST.NN (AST.JSVarDecl $1 []))}
+                    | Identifier Initializer  { fp (AST.NN (AST.JSVarDecl $1 $2))}
+
+-- VariableDeclarationNoIn :                                      See 12.2
+--         Identifier InitialiserNoInopt
+VariableDeclarationNoIn :: { AST.JSNode }
+VariableDeclarationNoIn : Identifier InitializerNoIn { fp (AST.NN (AST.JSVarDecl $1 $2)) }
+                        | Identifier                 { fp (AST.NN (AST.JSVarDecl $1 [])) }
+
+-- Initialiser :                                                                            See 12.2
+--         = AssignmentExpression
+Initializer :: { [AST.JSNode] }
+Initializer : SimpleAssign AssignmentExpression { $1:$2 {- Initializer -} }
+
+-- InitialiserNoIn :                                                                        See 12.2
+--         = AssignmentExpressionNoIn
+InitializerNoIn :: { [AST.JSNode] }
+InitializerNoIn : SimpleAssign AssignmentExpressionNoIn { $1:$2 {- InitializerNoIn -}}
+
+-- EmptyStatement :                                                                         See 12.3
+--         ;
+EmptyStatement :: { AST.JSNode }
+EmptyStatement : Semi { $1 }
+
+-- ExpressionStatement :                                                                    See 12.4
+--         [lookahead not in {{, function}] Expression  ;
+-- TODO: Sort out lookahead issue. Maybe by just putting production lower to set reduce/reduce conflict
+--       According to http://sideshowbarker.github.com/es5-spec/#x12.4, the ambiguity is with
+--       Block or FunctionDeclaration
+ExpressionStatement :: { AST.JSNode }
+ExpressionStatement : Expression { $1 {- ExpressionStatement -} }
+
+
+-- IfStatement :                                                                            See 12.5
+--         if ( Expression ) Statement else Statement
+--         if ( Expression ) Statement
+IfStatement :: { AST.JSNode } -- +++XXXX++
+IfStatement : If LParen Expression RParen StatementSemi IfElseRest
+                  { (fp (AST.NN (AST.JSIf $1 $2 $3 $4 $5 $6)) ) }
+
+IfElseRest :: { [AST.JSNode] }
+IfElseRest : Else Statement     { [$1,$2] }
+           |                    { [] }
+
+StatementSemi :: { [AST.JSNode] }
+StatementSemi : StatementNoEmpty Semi { [$1,$2] {- StatementSemi1 -}}
+              | StatementNoEmpty      { [$1]    {- StatementSemi2 -}}
+              | Semi                  { [$1]    {- StatementSemi3 -}}
+
+
+-- IterationStatement :                                                                     See 12.6
+--         do Statement while ( Expression );
+--         while ( Expression ) Statement
+--         for (ExpressionNoInopt; Expressionopt ; Expressionopt ) Statement
+--         for ( var VariableDeclarationListNoIn; Expressionopt ; Expressionopt ) Statement
+--         for ( LeftHandSideExpression in Expression ) Statement
+--         for ( var VariableDeclarationNoIn in Expression ) Statement
+IterationStatement :: { AST.JSNode }
+IterationStatement : Do Statement While LParen Expression RParen AutoSemi
+                     { fp (AST.NN (AST.JSDoWhile $1 $2 $3 $4 $5 $6 $7)) }
+                   | While LParen Expression RParen Statement
+                     { fp (AST.NN (AST.JSWhile $1 $2 $3 $4 $5)) }
+                   | For LParen ExpressionNoInOpt Semi ExpressionOpt Semi ExpressionOpt RParen Statement
+                     { fp (AST.NN (AST.JSFor $1 $2 $3 $4 $5 $6 $7 $8 $9)) }
+                   | For LParen Var VariableDeclarationListNoIn Semi ExpressionOpt Semi ExpressionOpt RParen Statement
+                     { fp (AST.NN (AST.JSForVar $1 $2 $3 $4 $5 $6 $7 $8 $9 $10)) }
+                   | For LParen LeftHandSideExpression In Expression RParen Statement
+                     { fp (AST.NN (AST.JSForIn $1 $2 $3 $4 $5 $6 $7)) }
+                   | For LParen Var VariableDeclarationNoIn In Expression RParen Statement
+                     { fp (AST.NN (AST.JSForVarIn $1 $2 $3 $4 $5 $6 $7 $8)) }
+
+-- ContinueStatement :                                                                      See 12.7
+--         continue [no LineTerminator here] Identifieropt ;
+-- TODO: deal with [no LineTerminator here]
+ContinueStatement :: { AST.JSNode }
+ContinueStatement : Continue AutoSemi             { fp (AST.NN (AST.JSContinue $1 []   $2)) }
+                  | Continue Identifier AutoSemi  { fp (AST.NN (AST.JSContinue $1 [$2] $3)) }
+
+-- BreakStatement :                                                                         See 12.8
+--         break [no LineTerminator here] Identifieropt ;
+-- TODO: deal with [no LineTerminator here]
+BreakStatement :: { AST.JSNode }
+BreakStatement : Break AutoSemi             { fp (AST.NN (AST.JSBreak $1 []   $2)) }
+               | Break Identifier AutoSemi  { fp (AST.NN (AST.JSBreak $1 [$2] $3)) }
+
+-- ReturnStatement :                                                                        See 12.9
+--         return [no LineTerminator here] Expressionopt ;
+-- TODO: deal with [no LineTerminator here]
+ReturnStatement :: { AST.JSNode }
+ReturnStatement : Return AutoSemi             { fp (AST.NN (AST.JSReturn $1 []   $2)) }
+                | Return Expression AutoSemi  { fp (AST.NN (AST.JSReturn $1 [$2] $3)) }
+
+-- WithStatement :                                                                          See 12.10
+--         with ( Expression ) Statement
+WithStatement :: { AST.JSNode }
+WithStatement : With LParen Expression RParen Statement AutoSemi  { fp (AST.NN (AST.JSWith $1 $2 $3 $4 [$5,$6])) }
+
+-- SwitchStatement :                                                                        See 12.11
+--         switch ( Expression ) CaseBlock
+SwitchStatement :: { AST.JSNode }
+SwitchStatement : Switch LParen Expression RParen CaseBlock { (AST.NN (AST.JSSwitch $1 $2 $3 $4 $5)) }
+
+-- CaseBlock :                                                                              See 12.11
+--         { CaseClausesopt }
+--         { CaseClausesopt DefaultClause CaseClausesopt }
+CaseBlock :: { AST.JSNode }
+CaseBlock : LBrace CaseClausesOpt RBrace                              { fp (AST.NN (AST.JSBlock [$1] $2             [$3])){- CaseBlock1 -}}
+          | LBrace CaseClausesOpt DefaultClause CaseClausesOpt RBrace { fp (AST.NN (AST.JSBlock [$1] ($2++[$3]++$4) [$5])){- CaseBlock2 -}}
+
+-- CaseClauses :                                                                            See 12.11
+--         CaseClause
+--         CaseClauses CaseClause
+CaseClausesOpt :: { [AST.JSNode] }
+CaseClausesOpt : CaseClause                { [$1] {- CaseClauses1 -}}
+               | CaseClausesOpt CaseClause { ($1++[$2]) {- CaseClauses2 -}}
+               |                           { [fp (AST.NT (AST.JSLiteral "") tokenPosnEmpty []) ] } -- { [] }
+
+-- CaseClause :                                                               See 12.11
+--        case Expression : StatementListopt
+CaseClause :: { AST.JSNode }
+CaseClause : Case Expression Colon StatementList  { fp (AST.NN (AST.JSCase $1 $2 $3 $4)) }
+           | Case Expression Colon                { fp (AST.NN (AST.JSCase $1 $2 $3 [])) }
+
+-- DefaultClause :                                                            See 12.11
+--        default : StatementListopt
+DefaultClause :: { AST.JSNode }
+DefaultClause : Default Colon                { fp (AST.NN (AST.JSDefault $1 $2 [])) }
+              | Default Colon StatementList  { fp (AST.NN (AST.JSDefault $1 $2 $3)) }
+
+-- LabelledStatement :                                                        See 12.12
+--        Identifier : Statement
+LabelledStatement :: { AST.JSNode }
+LabelledStatement : Identifier Colon Statement { fp (AST.NN (AST.JSLabelled $1 $2 $3)) }
+
+-- ThrowStatement :                                                           See 12.13
+--        throw [no LineTerminator here] Expression ;
+-- TODO : sort out no LineTerminator here
+--        Does it need a semi at the end?
+ThrowStatement :: { AST.JSNode }
+ThrowStatement : Throw Expression { fp (AST.NN (AST.JSThrow $1 $2)) }
+
+-- Note: worked in updated syntax as per https://developer.mozilla.org/en/JavaScript/Reference/Statements/try...catch
+--   i.e., 0 or more catches, then an optional finally
+-- TryStatement :                                                             See 12.14
+--        try Block Catch
+--        try Block Finally
+--        try Block Catch Finally
+TryStatement :: { AST.JSNode }
+TryStatement : Try Block Catches         { fp (AST.NN (AST.JSTry $1 $2 $3)         ) {- TryStatement1 -} }
+             | Try Block Finally         { fp (AST.NN (AST.JSTry $1 $2 [$3])       ) {- TryStatement2 -} }
+             | Try Block Catches Finally { fp (AST.NN (AST.JSTry $1 $2 ($3++[$4])) ) {- TryStatement3 -} }
+
+Catches :: { [AST.JSNode] }
+Catches : Catch         { [$1]       {- Catches 1 -} }
+        | Catches Catch { ($1++[$2]) {- Catches 2 -} }
+
+-- Note: worked in updated syntax as per https://developer.mozilla.org/en/JavaScript/Reference/Statements/try...catch
+-- <Catch> ::= 'catch' '(' Identifier ')' <Block>
+--   becomes
+-- <Catch> ::= 'catch' '(' Identifier ')' <Block>
+--           | 'catch' '(' Identifier 'if' ConditionalExpression ')' <Block>
+Catch :: { AST.JSNode }
+Catch : CatchL LParen Identifier                          RParen Block { fp (AST.NN (AST.JSCatch $1 $2 $3 [     ] $4 $5)) }
+      | CatchL LParen Identifier If ConditionalExpression RParen Block { fp (AST.NN (AST.JSCatch $1 $2 $3 ($4:$5) $6 $7)) }
+
+-- Finally :                                                                  See 12.14
+--        finally Block
+Finally :: { AST.JSNode }
+Finally : FinallyL Block { fp (AST.NN (AST.JSFinally $1 $2)) }
+
+-- DebuggerStatement :                                                        See 12.15
+--        debugger ;
+DebuggerStatement :: { AST.JSNode }
+DebuggerStatement : 'debugger' AutoSemi { fp (AST.NT (AST.JSLiteral "debugger") (ss $1) (gc $1)) }
+
+-- FunctionDeclaration :                                                      See clause 13
+--        function Identifier ( FormalParameterListopt ) { FunctionBody }
+FunctionDeclaration :: { AST.JSNode }
+FunctionDeclaration : Function Identifier LParen FormalParameterList RParen FunctionBody
+                      { fp (AST.NN (AST.JSFunction $1 $2 $3 $4 $5 $6) ) }
+                    | Function Identifier LParen RParen FunctionBody
+                      { fp (AST.NN (AST.JSFunction $1 $2 $3 [] $4 $5) ) }
+
+-- FunctionExpression :                                                       See clause 13
+--        function Identifieropt ( FormalParameterListopt ) { FunctionBody }
+FunctionExpression :: { AST.JSNode }
+FunctionExpression : Function IdentifierOpt LParen RParen FunctionBody
+                     { fp (AST.NN (AST.JSFunctionExpression $1 $2 $3 [] $4 $5) ) }
+                   | Function IdentifierOpt LParen FormalParameterList RParen FunctionBody
+                     { fp (AST.NN (AST.JSFunctionExpression $1 $2 $3 $4 $5 $6) ) }
+
+IdentifierOpt :: { [AST.JSNode] }
+IdentifierOpt : Identifier { [$1] {- IdentifierOpt -}}
+              |            { []   {- IdentifierOpt -}}
+
+-- FormalParameterList :                                                      See clause 13
+--        Identifier
+--        FormalParameterList , Identifier
+FormalParameterList :: { [AST.JSNode] }
+FormalParameterList : Identifier                            { [$1] {- FormalParameterList -}}
+                    | FormalParameterList Comma Identifier  { ($1++[$2]++[$3]) }
+
+-- FunctionBody :                                                             See clause 13
+--        SourceElementsopt
+FunctionBody :: { AST.JSNode }
+FunctionBody : LBrace SourceElements RBrace { (AST.NN (AST.JSBlock [$1] $2 [$3]) ) }
+             | LBrace                RBrace { (AST.NN (AST.JSBlock [$1] [] [$2]) ) }
+
+-- Program :                                                                  See clause 14
+--        SourceElementsopt
+
+Program :: { AST.JSNode }
+Program : SourceElementsTop Eof { (combineTop $1 $2) {- Program -}}
+        | Eof                   { fp (AST.NN (AST.JSSourceElementsTop [$1])) }
+
+-- For debugging/other entry points
+LiteralMain :: { AST.JSNode }
+LiteralMain : Literal Eof { $1 }
+
+PrimaryExpressionMain :: { AST.JSNode }
+PrimaryExpressionMain : PrimaryExpression Eof { $1 }
+
+StatementMain :: { AST.JSNode }
+StatementMain : Statement Eof { $1 }
+
+
+-- SourceElements :                                                           See clause 14
+--        SourceElement
+--        SourceElements SourceElement
+SourceElements :: { [AST.JSNode] }
+SourceElements : SourceElement                { [$1]     {- SourceElements -} }
+               | SourceElements SourceElement { $1++[$2] {- SourceElements -} }
+
+SourceElementsTop :: { AST.JSNode }
+SourceElementsTop : SourceElement                   { fp (AST.NN (AST.JSSourceElementsTop [$1]) ) }
+                  | SourceElementsTop SourceElement { (combineSourceElementsTop $1 $2) }
+
+-- SourceElement :
+--       Statement
+--       FunctionDeclaration
+SourceElement :: { AST.JSNode }
+SourceElement : Statement            { $1 {- SourceElement1 -} }
+              | FunctionDeclaration  { $1 {- SourceElement2 -} }
+
+{
+combineSourceElementsTop :: AST.JSNode -> AST.JSNode -> AST.JSNode
+combineSourceElementsTop (AST.NN (AST.JSSourceElementsTop xs)) x1 = fp (AST.NN (AST.JSSourceElementsTop (xs++[x1])))
+
+combineTop :: AST.JSNode -> AST.JSNode -> AST.JSNode
+combineTop (AST.NN (AST.JSSourceElementsTop xs)) x1 = fp (AST.NN (AST.JSSourceElementsTop (xs++[x1])))
+
+
+parseError :: Token -> Alex a
+-- parseError = throwError . UnexpectedToken
+parseError tok = alexError (show tok)
+
+-- --------------------------------
+
+{-
+mex :: [AST.JSNode] -> TokenPosn
+mex [] = tokenPosnEmpty
+mex xs = ex (head xs)
+
+ex :: AST.JSNode -> TokenPosn
+ex (AST.NN _node span _c) = span
+-}
+
+--ss token = toSrcSpan (token_span token)
+ss :: Token -> TokenPosn
+ss token = token_span token
+
+-- ------------------------------
+
+gc :: Token -> [CommentAnnotation]
+gc token = token_comment token
+mgc :: [Token] -> [CommentAnnotation]
+mgc xs = concatMap gc xs
+
+-- ---------------------------------------------------------------------
+
+fp :: AST.JSNode -> AST.JSNode
+fp (AST.NN x)      = (AST.NN x)
+fp (AST.NT x p cs) = (AST.NT x p cs)
+{-
+fp (AST.NN x p cs) = (AST.NN x p' cs)
+  where
+    p' = case (filter (/= NoComment) cs) of
+      [] -> p
+      [(CommentA posn _)]    -> posn
+      ((CommentA posn _):_)  -> posn
+-}
+
+}
+
+-- Set emacs mode
+-- Local Variables:
+-- mode:haskell
+-- End:
diff --git a/src/Language/JavaScript/Parser/Lexer.x b/src/Language/JavaScript/Parser/Lexer.x
new file mode 100644 (file)
index 0000000..9858fea
--- /dev/null
@@ -0,0 +1,640 @@
+{
+
+module Language.JavaScript.Parser.Lexer (
+    Token(..)
+    , AlexPosn(..)
+    , Alex
+    , lexCont
+    , alexError
+    , runAlex
+    ) where
+
+--import Control.Monad
+import Language.JavaScript.Parser.LexerUtils
+import Language.JavaScript.Parser.ParserMonad
+import Language.JavaScript.Parser.SrcLocation
+import Language.JavaScript.Parser.Token
+import qualified Data.Map as Map
+--import Data.Word (Word8)
+
+}
+
+-- %wrapper "basic"
+-- %wrapper "monad"
+%wrapper "monadUserState"
+-- %wrapper "monad-bytestring"
+
+-- character sets
+$lf = \n  -- line feed
+$cr = \r  -- carriage return
+$ht = \t  -- horizontal tab
+$sq = '   -- single quote
+$dq = \"  -- double quote
+$digit = 0-9                   -- digits
+$alpha = [a-zA-Z]              -- alphabetic characters
+$digit    = 0-9
+$non_zero_digit = 1-9
+$ident_letter = [a-zA-Z_]
+@eol_pattern = $lf | $cr $lf | $cr $lf
+
+$ls = \x2028
+$ps = \x2029
+@LineTerminatorSequence = $lf | $cr | $ls | $ps | $cr $lf
+
+
+$any_char = [\x00-\xff]
+$any_unicode_char = [\x00-\xffff]
+
+
+$eol_char = [\x000A\x000D\x2028\x2029] -- any end of line character
+--$eol_char = [$lf $cr] -- any end of line character
+$not_eol_char = ~$eol_char -- anything but an end of line character
+
+
+-- From GOLD Parser
+-- {ID Head}      = {Letter} + [_] + [$]
+@IDHead = $alpha | [_] | [\$]
+
+-- {ID Tail}      = {Alphanumeric} + [_] + [$]
+@IDTail = $alpha | $digit | [_] | [\$]
+
+-- {String Chars1} = {Printable} + {HT} - ["\]
+-- {String Chars2} = {Printable} + {HT} - [\'']
+$StringChars1 = [$printable $ht] # [$dq \\]
+$StringChars2 = [$printable $ht] # [$sq \\]
+
+-- LineContinuation :: \ LineTerminatorSequence
+@LineContinuation = [\\] @LineTerminatorSequence
+
+
+$short_str_char = [^ \n \r ' \" \\]
+
+-- {Hex Digit}    = {Digit} + [ABCDEF] + [abcdef]
+@HexDigit = $digit | [a-fA-F]
+-- {Oct Digit}    = {Digit} + [01234567]
+@OctDigit = $digit | [0-7]
+-- {RegExp Chars} = {Letter}+{Digit}+['^']+['$']+['*']+['+']+['?']+['{']+['}']+['|']+['-']+['.']+[',']+['#']+['[']+[']']+['_']+['<']+['>']
+--$RegExpChars = [$alpha $digit \^\$\*\+\?\{\}\|\-\.\,\#\[\]\_\<\>]
+--$RegExpChars = [$printable] # [\\]
+-- {Non Terminator} = {String Chars1} - {CR} - {LF}
+--$NonTerminator = $StringChars1 # [$cr $lf]
+$NonTerminator = [$printable] # [$cr $lf]
+-- {Non Zero Digits}={Digit}-[0]
+
+-- ~ (LineTerminator | MUL | BSLASH | DIV)
+$RegExpFirstChar = [$printable] # [ $cr $lf \* \\ \/]
+-- ~ ( LineTerminator | BSLASH | DIV )
+$RegExpChars = [$printable] # [ $cr $lf \\ \/]
+
+$MultiLineNotAsteriskChar               = [$any_unicode_char] # [\*]
+$MultiLineNotForwardSlashOrAsteriskChar = [$any_unicode_char] # [\* \/]
+
+-- See http://blog.stevenlevithan.com/archives/javascript-regex-and-unicode
+    -- *  \u0009 — Tab — \t
+    -- * \u000a — Line feed — \n — (newline character)
+    -- * \u000b — Vertical tab — \v
+    -- * \u000c — Form feed — \f
+    -- * \u000d — Carriage return — \r — (newline character)
+    -- * \u0020 — Space
+    -- * \u00a0 — No-break space
+    -- * \u1680 — Ogham space mark
+    -- * \u180e — Mongolian vowel separator
+    -- * \u2000 — En quad
+    -- * \u2001 — Em quad
+    -- * \u2002 — En space
+    -- * \u2003 — Em space
+    -- * \u2004 — Three-per-em space
+    -- * \u2005 — Four-per-em space
+    -- * \u2006 — Six-per-em space
+    -- * \u2007 — Figure space
+    -- * \u2008 — Punctuation space
+    -- * \u2009 — Thin space
+    -- * \u200a — Hair space
+    -- * \u2028 — Line separator — (newline character)
+    -- * \u2029 — Paragraph separator — (newline character)
+    -- * \u202f — Narrow no-break space
+    -- * \u205f — Medium mathematical space
+    -- * \u3000 — Ideographic space
+
+--$white_char   = [\ \f\v\t\r\n]
+-- Note: from edition 5 the BOM (\xfeff) is also considered whitespace
+$white_char = [\x0009\x000a\x000b\x000c\x000d\x0020\x00a0\x1680\x180e\x2000\x2001\x2002\x2003\x2004\x2005\x2006\x2007\x2008\x2009\x200a\x2028\x2029\x202f\x205f\x3000\xfeff]
+
+-- Identifier characters
+-- UnicodeLetter
+--       any character in the Unicode categories “Uppercase letter (Lu)”, “Lowercase letter (Ll)”,
+--       “Titlecase letter (Lt)”, “Modifier letter (Lm)”, “Other letter (Lo)”, or “Letter number (Nl)”.
+
+-- http://www.fileformat.info/info/unicode/category/Lu/list.htm etc, see unicode/doit.sh
+$UnicodeLetter = [\x41-\x5a\x61-\x7a\xaa-\xaa\xb5-\xb5\xba-\xba\xc0-\xd6\xd8-\xf6\xf8-\x2c1\x2c6-\x2d1\x2e0-\x2e4\x2ec-\x2ec\x2ee-\x2ee\x370-\x374\x376-\x377\x37a-\x37d\x386-\x386\x388-\x38a\x38c-\x38c\x38e-\x3a1\x3a3-\x3f5\x3f7-\x481\x48a-\x527\x531-\x556\x559-\x559\x561-\x587\x5d0-\x5ea\x5f0-\x5f2\x620-\x64a\x66e-\x66f\x671-\x6d3\x6d5-\x6d5\x6e5-\x6e6\x6ee-\x6ef\x6fa-\x6fc\x6ff-\x6ff\x710-\x710\x712-\x72f\x74d-\x7a5\x7b1-\x7b1\x7ca-\x7ea\x7f4-\x7f5\x7fa-\x7fa\x800-\x815\x81a-\x81a\x824-\x824\x828-\x828\x840-\x858\x904-\x939\x93d-\x93d\x950-\x950\x958-\x961\x971-\x977\x979-\x97f\x985-\x98c\x98f-\x990\x993-\x9a8\x9aa-\x9b0\x9b2-\x9b2\x9b6-\x9b9\x9bd-\x9bd\x9ce-\x9ce\x9dc-\x9dd\x9df-\x9e1\x9f0-\x9f1\xa05-\xa0a\xa0f-\xa10\xa13-\xa28\xa2a-\xa30\xa32-\xa33\xa35-\xa36\xa38-\xa39\xa59-\xa5c\xa5e-\xa5e\xa72-\xa74\xa85-\xa8d\xa8f-\xa91\xa93-\xaa8\xaaa-\xab0\xab2-\xab3\xab5-\xab9\xabd-\xabd\xad0-\xad0\xae0-\xae1\xb05-\xb0c\xb0f-\xb10\xb13-\xb28\xb2a-\xb30\xb32-\xb33\xb35-\xb39\xb3d-\xb3d\xb5c-\xb5d\xb5f-\xb61\xb71-\xb71\xb83-\xb83\xb85-\xb8a\xb8e-\xb90\xb92-\xb95\xb99-\xb9a\xb9c-\xb9c\xb9e-\xb9f\xba3-\xba4\xba8-\xbaa\xbae-\xbb9\xbd0-\xbd0\xc05-\xc0c\xc0e-\xc10\xc12-\xc28\xc2a-\xc33\xc35-\xc39\xc3d-\xc3d\xc58-\xc59\xc60-\xc61\xc85-\xc8c\xc8e-\xc90\xc92-\xca8\xcaa-\xcb3\xcb5-\xcb9\xcbd-\xcbd\xcde-\xcde\xce0-\xce1\xcf1-\xcf2\xd05-\xd0c\xd0e-\xd10\xd12-\xd3a\xd3d-\xd3d\xd4e-\xd4e\xd60-\xd61\xd7a-\xd7f\xd85-\xd96\xd9a-\xdb1\xdb3-\xdbb\xdbd-\xdbd\xdc0-\xdc6\xe01-\xe30\xe32-\xe33\xe40-\xe46\xe81-\xe82\xe84-\xe84\xe87-\xe88\xe8a-\xe8a\xe8d-\xe8d\xe94-\xe97\xe99-\xe9f\xea1-\xea3\xea5-\xea5\xea7-\xea7\xeaa-\xeab\xead-\xeb0\xeb2-\xeb3\xebd-\xebd\xec0-\xec4\xec6-\xec6\xedc-\xedd\xf00-\xf00\xf40-\xf47\xf49-\xf6c\xf88-\xf8c\x1000-\x1000\x10000-\x1000b\x1000d-\x1000f\x1001-\x1001\x10010-\x1001f\x1002-\x1002\x10020-\x10026\x10028-\x1002f\x1003-\x1003\x10030-\x1003a\x1003c-\x1003d\x1003f-\x1003f\x1004-\x1004\x10040-\x1004d\x1005-\x1005\x10050-\x1005d\x1006-\x1008\x10080-\x1008f\x1009-\x1009\x10090-\x1009f\x100a-\x100a\x100a0-\x100af\x100b-\x100b\x100b0-\x100bf\x100c-\x100c\x100c0-\x100cf\x100d-\x100d\x100d0-\x100df\x100e-\x100e\x100e0-\x100ef\x100f-\x100f\x100f0-\x100fa\x1010-\x1014\x10140-\x1014f\x1015-\x1015\x10150-\x1015f\x1016-\x1016\x10160-\x1016f\x1017-\x1017\x10170-\x10174\x1018-\x1028\x10280-\x1028f\x1029-\x1029\x10290-\x1029c\x102a-\x102a\x102a0-\x102d0\x10300-\x1031e\x10330-\x1034a\x10380-\x1039d\x103a0-\x103c3\x103c8-\x103cf\x103d1-\x103d5\x103f-\x103f\x10400-\x1049d\x1050-\x1055\x105a-\x105d\x1061-\x1061\x1065-\x1066\x106e-\x1070\x1075-\x1080\x10800-\x10805\x10808-\x10808\x1080a-\x1080f\x1081-\x1081\x10810-\x10835\x10837-\x10838\x1083c-\x1083c\x1083f-\x10855\x108e-\x108e\x10900-\x10915\x10920-\x10939\x10a0-\x10a0\x10a00-\x10a00\x10a1-\x10a1\x10a10-\x10a13\x10a15-\x10a17\x10a19-\x10a1f\x10a2-\x10a2\x10a20-\x10a2f\x10a3-\x10a3\x10a30-\x10a33\x10a4-\x10a6\x10a60-\x10a6f\x10a7-\x10a7\x10a70-\x10a7c\x10a8-\x10b0\x10b00-\x10b0f\x10b1-\x10b1\x10b10-\x10b1f\x10b2-\x10b2\x10b20-\x10b2f\x10b3-\x10b3\x10b30-\x10b35\x10b4-\x10b4\x10b40-\x10b4f\x10b5-\x10b5\x10b50-\x10b55\x10b6-\x10b6\x10b60-\x10b6f\x10b7-\x10b7\x10b70-\x10b72\x10b8-\x10c0\x10c00-\x10c0f\x10c1-\x10c1\x10c10-\x10c1f\x10c2-\x10c2\x10c20-\x10c2f\x10c3-\x10c3\x10c30-\x10c3f\x10c4-\x10c4\x10c40-\x10c48\x10c5-\x10c5\x10d0-\x10fa\x10fc-\x10fc\x1100-\x1100\x11003-\x1100f\x1101-\x1101\x11010-\x1101f\x1102-\x1102\x11020-\x1102f\x1103-\x1103\x11030-\x11037\x1104-\x1108\x11083-\x1108f\x1109-\x1109\x11090-\x1109f\x110a-\x110a\x110a0-\x110af\x110b-\x1200\x12000-\x1200f\x1201-\x1201\x12010-\x1201f\x1202-\x1202\x12020-\x1202f\x1203-\x1203\x12030-\x1203f\x1204-\x1204\x12040-\x1204f\x1205-\x1205\x12050-\x1205f\x1206-\x1206\x12060-\x1206f\x1207-\x1207\x12070-\x1207f\x1208-\x1208\x12080-\x1208f\x1209-\x1209\x12090-\x1209f\x120a-\x120a\x120a0-\x120af\x120b-\x120b\x120b0-\x120bf\x120c-\x120c\x120c0-\x120cf\x120d-\x120d\x120d0-\x120df\x120e-\x120e\x120e0-\x120ef\x120f-\x120f\x120f0-\x120ff\x1210-\x1210\x12100-\x1210f\x1211-\x1211\x12110-\x1211f\x1212-\x1212\x12120-\x1212f\x1213-\x1213\x12130-\x1213f\x1214-\x1214\x12140-\x1214f\x1215-\x1215\x12150-\x1215f\x1216-\x1216\x12160-\x1216f\x1217-\x1217\x12170-\x1217f\x1218-\x1218\x12180-\x1218f\x1219-\x1219\x12190-\x1219f\x121a-\x121a\x121a0-\x121af\x121b-\x121b\x121b0-\x121bf\x121c-\x121c\x121c0-\x121cf\x121d-\x121d\x121d0-\x121df\x121e-\x121e\x121e0-\x121ef\x121f-\x121f\x121f0-\x121ff\x1220-\x1220\x12200-\x1220f\x1221-\x1221\x12210-\x1221f\x1222-\x1222\x12220-\x1222f\x1223-\x1223\x12230-\x1223f\x1224-\x1224\x12240-\x1224f\x1225-\x1225\x12250-\x1225f\x1226-\x1226\x12260-\x1226f\x1227-\x1227\x12270-\x1227f\x1228-\x1228\x12280-\x1228f\x1229-\x1229\x12290-\x1229f\x122a-\x122a\x122a0-\x122af\x122b-\x122b\x122b0-\x122bf\x122c-\x122c\x122c0-\x122cf\x122d-\x122d\x122d0-\x122df\x122e-\x122e\x122e0-\x122ef\x122f-\x122f\x122f0-\x122ff\x1230-\x1230\x12300-\x1230f\x1231-\x1231\x12310-\x1231f\x1232-\x1232\x12320-\x1232f\x1233-\x1233\x12330-\x1233f\x1234-\x1234\x12340-\x1234f\x1235-\x1235\x12350-\x1235f\x1236-\x1236\x12360-\x1236e\x1237-\x1240\x12400-\x1240f\x1241-\x1241\x12410-\x1241f\x1242-\x1242\x12420-\x1242f\x1243-\x1243\x12430-\x1243f\x1244-\x1244\x12440-\x1244f\x1245-\x1245\x12450-\x1245f\x1246-\x1246\x12460-\x12462\x1247-\x1248\x124a-\x124d\x1250-\x1256\x1258-\x1258\x125a-\x125d\x1260-\x1288\x128a-\x128d\x1290-\x12b0\x12b2-\x12b5\x12b8-\x12be\x12c0-\x12c0\x12c2-\x12c5\x12c8-\x12d6\x12d8-\x1300\x13000-\x1300f\x1301-\x1301\x13010-\x1301f\x1302-\x1302\x13020-\x1302f\x1303-\x1303\x13030-\x1303f\x1304-\x1304\x13040-\x1304f\x1305-\x1305\x13050-\x1305f\x1306-\x1306\x13060-\x1306f\x1307-\x1307\x13070-\x1307f\x1308-\x1308\x13080-\x1308f\x1309-\x1309\x13090-\x1309f\x130a-\x130a\x130a0-\x130af\x130b-\x130b\x130b0-\x130bf\x130c-\x130c\x130c0-\x130cf\x130d-\x130d\x130d0-\x130df\x130e-\x130e\x130e0-\x130ef\x130f-\x130f\x130f0-\x130ff\x1310-\x1310\x13100-\x1311f\x1312-\x1312\x13120-\x1312f\x1313-\x1313\x13130-\x1313f\x1314-\x1314\x13140-\x1314f\x1315-\x1315\x13150-\x1317f\x1318-\x1318\x13180-\x1318f\x1319-\x1319\x13190-\x1319f\x131a-\x131a\x131a0-\x131af\x131b-\x131b\x131b0-\x131bf\x131c-\x131c\x131c0-\x131cf\x131d-\x131d\x131d0-\x131df\x131e-\x131e\x131e0-\x131ef\x131f-\x131f\x131f0-\x131ff\x1320-\x1320\x13200-\x1320f\x1321-\x1321\x13210-\x1321f\x1322-\x1322\x13220-\x1322f\x1323-\x1323\x13230-\x1323f\x1324-\x1324\x13240-\x1324f\x1325-\x1325\x13250-\x1325f\x1326-\x1326\x13260-\x1326f\x1327-\x1327\x13270-\x1327f\x1328-\x1328\x13280-\x1328f\x1329-\x1329\x13290-\x1329f\x132a-\x132a\x132a0-\x132af\x132b-\x132b\x132b0-\x132bf\x132c-\x132c\x132c0-\x132cf\x132d-\x132d\x132d0-\x132df\x132e-\x132e\x132e0-\x132ef\x132f-\x132f\x132f0-\x132ff\x1330-\x1330\x13300-\x1330f\x1331-\x1331\x13310-\x1331f\x1332-\x1332\x13320-\x1332f\x1333-\x1333\x13330-\x1333f\x1334-\x1334\x13340-\x1334f\x1335-\x1335\x13350-\x1335f\x1336-\x1336\x13360-\x1336f\x1337-\x1337\x13370-\x1337f\x1338-\x1338\x13380-\x1338f\x1339-\x1339\x13390-\x1339f\x133a-\x133a\x133a0-\x133af\x133b-\x133b\x133b0-\x133bf\x133c-\x133c\x133c0-\x133cf\x133d-\x133d\x133d0-\x133df\x133e-\x133e\x133e0-\x133ef\x133f-\x133f\x133f0-\x133ff\x1340-\x1340\x13400-\x1340f\x1341-\x1341\x13410-\x1341f\x1342-\x1342\x13420-\x1342e\x1343-\x135a\x1380-\x138f\x13a0-\x13f4\x1401-\x166c\x166f-\x167f\x16800-\x1680f\x1681-\x1681\x16810-\x1681f\x1682-\x1682\x16820-\x1682f\x1683-\x1683\x16830-\x1683f\x1684-\x1684\x16840-\x1684f\x1685-\x1685\x16850-\x1685f\x1686-\x1686\x16860-\x1686f\x1687-\x1687\x16870-\x1687f\x1688-\x1688\x16880-\x1688f\x1689-\x1689\x16890-\x1689f\x168a-\x168a\x168a0-\x168af\x168b-\x168b\x168b0-\x168bf\x168c-\x168c\x168c0-\x168cf\x168d-\x168d\x168d0-\x168df\x168e-\x168e\x168e0-\x168ef\x168f-\x168f\x168f0-\x168ff\x1690-\x1690\x16900-\x1690f\x1691-\x1691\x16910-\x1691f\x1692-\x1692\x16920-\x1692f\x1693-\x1693\x16930-\x1693f\x1694-\x1694\x16940-\x1694f\x1695-\x1695\x16950-\x1695f\x1696-\x1696\x16960-\x1696f\x1697-\x1697\x16970-\x1697f\x1698-\x1698\x16980-\x1698f\x1699-\x1699\x16990-\x1699f\x169a-\x169a\x169a0-\x169ff\x16a0-\x16a0\x16a00-\x16a0f\x16a1-\x16a1\x16a10-\x16a1f\x16a2-\x16a2\x16a20-\x16a2f\x16a3-\x16a3\x16a30-\x16a38\x16a4-\x16ea\x16ee-\x16f0\x1700-\x170c\x170e-\x1711\x1720-\x1731\x1740-\x1751\x1760-\x176c\x176e-\x1770\x1780-\x17b3\x17d7-\x17d7\x17dc-\x17dc\x1820-\x1877\x1880-\x18a8\x18aa-\x18aa\x18b0-\x18f5\x1900-\x191c\x1950-\x196d\x1970-\x1974\x1980-\x19ab\x19c1-\x19c7\x1a00-\x1a16\x1a20-\x1a54\x1aa7-\x1aa7\x1b000-\x1b001\x1b05-\x1b33\x1b45-\x1b4b\x1b83-\x1ba0\x1bae-\x1baf\x1bc0-\x1be5\x1c00-\x1c23\x1c4d-\x1c4f\x1c5a-\x1c7d\x1ce9-\x1cec\x1cee-\x1cf1\x1d00-\x1d40\x1d400-\x1d40f\x1d41-\x1d41\x1d410-\x1d41f\x1d42-\x1d42\x1d420-\x1d42f\x1d43-\x1d43\x1d430-\x1d43f\x1d44-\x1d44\x1d440-\x1d44f\x1d45-\x1d45\x1d450-\x1d454\x1d456-\x1d45f\x1d46-\x1d46\x1d460-\x1d46f\x1d47-\x1d47\x1d470-\x1d47f\x1d48-\x1d48\x1d480-\x1d48f\x1d49-\x1d49\x1d490-\x1d49c\x1d49e-\x1d49f\x1d4a-\x1d4a\x1d4a2-\x1d4a2\x1d4a5-\x1d4a6\x1d4a9-\x1d4ac\x1d4ae-\x1d4af\x1d4b-\x1d4b\x1d4b0-\x1d4b9\x1d4bb-\x1d4bb\x1d4bd-\x1d4bf\x1d4c-\x1d4c\x1d4c0-\x1d4c3\x1d4c5-\x1d4cf\x1d4d-\x1d4d\x1d4d0-\x1d4df\x1d4e-\x1d4e\x1d4e0-\x1d4ef\x1d4f-\x1d4f\x1d4f0-\x1d4ff\x1d50-\x1d50\x1d500-\x1d505\x1d507-\x1d50a\x1d50d-\x1d50f\x1d51-\x1d51\x1d510-\x1d514\x1d516-\x1d51c\x1d51e-\x1d51f\x1d52-\x1d52\x1d520-\x1d52f\x1d53-\x1d53\x1d530-\x1d539\x1d53b-\x1d53e\x1d54-\x1d54\x1d540-\x1d544\x1d546-\x1d546\x1d54a-\x1d54f\x1d55-\x1d55\x1d550-\x1d550\x1d552-\x1d55f\x1d56-\x1d56\x1d560-\x1d56f\x1d57-\x1d57\x1d570-\x1d57f\x1d58-\x1d58\x1d580-\x1d58f\x1d59-\x1d59\x1d590-\x1d59f\x1d5a-\x1d5a\x1d5a0-\x1d5af\x1d5b-\x1d5b\x1d5b0-\x1d5bf\x1d5c-\x1d5c\x1d5c0-\x1d5cf\x1d5d-\x1d5d\x1d5d0-\x1d5df\x1d5e-\x1d5e\x1d5e0-\x1d5ef\x1d5f-\x1d5f\x1d5f0-\x1d5ff\x1d60-\x1d60\x1d600-\x1d60f\x1d61-\x1d61\x1d610-\x1d61f\x1d62-\x1d62\x1d620-\x1d62f\x1d63-\x1d63\x1d630-\x1d63f\x1d64-\x1d64\x1d640-\x1d64f\x1d65-\x1d65\x1d650-\x1d65f\x1d66-\x1d66\x1d660-\x1d66f\x1d67-\x1d67\x1d670-\x1d67f\x1d68-\x1d68\x1d680-\x1d68f\x1d69-\x1d69\x1d690-\x1d69f\x1d6a-\x1d6a\x1d6a0-\x1d6a5\x1d6a8-\x1d6af\x1d6b-\x1d6b\x1d6b0-\x1d6bf\x1d6c-\x1d6c\x1d6c0-\x1d6c0\x1d6c2-\x1d6cf\x1d6d-\x1d6d\x1d6d0-\x1d6da\x1d6dc-\x1d6df\x1d6e-\x1d6e\x1d6e0-\x1d6ef\x1d6f-\x1d6f\x1d6f0-\x1d6fa\x1d6fc-\x1d6ff\x1d70-\x1d70\x1d700-\x1d70f\x1d71-\x1d71\x1d710-\x1d714\x1d716-\x1d71f\x1d72-\x1d72\x1d720-\x1d72f\x1d73-\x1d73\x1d730-\x1d734\x1d736-\x1d73f\x1d74-\x1d74\x1d740-\x1d74e\x1d75-\x1d75\x1d750-\x1d75f\x1d76-\x1d76\x1d760-\x1d76e\x1d77-\x1d77\x1d770-\x1d77f\x1d78-\x1d78\x1d780-\x1d788\x1d78a-\x1d78f\x1d79-\x1d79\x1d790-\x1d79f\x1d7a-\x1d7a\x1d7a0-\x1d7a8\x1d7aa-\x1d7af\x1d7b-\x1d7b\x1d7b0-\x1d7bf\x1d7c-\x1d7c\x1d7c0-\x1d7c2\x1d7c4-\x1d7cb\x1d7d-\x1dbf\x1e00-\x1f15\x1f18-\x1f1d\x1f20-\x1f45\x1f48-\x1f4d\x1f50-\x1f57\x1f59-\x1f59\x1f5b-\x1f5b\x1f5d-\x1f5d\x1f5f-\x1f7d\x1f80-\x1fb4\x1fb6-\x1fbc\x1fbe-\x1fbe\x1fc2-\x1fc4\x1fc6-\x1fcc\x1fd0-\x1fd3\x1fd6-\x1fdb\x1fe0-\x1fec\x1ff2-\x1ff4\x1ff6-\x1ffc\x20000-\x20000\x2071-\x2071\x207f-\x207f\x2090-\x209c\x2102-\x2102\x2107-\x2107\x210a-\x2113\x2115-\x2115\x2119-\x211d\x2124-\x2124\x2126-\x2126\x2128-\x2128\x212a-\x212d\x212f-\x2139\x213c-\x213f\x2145-\x2149\x214e-\x214e\x2160-\x2188\x2a6d6-\x2a6d6\x2a700-\x2a700\x2b734-\x2b734\x2b740-\x2b740\x2b81d-\x2b81d\x2c00-\x2c2e\x2c30-\x2c5e\x2c60-\x2ce4\x2ceb-\x2cee\x2d00-\x2d25\x2d30-\x2d65\x2d6f-\x2d6f\x2d80-\x2d96\x2da0-\x2da6\x2da8-\x2dae\x2db0-\x2db6\x2db8-\x2dbe\x2dc0-\x2dc6\x2dc8-\x2dce\x2dd0-\x2dd6\x2dd8-\x2dde\x2e2f-\x2e2f\x2f800-\x2fa1d\x3005-\x3007\x3021-\x3029\x3031-\x3035\x3038-\x303c\x3041-\x3096\x309d-\x309f\x30a1-\x30fa\x30fc-\x30ff\x3105-\x312d\x3131-\x318e\x31a0-\x31ba\x31f0-\x31ff\x3400-\x3400\x4db5-\x4db5\x4e00-\x4e00\x9fcb-\x9fcb\xa000-\xa48c\xa4d0-\xa4fd\xa500-\xa60c\xa610-\xa61f\xa62a-\xa62b\xa640-\xa66e\xa67f-\xa697\xa6a0-\xa6ef\xa717-\xa71f\xa722-\xa788\xa78b-\xa78e\xa790-\xa791\xa7a0-\xa7a9\xa7fa-\xa801\xa803-\xa805\xa807-\xa80a\xa80c-\xa822\xa840-\xa873\xa882-\xa8b3\xa8f2-\xa8f7\xa8fb-\xa8fb\xa90a-\xa925\xa930-\xa946\xa960-\xa97c\xa984-\xa9b2\xa9cf-\xa9cf\xaa00-\xaa28\xaa40-\xaa42\xaa44-\xaa4b\xaa60-\xaa76\xaa7a-\xaa7a\xaa80-\xaaaf\xaab1-\xaab1\xaab5-\xaab6\xaab9-\xaabd\xaac0-\xaac0\xaac2-\xaac2\xaadb-\xaadd\xab01-\xab06\xab09-\xab0e\xab11-\xab16\xab20-\xab26\xab28-\xab2e\xabc0-\xabe2\xac00-\xac00\xd7a3-\xd7a3\xd7b0-\xd7c6\xd7cb-\xd7fb\xf900-\xfa2d\xfa30-\xfa6d\xfa70-\xfad9\xfb00-\xfb06\xfb13-\xfb17\xfb1d-\xfb1d\xfb1f-\xfb28\xfb2a-\xfb36\xfb38-\xfb3c\xfb3e-\xfb3e\xfb40-\xfb41\xfb43-\xfb44\xfb46-\xfbb1\xfbd3-\xfd3d\xfd50-\xfd8f\xfd92-\xfdc7\xfdf0-\xfdfb\xfe70-\xfe74\xfe76-\xfefc\xff21-\xff3a\xff41-\xff5a\xff66-\xffbe\xffc2-\xffc7\xffca-\xffcf\xffd2-\xffd7]
+
+-- UnicodeCombiningMark
+--       any character in the Unicode categories “Non-spacing mark (Mn)” or “Combining spacing mark (Mc)”
+$UnicodeCombiningMark = [\x300-\x36f\x483-\x487\x591-\x5bd\x5bf-\x5bf\x5c1-\x5c2\x5c4-\x5c5\x5c7-\x5c7\x610-\x61a\x64b-\x65f\x670-\x670\x6d6-\x6dc\x6df-\x6e4\x6e7-\x6e8\x6ea-\x6ed\x711-\x711\x730-\x74a\x7a6-\x7b0\x7eb-\x7f3\x816-\x819\x81b-\x823\x825-\x827\x829-\x82d\x859-\x85b\x900-\x903\x93a-\x93c\x93e-\x94f\x951-\x957\x962-\x963\x981-\x983\x9bc-\x9bc\x9be-\x9c4\x9c7-\x9c8\x9cb-\x9cd\x9d7-\x9d7\x9e2-\x9e3\xa01-\xa03\xa3c-\xa3c\xa3e-\xa42\xa47-\xa48\xa4b-\xa4d\xa51-\xa51\xa70-\xa71\xa75-\xa75\xa81-\xa83\xabc-\xabc\xabe-\xac5\xac7-\xac9\xacb-\xacd\xae2-\xae3\xb01-\xb03\xb3c-\xb3c\xb3e-\xb44\xb47-\xb48\xb4b-\xb4d\xb56-\xb57\xb62-\xb63\xb82-\xb82\xbbe-\xbc2\xbc6-\xbc8\xbca-\xbcd\xbd7-\xbd7\xc01-\xc03\xc3e-\xc44\xc46-\xc48\xc4a-\xc4d\xc55-\xc56\xc62-\xc63\xc82-\xc83\xcbc-\xcbc\xcbe-\xcc4\xcc6-\xcc8\xcca-\xccd\xcd5-\xcd6\xce2-\xce3\xd02-\xd03\xd3e-\xd44\xd46-\xd48\xd4a-\xd4d\xd57-\xd57\xd62-\xd63\xd82-\xd83\xdca-\xdca\xdcf-\xdd4\xdd6-\xdd6\xdd8-\xddf\xdf2-\xdf3\xe31-\xe31\xe34-\xe3a\xe47-\xe4e\xeb1-\xeb1\xeb4-\xeb9\xebb-\xebc\xec8-\xecd\xf18-\xf19\xf35-\xf35\xf37-\xf37\xf39-\xf39\xf3e-\xf3f\xf71-\xf84\xf86-\xf87\xf8d-\xf97\xf99-\xfbc\xfc6-\xfc6\x101fd-\x101fd\x102b-\x103e\x1056-\x1059\x105e-\x1060\x1062-\x1064\x1067-\x106d\x1071-\x1074\x1082-\x108d\x108f-\x108f\x109a-\x109d\x10a01-\x10a03\x10a05-\x10a06\x10a0c-\x10a0f\x10a38-\x10a3a\x10a3f-\x10a3f\x11000-\x11002\x11038-\x11046\x11080-\x11082\x110b0-\x110ba\x135d-\x135f\x1712-\x1714\x1732-\x1734\x1752-\x1753\x1772-\x1773\x17b6-\x17d3\x17dd-\x17dd\x180b-\x180d\x18a9-\x18a9\x1920-\x192b\x1930-\x193b\x19b0-\x19c0\x19c8-\x19c9\x1a17-\x1a1b\x1a55-\x1a5e\x1a60-\x1a7c\x1a7f-\x1a7f\x1b00-\x1b04\x1b34-\x1b44\x1b6b-\x1b73\x1b80-\x1b82\x1ba1-\x1baa\x1be6-\x1bf3\x1c24-\x1c37\x1cd0-\x1cd2\x1cd4-\x1ce8\x1ced-\x1ced\x1cf2-\x1cf2\x1d165-\x1d169\x1d16d-\x1d172\x1d17b-\x1d182\x1d185-\x1d18b\x1d1aa-\x1d1ad\x1d242-\x1d244\x1dc0-\x1de6\x1dfc-\x1dff\x20d0-\x20dc\x20e1-\x20e1\x20e5-\x20f0\x2cef-\x2cf1\x2d7f-\x2d7f\x2de0-\x2dff\x302a-\x302f\x3099-\x309a\xa66f-\xa66f\xa67c-\xa67d\xa6f0-\xa6f1\xa802-\xa802\xa806-\xa806\xa80b-\xa80b\xa823-\xa827\xa880-\xa881\xa8b4-\xa8c4\xa8e0-\xa8f1\xa926-\xa92d\xa947-\xa953\xa980-\xa983\xa9b3-\xa9c0\xaa29-\xaa36\xaa43-\xaa43\xaa4c-\xaa4d\xaa7b-\xaa7b\xaab0-\xaab0\xaab2-\xaab4\xaab7-\xaab8\xaabe-\xaabf\xaac1-\xaac1\xabe3-\xabea\xabec-\xabed\xe0100-\xe01ef\xfb1e-\xfb1e\xfe00-\xfe0f]
+
+-- UnicodeDigit
+--       any character in the Unicode category “Decimal number (Nd)”
+$UnicodeDigit = [\x30-\x39\x660-\x669\x6f0-\x6f9\x7c0-\x7c9\x966-\x96f\x9e6-\x9ef\xa66-\xa6f\xae6-\xaef\xb66-\xb6f\xbe6-\xbef\xc66-\xc6f\xce6-\xcef\xd66-\xd6f\xe50-\xe59\xed0-\xed9\xf20-\xf29\x1040-\x1049\x104a0-\x104a9\x1090-\x1099\x11066-\x1106f\x17e0-\x17e9\x1810-\x1819\x1946-\x194f\x19d0-\x19d9\x1a80-\x1a89\x1a90-\x1a99\x1b50-\x1b59\x1bb0-\x1bb9\x1c40-\x1c49\x1c50-\x1c59\x1d7ce-\x1d7ff\xa620-\xa629\xa8d0-\xa8d9\xa900-\xa909\xa9d0-\xa9d9\xaa50-\xaa59\xabf0-\xabf9]
+
+-- UnicodeConnectorPunctuation
+--       any character in the Unicode category “Connector punctuation (Pc)”
+$UnicodeConnectorPunctuation = [\x5f-\x5f\x203f-\x2040\x2054-\x2054\xfe33-\xfe34\xfe4d-\xfe4f]
+
+-- UnicodeEscapeSequence ::
+--       u HexDigit HexDigit HexDigit HexDigit
+$HexDigit = [0-9a-fA-F]
+@UnicodeEscapeSequence = u $HexDigit $HexDigit $HexDigit $HexDigit
+
+-- IdentifierStart ::
+--         UnicodeLetter
+--         $
+--         _
+--         \ UnicodeEscapeSequence
+@IdentifierStart = $UnicodeLetter | [\$] | [_] | [\\] @UnicodeEscapeSequence
+
+-- IdentifierPart ::
+--         IdentifierStart
+--         UnicodeCombiningMark
+--         UnicodeDigit
+--         UnicodeConnectorPunctuation
+--         \ UnicodeEscapeSequence
+
+$ZWNJ = [\x200c]
+$ZWJ  = [\x200d]
+@IdentifierPart = @IdentifierStart | $UnicodeCombiningMark | $UnicodeDigit | UnicodeConnectorPunctuation
+        [\\] @UnicodeEscapeSequence | $ZWNJ | $ZWJ
+
+-- ! ------------------------------------------------- Terminals
+tokens :-
+
+-- State: 0 is regex allowed, 1 is / or /= allowed
+
+<0> () ; -- { registerStates lexToken reg divide }
+
+-- Skip Whitespace
+<reg,divide> $white_char+   { adapt (mkString wsToken) }
+
+-- Skip one line comment
+<reg,divide> "//"($not_eol_char)*   { adapt (mkString commentToken) }
+
+-- ---------------------------------------------------------------------
+-- Comment definition from the ECMAScript spec, ver 3
+
+-- MultiLineComment ::
+--        /* MultiLineCommentChars(opt) */
+-- MultiLineCommentChars ::
+--        MultiLineNotAsteriskChar MultiLineCommentChars(opt)
+--        * PostAsteriskCommentChars(opt)
+-- PostAsteriskCommentChars ::
+--        MultiLineNotForwardSlashOrAsteriskChar MultiLineCommentChars(opt)
+--        * PostAsteriskCommentChars(opt)
+-- MultiLineNotAsteriskChar ::
+--        SourceCharacter but not asterisk *
+-- MultiLineNotForwardSlashOrAsteriskChar ::
+--        SourceCharacter but not forward-slash / or asterisk *
+
+-- Skip multi-line comments. Note: may not nest
+-- <reg,divide> "/*"($any_char)*"*/"  ;
+-- <reg,divide> "/*" (($MultiLineNotAsteriskChar)*| ("*")+ ($MultiLineNotForwardSlashOrAsteriskChar) )* ("*")+ "/"  ;
+<reg,divide> "/*" (($MultiLineNotAsteriskChar)*| ("*")+ ($MultiLineNotForwardSlashOrAsteriskChar) )* ("*")+ "/"  { adapt (mkString commentToken) }
+
+
+-- Identifier    = {ID Head}{ID Tail}*
+-- <reg,divide> @IDHead(@IDTail)*  { \loc len str -> keywordOrIdent (take len str) loc }
+<reg,divide> @IdentifierStart(@IdentifierPart)*  { \ap@(loc,_,_,str) len -> keywordOrIdent (take len str) (toTokenPosn loc) }
+
+-- StringLiteral = '"' ( {String Chars1} | '\' {Printable} )* '"'
+--                | '' ( {String Chars2} | '\' {Printable} )* ''
+<reg,divide>  $dq ( $StringChars1 | \\ $printable | @LineContinuation )* $dq
+            | $sq ( $StringChars2 | \\ $printable | @LineContinuation )* $sq { adapt (mkString stringToken) }
+
+-- HexIntegerLiteral = '0x' {Hex Digit}+
+<reg,divide> ("0x"|"0X") @HexDigit+ { adapt (mkString hexIntegerToken) }
+
+-- OctalLiteral = '0' {Octal Digit}+
+<reg,divide> ("0") @OctDigit+ { adapt (mkString octalToken) }
+
+-- RegExp         = '/' ({RegExp Chars} | '\' {Non Terminator})+ '/' ( 'g' | 'i' | 'm' )*
+-- <reg> "/" ($RegExpChars | "\" $NonTerminator)+ "/" ("g"|"i"|"m")* { mkString regExToken }
+
+-- Based on the Jint version
+<reg> "/" ($RegExpFirstChar | "\" $NonTerminator)  ($RegExpChars | "\" $NonTerminator)* "/" ("g"|"i"|"m")* { adapt (mkString regExToken) }
+
+
+
+-- TODO: Work in SignedInteger
+
+-- DecimalLiteral= {Non Zero Digits}+ '.' {Digit}* ('e' | 'E' ) {Non Zero Digits}+ {Digit}*
+--              |  {Non Zero Digits}+ '.' {Digit}*
+--              | '0' '.' {Digit}+ ('e' | 'E' ) {Non Zero Digits}+ {Digit}*
+--              | {Non Zero Digits}+ {Digit}*
+--              | '0'
+--              | '0' '.' {Digit}+
+
+-- <reg,divide> $non_zero_digit $digit* "." $digit* ("e"|"E") ("+"|"-")? $non_zero_digit+ $digit*
+--     | $non_zero_digit $digit* "." $digit*
+--     | "0." $digit+  ("e"|"E") ("+"|"-")? $non_zero_digit+ $digit*
+--     | $non_zero_digit+ $digit*
+--     | "0"
+--     | "0." $digit+                    { mkString decimalToken }
+
+<reg,divide> "0"              "." $digit* ("e"|"E") ("+"|"-")? $digit+
+    | $non_zero_digit $digit* "." $digit* ("e"|"E") ("+"|"-")? $digit+
+    |                "." $digit+          ("e"|"E") ("+"|"-")? $digit+
+    |        "0"                          ("e"|"E") ("+"|"-")? $digit+
+    | $non_zero_digit $digit*             ("e"|"E") ("+"|"-")? $digit+
+-- ++FOO++
+    |        "0"              "." $digit*
+    | $non_zero_digit $digit* "." $digit*
+    |                "." $digit+
+    |        "0"
+    | $non_zero_digit $digit*         { adapt (mkString decimalToken) }
+
+
+-- beginning of file
+<bof> {
+   @eol_pattern                         ;
+   -- @eol_pattern                         { endOfLine lexToken }
+   -- @eol_pattern                         { endOfLine alexMonadScan }
+}
+
+-- / or /= only allowed in state 1
+<divide> {
+     "/="       { adapt (mkString assignToken)}
+     "/"       { adapt (symbolToken DivToken)}
+    }
+
+<reg,divide> {
+   --   \;     { adapt (symbolToken  SemiColonToken)}
+     ";"       { adapt (symbolToken  SemiColonToken)}
+     ","       { adapt (symbolToken  CommaToken)}
+     "?"       { adapt (symbolToken  HookToken)}
+     ":"       { adapt (symbolToken  ColonToken)}
+     "||"      { adapt (symbolToken  OrToken)}
+     "&&"      { adapt (symbolToken  AndToken)}
+     "|"       { adapt (symbolToken  BitwiseOrToken)}
+     "^"       { adapt (symbolToken  BitwiseXorToken)}
+     "&"       { adapt (symbolToken  BitwiseAndToken)}
+     "==="     { adapt (symbolToken  StrictEqToken)}
+     "=="      { adapt (symbolToken  EqToken)}
+     "*=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|="
+               { adapt (mkString assignToken)}
+     "="        { adapt (symbolToken  SimpleAssignToken)}
+     "!=="     { adapt (symbolToken  StrictNeToken)}
+     "!="      { adapt (symbolToken  NeToken)}
+     "<<"      { adapt (symbolToken  LshToken)}
+     "<="      { adapt (symbolToken  LeToken)}
+     "<"       { adapt (symbolToken  LtToken)}
+     ">>>"     { adapt (symbolToken  UrshToken)}
+     ">>"      { adapt (symbolToken  RshToken)}
+     ">="      { adapt (symbolToken  GeToken)}
+     ">"       { adapt (symbolToken  GtToken)}
+     "++"      { adapt (symbolToken  IncrementToken)}
+     "--"      { adapt (symbolToken  DecrementToken)}
+     "+"       { adapt (symbolToken  PlusToken)}
+     "-"       { adapt (symbolToken  MinusToken)}
+     "*"       { adapt (symbolToken  MulToken)}
+     "%"       { adapt (symbolToken  ModToken)}
+     "!"       { adapt (symbolToken  NotToken)}
+     "~"       { adapt (symbolToken  BitwiseNotToken)}
+     "."       { adapt (symbolToken  DotToken)}
+     "["       { adapt (symbolToken  LeftBracketToken)}
+     "]"       { adapt (symbolToken  RightBracketToken)}
+     "{"       { adapt (symbolToken  LeftCurlyToken)}
+     "}"       { adapt (symbolToken  RightCurlyToken)}
+     "("       { adapt (symbolToken  LeftParenToken)}
+     ")"       { adapt (symbolToken  RightParenToken)}
+     "@*/"     { adapt (symbolToken  CondcommentEndToken)}
+}
+
+
+
+
+
+{
+
+{-
+-- The next function select between the two lex input states, as called for in
+-- secion 7 of ECMAScript Language Specification, Edition 3, 24 March 2000.
+
+The method is inspired by the lexer in http://jint.codeplex.com/
+
+-}
+classifyToken :: Token -> Int
+classifyToken aToken =
+   case aToken of
+      IdentifierToken {}   -> divide
+      NullToken {}         -> divide
+      TrueToken {}         -> divide
+      FalseToken {}        -> divide
+      ThisToken {}         -> divide
+      OctalToken {}        -> divide
+      DecimalToken {}      -> divide
+      HexIntegerToken {}   -> divide
+      StringToken {}       -> divide
+      RightCurlyToken {}   -> divide
+      RightParenToken {}   -> divide
+      RightBracketToken {} -> divide
+      _other               -> reg
+
+
+{-
+--lexToken :: Alex Token
+lexToken = do
+  inp <- alexGetInput
+  lt  <- getLastToken
+  case alexScan inp (classifyToken lt) of
+    AlexEOF        -> alexEOF
+    AlexError inp'@(pos,_,_,_) -> alexError ("lexical error @ line " ++ show (getLineNum(pos)) ++
+                                             " and column " ++ show (getColumnNum(pos)))
+    AlexSkip inp' _len -> do
+       alexSetInput inp'
+       lexToken
+    AlexToken inp' len action -> do
+       alexSetInput inp'
+       token <- action (ignorePendingBytes inp) len
+       setLastToken token
+       return token
+-}
+
+--lexToken :: Alex Token
+lexToken = do
+  inp <- alexGetInput
+  lt  <- getLastToken
+  case lt of
+    TailToken {} -> alexEOF
+    _other ->
+      case alexScan inp (classifyToken lt) of
+        AlexEOF        -> do
+          token <- tailToken
+          setLastToken token
+          return token
+        AlexError inp'@(pos,_,_,_) -> alexError ("lexical error @ line " ++ show (getLineNum(pos)) ++
+                                                 " and column " ++ show (getColumnNum(pos)))
+        AlexSkip inp' _len -> do
+          alexSetInput inp'
+          lexToken
+        AlexToken inp' len action -> do
+          alexSetInput inp'
+          -- token <- action (ignorePendingBytes inp) len
+          token <- action inp len
+          setLastToken token
+          return token
+
+
+-- This is called by the Happy parser.
+--lexCont :: (Token -> P a) -> P a
+--lexCont :: (Token -> Alex Token) -> Alex Token
+lexCont cont = do
+   lexLoop
+   where
+   -- lexLoop :: P a
+   lexLoop = do
+      tok <- lexToken
+      case tok of
+         CommentToken {} -> do
+            addComment tok
+            lexLoop
+         WsToken {} -> do
+            addComment tok
+            lexLoop
+         _other -> do
+            cs <- getComment
+            let tok' = tok{ token_comment=(toCommentAnnotation cs) }
+            setComment []
+            cont tok'
+
+toCommentAnnotation []    = [NoComment]
+--toCommentAnnotation xs =  reverse $ map (\tok -> (CommentA (token_span tok) (token_literal tok))) xs
+
+toCommentAnnotation xs =  reverse $ map go xs
+  where
+    go tok@(CommentToken {}) = (CommentA (token_span tok) (token_literal tok))
+    go tok@(WsToken      {}) = (WhiteSpace (token_span tok) (token_literal tok))
+
+-- ---------------------------------------------------------------------
+
+getLineNum :: AlexPosn -> Int
+getLineNum (AlexPn _offset lineNum _colNum) = lineNum
+
+getColumnNum :: AlexPosn -> Int
+getColumnNum (AlexPn _offset _lineNum colNum) = colNum
+
+-- ---------------------------------------------------------------------
+
+getLastToken :: Alex Token
+getLastToken = Alex $ \s@AlexState{alex_ust=ust} -> Right (s, previousToken ust)
+
+setLastToken :: Token -> Alex ()
+setLastToken (WsToken {}) = Alex $ \s -> Right (s, ())
+setLastToken tok          = Alex $ \s -> Right (s{alex_ust=(alex_ust s){previousToken=tok}}, ())
+
+getComment :: Alex [Token]
+--getComments = reverse <$> Alex $ \s@AlexState{alex_ust=ust} -> Right (s, comments ust)
+getComment = Alex $ \s@AlexState{alex_ust=ust} -> Right (s, comment ust)
+
+
+addComment :: Token -> Alex ()
+addComment c = Alex $ \s ->  Right (s{alex_ust=(alex_ust s){comment=c:(  comment (alex_ust s)  )}}, ())
+
+
+setComment :: [Token] -> Alex ()
+setComment cs = Alex $ \s -> Right (s{alex_ust=(alex_ust s){comment=cs }}, ())
+
+alexEOF :: Alex Token
+alexEOF = do return (EOFToken tokenPosnEmpty [])
+
+tailToken :: Alex Token
+tailToken = do return (TailToken tokenPosnEmpty [])
+
+-- adapt :: (TokenPosn -> Int -> String -> Alex Token) -> (AlexPosn,Char,String) -> Int -> Alex Token
+adapt :: (TokenPosn -> Int -> String -> Alex Token) -> AlexInput -> Int -> Alex Token
+adapt f loc@(p@(AlexPn offset line col),_,_,inp) len =
+  (f (TokenPn offset line col) len inp)
+
+{-
+mkComment :: (AlexPosn,Char,String) -> Int -> Alex Token
+mkComment loc@(p@(AlexPn offset line col),_,inp) len = do
+  return (CommentToken (TokenPn offset line col) (take len inp))
+-}
+
+toTokenPosn :: AlexPosn -> TokenPosn
+toTokenPosn (AlexPn offset line col) = (TokenPn offset line col)
+
+-- ---------------------------------------------------------------------
+
+-- a keyword or an identifier (the syntax overlaps)
+keywordOrIdent :: String -> TokenPosn -> Alex Token
+keywordOrIdent str location
+   = return $ case Map.lookup str keywords of
+         Just symbol -> symbol location str []
+         Nothing -> IdentifierToken location str []
+
+-- mapping from strings to keywords
+--keywords :: Map.Map String (TokenPosn -> String -> Token)
+keywords :: Map.Map String (TokenPosn -> String -> [CommentAnnotation] -> Token)
+keywords = Map.fromList keywordNames
+
+--keywordNames :: [(String, TokenPosn -> String -> Token)]
+keywordNames :: [(String, TokenPosn -> String -> [CommentAnnotation] -> Token)]
+keywordNames =
+   [
+    ("break",BreakToken),
+    ("case",CaseToken),
+    ("catch",CatchToken),
+
+    ("const",ConstToken), -- not a keyword, nominally a future reserved word, but actually in use
+
+    ("continue",ContinueToken),
+    ("debugger",DebuggerToken),
+    ("default",DefaultToken),
+    ("delete",DeleteToken),
+    ("do",DoToken),
+    ("else",ElseToken),
+
+    ("enum",EnumToken),  -- not a keyword,  nominally a future reserved word, but actually in use
+
+    ("false",FalseToken), -- boolean literal
+
+    ("finally",FinallyToken),
+    ("for",ForToken),
+    ("function",FunctionToken),
+    ("if",IfToken),
+    ("in",InToken),
+    ("instanceof",InstanceofToken),
+    ("new",NewToken),
+
+    ("null",NullToken), -- null literal
+
+    ("return",ReturnToken),
+    ("switch",SwitchToken),
+    ("this",ThisToken),
+    ("throw",ThrowToken),
+    ("true",TrueToken),
+    ("try",TryToken),
+    ("typeof",TypeofToken),
+    ("var",VarToken),
+    ("void",VoidToken),
+    ("while",WhileToken),
+    ("with",WithToken),
+    -- TODO: no idea if these are reserved or not, but they are needed
+    --       handled in parser, in the Identifier rule
+    ("get",GetToken),("set",SetToken),
+    {- Come from Table 6 of ECMASCRIPT 5.1, Attributes of a Named Accessor Property
+       Also include
+
+         Enumerable
+         Configurable
+
+      Table 7 includes
+
+         Value
+     -}
+
+
+    -- Future Reserved Words
+    ("class", FutureToken),
+    -- ("code",  FutureToken), **** not any more
+    -- ("const", FutureToken), **** an actual token, used in productions
+    -- enum                    **** an actual token, used in productions
+    ("export",     FutureToken),
+    ("extends",    FutureToken),
+
+    ("import",     FutureToken),
+    ("super",      FutureToken),
+
+
+    -- Strict mode FutureReservedWords
+    ("implements", FutureToken),
+    ("interface",  FutureToken),
+    ("let",        FutureToken),
+    -- ("mode",       FutureToken),  **** not any more
+    -- ("of",         FutureToken),  **** not any more
+    -- ("one",        FutureToken),  **** not any more
+    -- ("or",         FutureToken),  **** not any more
+
+    ("package",    FutureToken),
+    ("private",    FutureToken),
+    ("protected",  FutureToken),
+    ("public",     FutureToken),
+    ("static",     FutureToken),
+    -- ("strict",     FutureToken),  *** not any more
+    ("yield",      FutureToken)
+   ]
+}
+
+
+-- -- Edition 5.1 of ECMASCRIPT
+
+-- 7.6.1.1 Keywords
+
+-- The following tokens are ECMAScript keywords and may not be used as Identifiers in ECMAScript programs.
+
+-- Syntax
+-- Keyword :: one of
+--   break
+--   case
+--   catch
+--   continue
+--   debugger
+--   default
+--   delete
+--   do
+--   else
+--   finally
+--   for
+--   function
+--   if
+--   in
+--   instanceof
+--   new
+--   return
+--   switch
+--   this
+--   throw
+--   try
+--   typeof
+--   var
+--   void
+--   while
+--   with
+
+-- 7.6.1.2 Future Reserved Words
+
+-- The following words are used as keywords in proposed extensions and
+-- are therefore reserved to allow for the possibility of future adoption
+-- of those extensions.
+
+-- Syntax
+-- FutureReservedWord :: one of
+--   class
+--   const
+--   enum
+--   export
+--   extends
+--   import
+--   super
+
+-- The following tokens are also considered to be FutureReservedWords
+-- when they occur within strict mode code (see 10.1.1). The occurrence
+-- of any of these tokens within strict mode code in any context where
+-- the occurrence of a FutureReservedWord would produce an error must
+-- also produce an equivalent error:
+
+--  implements
+--  interface
+--  let
+--  package
+--  private
+--  protected
+--  public
+--  static
+--  yield
+
+
+
+
+-- Set emacs mode
+-- Local Variables:
+-- mode:haskell
+-- End:
diff --git a/src/Language/JavaScript/Parser/LexerUtils.hs b/src/Language/JavaScript/Parser/LexerUtils.hs
new file mode 100644 (file)
index 0000000..eb48f9c
--- /dev/null
@@ -0,0 +1,110 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      : Language.JavaScript.LexerUtils
+-- Based on language-python version by Bernie Pope
+-- Copyright   : (c) 2009 Bernie Pope
+-- License     : BSD-style
+-- Stability   : experimental
+-- Portability : ghc
+--
+-- Various utilities to support the JavaScript lexer.
+-----------------------------------------------------------------------------
+
+module Language.JavaScript.Parser.LexerUtils (
+  StartCode
+  -- , AlexInput
+  -- , alexGetChar
+  -- , alexInputPrevChar
+  , symbolToken
+  , mkString
+  , commentToken
+  , wsToken
+  , regExToken
+  , decimalToken
+  -- , endOfLine
+  , endOfFileToken
+  , assignToken
+  , hexIntegerToken
+  , octalToken
+  , stringToken
+  --, lexicalError
+  ) where
+
+--import Control.Monad.Error.Class (throwError)
+import Language.JavaScript.Parser.Token as Token
+import Language.JavaScript.Parser.SrcLocation
+import Prelude hiding (span)
+
+-- Functions for building tokens
+
+type StartCode = Int
+
+symbolToken :: Monad m => (TokenPosn -> [CommentAnnotation] -> Token) -> TokenPosn -> Int -> String -> m Token
+symbolToken mkToken location _ _ = return (mkToken location [])
+
+-- special tokens for the end of file and end of line
+endOfFileToken :: Token
+endOfFileToken = EOFToken tokenPosnEmpty []
+
+mkString
+  :: (Monad m) => (TokenPosn -> String -> Token) -> TokenPosn -> Int -> String -> m Token
+mkString toToken loc len str = do return (toToken loc (take len str))
+
+decimalToken :: TokenPosn -> String -> Token
+decimalToken loc str = DecimalToken loc str []
+
+hexIntegerToken :: TokenPosn -> String -> Token
+hexIntegerToken loc str = HexIntegerToken loc str []
+
+octalToken :: TokenPosn -> String -> Token
+octalToken loc str = OctalToken loc str []
+
+assignToken :: TokenPosn -> String -> Token
+assignToken loc str = AssignToken loc str []
+
+regExToken :: TokenPosn -> String -> Token
+regExToken loc str = RegExToken loc str []
+
+stringToken :: TokenPosn -> String -> Token
+stringToken loc str = StringToken loc str1 delimiter []
+  where
+    str1 = init $ tail str
+    -- str1 = stripLineContinuations $ init $ tail str
+    delimiter = head str
+
+commentToken :: TokenPosn -> String -> Token
+commentToken loc str = CommentToken loc str []
+
+wsToken :: TokenPosn -> String -> Token
+wsToken loc str = WsToken loc str []
+
+-- ---------------------------------------------------------------------
+-- Strip out any embedded line continuations
+-- Recognise by \ followed by $lf | $cr | $ls | $ps | $cr $lf
+-- $ls = \x2028, $ps = \x2029
+stripLineContinuations :: String -> String
+stripLineContinuations xs = doStripLineContinuations [] [] xs
+
+doStripLineContinuations :: String -> String -> String -> String
+doStripLineContinuations acc matched xs
+  | xs == []      = acc -- Assume we are passed well-formed strings, should not be a dangling match
+  | matched == [] = if (head xs == '\\')
+                        then doStripLineContinuations acc ['\\'] (tail xs)
+                        else doStripLineContinuations (acc ++ [head xs]) [] (tail xs)
+  | otherwise = if ((head xs == '\n') || (head xs == '\r') || (head xs == '\x2028') || (head xs == '\x2029'))
+                        then doStripLineContinuations acc (matched++[head xs]) (tail xs)
+                        else (if (matched == ['\\'])
+                                 then doStripLineContinuations (acc++matched ++ [head xs]) [] (tail xs)
+                                 else doStripLineContinuations (acc++[head xs]) [] (tail xs))
+
+-- -----------------------------------------------------------------------------
+-- Functionality required by Alex
+{-
+lexicalError :: P a
+lexicalError = do
+  location <- getLocation
+  c <- liftM head getInput
+  -- (_,c,_,_) <- getInput
+  throwError $ UnexpectedChar c location
+-}
+-- EOF
diff --git a/src/Language/JavaScript/Parser/ParseError.hs b/src/Language/JavaScript/Parser/ParseError.hs
new file mode 100644 (file)
index 0000000..318be95
--- /dev/null
@@ -0,0 +1,34 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      : Language.JavaScript.ParseError
+-- Based on language-python version by Bernie Pope
+-- Copyright   : (c) 2009 Bernie Pope
+-- License     : BSD-style
+-- Stability   : experimental
+-- Portability : ghc
+--
+-- Error values for the lexer and parser.
+-----------------------------------------------------------------------------
+
+module Language.JavaScript.Parser.ParseError ( ParseError (..) ) where
+
+--import Language.JavaScript.Parser.Pretty
+import Control.Monad.Error.Class
+import Language.JavaScript.Parser.Lexer
+import Language.JavaScript.Parser.SrcLocation (TokenPosn)
+-- import Language.JavaScript.Parser.Token (Token)
+
+data ParseError
+   = UnexpectedToken Token
+     -- ^ An error from the parser. Token found where it should not be.
+     --   Note: tokens contain their own source span.
+   | UnexpectedChar Char TokenPosn
+     -- ^ An error from the lexer. Character found where it should not be.
+   | StrError String
+     -- ^ A generic error containing a string message. No source location.
+   deriving (Eq, {- Ord,-} Show)
+
+instance Error ParseError where
+   noMsg = StrError ""
+   strMsg = StrError
+
diff --git a/src/Language/JavaScript/Parser/Parser.hs b/src/Language/JavaScript/Parser/Parser.hs
new file mode 100644 (file)
index 0000000..1ad8ead
--- /dev/null
@@ -0,0 +1,78 @@
+module Language.JavaScript.Parser.Parser (
+   -- * Parsing
+     parse
+   , readJs
+   -- , readJsKeepComments
+   , parseFile
+   , parseFileUtf8
+   -- * Parsing expressions
+   -- parseExpr
+   , parseUsing
+   , showStripped
+   , showStrippedMaybe
+   ) where
+
+import Language.JavaScript.Parser.ParseError
+import Language.JavaScript.Parser.Grammar5
+import Language.JavaScript.Parser.Lexer
+import qualified Language.JavaScript.Parser.AST as AST
+import System.IO
+
+-- | Parse one compound statement, or a sequence of simple statements.
+-- Generally used for interactive input, such as from the command line of an interpreter.
+-- Return comments in addition to the parsed statements.
+parse :: String -- ^ The input stream (Javascript source code).
+      -> String -- ^ The name of the Javascript source (filename or input device).
+      -> Either String  AST.JSNode
+         -- ^ An error or maybe the abstract syntax tree (AST) of zero
+         -- or more Javascript statements, plus comments.
+parse input _srcName = runAlex input parseProgram
+
+
+readJs :: String -> AST.JSNode
+readJs input = do
+  case (parse input "src") of
+    Left msg -> error (show msg)
+    Right p -> p
+
+-- | Parse the given file.
+-- For UTF-8 support, make sure your locale is set such that
+-- "System.IO.localeEncoding" returns "utf8"
+parseFile :: FilePath -> IO AST.JSNode
+parseFile filename =
+  do
+     x <- readFile (filename)
+     return $ readJs x
+
+-- | Parse the given file, explicitly setting the encoding to UTF8
+-- when reading it
+parseFileUtf8 :: FilePath -> IO AST.JSNode
+parseFileUtf8 filename =
+  do
+     h <- openFile filename ReadMode
+     hSetEncoding h utf8
+     x <- hGetContents h
+     return $ readJs x
+
+showStripped :: AST.JSNode -> String
+showStripped ast = AST.showStripped ast
+
+showStrippedMaybe :: Show a => Either a AST.JSNode -> String
+showStrippedMaybe maybeAst = do
+  case maybeAst of
+    Left msg -> "Left (" ++ show msg ++ ")"
+    Right p -> "Right (" ++ AST.showStripped p ++ ")"
+
+-- | Parse one compound statement, or a sequence of simple statements.
+-- Generally used for interactive input, such as from the command line of an interpreter.
+-- Return comments in addition to the parsed statements.
+parseUsing ::
+      Alex AST.JSNode -- ^ The parser to be used
+      -> String -- ^ The input stream (Javascript source code).
+      -> String -- ^ The name of the Javascript source (filename or input device).
+      -> Either String AST.JSNode
+         -- ^ An error or maybe the abstract syntax tree (AST) of zero
+         -- or more Javascript statements, plus comments.
+
+parseUsing p input _srcName = runAlex input p
+
diff --git a/src/Language/JavaScript/Parser/ParserMonad.hs b/src/Language/JavaScript/Parser/ParserMonad.hs
new file mode 100644 (file)
index 0000000..935ea0c
--- /dev/null
@@ -0,0 +1,37 @@
+{-# OPTIONS  #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      : Language.JavaScript.ParserMonad
+-- Copyright   : (c) 2012 Alan Zimmerman
+-- License     : BSD-style
+-- Stability   : experimental
+-- Portability : ghc
+--
+-- Monad support for JavaScript parser and lexer.
+-----------------------------------------------------------------------------
+
+module Language.JavaScript.Parser.ParserMonad
+       (
+         AlexUserState(..)
+       , alexInitUserState
+       ) where
+
+import Language.JavaScript.Parser.Token
+import Language.JavaScript.Parser.SrcLocation
+
+data AlexUserState = AlexUserState
+  {
+    previousToken :: !Token  -- ^the previous token
+  , comment :: [Token]       -- ^the previous comment, if any
+  }
+
+alexInitUserState :: AlexUserState
+alexInitUserState = AlexUserState
+   {
+     previousToken = initToken
+   , comment = []
+   }
+
+initToken :: Token
+initToken = CommentToken tokenPosnEmpty "" []
+
diff --git a/src/Language/JavaScript/Parser/SrcLocation.hs b/src/Language/JavaScript/Parser/SrcLocation.hs
new file mode 100644 (file)
index 0000000..d9c8586
--- /dev/null
@@ -0,0 +1,21 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+module Language.JavaScript.Parser.SrcLocation (
+  TokenPosn(..)
+  , tokenPosnEmpty
+  ) where
+
+import Data.Data
+
+-- | `TokenPosn' records the location of a token in the input text.  It has three
+-- fields: the address (number of characters preceding the token), line number
+-- and column of a token within the file.
+-- Note: The lexer assumes the usual eight character tab stops.
+
+data TokenPosn = TokenPn !Int -- address (number of characters preceding the token)
+                         !Int -- line number
+                         !Int -- column
+        deriving (Eq,Show, Read, Data, Typeable)
+
+tokenPosnEmpty :: TokenPosn
+tokenPosnEmpty = TokenPn 0 0 0
+
diff --git a/src/Language/JavaScript/Parser/StringEscape.hs b/src/Language/JavaScript/Parser/StringEscape.hs
new file mode 100644 (file)
index 0000000..6ba5be5
--- /dev/null
@@ -0,0 +1,82 @@
+{-# OPTIONS  #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      : Language.Python.Common.StringEscape
+-- Copyright   : (c) 2009 Bernie Pope 
+-- License     : BSD-style
+-- Maintainer  : bjpop@csse.unimelb.edu.au
+-- Stability   : experimental
+-- Portability : ghc
+--
+-- Conversion to/from escaped characters in strings. Note: currently does not
+-- support escaped Unicode character names.
+-- 
+-- See:
+-- 
+--    * Version 2.6 <http://www.python.org/doc/2.6/reference/lexical_analysis.html#string-literals>
+--  
+--    * Version 3.1 <http://www.python.org/doc/3.1/reference/lexical_analysis.html#string-and-bytes-literals> 
+-----------------------------------------------------------------------------
+
+module Language.JavaScript.Parser.StringEscape ( 
+   -- * String conversion. 
+   unescapeString, 
+   unescapeRawString,
+   -- * Digits allowed in octal and hex representation.
+   octalDigits,
+   hexDigits) where
+
+import Numeric (readHex, readOct)
+
+-- | Convert escaped sequences of characters into /real/ characters in a normal Python string.
+unescapeString :: String -> String
+unescapeString ('\\':'\\':cs) = '\\' : unescapeString cs -- Backslash (\)
+unescapeString ('\\':'\'':cs) = '\'' : unescapeString cs -- Single quote (')
+unescapeString ('\\':'"':cs) = '"' : unescapeString cs   -- Double quote (")
+unescapeString ('\\':'a':cs) = '\a' : unescapeString cs  -- ASCII Bell (BEL)
+unescapeString ('\\':'b':cs) = '\b' : unescapeString cs  -- ASCII Backspace (BS)
+unescapeString ('\\':'f':cs) = '\f' : unescapeString cs  -- ASCII Formfeed (FF)
+unescapeString ('\\':'n':cs) = '\n' : unescapeString cs  -- ASCII Linefeed (LF)
+unescapeString ('\\':'r':cs) = '\r' : unescapeString cs  -- ASCII Carriage Return (CR)
+unescapeString ('\\':'t':cs) = '\t' : unescapeString cs  -- ASCII Horizontal Tab (TAB)
+unescapeString ('\\':'v':cs) = '\v' : unescapeString cs  -- ASCII Vertical Tab (VT)
+unescapeString ('\\':'\n':cs) = unescapeString cs        -- line continuation
+unescapeString ('\\':rest@(o:_))
+   | o `elem` octalDigits = unescapeNumeric 3 octalDigits (fst . head . readOct) rest 
+unescapeString ('\\':'x':rest@(h:_))
+   | h `elem` hexDigits = unescapeNumeric 2 hexDigits (fst . head . readHex) rest 
+unescapeString (c:cs) = c : unescapeString cs 
+unescapeString [] = []
+
+-- | Convert escaped sequences of characters into /real/ characters in a raw Python string.
+-- Note: despite their name, Python raw strings do allow a small set of character escapings,
+-- namely the single and double quote characters and the line continuation marker.
+unescapeRawString :: String -> String
+unescapeRawString ('\\':'\'':cs) = '\'' : unescapeRawString cs -- Single quote (')
+unescapeRawString ('\\':'"':cs) = '"' : unescapeRawString cs -- Double quote (")
+unescapeRawString ('\\':'\n':cs) = unescapeRawString cs -- line continuation
+unescapeRawString (c:cs) = c : unescapeRawString cs
+unescapeRawString [] = []
+
+{- 
+   This is a bit complicated because Python allows between 1 and 3 octal
+   characters after the \, and 1 and 2 hex characters after a \x.
+-}
+unescapeNumeric :: Int -> String -> (String -> Int) -> String -> String
+unescapeNumeric n numericDigits readNumeric str
+   = loop n [] str 
+   where
+   loop _ acc [] = [numericToChar acc]
+   loop 0 acc rest
+      = numericToChar acc : unescapeString rest
+   loop n1 acc (c:cs)
+      | c `elem` numericDigits = loop (n1-1) (c:acc) cs
+      | otherwise = numericToChar acc : unescapeString (c:cs)
+   numericToChar :: String -> Char
+   numericToChar = toEnum . readNumeric . reverse
+
+octalDigits, hexDigits :: String
+-- | The set of valid octal digits in Python.
+octalDigits = "01234567"
+-- | The set of valid hex digits in Python.
+hexDigits = "0123456789abcdef"
diff --git a/src/Language/JavaScript/Parser/Token.hs b/src/Language/JavaScript/Parser/Token.hs
new file mode 100644 (file)
index 0000000..9a1ec40
--- /dev/null
@@ -0,0 +1,152 @@
+{-# LANGUAGE CPP, DeriveDataTypeable #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      : Language.Python.Common.Token
+-- Copyright   : (c) 2009 Bernie Pope
+-- License     : BSD-style
+-- Maintainer  : bjpop@csse.unimelb.edu.au
+-- Stability   : experimental
+-- Portability : ghc
+--
+-- Lexical tokens for the Python lexer. Contains the superset of tokens from
+-- version 2 and version 3 of Python (they are mostly the same).
+-----------------------------------------------------------------------------
+
+module Language.JavaScript.Parser.Token (
+   -- * The tokens
+   Token (..)
+   , CommentAnnotation(..)
+   -- * String conversion
+   , debugTokenString
+   -- * Classification
+   -- TokenClass (..),
+   ) where
+
+import Data.Data
+import Language.JavaScript.Parser.SrcLocation
+
+data CommentAnnotation = CommentA TokenPosn String
+                       | WhiteSpace TokenPosn String
+                       | NoComment
+   deriving (Eq,{-Ord,-}Show,Typeable,Data,Read)
+
+-- | Lexical tokens.
+-- Each may be annotated with any comment occuring between the prior token and this one
+data Token
+   -- Comment
+   = CommentToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation] } -- ^ Single line comment.
+   | WsToken      { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation] } -- ^ White space, for preservation.
+
+   -- Identifiers
+   | IdentifierToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }            -- ^ Identifier.
+
+   -- Javascript Literals
+
+   | DecimalToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]   }
+     -- ^ Literal: Decimal
+   | HexIntegerToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]   }
+     -- ^ Literal: Hexadecimal Integer
+   | OctalToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]   }
+     -- ^ Literal: Octal Integer
+   | StringToken { token_span :: !TokenPosn, token_literal :: !String, token_delimiter :: !Char, token_comment :: ![CommentAnnotation]  }
+     -- ^ Literal: string, delimited by either single or double quotes
+   | RegExToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]   }
+     -- ^ Literal: Regular Expression
+
+   -- Keywords
+   | BreakToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | CaseToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | CatchToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | ConstToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | ContinueToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | DebuggerToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | DefaultToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | DeleteToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | DoToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | ElseToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | EnumToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | FalseToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | FinallyToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | ForToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | FunctionToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | IfToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | InToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | InstanceofToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | NewToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | NullToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | ReturnToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | SwitchToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | ThisToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | ThrowToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | TrueToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | TryToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | TypeofToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | VarToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | VoidToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | WhileToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | WithToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   -- Future reserved words
+   | FutureToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   -- Needed, not sure what they are though.
+   | GetToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | SetToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+
+   -- Delimiters
+   -- Operators
+   | SemiColonToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | CommaToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | HookToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | ColonToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | OrToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | AndToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | BitwiseOrToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | BitwiseXorToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | BitwiseAndToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | StrictEqToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | EqToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | AssignToken { token_span :: !TokenPosn, token_literal :: !String, token_comment :: ![CommentAnnotation]  }
+   | SimpleAssignToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | StrictNeToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | NeToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | LshToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | LeToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | LtToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | UrshToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | RshToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | GeToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | GtToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | IncrementToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | DecrementToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | PlusToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | MinusToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | MulToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | DivToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | ModToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | NotToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | BitwiseNotToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | DotToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | LeftBracketToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | RightBracketToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | LeftCurlyToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | RightCurlyToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | LeftParenToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | RightParenToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+   | CondcommentEndToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }
+
+   -- Special cases
+   | TailToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  } -- ^ Stuff between last JS and EOF
+   | EOFToken { token_span :: !TokenPosn, token_comment :: ![CommentAnnotation]  }  -- ^ End of file
+   deriving (Eq,{-Ord,-}Show,Typeable{-,Data-})
+
+
+-- | Produce a string from a token containing detailed information. Mainly intended for debugging.
+debugTokenString :: Token -> String
+debugTokenString _token =
+  "blah"
+  {-
+   render (text (show $ toConstr token) <+> pretty (token_span token) <+>
+          if hasLiteral token then text (token_literal token) else empty)
+   -}
+
+
+-- EOF
diff --git a/src/Language/JavaScript/Pretty/Printer.hs b/src/Language/JavaScript/Pretty/Printer.hs
new file mode 100644 (file)
index 0000000..e0e03e6
--- /dev/null
@@ -0,0 +1,223 @@
+module Language.JavaScript.Pretty.Printer (
+  -- * Printing
+  renderJS
+  , renderToString
+  ) where
+
+import Data.Char
+import Data.List
+import Data.Monoid (Monoid, mappend, mempty, mconcat)
+import Language.JavaScript.Parser.AST
+import Language.JavaScript.Parser.Parser
+import Language.JavaScript.Parser.SrcLocation
+import Language.JavaScript.Parser.Token
+import qualified Blaze.ByteString.Builder as BB
+import qualified Blaze.ByteString.Builder.Char.Utf8 as BS
+import qualified Data.ByteString.Lazy as LB
+import qualified Codec.Binary.UTF8.String as US
+
+import Debug.Trace
+
+-- ---------------------------------------------------------------------
+
+data Foo = Foo (Int,Int) BB.Builder
+
+-- ---------------------------------------------------------------------
+-- Pretty printer stuff via blaze-builder
+
+(<>) :: BB.Builder -> BB.Builder -> BB.Builder
+(<>) a b = mappend a b
+
+(<+>) :: BB.Builder -> BB.Builder -> BB.Builder
+(<+>) a b = mconcat [a, (text " "), b]
+
+--() ((Int, Int), BB.Builder) -> ((Int, Int), BB.Builder) -> ((Int, Int), BB.Builder)
+--() a b =
+
+hcat :: (Monoid a) => [a] -> a
+hcat xs = mconcat xs
+
+empty :: BB.Builder
+empty = mempty
+
+text :: String -> BB.Builder
+text s = BS.fromString s
+
+char :: Char -> BB.Builder
+char c = BS.fromChar c
+
+comma :: BB.Builder
+comma = BS.fromChar ','
+
+punctuate :: a -> [a] -> [a]
+punctuate p xs = intersperse p xs
+
+-- ---------------------------------------------------------------------
+
+(<!>) :: Foo -> Foo -> Foo
+(<!>) (Foo _ bb1) (Foo (r,c) bb2) = Foo (r,c) (mappend bb1 bb2)
+--(<!>) a b = mappend a b
+
+-- ---------------------------------------------------------------------
+
+renderJS :: JSNode -> BB.Builder
+renderJS node = bb
+  where
+    Foo _ bb = rn node (Foo (1,1) empty)
+
+-- Take in the current
+-- rn :: (Int, Int) -> JSNode -> ((Int, Int), BB.Builder)
+rn :: JSNode -> Foo -> Foo
+
+-- Terminals
+rn (NT (JSIdentifier s     ) p cs) foo = rcs cs p s  foo
+rn (NT (JSDecimal i        ) p cs) foo = rcs cs p i foo
+rn (NT (JSLiteral l        ) p cs) foo = rcs cs p l foo
+rn (NT (JSHexInteger i     ) p cs) foo = rcs cs p i foo
+rn (NT (JSOctal i          ) p cs) foo = rcs cs p i foo
+rn (NT (JSStringLiteral s l) p cs) foo = rcs cs p ((s:l)++[s]) foo
+rn (NT (JSRegEx s          ) p cs) foo = rcs cs p s foo
+
+-- Non-Terminals
+rn (NN (JSArguments lb xs rb))                    foo = rJS ([lb] ++ xs ++ [rb]) foo
+rn (NN (JSArrayLiteral lb xs rb))                 foo = rJS ([lb] ++ xs ++ [rb]) foo
+rn (NN (JSBlock lb x rb))                         foo = rJS (lb ++ x ++ rb) foo
+rn (NN (JSBreak b x1s as))                        foo = rJS ([b]++x1s++[as]) foo
+rn (NN (JSCallExpression s os xs cs))             foo = rJS (os ++ xs ++ cs) foo
+rn (NN (JSCase ca x1 c x2s))                      foo = rJS ([ca,x1,c]++x2s) foo
+rn (NN (JSCatch c lb x1 x2s rb x3))               foo = rJS ([c,lb,x1]++x2s++[rb,x3]) foo
+rn (NN (JSContinue c xs as))                      foo = rJS ([c]++xs++[as]) foo
+rn (NN (JSDefault d c xs))                        foo = rJS ([d,c]++xs) foo
+rn (NN (JSDoWhile d x1 w lb x2 rb x3))            foo = rJS ([d,x1,w,lb,x2,rb,x3]) foo
+rn (NN (JSElision c))                             foo = rJS [c] foo
+rn (NN (JSExpression xs))                         foo = rJS xs foo
+rn (NN (JSExpressionBinary s lhs op rhs))         foo = rJS (lhs ++ [op] ++ rhs) foo
+rn (NN (JSExpressionParen lb e rb))               foo = rJS ([lb,e,rb]) foo
+rn (NN (JSExpressionPostfix s xs op))             foo = rJS (xs ++ [op]) foo
+rn (NN (JSExpressionTernary cond h v1 c v2))      foo = rJS (cond ++[h] ++ v1 ++ [c] ++ v2) foo
+rn (NN (JSFinally f x))                           foo = rJS [f,x] foo
+rn (NN (JSFor f lb x1s s1 x2s s2 x3s rb x4))      foo = rJS ([f,lb]++x1s++[s1]++x2s++[s2]++x3s++[rb,x4]) foo
+rn (NN (JSForIn f lb x1s i x2 rb x3))             foo = rJS ([f,lb]++x1s++[i,x2,rb,x3]) foo
+rn (NN (JSForVar f lb v x1s s1 x2s s2 x3s rb x4)) foo = rJS ([f,lb,v]++x1s++[s1]++x2s++[s2]++x3s++[rb,x4]) foo
+rn (NN (JSForVarIn f lb v x1 i x2 rb x3))         foo = rJS [f,lb,v,x1,i,x2,rb,x3] foo
+rn (NN (JSFunction f x1 lb x2s rb x3))            foo = rJS ([f,x1,lb]++x2s++[rb,x3]) foo
+-- rn (NN (JSFunctionBody xs))                       foo = rJS xs foo
+rn (NN (JSFunctionExpression f x1s lb x2s rb x3)) foo = rJS ([f] ++ x1s ++ [lb] ++ x2s ++ [rb,x3]) foo
+rn (NN (JSIf i lb x1 rb x2s x3s))                 foo = rJS ([i,lb,x1,rb]++x2s++x3s) foo
+rn (NN (JSLabelled l c v))                        foo = rJS [l,c,v] foo
+rn (NN (JSMemberDot xs dot n))                    foo = rJS (xs ++ [dot,n]) foo
+rn (NN (JSMemberSquare xs lb e rb))               foo = rJS (xs ++ [lb,e,rb]) foo
+rn (NN (JSObjectLiteral lb xs rb))                foo = rJS ([lb] ++ xs ++ [rb]) foo
+rn (NN (JSOperator n))                            foo = rJS [n] foo
+rn (NN (JSPropertyAccessor s n lb1 ps rb1 b))     foo = rJS ([s,n,lb1] ++ ps ++ [rb1,b]) foo
+rn (NN (JSPropertyNameandValue n colon vs))       foo = rJS ([n,colon] ++ vs) foo
+rn (NN (JSReturn r xs as))                        foo = rJS ([r] ++ xs ++ [as]) foo
+-- rn (NN (JSSourceElements    xs))                  foo = rJS xs foo
+rn (NN (JSSourceElementsTop xs))                  foo = rJS xs foo
+-- rn (NN (JSStatementBlock lb x rb))                foo = rJS [lb,x,rb] foo
+-- rn (NN (JSStatementList xs))                      foo = rJS xs foo
+rn (NN (JSSwitch s lb x rb x2))                   foo = rJS ([s,lb,x,rb,x2]) foo
+rn (NN (JSThrow t x))                             foo = rJS [t,x] foo
+rn (NN (JSTry t x1 x2s))                          foo = rJS ([t,x1]++x2s) foo
+rn (NN (JSUnary l n))                             foo = rJS [n] foo
+rn (NN (JSVarDecl x1 x2s))                        foo = rJS ([x1]++x2s) foo
+rn (NN (JSVariables n xs as))                     foo = rJS ([n]++xs++[as]) foo
+rn (NN (JSWhile w lb x1 rb x2))                   foo = rJS [w,lb,x1,rb,x2] foo
+rn (NN (JSWith w lb x1 rb x2s))                   foo = rJS ([w,lb,x1,rb]++x2s) foo
+
+-- Debug helper
+rn what foo = rs (show what) foo
+
+--rn _ _ = undefined
+
+-- ---------------------------------------------------------------------
+-- Helper functions
+
+-- ---------------------------------------------------------------------
+-- Need a function that
+-- a) renders all comments, according to their positions
+-- b) advances to the position of the required string
+-- c) renders the string, advancing the position
+rcs :: [CommentAnnotation] -> TokenPosn -> String -> Foo -> Foo
+rcs cs p s foo = rps p s (rc cs foo)
+
+rc :: [CommentAnnotation] -> Foo -> Foo
+rc cs foo = foldl' go foo cs
+  where
+    go :: Foo -> CommentAnnotation -> Foo
+    go foo NoComment = foo
+    go foo (CommentA   p s) = rps p s foo
+    go foo (WhiteSpace p s) = rps p s foo
+
+-- Render a string at the given position
+rps :: TokenPosn -> String -> Foo -> Foo
+rps p s foo = (rs s foo')
+  where
+    foo' = (goto p foo)
+
+-- Render a string
+rs :: String -> Foo -> Foo
+rs s (Foo (r,c) bb) = (Foo (r',c') (bb <> (text s)))
+  where
+    (r',c') = foldl' (\(row,col) char -> go (row,col) char) (r,c) s
+
+    go (r,c) '\n' = (r+1,1)
+    go (r,c) '\t' = (r,c+8)
+    go (r,c) _    = (r,c+1)
+
+
+goto :: TokenPosn -> Foo -> Foo
+goto (TokenPn _ ltgt ctgt) (Foo (lcur,ccur) bb) = (Foo (lnew,cnew) (bb <> bb'))
+-- goto (TokenPn _ ltgt ctgt) (Foo (lcur,ccur) bb) = trace ("goto " ++ (show $ (ltgt,ctgt)) ++ "," ++ (show $ (lcur,ccur)) ++ "," ++ (show $ (lnew,cnew)) ) $  (Foo (lnew,cnew) (bb <> bb'))
+  where
+    (bbline,ccur') = if (lcur < ltgt) then (text $ (take (ltgt - lcur) $ repeat '\n'),1) else (mempty,ccur)
+    bbcol  = if (ccur' < ctgt) then (text $ take (ctgt - ccur') $ repeat ' ' ) else mempty
+    bb' = bbline <> bbcol
+    lnew = if (lcur < ltgt) then ltgt else lcur
+    cnew = if (ccur' < ctgt) then ctgt else ccur'
+
+
+rJS :: [JSNode] -> Foo -> Foo
+rJS xs foo = foldl' (flip rn) foo xs
+
+renderToString :: JSNode -> String
+-- need to be careful to not lose the unicode encoding on output
+renderToString js = US.decode $ LB.unpack $ BB.toLazyByteString $ renderJS js
+
+
+-- ---------------------------------------------------------------------
+-- Test stuff
+
+_r :: JSNode -> String
+_r js = map (\x -> chr (fromIntegral x)) $ LB.unpack $ BB.toLazyByteString $ renderJS js
+
+_t :: String -> String
+_t str = _r $ readJs str
+
+
+-- readJs "/*a*/x"
+_ax = (NN
+     (JSExpression
+       [NT
+        (JSIdentifier "x")
+        (TokenPn 5 1 6)
+        [CommentA (TokenPn 0 1 1) "/*a*/"]])
+      )
+
+
+-- readJs "//j\nthis_"
+-- NS (JSSourceElementsTop [NS (JSExpression [NS (JSIdentifier "this_") (TokenPn 4 2 1) [CommentA (TokenPn 0 1 1) "//j"]]) (TokenPn 4 2 1) []]) (TokenPn 4 2 1) []
+
+_r1 = NN
+      (
+        JSExpression
+          [
+            NT
+              (JSIdentifier "this_")
+              (TokenPn 4 2 1)
+              [CommentA (TokenPn 0 1 1) "//j"]
+          ])
+
+
+-- EOF
+
diff --git a/test/Unicode.js b/test/Unicode.js
new file mode 100644 (file)
index 0000000..1ac26e1
--- /dev/null
@@ -0,0 +1,6 @@
+// -*- coding: utf-8 -*-
+
+àáâãäå = 1;
+
+
\ No newline at end of file
diff --git a/test/k.js b/test/k.js
new file mode 100644 (file)
index 0000000..232c4b9
--- /dev/null
+++ b/test/k.js
@@ -0,0 +1 @@
+function f() {}
diff --git a/test/unicode.txt b/test/unicode.txt
new file mode 100644 (file)
index 0000000..b18bbfe
--- /dev/null
@@ -0,0 +1,30 @@
+-*- coding: utf-8; mode: xub -*-
+¢ € ₠ £ ¥ ¤
+ ° © ® ™ § ¶ † ‡ ※
+ •◦ ‣ ✓ ●■◆ ○□◇ ★☆ ♠♣♥♦ ♤♧♡♢
+ “” ‘’ ¿¡  «» ‹›  ¶§ª - ‐ ‑ ‒ – — ― …
+àáâãäåæç èéêë ìíîï ðñòóôõö øùúûüýþÿ ÀÁÂÃÄÅ Ç ÈÉÊË ÌÍÎÏ ÐÑ ÒÓÔÕÖ ØÙÚÛÜÝÞß 
+Æ  ᴁ ᴂ ᴈ
+ ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω
+ ⌈⌉ ⌊⌋ ∏ ∑ ∫ ×÷ ⊕ ⊖ ⊗ ⊘ ⊙ ∙ ∘ ′ ″ ‴ ∼ ∂ √ ≔ × ⁱ ⁰ ¹ ² ³ ₀ ₁ ₂
+ π ∞ ± ∎
+ ∀¬∧∨∃⊦∵∴∅∈∉⊂⊃⊆⊇⊄⋂⋃
+ ≠≤≥≮≯≫≪≈≡
+ ℕℤℚℝℂ
+ ←→↑↓ ↔ ↖↗↙↘  ⇐⇒⇑⇓ ⇔⇗  ⇦⇨⇧⇩ ↞↠↟↡ ↺↻ ☞☜☝☟
+λ ƒ Ɱ
+ ⌘ ⌥ ‸ ⇧ ⌤ ↑ ↓ → ← ⇞ ⇟ ↖ ↘ ⌫ ⌦ ⎋⏏ ↶↷ ◀▶▲▼ ◁▷△▽ ⇄ ⇤⇥ ↹ ↵↩⏎ ⌧ ⌨ ␣ ⌶ ⎗⎘⎙⎚ ⌚⌛ ✂✄ ✉✍
+
+ ♩♪♫♬♭♮♯
+ ➀➁➂➃➄➅➆➇➈➉
+ 卐卍✝✚✡☥⎈☭☪☮☺☹ ☯☰☱☲☳☴☵☶☷ ☠☢☣☤♲♳⌬♨♿ ☉☼☾☽ ♀♂ ♔♕♖ ♗♘♙ ♚♛ ♜♝♞♟
+ ❦
+ 、。!,:「」『』〈〉《》〖〗【】〔〕
+
+ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ
+
+林花謝了春紅 太匆匆, 無奈朝來寒雨 晚來風
+胭脂淚 留人醉 幾時重, 自是人生長恨 水長東
+
+ http://xahlee.org/emacs/unicode-browser.html
+ http://xahlee.org/Periodic_dosage_dir/t1/20040505_unicode.html