├── .ghci ├── .gitignore ├── .travis.yml ├── ChangeLog.md ├── LICENSE ├── Makefile ├── README.md ├── Setup.hs ├── TODO.txt ├── cabal.project ├── ecmascript3.txt ├── ecmascript5.txt ├── language-javascript.cabal ├── src └── Language │ └── JavaScript │ ├── Parser.hs │ ├── Parser │ ├── AST.hs │ ├── Grammar.y │ ├── Grammar7.y │ ├── Lexer.x │ ├── LexerUtils.hs │ ├── ParseError.hs │ ├── Parser.hs │ ├── ParserMonad.hs │ ├── SrcLocation.hs │ └── Token.hs │ ├── Pretty │ └── Printer.hs │ └── Process │ └── Minify.hs ├── test ├── Test │ └── Language │ │ └── Javascript │ │ ├── ExpressionParser.hs │ │ ├── Lexer.hs │ │ ├── LiteralParser.hs │ │ ├── Minify.hs │ │ ├── ModuleParser.hs │ │ ├── ProgramParser.hs │ │ ├── RoundTrip.hs │ │ └── StatementParser.hs ├── Unicode.js ├── k.js ├── testsuite.hs └── unicode.txt └── unicode ├── combiningmark.sh ├── connector-punctuation.sh ├── digit.sh ├── doit.sh ├── list-cm.txt ├── list-nd.txt ├── list-pc.txt ├── list.hs └── list.txt /.ghci: -------------------------------------------------------------------------------- 1 | -- Startup commands for the GHC interpreter 2 | :set -hide-package monads-tf 3 | :set -hide-package monads-fd 4 | :set -i./src 5 | :set -i./dist/build 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.hi 3 | *.o 4 | *~ 5 | dist/ 6 | dist-newstyle/ 7 | parse.txt 8 | src/Language/JavaScript/Parser/Grammar5.hs 9 | src/Language/JavaScript/Parser/Lexer.info 10 | unicode/*.htm 11 | 12 | # stack 13 | .stack-work/ 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | language: c 3 | 4 | os: linux 5 | dist: xenial 6 | 7 | env: 8 | - GHCVER=7.10.3 9 | - GHCVER=8.0.2 10 | - GHCVER=8.2.2 11 | - GHCVER=8.4.4 12 | - GHCVER=8.6.5 13 | - GHCVER=8.8.3 14 | 15 | before_install: 16 | - sudo add-apt-repository -y ppa:hvr/ghc 17 | - sudo apt-get update 18 | - sudo apt-get install alex-3.1.7 happy-1.19.5 cabal-install-3.0 ghc-$GHCVER 19 | - export PATH=/opt/cabal/bin:/opt/ghc/$GHCVER/bin:/opt/alex/3.1.7/bin:/opt/happy/1.19.5/bin:$PATH 20 | 21 | install: 22 | - cabal-3.0 update 23 | 24 | script: 25 | - cabal-3.0 configure --enable-tests 26 | - cabal-3.0 build 27 | - cabal-3.0 test --test-show-details=streaming 28 | - cabal-3.0 check 29 | - cabal-3.0 haddock 30 | - cabal-3.0 sdist 31 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | # ChangeLog for `language-javascript` 2 | 3 | ## 0.7.1.0 -- 2020-03-22 4 | + Add support for `async` function specifiers and `await` keyword. 5 | 6 | ## 0.7.0.0 -- 2019-10-10 7 | 8 | + Add support for (Ryan Hendrickson): 9 | - Destructuring in var declarations 10 | - `const` in for statements 11 | - ES6 property shorthand syntax 12 | - Template literals 13 | - Computed property names 14 | - Bare import declarations 15 | - Exotic parameter syntaxes 16 | - Generators and `yield` 17 | - Method definitions 18 | - classes 19 | `- super` keyword 20 | 21 | ## 0.6.0.13 -- 2019-06-17 22 | 23 | + Add support for (Cyril Sobierajewicz): 24 | - Unparenthesized arrow functions of one parameter 25 | - Export from declarations 26 | - Add back support for identifiers named `as` 27 | 28 | ## 0.6.0.12 -- 2019-05-03 29 | 30 | + Add support for for..of and friends (Franco Bulgarelli) 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c)2010, Alan Zimmerman 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of Alan Zimmerman nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | LIBSRC = $(shell find src/Language -name \*.hs) $(LEXER) $(GRAMMAR) 3 | TESTSRC = $(shell find Tests -name \*.hs) 4 | 5 | LEXER = dist/build/Language/JavaScript/Parser/Lexer.hs 6 | GRAMMAR = dist/build/Language/JavaScript/Parser/Grammar5.hs 7 | 8 | GHC = cabal exec -- ghc 9 | GHCFLAGS = -Wall -fwarn-tabs 10 | 11 | 12 | check : testsuite.exe 13 | ./testsuite.exe 14 | 15 | 16 | clean : 17 | find dist/build/ src/ -name \*.{o -o -name \*.hi | xargs rm -f 18 | rm -f $(LEXER) $(GRAMMAR) $(TARGETS) *.exe 19 | 20 | testsuite.exe : testsuite.hs $(LIBSRC) $(TESTSRC) 21 | $(GHC) $(GHCFLAGS) -O2 -i:src -i:dist/build --make $< -o $@ 22 | 23 | 24 | $(GRAMMAR) : src/Language/JavaScript/Parser/Grammar5.y 25 | happy $+ -o $@ 26 | 27 | $(LEXER) : src/Language/JavaScript/Parser/Lexer.x 28 | alex $+ -o $@ 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Parser for JavaScript 2 | --------------------- 3 | 4 | [![Build Status](https://secure.travis-ci.org/erikd/language-javascript.png?branch=master)](http://travis-ci.org/erikd/language-javascript) 5 | 6 | Based (loosely) on language-python 7 | 8 | Two Versions 9 | ------------ 10 | 11 | There are currently two versions: 12 | 13 | * 0.5 series : Is a continuation of the 0.5.X.Y series, from the [master] 14 | (https://github.com/erikd/language-javascript/tree/master) branch of this 15 | github repository. 16 | 17 | * 0.6 and 0.7 series : This has a vastly different and improved AST which makes if far 18 | more difficult to build an non-sensical Javascript AST. This code is in the 19 | [new-ast](https://github.com/erikd/language-javascript/tree/new-ast) branch of 20 | this github repository. 21 | 22 | 23 | How to build 24 | ------------ 25 | 26 | Make sure your locale supports UTF-8. For example, on most Unix-like platforms, 27 | you can type: 28 | 29 | export LC_ALL=en_US.UTF-8 30 | 31 | Library: 32 | 33 | cabal clean && cabal configure && cabal build 34 | 35 | Tests: 36 | 37 | cabal clean && cabal configure -fbuildtests && cabal build 38 | 39 | Running the tests 40 | 41 | ./dist/build/runtests/runtests 42 | 43 | 44 | To debug the grammar 45 | 46 | happy -iparse.txt -g -a -d src/Language/JavaScript/Parser/Grammar5.y 47 | 48 | This generates src/Language/JavaScript/Parser/Grammar5.hs, delete this 49 | when done with the debug version 50 | 51 | 52 | UTF8/Unicode version 53 | -------------------- 54 | 55 | Alex 3.0 now supports unicode natively, and has been included as a 56 | dependency in the cabal file. 57 | 58 | Note: The generation of the lexical analyser has been separated out, 59 | to remove the install-time dependency on Alex. If any changes 60 | need to be made to the lexer, the Lexer.x source lies in 61 | src-dev, and the runalex.sh script will invoke Alex with the 62 | appropriate directories. 63 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | Things to do 2 | 3 | Useful resource: http://sideshowbarker.github.com/es5-spec 4 | http://test262.ecmascript.org 5 | http://www.ecma-international.org/publications/standards/Ecma-262.htm 6 | 7 | 2. Separate out the different versions of JavaScript. 8 | 9 | Necessary? Depends what this tool is used for. Current assumption is 10 | that it is fed well-formed JS, and generates an AST for further 11 | manipulation. 12 | 13 | 3. Simplify the AST. *JSElement at the very least is redundant. 14 | 15 | 4. Clarify the external interfaces required. 16 | 17 | 5. Process comments. Some kinds of hooks exist, but they are essentially discarded. 18 | 19 | 8. String literals for ed 5 - continuation chars etc. 20 | 21 | 10. Sort out [no line terminator here] in PostfixExpression 22 | 23 | 11. Export AST as JSON or XML 24 | 25 | nicferrier Nic Ferrier 26 | @paul_houle better tools come from the languages making their ast available, 27 | as json or xml: gcc --astxml a.c 28 | 29 | 12. Look at using the AST in WebBits 30 | http://hackage.haskell.org/package/WebBits-0.15 31 | 32 | 13. Numeric literals Infinity, NaN 33 | 34 | 14. Look at http://jsshaper.org/ 35 | 36 | 15. Store number of rows/cols in a comment, to speed output 37 | 38 | EOF 39 | 40 | -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | packages: 2 | ./ 3 | 4 | test-show-details: direct 5 | 6 | tests: True 7 | -------------------------------------------------------------------------------- /ecmascript5.txt: -------------------------------------------------------------------------------- 1 | Annex A 2 | (informative) 3 | Grammar Summary 4 | A.1 Lexical Grammar 5 | SourceCharacter :: See clause 6 6 | any Unicode code unit 7 | InputElementDiv :: See clause 7 8 | WhiteSpace 9 | LineTerminator 10 | Comment 11 | Token 12 | DivPunctuator 13 | InputElementRegExp :: See clause 7 14 | WhiteSpace 15 | LineTerminator 16 | Comment 17 | Token 18 | RegularExpressionLiteral 19 | WhiteSpace :: See 7.2 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | LineTerminator :: See 7.3 28 | 29 | 30 | 31 | 32 | LineTerminatorSequence :: See 7.3 33 | 34 | [lookahead ∉ ] 35 | 36 | 37 | 38 | Comment :: See 7.4 39 | MultiLineComment 40 | SingleLineComment 41 | MultiLineComment :: See 7.4 42 | /* MultiLineCommentCharsopt */ 43 | MultiLineCommentChars :: See 7.4 44 | MultiLineNotAsteriskChar MultiLineCommentCharsopt 45 | * PostAsteriskCommentCharsopt 46 | PostAsteriskCommentChars :: See 7.4 47 | MultiLineNotForwardSlashOrAsteriskChar MultiLineCommentCharsopt 48 | * PostAsteriskCommentCharsopt 49 | MultiLineNotAsteriskChar :: See 7.4 50 | SourceCharacter but not asterisk * 51 | MultiLineNotForwardSlashOrAsteriskChar :: See 7.4 52 | SourceCharacter but not forward-slash / or asterisk * 53 | SingleLineComment :: See 7.4 54 | // SingleLineCommentCharsopt 55 | SingleLineCommentChars :: See 7.4 56 | SingleLineCommentChar SingleLineCommentCharsopt 57 | SingleLineCommentChar :: See 7.4 58 | SourceCharacter but not LineTerminator 59 | Token :: See 7.5 60 | IdentifierName 61 | Punctuator 62 | NumericLiteral 63 | StringLiteral 64 | Identifier :: See 7.6 65 | IdentifierName but not ReservedWord 66 | IdentifierName :: See 7.6 67 | IdentifierStart 68 | IdentifierName IdentifierPart 69 | IdentifierStart :: See 7.6 70 | UnicodeLetter 71 | $ 72 | _ 73 | \ UnicodeEscapeSequence 74 | IdentifierPart :: See 7.6 75 | IdentifierStart 76 | UnicodeCombiningMark 77 | UnicodeDigit 78 | UnicodeConnectorPunctuation 79 | 80 | 81 | See 7.6 82 | UnicodeLetter 83 | any character in the Unicode categories “Uppercase letter (Lu)”, “Lowercase letter 84 | (Ll)”, “Titlecase letter (Lt)”, “Modifier letter (Lm)”, “Other letter (Lo)”, or “Letter 85 | number (Nl)”. 86 | See 7.6 87 | UnicodeCombiningMark 88 | any character in the Unicode categories “Non-spacing mark (Mn)” or “Combining 89 | spacing mark (Mc)” 90 | See 7.6 91 | UnicodeDigit 92 | any character in the Unicode category “Decimal number (Nd)” 93 | See 7.6 94 | UnicodeConnectorPunctuation 95 | any character in the Unicode category “Connector punctuation (Pc)” 96 | ReservedWord :: See 7.6.1 97 | Keyword 98 | FutureReservedWord 99 | NullLiteral 100 | BooleanLiteral 101 | Keyword :: one of See 7.6.1.1 102 | instanceof typeof 103 | break do 104 | new var 105 | case else 106 | return void 107 | catch finally 108 | switch while 109 | continue for 110 | this with 111 | debugger function 112 | throw 113 | default if 114 | try 115 | delete in 116 | FutureReservedWord :: one of See 7.6.1.2 117 | extends super 118 | class enum 119 | import 120 | const export 121 | or in strict mode code one of 122 | implements let private public 123 | interface package protected static 124 | yield 125 | Punctuator :: one of See 7.7 126 | ) [ ] 127 | { } ( 128 | . ; , < > <= 129 | >= == != === !== 130 | + - * % ++ -- 131 | << >> >>> & | ^ 132 | ! ~ && || ? : 133 | = += -= *= %= <<= 134 | >>= >>>= &= |= ^= 135 | DivPunctuator :: one of See 7.7 136 | / /= 137 | Literal :: See 7.8 138 | NullLiteral 139 | BooleanLiteral 140 | NumericLiteral 141 | StringLiteral 142 | NullLiteral :: See 7.8.1 143 | null 144 | BooleanLiteral :: See 7.8.2 145 | true 146 | false 147 | NumericLiteral :: See 7.8.3 148 | DecimalLiteral 149 | HexIntegerLiteral 150 | DecimalLiteral :: See 7.8.3 151 | DecimalIntegerLiteral . DecimalDigitsopt ExponentPartopt 152 | . DecimalDigits ExponentPartopt 153 | DecimalIntegerLiteral ExponentPartopt 154 | DecimalIntegerLiteral :: See 7.8.3 155 | 0 156 | NonZeroDigit DecimalDigitsopt 157 | DecimalDigits :: See 7.8.3 158 | DecimalDigit 159 | DecimalDigits DecimalDigit 160 | DecimalDigit :: one of See 7.8.3 161 | 0 1 2 3 4 5 6 7 8 9 162 | ExponentIndicator :: one of See 7.8.3 163 | e E 164 | SignedInteger :: See 7.8.3 165 | DecimalDigits 166 | + DecimalDigits 167 | - DecimalDigits 168 | HexIntegerLiteral :: See 7.8.3 169 | 0x HexDigit 170 | 0X HexDigit 171 | HexIntegerLiteral HexDigit 172 | HexDigit :: one of See 7.8.3 173 | 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F 174 | StringLiteral :: See 7.8.4 175 | " DoubleStringCharactersopt " 176 | ' SingleStringCharactersopt ' 177 | DoubleStringCharacters :: See 7.8.4 178 | DoubleStringCharacter DoubleStringCharactersopt 179 | SingleStringCharacters :: See 7.8.4 180 | SingleStringCharacter SingleStringCharactersopt 181 | DoubleStringCharacter :: See 7.8.4 182 | SourceCharacter but not double-quote " or backslash \ or LineTerminator 183 | \ EscapeSequence 184 | LineContinuation 185 | SingleStringCharacter :: See 7.8.4 186 | SourceCharacter but not single-quote ' or backslash \ or LineTerminator 187 | \ EscapeSequence 188 | LineContinuation 189 | LineContinuation :: See 7.8.4 190 | \ LineTerminatorSequence 191 | EscapeSequence :: See 7.8.4 192 | CharacterEscapeSequence 193 | 0 [lookahead ∉ DecimalDigit] 194 | HexEscapeSequence 195 | UnicodeEscapeSequence 196 | CharacterEscapeSequence :: See 7.8.4 197 | SingleEscapeCharacter 198 | NonEscapeCharacter 199 | SingleEscapeCharacter :: one of See 7.8.4 200 | ' " \ b f n r t v 201 | NonEscapeCharacter :: See 7.8.4 202 | SourceCharacter but not EscapeCharacter or LineTerminator 203 | EscapeCharacter :: See 7.8.4 204 | SingleEscapeCharacter 205 | DecimalDigit 206 | x 207 | u 208 | HexEscapeSequence :: See 7.8.4 209 | x HexDigit HexDigit 210 | UnicodeEscapeSequence :: See 7.8.4 211 | u HexDigit HexDigit HexDigit HexDigit 212 | RegularExpressionLiteral :: See 7.8.5 213 | / RegularExpressionBody / RegularExpressionFlags 214 | RegularExpressionBody :: See 7.8.5 215 | RegularExpressionFirstChar RegularExpressionChars 216 | RegularExpressionChars :: See 7.8.5 217 | [empty] 218 | RegularExpressionChars RegularExpressionChar 219 | RegularExpressionFirstChar :: See 7.8.5 220 | RegularExpressionNonTerminator but not * or \ or / or [ 221 | RegularExpressionBackslashSequence 222 | RegularExpressionClass 223 | RegularExpressionChar :: See 7.8.5 224 | RegularExpressionNonTerminator but not \ or / or [ 225 | RegularExpressionBackslashSequence 226 | RegularExpressionClass 227 | RegularExpressionBackslashSequence :: See 7.8.5 228 | \ NonTerminator 229 | RegularExpressionNonTerminator :: See 7.8.5 230 | SourceCharacter but not LineTerminator 231 | RegularExpressionClass :: See 7.8.5 232 | [ RegularExpressionClassChars ] 233 | RegularExpressionClassChars :: See 7.8.5 234 | [empty] 235 | RegularExpressionClassChars RegularExpressionClassChar 236 | RegularExpressionClassChar :: See 7.8.5 237 | RegularExpressionNonTerminator but not ] or \ 238 | RegularExpressionBackslashSequence 239 | RegularExpressionFlags :: See 7.8.5 240 | [empty] 241 | RegularExpressionFlags IdentifierPart 242 | A.2 Number Conversions 243 | StringNumericLiteral ::: See 9.3.1 244 | StrWhiteSpaceopt 245 | StrWhiteSpaceopt StrNumericLiteral StrWhiteSpaceopt 246 | StrWhiteSpace ::: See 9.3.1 247 | StrWhiteSpaceChar StrWhiteSpaceopt 248 | StrWhiteSpaceChar ::: See 9.3.1 249 | WhiteSpace 250 | LineTerminator 251 | StrNumericLiteral ::: See 9.3.1 252 | StrDecimalLiteral 253 | HexIntegerLiteral 254 | StrDecimalLiteral ::: See 9.3.1 255 | StrUnsignedDecimalLiteral 256 | + StrUnsignedDecimalLiteral 257 | - StrUnsignedDecimalLiteral 258 | StrUnsignedDecimalLiteral ::: See 9.3.1 259 | Infinity 260 | DecimalDigits . DecimalDigitsopt ExponentPartopt 261 | . DecimalDigits ExponentPartopt 262 | DecimalDigits ExponentPartopt 263 | DecimalDigits ::: See 9.3.1 264 | DecimalDigit 265 | DecimalDigits DecimalDigit 266 | DecimalDigit ::: one of See 9.3.1 267 | 0 1 2 3 4 5 6 7 8 9 268 | ExponentPart ::: See 9.3.1 269 | ExponentIndicator SignedInteger 270 | ExponentIndicator ::: one of See 9.3.1 271 | e E 272 | SignedInteger ::: See 9.3.1 273 | DecimalDigits 274 | + DecimalDigits 275 | - DecimalDigits 276 | 277 | HexIntegerLiteral ::: See 9.3.1 278 | 0x HexDigit 279 | 0X HexDigit 280 | HexIntegerLiteral HexDigit 281 | HexDigit ::: one of See 9.3.1 282 | 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F 283 | A.3 Expressions 284 | PrimaryExpression : See 11.1 285 | this 286 | Identifier 287 | Literal 288 | ArrayLiteral 289 | ObjectLiteral 290 | ( Expression ) 291 | ArrayLiteral : See 11.1.4 292 | [ Elisionopt ] 293 | [ ElementList ] 294 | [ ElementList , Elisionopt ] 295 | ElementList : See 11.1.4 296 | Elisionopt AssignmentExpression 297 | ElementList , Elisionopt AssignmentExpression 298 | Elision : See 11.1.4 299 | , 300 | Elision , 301 | ObjectLiteral : See 11.1.5 302 | { } 303 | { PropertyNameAndValueList } 304 | { PropertyNameAndValueList , } 305 | PropertyNameAndValueList : See 11.1.5 306 | PropertyAssignment 307 | PropertyNameAndValueList , PropertyAssignment 308 | PropertyAssignment : See 11.1.5 309 | PropertyName : AssignmentExpression 310 | get PropertyName() { FunctionBody } 311 | set PropertyName( PropertySetParameterList ) { FunctionBody } 312 | PropertyName : See 11.1.5 313 | IdentifierName 314 | StringLiteral 315 | NumericLiteral 316 | PropertySetParameterList : See 11.1.5 317 | Identifier 318 | MemberExpression : See 11.2 319 | PrimaryExpression 320 | FunctionExpression 321 | MemberExpression [ Expression ] 322 | MemberExpression . IdentifierName 323 | new MemberExpression Arguments 324 | NewExpression : See 11.2 325 | MemberExpression 326 | new NewExpression 327 | CallExpression : See 11.2 328 | MemberExpression Arguments 329 | CallExpression Arguments 330 | CallExpression [ Expression ] 331 | CallExpression . IdentifierName 332 | Arguments : See 11.2 333 | () 334 | ( ArgumentList ) 335 | ArgumentList : See 11.2 336 | AssignmentExpression 337 | ArgumentList , AssignmentExpression 338 | LeftHandSideExpression : See 11.2 339 | NewExpression 340 | CallExpression 341 | PostfixExpression : See 11.3 342 | LeftHandSideExpression 343 | [no LineTerminator here] 344 | LeftHandSideExpression ++ 345 | [no LineTerminator here] 346 | LeftHandSideExpression -- 347 | UnaryExpression : See 11.4 348 | PostfixExpression 349 | delete UnaryExpression 350 | void UnaryExpression 351 | typeof UnaryExpression 352 | ++ UnaryExpression 353 | -- UnaryExpression 354 | + UnaryExpression 355 | - UnaryExpression 356 | ~ UnaryExpression 357 | ! UnaryExpression 358 | MultiplicativeExpression : See 11.5 359 | UnaryExpression 360 | MultiplicativeExpression * UnaryExpression 361 | MultiplicativeExpression / UnaryExpression 362 | MultiplicativeExpression % UnaryExpression 363 | AdditiveExpression : See 11.6 364 | MultiplicativeExpression 365 | AdditiveExpression + MultiplicativeExpression 366 | AdditiveExpression - MultiplicativeExpression 367 | ShiftExpression : See 11.7 368 | AdditiveExpression 369 | ShiftExpression << AdditiveExpression 370 | ShiftExpression >> AdditiveExpression 371 | ShiftExpression >>> AdditiveExpression 372 | RelationalExpression : See 11.8 373 | ShiftExpression 374 | RelationalExpression < ShiftExpression 375 | RelationalExpression > ShiftExpression 376 | RelationalExpression <= ShiftExpression 377 | RelationalExpression >= ShiftExpression 378 | RelationalExpression instanceof ShiftExpression 379 | RelationalExpression in ShiftExpression 380 | RelationalExpressionNoIn : See 11.8 381 | ShiftExpression 382 | RelationalExpressionNoIn < ShiftExpression 383 | RelationalExpressionNoIn > ShiftExpression 384 | RelationalExpressionNoIn <= ShiftExpression 385 | RelationalExpressionNoIn >= ShiftExpression 386 | RelationalExpressionNoIn instanceof ShiftExpression 387 | EqualityExpression : See 11.9 388 | RelationalExpression 389 | EqualityExpression == RelationalExpression 390 | EqualityExpression != RelationalExpression 391 | EqualityExpression === RelationalExpression 392 | EqualityExpression !== RelationalExpression 393 | EqualityExpressionNoIn : See 11.9 394 | RelationalExpressionNoIn 395 | EqualityExpressionNoIn == RelationalExpressionNoIn 396 | EqualityExpressionNoIn != RelationalExpressionNoIn 397 | EqualityExpressionNoIn === RelationalExpressionNoIn 398 | EqualityExpressionNoIn !== RelationalExpressionNoIn 399 | BitwiseANDExpression : See 11.10 400 | EqualityExpression 401 | BitwiseANDExpression & EqualityExpression 402 | BitwiseANDExpressionNoIn : See 11.10 403 | EqualityExpressionNoIn 404 | BitwiseANDExpressionNoIn & EqualityExpressionNoIn 405 | BitwiseXORExpression : See 11.10 406 | BitwiseANDExpression 407 | BitwiseXORExpression ^ BitwiseANDExpression 408 | BitwiseXORExpressionNoIn : See 11.10 409 | BitwiseANDExpressionNoIn 410 | BitwiseXORExpressionNoIn ^ BitwiseANDExpressionNoIn 411 | BitwiseORExpression : See 11.10 412 | BitwiseXORExpression 413 | BitwiseORExpression | BitwiseXORExpression 414 | BitwiseORExpressionNoIn : See 11.10 415 | BitwiseXORExpressionNoIn 416 | BitwiseORExpressionNoIn | BitwiseXORExpressionNoIn 417 | LogicalANDExpression : See 11.11 418 | BitwiseORExpression 419 | LogicalANDExpression && BitwiseORExpression 420 | LogicalANDExpressionNoIn : See 11.11 421 | BitwiseORExpressionNoIn 422 | LogicalANDExpressionNoIn && BitwiseORExpressionNoIn 423 | LogicalORExpression : See 11.11 424 | LogicalANDExpression 425 | LogicalORExpression || LogicalANDExpression 426 | LogicalORExpressionNoIn : See 11.11 427 | LogicalANDExpressionNoIn 428 | LogicalORExpressionNoIn || LogicalANDExpressionNoIn 429 | ConditionalExpression : See 11.12 430 | LogicalORExpression 431 | LogicalORExpression ? AssignmentExpression : AssignmentExpression 432 | ConditionalExpressionNoIn : See 11.12 433 | LogicalORExpressionNoIn 434 | LogicalORExpressionNoIn ? AssignmentExpressionNoIn : AssignmentExpressionNoIn 435 | AssignmentExpression : See 11.13 436 | ConditionalExpression 437 | LeftHandSideExpression AssignmentOperator AssignmentExpression 438 | AssignmentExpressionNoIn : See 11.13 439 | ConditionalExpressionNoIn 440 | LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn 441 | AssignmentOperator : one of See 11.13 442 | -= <<= >>= >>>= &= ^= |= 443 | = *= /= %= += 444 | 445 | Expression : See 11.14 446 | AssignmentExpression 447 | Expression , AssignmentExpression 448 | ExpressionNoIn : See 11.14 449 | AssignmentExpressionNoIn 450 | ExpressionNoIn , AssignmentExpressionNoIn 451 | A.4 Statements 452 | Statement : See clause 12 453 | Block 454 | VariableStatement 455 | EmptyStatement 456 | ExpressionStatement 457 | IfStatement 458 | IterationStatement 459 | ContinueStatement 460 | BreakStatement 461 | ReturnStatement 462 | WithStatement 463 | LabelledStatement 464 | SwitchStatement 465 | ThrowStatement 466 | TryStatement 467 | DebuggerStatement 468 | Block : See 12.1 469 | { StatementListopt } 470 | StatementList : See 12.1 471 | Statement 472 | StatementList Statement 473 | VariableStatement : See 12.2 474 | var VariableDeclarationList ; 475 | VariableDeclarationList : See 12.2 476 | VariableDeclaration 477 | VariableDeclarationList , VariableDeclaration 478 | VariableDeclarationListNoIn : See 12.2 479 | VariableDeclarationNoIn 480 | VariableDeclarationListNoIn , VariableDeclarationNoIn 481 | VariableDeclaration : See 12.2 482 | Identifier Initialiseropt 483 | VariableDeclarationNoIn : See 12.2 484 | Identifier InitialiserNoInopt 485 | Initialiser : See 12.2 486 | = AssignmentExpression 487 | InitialiserNoIn : See 12.2 488 | = AssignmentExpressionNoIn 489 | EmptyStatement : See 12.3 490 | ; 491 | ExpressionStatement : See 12.4 492 | [lookahead ∉ {{, function}] Expression ; 493 | IfStatement : See 12.5 494 | if ( Expression ) Statement else Statement 495 | if ( Expression ) Statement 496 | IterationStatement : See 12.6 497 | do Statement while ( Expression ); 498 | while ( Expression ) Statement 499 | for (ExpressionNoInopt; Expressionopt ; Expressionopt ) Statement 500 | for ( var VariableDeclarationListNoIn; Expressionopt ; Expressionopt ) Statement 501 | for ( LeftHandSideExpression in Expression ) Statement 502 | for ( var VariableDeclarationNoIn in Expression ) Statement 503 | ContinueStatement : See 12.7 504 | continue [no LineTerminator here] Identifieropt ; 505 | BreakStatement : See 12.8 506 | break [no LineTerminator here] Identifieropt ; 507 | ReturnStatement : See 12.9 508 | return [no LineTerminator here] Expressionopt ; 509 | WithStatement : See 12.10 510 | with ( Expression ) Statement 511 | SwitchStatement : See 12.11 512 | switch ( Expression ) CaseBlock 513 | CaseBlock : See 12.11 514 | { CaseClausesopt } 515 | { CaseClausesopt DefaultClause CaseClausesopt } 516 | CaseClauses : See 12.11 517 | CaseClause 518 | CaseClauses CaseClause 519 | CaseClause : See 12.11 520 | case Expression : StatementListopt 521 | DefaultClause : See 12.11 522 | default : StatementListopt 523 | LabelledStatement : See 12.12 524 | Identifier : Statement 525 | ThrowStatement : See 12.13 526 | throw [no LineTerminator here] Expression ; 527 | TryStatement : See 12.14 528 | try Block Catch 529 | try Block Finally 530 | try Block Catch Finally 531 | Catch : See 12.14 532 | catch ( Identifier ) Block 533 | Finally : See 12.14 534 | finally Block 535 | DebuggerStatement : See 12.15 536 | debugger ; 537 | A.5 Functions and Programs 538 | FunctionDeclaration : See clause 13 539 | function Identifier ( FormalParameterListopt ) { FunctionBody } 540 | FunctionExpression : See clause 13 541 | function Identifieropt ( FormalParameterListopt ) { FunctionBody } 542 | FormalParameterList : See clause 13 543 | Identifier 544 | FormalParameterList , Identifier 545 | FunctionBody : See clause 13 546 | SourceElementsopt 547 | Program : See clause 14 548 | SourceElementsopt 549 | SourceElements : See clause 14 550 | SourceElement 551 | SourceElements SourceElement 552 | SourceElement : 553 | Statement 554 | FunctionDeclaration 555 | -------------------------------------------------------------------------------- /language-javascript.cabal: -------------------------------------------------------------------------------- 1 | Name: language-javascript 2 | Version: 0.7.1.0 3 | Synopsis: Parser for JavaScript 4 | Description: Parses Javascript into an Abstract Syntax Tree (AST). Initially intended as frontend to hjsmin. 5 | . 6 | Note: Version 0.5.0 breaks compatibility with prior versions, the AST has been reworked to allow 7 | round trip processing of JavaScript. 8 | License: BSD3 9 | License-file: LICENSE 10 | Author: Alan Zimmerman 11 | Maintainer: Erik de Castro Lopo 12 | Copyright: (c) 2010-2015 Alan Zimmerman 13 | (c) 2015-2019 Erik de Castro Lopo 14 | (c) 2018 Daniel Gasienica 15 | Category: Language 16 | Build-type: Simple 17 | homepage: https://github.com/erikd/language-javascript 18 | bug-reports: https://github.com/erikd/language-javascript/issues 19 | Extra-source-files: README.md 20 | ChangeLog.md 21 | .ghci 22 | test/Unicode.js 23 | test/k.js 24 | test/unicode.txt 25 | src/Language/JavaScript/Parser/Lexer.x 26 | 27 | -- Version requirement upped for test support in later Cabal 28 | Cabal-version: >= 1.9.2 29 | 30 | 31 | Library 32 | Build-depends: base >= 4 && < 5 33 | , array >= 0.3 34 | , mtl >= 1.1 35 | , containers >= 0.2 36 | , blaze-builder >= 0.2 37 | , bytestring >= 0.9.1 38 | , text >= 1.2 39 | , utf8-string >= 0.3.7 && < 2 40 | if !impl(ghc>=8.0) 41 | build-depends: semigroups >= 0.16.1 42 | 43 | if impl(ghc >= 7.10) 44 | build-tools: happy >= 1.19, alex >= 3.1.4 45 | else 46 | if impl(ghc >= 7.8) 47 | build-tools: happy >= 1.19, alex >= 3.1 48 | else 49 | build-tools: happy >= 1.18.5, alex >= 3.0.5 50 | hs-source-dirs: src 51 | Exposed-modules: Language.JavaScript.Parser 52 | Language.JavaScript.Parser.AST 53 | Language.JavaScript.Parser.Grammar7 54 | Language.JavaScript.Parser.Lexer 55 | Language.JavaScript.Parser.Parser 56 | Language.JavaScript.Parser.SrcLocation 57 | Language.JavaScript.Pretty.Printer 58 | Language.JavaScript.Process.Minify 59 | Other-modules: Language.JavaScript.Parser.LexerUtils 60 | Language.JavaScript.Parser.ParseError 61 | Language.JavaScript.Parser.ParserMonad 62 | Language.JavaScript.Parser.Token 63 | ghc-options: -Wall -fwarn-tabs 64 | 65 | Test-Suite testsuite 66 | Type: exitcode-stdio-1.0 67 | Main-is: testsuite.hs 68 | hs-source-dirs: test 69 | ghc-options: -Wall -fwarn-tabs 70 | build-depends: base, Cabal >= 1.9.2 71 | , QuickCheck >= 2 72 | , hspec 73 | , array >= 0.3 74 | , containers >= 0.2 75 | , mtl >= 1.1 76 | , utf8-string >= 0.3.7 && < 2 77 | , bytestring >= 0.9.1 78 | , blaze-builder >= 0.2 79 | , language-javascript 80 | 81 | Other-modules: Test.Language.Javascript.ExpressionParser 82 | Test.Language.Javascript.Lexer 83 | Test.Language.Javascript.LiteralParser 84 | Test.Language.Javascript.Minify 85 | Test.Language.Javascript.ModuleParser 86 | Test.Language.Javascript.ProgramParser 87 | Test.Language.Javascript.RoundTrip 88 | Test.Language.Javascript.StatementParser 89 | 90 | source-repository head 91 | type: git 92 | location: https://github.com/erikd/language-javascript.git 93 | -------------------------------------------------------------------------------- /src/Language/JavaScript/Parser.hs: -------------------------------------------------------------------------------- 1 | module Language.JavaScript.Parser 2 | ( 3 | PA.parse 4 | , PA.parseModule 5 | , PA.readJs 6 | , PA.readJsModule 7 | , PA.parseFile 8 | , PA.parseFileUtf8 9 | , PA.showStripped 10 | , PA.showStrippedMaybe 11 | -- * AST elements 12 | , JSExpression (..) 13 | , JSAnnot (..) 14 | , JSBinOp (..) 15 | , JSBlock (..) 16 | , JSUnaryOp (..) 17 | , JSSemi (..) 18 | , JSAssignOp (..) 19 | , JSTryCatch (..) 20 | , JSTryFinally (..) 21 | , JSStatement (..) 22 | , JSSwitchParts (..) 23 | , JSAST(..) 24 | 25 | 26 | , CommentAnnotation(..) 27 | -- , ParseError(..) 28 | -- Source locations 29 | , TokenPosn(..) 30 | , tokenPosnEmpty 31 | -- * Pretty Printing 32 | , renderJS 33 | , renderToString 34 | , renderToText 35 | ) where 36 | 37 | 38 | import Language.JavaScript.Parser.AST 39 | import Language.JavaScript.Parser.Token 40 | import qualified Language.JavaScript.Parser.Parser as PA 41 | import Language.JavaScript.Parser.SrcLocation 42 | import Language.JavaScript.Pretty.Printer 43 | 44 | -- EOF 45 | -------------------------------------------------------------------------------- /src/Language/JavaScript/Parser/LexerUtils.hs: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- | 3 | -- Module : Language.JavaScript.LexerUtils 4 | -- Based on language-python version by Bernie Pope 5 | -- Copyright : (c) 2009 Bernie Pope 6 | -- License : BSD-style 7 | -- Stability : experimental 8 | -- Portability : ghc 9 | -- 10 | -- Various utilities to support the JavaScript lexer. 11 | ----------------------------------------------------------------------------- 12 | 13 | module Language.JavaScript.Parser.LexerUtils 14 | ( StartCode 15 | , symbolToken 16 | , mkString 17 | , mkString' 18 | , commentToken 19 | , wsToken 20 | , regExToken 21 | , decimalToken 22 | , hexIntegerToken 23 | , octalToken 24 | , stringToken 25 | ) where 26 | 27 | import Language.JavaScript.Parser.Token as Token 28 | import Language.JavaScript.Parser.SrcLocation 29 | import Prelude hiding (span) 30 | 31 | -- Functions for building tokens 32 | 33 | type StartCode = Int 34 | 35 | symbolToken :: Monad m => (TokenPosn -> [CommentAnnotation] -> Token) -> TokenPosn -> Int -> String -> m Token 36 | symbolToken mkToken location _ _ = return (mkToken location []) 37 | 38 | mkString :: (Monad m) => (TokenPosn -> String -> Token) -> TokenPosn -> Int -> String -> m Token 39 | mkString toToken loc len str = return (toToken loc (take len str)) 40 | 41 | mkString' :: (Monad m) => (TokenPosn -> String -> [CommentAnnotation] -> Token) -> TokenPosn -> Int -> String -> m Token 42 | mkString' toToken loc len str = return (toToken loc (take len str) []) 43 | 44 | decimalToken :: TokenPosn -> String -> Token 45 | decimalToken loc str = DecimalToken loc str [] 46 | 47 | hexIntegerToken :: TokenPosn -> String -> Token 48 | hexIntegerToken loc str = HexIntegerToken loc str [] 49 | 50 | octalToken :: TokenPosn -> String -> Token 51 | octalToken loc str = OctalToken loc str [] 52 | 53 | regExToken :: TokenPosn -> String -> Token 54 | regExToken loc str = RegExToken loc str [] 55 | 56 | stringToken :: TokenPosn -> String -> Token 57 | stringToken loc str = StringToken loc str [] 58 | 59 | commentToken :: TokenPosn -> String -> Token 60 | commentToken loc str = CommentToken loc str [] 61 | 62 | wsToken :: TokenPosn -> String -> Token 63 | wsToken loc str = WsToken loc str [] 64 | -------------------------------------------------------------------------------- /src/Language/JavaScript/Parser/ParseError.hs: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------- 2 | -- | 3 | -- Module : Language.JavaScript.ParseError 4 | -- Based on language-python version by Bernie Pope 5 | -- Copyright : (c) 2009 Bernie Pope 6 | -- License : BSD-style 7 | -- Stability : experimental 8 | -- Portability : ghc 9 | -- 10 | -- Error values for the lexer and parser. 11 | ----------------------------------------------------------------------------- 12 | 13 | module Language.JavaScript.Parser.ParseError 14 | ( Error (..) 15 | , ParseError (..) 16 | ) where 17 | 18 | --import Language.JavaScript.Parser.Pretty 19 | -- import Control.Monad.Error.Class -- Control.Monad.Trans.Except 20 | import Language.JavaScript.Parser.Lexer 21 | import Language.JavaScript.Parser.SrcLocation (TokenPosn) 22 | -- import Language.JavaScript.Parser.Token (Token) 23 | 24 | data ParseError 25 | = UnexpectedToken Token 26 | -- ^ An error from the parser. Token found where it should not be. 27 | -- Note: tokens contain their own source span. 28 | | UnexpectedChar Char TokenPosn 29 | -- ^ An error from the lexer. Character found where it should not be. 30 | | StrError String 31 | -- ^ A generic error containing a string message. No source location. 32 | deriving (Eq, {- Ord,-} Show) 33 | 34 | class Error a where 35 | -- | Creates an exception without a message. 36 | -- The default implementation is @'strMsg' \"\"@. 37 | noMsg :: a 38 | -- | Creates an exception with a message. 39 | -- The default implementation of @'strMsg' s@ is 'noMsg'. 40 | strMsg :: String -> a 41 | 42 | instance Error ParseError where 43 | noMsg = StrError "" 44 | strMsg = StrError 45 | 46 | -------------------------------------------------------------------------------- /src/Language/JavaScript/Parser/Parser.hs: -------------------------------------------------------------------------------- 1 | module Language.JavaScript.Parser.Parser ( 2 | -- * Parsing 3 | parse 4 | , parseModule 5 | , readJs 6 | , readJsModule 7 | -- , readJsKeepComments 8 | , parseFile 9 | , parseFileUtf8 10 | -- * Parsing expressions 11 | -- parseExpr 12 | , parseUsing 13 | , showStripped 14 | , showStrippedMaybe 15 | ) where 16 | 17 | import qualified Language.JavaScript.Parser.Grammar7 as P 18 | import Language.JavaScript.Parser.Lexer 19 | import qualified Language.JavaScript.Parser.AST as AST 20 | import System.IO 21 | 22 | -- | Parse JavaScript Program (Script) 23 | -- Parse one compound statement, or a sequence of simple statements. 24 | -- Generally used for interactive input, such as from the command line of an interpreter. 25 | -- Return comments in addition to the parsed statements. 26 | parse :: String -- ^ The input stream (Javascript source code). 27 | -> String -- ^ The name of the Javascript source (filename or input device). 28 | -> Either String AST.JSAST 29 | -- ^ An error or maybe the abstract syntax tree (AST) of zero 30 | -- or more Javascript statements, plus comments. 31 | parse = parseUsing P.parseProgram 32 | 33 | -- | Parse JavaScript module 34 | parseModule :: String -- ^ The input stream (JavaScript source code). 35 | -> String -- ^ The name of the JavaScript source (filename or input device). 36 | -> Either String AST.JSAST 37 | -- ^ An error or maybe the abstract syntax tree (AST) of zero 38 | -- or more JavaScript statements, plus comments. 39 | parseModule = parseUsing P.parseModule 40 | 41 | readJsWith :: (String -> String -> Either String AST.JSAST) 42 | -> String 43 | -> AST.JSAST 44 | readJsWith f input = 45 | case f input "src" of 46 | Left msg -> error (show msg) 47 | Right p -> p 48 | 49 | readJs :: String -> AST.JSAST 50 | readJs = readJsWith parse 51 | 52 | readJsModule :: String -> AST.JSAST 53 | readJsModule = readJsWith parseModule 54 | 55 | -- | Parse the given file. 56 | -- For UTF-8 support, make sure your locale is set such that 57 | -- "System.IO.localeEncoding" returns "utf8" 58 | parseFile :: FilePath -> IO AST.JSAST 59 | parseFile filename = 60 | do 61 | x <- readFile filename 62 | return $ readJs x 63 | 64 | -- | Parse the given file, explicitly setting the encoding to UTF8 65 | -- when reading it 66 | parseFileUtf8 :: FilePath -> IO AST.JSAST 67 | parseFileUtf8 filename = 68 | do 69 | h <- openFile filename ReadMode 70 | hSetEncoding h utf8 71 | x <- hGetContents h 72 | return $ readJs x 73 | 74 | showStripped :: AST.JSAST -> String 75 | showStripped = AST.showStripped 76 | 77 | showStrippedMaybe :: Show a => Either a AST.JSAST -> String 78 | showStrippedMaybe maybeAst = 79 | case maybeAst of 80 | Left msg -> "Left (" ++ show msg ++ ")" 81 | Right p -> "Right (" ++ AST.showStripped p ++ ")" 82 | 83 | -- | Parse one compound statement, or a sequence of simple statements. 84 | -- Generally used for interactive input, such as from the command line of an interpreter. 85 | -- Return comments in addition to the parsed statements. 86 | parseUsing :: 87 | Alex AST.JSAST -- ^ The parser to be used 88 | -> String -- ^ The input stream (Javascript source code). 89 | -> String -- ^ The name of the Javascript source (filename or input device). 90 | -> Either String AST.JSAST 91 | -- ^ An error or maybe the abstract syntax tree (AST) of zero 92 | -- or more Javascript statements, plus comments. 93 | 94 | parseUsing p input _srcName = runAlex input p 95 | -------------------------------------------------------------------------------- /src/Language/JavaScript/Parser/ParserMonad.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS #-} 2 | ----------------------------------------------------------------------------- 3 | -- | 4 | -- Module : Language.JavaScript.ParserMonad 5 | -- Copyright : (c) 2012 Alan Zimmerman 6 | -- License : BSD-style 7 | -- Stability : experimental 8 | -- Portability : ghc 9 | -- 10 | -- Monad support for JavaScript parser and lexer. 11 | ----------------------------------------------------------------------------- 12 | 13 | module Language.JavaScript.Parser.ParserMonad 14 | ( AlexUserState(..) 15 | , alexInitUserState 16 | ) where 17 | 18 | import Language.JavaScript.Parser.Token 19 | import Language.JavaScript.Parser.SrcLocation 20 | 21 | data AlexUserState = AlexUserState 22 | { previousToken :: !Token -- ^the previous token 23 | , comment :: [Token] -- ^the previous comment, if any 24 | , inTemplate :: Bool -- ^whether the parser is expecting template characters 25 | } 26 | 27 | alexInitUserState :: AlexUserState 28 | alexInitUserState = AlexUserState 29 | { previousToken = initToken 30 | , comment = [] 31 | , inTemplate = False 32 | } 33 | 34 | initToken :: Token 35 | initToken = CommentToken tokenPosnEmpty "" [] 36 | -------------------------------------------------------------------------------- /src/Language/JavaScript/Parser/SrcLocation.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable #-} 2 | module Language.JavaScript.Parser.SrcLocation ( 3 | TokenPosn(..) 4 | , tokenPosnEmpty 5 | ) where 6 | 7 | import Data.Data 8 | 9 | -- | `TokenPosn' records the location of a token in the input text. It has three 10 | -- fields: the address (number of characters preceding the token), line number 11 | -- and column of a token within the file. 12 | -- Note: The lexer assumes the usual eight character tab stops. 13 | 14 | data TokenPosn = TokenPn !Int -- address (number of characters preceding the token) 15 | !Int -- line number 16 | !Int -- column 17 | deriving (Eq,Show, Read, Data, Typeable) 18 | 19 | tokenPosnEmpty :: TokenPosn 20 | tokenPosnEmpty = TokenPn 0 0 0 21 | 22 | -------------------------------------------------------------------------------- /src/Language/JavaScript/Parser/Token.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP, DeriveDataTypeable #-} 2 | ----------------------------------------------------------------------------- 3 | -- | 4 | -- Module : Language.Python.Common.Token 5 | -- Copyright : (c) 2009 Bernie Pope 6 | -- License : BSD-style 7 | -- Maintainer : bjpop@csse.unimelb.edu.au 8 | -- Stability : experimental 9 | -- Portability : ghc 10 | -- 11 | -- Lexical tokens for the Python lexer. Contains the superset of tokens from 12 | -- version 2 and version 3 of Python (they are mostly the same). 13 | ----------------------------------------------------------------------------- 14 | 15 | module Language.JavaScript.Parser.Token 16 | ( 17 | -- * The tokens 18 | Token (..) 19 | , CommentAnnotation (..) 20 | -- * String conversion 21 | , debugTokenString 22 | -- * Classification 23 | -- TokenClass (..), 24 | ) where 25 | 26 | import Data.Data 27 | import Language.JavaScript.Parser.SrcLocation 28 | 29 | data CommentAnnotation 30 | = CommentA TokenPosn String 31 | | WhiteSpace TokenPosn String 32 | | NoComment 33 | deriving (Eq, Show, Typeable, Data, Read) 34 | 35 | -- | Lexical tokens. 36 | -- Each may be annotated with any comment occurring between the prior token and this one 37 | data Token 38 | -- Comment 39 | = CommentToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } -- ^ Single line comment. 40 | | WsToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } -- ^ White space, for preservation. 41 | 42 | -- Identifiers 43 | | IdentifierToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } -- ^ Identifier. 44 | 45 | -- Javascript Literals 46 | 47 | | DecimalToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 48 | -- ^ Literal: Decimal 49 | | HexIntegerToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 50 | -- ^ Literal: Hexadecimal Integer 51 | | OctalToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 52 | -- ^ Literal: Octal Integer 53 | | StringToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 54 | -- ^ Literal: string, delimited by either single or double quotes 55 | | RegExToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 56 | -- ^ Literal: Regular Expression 57 | 58 | -- Keywords 59 | | AsyncToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 60 | | AwaitToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 61 | | BreakToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 62 | | CaseToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 63 | | CatchToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 64 | | ClassToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 65 | | ConstToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 66 | | LetToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 67 | | ContinueToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 68 | | DebuggerToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 69 | | DefaultToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 70 | | DeleteToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 71 | | DoToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 72 | | ElseToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 73 | | EnumToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 74 | | ExtendsToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 75 | | FalseToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 76 | | FinallyToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 77 | | ForToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 78 | | FunctionToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 79 | | FromToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 80 | | IfToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 81 | | InToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 82 | | InstanceofToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 83 | | NewToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 84 | | NullToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 85 | | OfToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 86 | | ReturnToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 87 | | StaticToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 88 | | SuperToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 89 | | SwitchToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 90 | | ThisToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 91 | | ThrowToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 92 | | TrueToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 93 | | TryToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 94 | | TypeofToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 95 | | VarToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 96 | | VoidToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 97 | | WhileToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 98 | | YieldToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 99 | | ImportToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 100 | | WithToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 101 | | ExportToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 102 | -- Future reserved words 103 | | FutureToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 104 | -- Needed, not sure what they are though. 105 | | GetToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 106 | | SetToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 107 | 108 | -- Delimiters 109 | -- Operators 110 | | AutoSemiToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 111 | | SemiColonToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 112 | | CommaToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 113 | | HookToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 114 | | ColonToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 115 | | OrToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 116 | | AndToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 117 | | BitwiseOrToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 118 | | BitwiseXorToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 119 | | BitwiseAndToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 120 | | StrictEqToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 121 | | EqToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 122 | | TimesAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 123 | | DivideAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 124 | | ModAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 125 | | PlusAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 126 | | MinusAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 127 | | LshAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 128 | | RshAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 129 | | UrshAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 130 | | AndAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 131 | | XorAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 132 | | OrAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 133 | | SimpleAssignToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 134 | | StrictNeToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 135 | | NeToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 136 | | LshToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 137 | | LeToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 138 | | LtToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 139 | | UrshToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 140 | | RshToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 141 | | GeToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 142 | | GtToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 143 | | IncrementToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 144 | | DecrementToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 145 | | PlusToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 146 | | MinusToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 147 | | MulToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 148 | | DivToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 149 | | ModToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 150 | | NotToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 151 | | BitwiseNotToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 152 | | ArrowToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 153 | | SpreadToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 154 | | DotToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 155 | | LeftBracketToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 156 | | RightBracketToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 157 | | LeftCurlyToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 158 | | RightCurlyToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 159 | | LeftParenToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 160 | | RightParenToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 161 | | CondcommentEndToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } 162 | 163 | -- Template literal lexical components 164 | | NoSubstitutionTemplateToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 165 | | TemplateHeadToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 166 | | TemplateMiddleToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 167 | | TemplateTailToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 168 | 169 | -- Special cases 170 | | AsToken { tokenSpan :: !TokenPosn, tokenLiteral :: !String, tokenComment :: ![CommentAnnotation] } 171 | | TailToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } -- ^ Stuff between last JS and EOF 172 | | EOFToken { tokenSpan :: !TokenPosn, tokenComment :: ![CommentAnnotation] } -- ^ End of file 173 | deriving (Eq, Show, Typeable) 174 | 175 | 176 | -- | Produce a string from a token containing detailed information. Mainly intended for debugging. 177 | debugTokenString :: Token -> String 178 | debugTokenString = takeWhile (/= ' ') . show 179 | -------------------------------------------------------------------------------- /src/Language/JavaScript/Pretty/Printer.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE CPP, FlexibleInstances, NoOverloadedStrings, TypeSynonymInstances #-} 3 | 4 | module Language.JavaScript.Pretty.Printer 5 | ( -- * Printing 6 | renderJS 7 | , renderToString 8 | , renderToText 9 | ) where 10 | 11 | import Blaze.ByteString.Builder (Builder, toLazyByteString) 12 | import Data.List 13 | #if ! MIN_VERSION_base(4,13,0) 14 | import Data.Monoid (mempty) 15 | import Data.Semigroup ((<>)) 16 | #endif 17 | import Data.Text.Lazy (Text) 18 | import Language.JavaScript.Parser.AST 19 | import Language.JavaScript.Parser.SrcLocation 20 | import Language.JavaScript.Parser.Token 21 | import qualified Blaze.ByteString.Builder.Char.Utf8 as BS 22 | import qualified Data.ByteString.Lazy as LB 23 | import qualified Data.Text.Lazy.Encoding as LT 24 | import qualified Codec.Binary.UTF8.String as US 25 | 26 | -- --------------------------------------------------------------------- 27 | 28 | data PosAccum = PosAccum (Int, Int) Builder 29 | 30 | -- --------------------------------------------------------------------- 31 | -- Pretty printer stuff via blaze-builder 32 | 33 | str :: String -> Builder 34 | str = BS.fromString 35 | 36 | -- --------------------------------------------------------------------- 37 | 38 | renderJS :: JSAST -> Builder 39 | renderJS node = bb 40 | where 41 | PosAccum _ bb = PosAccum (1,1) mempty |> node 42 | 43 | 44 | renderToString :: JSAST -> String 45 | -- need to be careful to not lose the unicode encoding on output 46 | renderToString js = US.decode $ LB.unpack $ toLazyByteString $ renderJS js 47 | 48 | renderToText :: JSAST -> Text 49 | -- need to be careful to not lose the unicode encoding on output 50 | renderToText = LT.decodeUtf8 . toLazyByteString . renderJS 51 | 52 | 53 | class RenderJS a where 54 | -- Render node. 55 | (|>) :: PosAccum -> a -> PosAccum 56 | 57 | 58 | instance RenderJS JSAST where 59 | (|>) pacc (JSAstProgram xs a) = pacc |> xs |> a 60 | (|>) pacc (JSAstModule xs a) = pacc |> xs |> a 61 | (|>) pacc (JSAstStatement s a) = pacc |> s |> a 62 | (|>) pacc (JSAstExpression e a) = pacc |> e |> a 63 | (|>) pacc (JSAstLiteral x a) = pacc |> x |> a 64 | 65 | instance RenderJS JSExpression where 66 | -- Terminals 67 | (|>) pacc (JSIdentifier annot s) = pacc |> annot |> s 68 | (|>) pacc (JSDecimal annot i) = pacc |> annot |> i 69 | (|>) pacc (JSLiteral annot l) = pacc |> annot |> l 70 | (|>) pacc (JSHexInteger annot i) = pacc |> annot |> i 71 | (|>) pacc (JSOctal annot i) = pacc |> annot |> i 72 | (|>) pacc (JSStringLiteral annot s) = pacc |> annot |> s 73 | (|>) pacc (JSRegEx annot s) = pacc |> annot |> s 74 | 75 | -- Non-Terminals 76 | (|>) pacc (JSArrayLiteral als xs ars) = pacc |> als |> "[" |> xs |> ars |> "]" 77 | (|>) pacc (JSArrowExpression xs a x) = pacc |> xs |> a |> "=>" |> x 78 | (|>) pacc (JSAssignExpression lhs op rhs) = pacc |> lhs |> op |> rhs 79 | (|>) pacc (JSAwaitExpression a e) = pacc |> a |> "await" |> e 80 | (|>) pacc (JSCallExpression ex lb xs rb) = pacc |> ex |> lb |> "(" |> xs |> rb |> ")" 81 | (|>) pacc (JSCallExpressionDot ex os xs) = pacc |> ex |> os |> "." |> xs 82 | (|>) pacc (JSCallExpressionSquare ex als xs ars) = pacc |> ex |> als |> "[" |> xs |> ars |> "]" 83 | (|>) pacc (JSClassExpression annot n h lb xs rb) = pacc |> annot |> "class" |> n |> h |> lb |> "{" |> xs |> rb |> "}" 84 | (|>) pacc (JSCommaExpression le c re) = pacc |> le |> c |> "," |> re 85 | (|>) pacc (JSExpressionBinary lhs op rhs) = pacc |> lhs |> op |> rhs 86 | (|>) pacc (JSExpressionParen alp e arp) = pacc |> alp |> "(" |> e |> arp |> ")" 87 | (|>) pacc (JSExpressionPostfix xs op) = pacc |> xs |> op 88 | (|>) pacc (JSExpressionTernary cond h v1 c v2) = pacc |> cond |> h |> "?" |> v1 |> c |> ":" |> v2 89 | (|>) pacc (JSFunctionExpression annot n lb x2s rb x3) = pacc |> annot |> "function" |> n |> lb |> "(" |> x2s |> rb |> ")" |> x3 90 | (|>) pacc (JSGeneratorExpression annot s n lb x2s rb x3) = pacc |> annot |> "function" |> s |> "*" |> n |> lb |> "(" |> x2s |> rb |> ")" |> x3 91 | (|>) pacc (JSMemberDot xs dot n) = pacc |> xs |> "." |> dot |> n 92 | (|>) pacc (JSMemberExpression e lb a rb) = pacc |> e |> lb |> "(" |> a |> rb |> ")" 93 | (|>) pacc (JSMemberNew a lb n rb s) = pacc |> a |> "new" |> lb |> "(" |> n |> rb |> ")" |> s 94 | (|>) pacc (JSMemberSquare xs als e ars) = pacc |> xs |> als |> "[" |> e |> ars |> "]" 95 | (|>) pacc (JSNewExpression n e) = pacc |> n |> "new" |> e 96 | (|>) pacc (JSObjectLiteral alb xs arb) = pacc |> alb |> "{" |> xs |> arb |> "}" 97 | (|>) pacc (JSTemplateLiteral t a h ps) = pacc |> t |> a |> h |> ps 98 | (|>) pacc (JSUnaryExpression op x) = pacc |> op |> x 99 | (|>) pacc (JSVarInitExpression x1 x2) = pacc |> x1 |> x2 100 | (|>) pacc (JSYieldExpression y x) = pacc |> y |> "yield" |> x 101 | (|>) pacc (JSYieldFromExpression y s x) = pacc |> y |> "yield" |> s |> "*" |> x 102 | (|>) pacc (JSSpreadExpression a e) = pacc |> a |> "..." |> e 103 | 104 | instance RenderJS JSArrowParameterList where 105 | (|>) pacc (JSUnparenthesizedArrowParameter p) = pacc |> p 106 | (|>) pacc (JSParenthesizedArrowParameterList lb ps rb) = pacc |> lb |> "(" |> ps |> ")" |> rb 107 | -- ----------------------------------------------------------------------------- 108 | -- Need an instance of RenderJS for every component of every JSExpression or JSAnnot 109 | -- constuctor. 110 | -- ----------------------------------------------------------------------------- 111 | 112 | instance RenderJS JSAnnot where 113 | (|>) pacc (JSAnnot p cs) = pacc |> cs |> p 114 | (|>) pacc JSNoAnnot = pacc 115 | (|>) pacc JSAnnotSpace = pacc |> " " 116 | 117 | instance RenderJS String where 118 | (|>) (PosAccum (r,c) bb) s = PosAccum (r',c') (bb <> str s) 119 | where 120 | (r',c') = foldl' (\(row,col) ch -> go (row,col) ch) (r,c) s 121 | 122 | go (rx,_) '\n' = (rx+1,1) 123 | go (rx,cx) '\t' = (rx,cx+8) 124 | go (rx,cx) _ = (rx,cx+1) 125 | 126 | 127 | instance RenderJS TokenPosn where 128 | (|>) (PosAccum (lcur,ccur) bb) (TokenPn _ ltgt ctgt) = PosAccum (lnew,cnew) (bb <> bb') 129 | where 130 | (bbline,ccur') = if lcur < ltgt then (str (replicate (ltgt - lcur) '\n'),1) else (mempty,ccur) 131 | bbcol = if ccur' < ctgt then str (replicate (ctgt - ccur') ' ') else mempty 132 | bb' = bbline <> bbcol 133 | lnew = if lcur < ltgt then ltgt else lcur 134 | cnew = if ccur' < ctgt then ctgt else ccur' 135 | 136 | 137 | instance RenderJS [CommentAnnotation] where 138 | (|>) = foldl' (|>) 139 | 140 | 141 | instance RenderJS CommentAnnotation where 142 | (|>) pacc NoComment = pacc 143 | (|>) pacc (CommentA p s) = pacc |> p |> s 144 | (|>) pacc (WhiteSpace p s) = pacc |> p |> s 145 | 146 | 147 | instance RenderJS [JSExpression] where 148 | (|>) = foldl' (|>) 149 | 150 | 151 | instance RenderJS JSBinOp where 152 | (|>) pacc (JSBinOpAnd annot) = pacc |> annot |> "&&" 153 | (|>) pacc (JSBinOpBitAnd annot) = pacc |> annot |> "&" 154 | (|>) pacc (JSBinOpBitOr annot) = pacc |> annot |> "|" 155 | (|>) pacc (JSBinOpBitXor annot) = pacc |> annot |> "^" 156 | (|>) pacc (JSBinOpDivide annot) = pacc |> annot |> "/" 157 | (|>) pacc (JSBinOpEq annot) = pacc |> annot |> "==" 158 | (|>) pacc (JSBinOpGe annot) = pacc |> annot |> ">=" 159 | (|>) pacc (JSBinOpGt annot) = pacc |> annot |> ">" 160 | (|>) pacc (JSBinOpIn annot) = pacc |> annot |> "in" 161 | (|>) pacc (JSBinOpInstanceOf annot) = pacc |> annot |> "instanceof" 162 | (|>) pacc (JSBinOpLe annot) = pacc |> annot |> "<=" 163 | (|>) pacc (JSBinOpLsh annot) = pacc |> annot |> "<<" 164 | (|>) pacc (JSBinOpLt annot) = pacc |> annot |> "<" 165 | (|>) pacc (JSBinOpMinus annot) = pacc |> annot |> "-" 166 | (|>) pacc (JSBinOpMod annot) = pacc |> annot |> "%" 167 | (|>) pacc (JSBinOpNeq annot) = pacc |> annot |> "!=" 168 | (|>) pacc (JSBinOpOf annot) = pacc |> annot |> "of" 169 | (|>) pacc (JSBinOpOr annot) = pacc |> annot |> "||" 170 | (|>) pacc (JSBinOpPlus annot) = pacc |> annot |> "+" 171 | (|>) pacc (JSBinOpRsh annot) = pacc |> annot |> ">>" 172 | (|>) pacc (JSBinOpStrictEq annot) = pacc |> annot |> "===" 173 | (|>) pacc (JSBinOpStrictNeq annot) = pacc |> annot |> "!==" 174 | (|>) pacc (JSBinOpTimes annot) = pacc |> annot |> "*" 175 | (|>) pacc (JSBinOpUrsh annot) = pacc |> annot |> ">>>" 176 | 177 | 178 | instance RenderJS JSUnaryOp where 179 | (|>) pacc (JSUnaryOpDecr annot) = pacc |> annot |> "--" 180 | (|>) pacc (JSUnaryOpDelete annot) = pacc |> annot |> "delete" 181 | (|>) pacc (JSUnaryOpIncr annot) = pacc |> annot |> "++" 182 | (|>) pacc (JSUnaryOpMinus annot) = pacc |> annot |> "-" 183 | (|>) pacc (JSUnaryOpNot annot) = pacc |> annot |> "!" 184 | (|>) pacc (JSUnaryOpPlus annot) = pacc |> annot |> "+" 185 | (|>) pacc (JSUnaryOpTilde annot) = pacc |> annot |> "~" 186 | (|>) pacc (JSUnaryOpTypeof annot) = pacc |> annot |> "typeof" 187 | (|>) pacc (JSUnaryOpVoid annot) = pacc |> annot |> "void" 188 | 189 | 190 | instance RenderJS JSAssignOp where 191 | (|>) pacc (JSAssign annot) = pacc |> annot |> "=" 192 | (|>) pacc (JSTimesAssign annot) = pacc |> annot |> "*=" 193 | (|>) pacc (JSDivideAssign annot) = pacc |> annot |> "/=" 194 | (|>) pacc (JSModAssign annot) = pacc |> annot |> "%=" 195 | (|>) pacc (JSPlusAssign annot) = pacc |> annot |> "+=" 196 | (|>) pacc (JSMinusAssign annot) = pacc |> annot |> "-=" 197 | (|>) pacc (JSLshAssign annot) = pacc |> annot |> "<<=" 198 | (|>) pacc (JSRshAssign annot) = pacc |> annot |> ">>=" 199 | (|>) pacc (JSUrshAssign annot) = pacc |> annot |> ">>>=" 200 | (|>) pacc (JSBwAndAssign annot) = pacc |> annot |> "&=" 201 | (|>) pacc (JSBwXorAssign annot) = pacc |> annot |> "^=" 202 | (|>) pacc (JSBwOrAssign annot) = pacc |> annot |> "|=" 203 | 204 | 205 | instance RenderJS JSSemi where 206 | (|>) pacc (JSSemi annot) = pacc |> annot |> ";" 207 | (|>) pacc JSSemiAuto = pacc 208 | 209 | 210 | instance RenderJS JSTryCatch where 211 | (|>) pacc (JSCatch anc alb x1 arb x3) = pacc |> anc |> "catch" |> alb |> "(" |> x1 |> arb |> ")" |> x3 212 | (|>) pacc (JSCatchIf anc alb x1 aif ex arb x3) = pacc |> anc |> "catch" |> alb |> "(" |> x1 |> aif |> "if" |> ex |> arb |> ")" |> x3 213 | 214 | instance RenderJS [JSTryCatch] where 215 | (|>) = foldl' (|>) 216 | 217 | instance RenderJS JSTryFinally where 218 | (|>) pacc (JSFinally annot x) = pacc |> annot |> "finally" |> x 219 | (|>) pacc JSNoFinally = pacc 220 | 221 | instance RenderJS JSSwitchParts where 222 | (|>) pacc (JSCase annot x1 c x2s) = pacc |> annot |> "case" |> x1 |> c |> ":" |> x2s 223 | (|>) pacc (JSDefault annot c xs) = pacc |> annot |> "default" |> c |> ":" |> xs 224 | 225 | instance RenderJS [JSSwitchParts] where 226 | (|>) = foldl' (|>) 227 | 228 | instance RenderJS JSStatement where 229 | (|>) pacc (JSStatementBlock alb blk arb s) = pacc |> alb |> "{" |> blk |> arb |> "}" |> s 230 | (|>) pacc (JSBreak annot mi s) = pacc |> annot |> "break" |> mi |> s 231 | (|>) pacc (JSClass annot n h lb xs rb s) = pacc |> annot |> "class" |> n |> h |> lb |> "{" |> xs |> rb |> "}" |> s 232 | (|>) pacc (JSContinue annot mi s) = pacc |> annot |> "continue" |> mi |> s 233 | (|>) pacc (JSConstant annot xs s) = pacc |> annot |> "const" |> xs |> s 234 | (|>) pacc (JSDoWhile ad x1 aw alb x2 arb x3) = pacc |> ad |> "do" |> x1 |> aw |> "while" |> alb |> "(" |> x2 |> arb |> ")" |> x3 235 | (|>) pacc (JSEmptyStatement a) = pacc |> a |> ";" 236 | (|>) pacc (JSFor af alb x1s s1 x2s s2 x3s arb x4) = pacc |> af |> "for" |> alb |> "(" |> x1s |> s1 |> ";" |> x2s |> s2 |> ";" |> x3s |> arb |> ")" |> x4 237 | (|>) pacc (JSForIn af alb x1s i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> x1s |> i |> x2 |> arb |> ")" |> x3 238 | (|>) pacc (JSForVar af alb v x1s s1 x2s s2 x3s arb x4) = pacc |> af |> "for" |> alb |> "(" |> "var" |> v |> x1s |> s1 |> ";" |> x2s |> s2 |> ";" |> x3s |> arb |> ")" |> x4 239 | (|>) pacc (JSForVarIn af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "var" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 240 | (|>) pacc (JSForLet af alb v x1s s1 x2s s2 x3s arb x4) = pacc |> af |> "for" |> alb |> "(" |> "let" |> v |> x1s |> s1 |> ";" |> x2s |> s2 |> ";" |> x3s |> arb |> ")" |> x4 241 | (|>) pacc (JSForLetIn af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "let" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 242 | (|>) pacc (JSForLetOf af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "let" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 243 | (|>) pacc (JSForConst af alb v x1s s1 x2s s2 x3s arb x4) = pacc |> af |> "for" |> alb |> "(" |> "const" |> v |> x1s |> s1 |> ";" |> x2s |> s2 |> ";" |> x3s |> arb |> ")" |> x4 244 | (|>) pacc (JSForConstIn af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "const" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 245 | (|>) pacc (JSForConstOf af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "const" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 246 | (|>) pacc (JSForOf af alb x1s i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> x1s |> i |> x2 |> arb |> ")" |> x3 247 | (|>) pacc (JSForVarOf af alb v x1 i x2 arb x3) = pacc |> af |> "for" |> alb |> "(" |> "var" |> v |> x1 |> i |> x2 |> arb |> ")" |> x3 248 | (|>) pacc (JSAsyncFunction aa af n alb x2s arb x3 s) = pacc |> aa |> "async" |> af |> "function" |> n |> alb |> "(" |> x2s |> arb |> ")" |> x3 |> s 249 | (|>) pacc (JSFunction af n alb x2s arb x3 s) = pacc |> af |> "function" |> n |> alb |> "(" |> x2s |> arb |> ")" |> x3 |> s 250 | (|>) pacc (JSGenerator af as n alb x2s arb x3 s) = pacc |> af |> "function" |> as |> "*" |> n |> alb |> "(" |> x2s |> arb |> ")" |> x3 |> s 251 | (|>) pacc (JSIf annot alb x1 arb x2s) = pacc |> annot |> "if" |> alb |> "(" |> x1 |> arb |> ")" |> x2s 252 | (|>) pacc (JSIfElse annot alb x1 arb x2s ea x3s) = pacc |> annot |> "if" |> alb |> "(" |> x1 |> arb |> ")" |> x2s |> ea |> "else" |> x3s 253 | (|>) pacc (JSLabelled l c v) = pacc |> l |> c |> ":" |> v 254 | (|>) pacc (JSLet annot xs s) = pacc |> annot |> "let" |> xs |> s 255 | (|>) pacc (JSExpressionStatement l s) = pacc |> l |> s 256 | (|>) pacc (JSAssignStatement lhs op rhs s) = pacc |> lhs |> op |> rhs |> s 257 | (|>) pacc (JSMethodCall e lp a rp s) = pacc |> e |> lp |> "(" |> a |> rp |> ")" |> s 258 | (|>) pacc (JSReturn annot me s) = pacc |> annot |> "return" |> me |> s 259 | (|>) pacc (JSSwitch annot alp x arp alb x2 arb s) = pacc |> annot |> "switch" |> alp |> "(" |> x |> arp |> ")" |> alb |> "{" |> x2 |> arb |> "}" |> s 260 | (|>) pacc (JSThrow annot x s) = pacc |> annot |> "throw" |> x |> s 261 | (|>) pacc (JSTry annot tb tcs tf) = pacc |> annot |> "try" |> tb |> tcs |> tf 262 | (|>) pacc (JSVariable annot xs s) = pacc |> annot |> "var" |> xs |> s 263 | (|>) pacc (JSWhile annot alp x1 arp x2) = pacc |> annot |> "while" |> alp |> "(" |> x1 |> arp |> ")" |> x2 264 | (|>) pacc (JSWith annot alp x1 arp x s) = pacc |> annot |> "with" |> alp |> "(" |> x1 |> arp |> ")" |> x |> s 265 | 266 | instance RenderJS [JSStatement] where 267 | (|>) = foldl' (|>) 268 | 269 | instance RenderJS [JSModuleItem] where 270 | (|>) = foldl' (|>) 271 | 272 | instance RenderJS JSModuleItem where 273 | (|>) pacc (JSModuleImportDeclaration annot decl) = pacc |> annot |> "import" |> decl 274 | (|>) pacc (JSModuleExportDeclaration annot decl) = pacc |> annot |> "export" |> decl 275 | (|>) pacc (JSModuleStatementListItem s) = pacc |> s 276 | 277 | instance RenderJS JSBlock where 278 | (|>) pacc (JSBlock alb ss arb) = pacc |> alb |> "{" |> ss |> arb |> "}" 279 | 280 | instance RenderJS JSObjectProperty where 281 | (|>) pacc (JSPropertyNameandValue n c vs) = pacc |> n |> c |> ":" |> vs 282 | (|>) pacc (JSPropertyIdentRef a s) = pacc |> a |> s 283 | (|>) pacc (JSObjectMethod m) = pacc |> m 284 | 285 | instance RenderJS JSMethodDefinition where 286 | (|>) pacc (JSMethodDefinition n alp ps arp b) = pacc |> n |> alp |> "(" |> ps |> arp |> ")" |> b 287 | (|>) pacc (JSGeneratorMethodDefinition s n alp ps arp b) = pacc |> s |> "*" |> n |> alp |> "(" |> ps |> arp |> ")" |> b 288 | (|>) pacc (JSPropertyAccessor s n alp ps arp b) = pacc |> s |> n |> alp |> "(" |> ps |> arp |> ")" |> b 289 | 290 | instance RenderJS JSPropertyName where 291 | (|>) pacc (JSPropertyIdent a s) = pacc |> a |> s 292 | (|>) pacc (JSPropertyString a s) = pacc |> a |> s 293 | (|>) pacc (JSPropertyNumber a s) = pacc |> a |> s 294 | (|>) pacc (JSPropertyComputed lb x rb) = pacc |> lb |> "[" |> x |> rb |> "]" 295 | 296 | instance RenderJS JSAccessor where 297 | (|>) pacc (JSAccessorGet annot) = pacc |> annot |> "get" 298 | (|>) pacc (JSAccessorSet annot) = pacc |> annot |> "set" 299 | 300 | instance RenderJS JSArrayElement where 301 | (|>) pacc (JSArrayElement e) = pacc |> e 302 | (|>) pacc (JSArrayComma a) = pacc |> a |> "," 303 | 304 | instance RenderJS [JSArrayElement] where 305 | (|>) = foldl' (|>) 306 | 307 | instance RenderJS JSImportDeclaration where 308 | (|>) pacc (JSImportDeclaration imp from annot) = pacc |> imp |> from |> annot 309 | (|>) pacc (JSImportDeclarationBare annot m s) = pacc |> annot |> m |> s 310 | 311 | instance RenderJS JSImportClause where 312 | (|>) pacc (JSImportClauseDefault x) = pacc |> x 313 | (|>) pacc (JSImportClauseNameSpace x) = pacc |> x 314 | (|>) pacc (JSImportClauseNamed x) = pacc |> x 315 | (|>) pacc (JSImportClauseDefaultNameSpace x1 annot x2) = pacc |> x1 |> annot |> "," |> x2 316 | (|>) pacc (JSImportClauseDefaultNamed x1 annot x2) = pacc |> x1 |> annot |> "," |> x2 317 | 318 | instance RenderJS JSFromClause where 319 | (|>) pacc (JSFromClause from annot m) = pacc |> from |> "from" |> annot |> m 320 | 321 | instance RenderJS JSImportNameSpace where 322 | (|>) pacc (JSImportNameSpace star annot x) = pacc |> star |> annot |> "as" |> x 323 | 324 | instance RenderJS JSImportsNamed where 325 | (|>) pacc (JSImportsNamed lb xs rb) = pacc |> lb |> "{" |> xs |> rb |> "}" 326 | 327 | instance RenderJS JSImportSpecifier where 328 | (|>) pacc (JSImportSpecifier x1) = pacc |> x1 329 | (|>) pacc (JSImportSpecifierAs x1 annot x2) = pacc |> x1 |> annot |> "as" |> x2 330 | 331 | instance RenderJS JSExportDeclaration where 332 | (|>) pacc (JSExport x1 s) = pacc |> x1 |> s 333 | (|>) pacc (JSExportLocals xs semi) = pacc |> xs |> semi 334 | (|>) pacc (JSExportFrom xs from semi) = pacc |> xs |> from |> semi 335 | 336 | instance RenderJS JSExportClause where 337 | (|>) pacc (JSExportClause alb JSLNil arb) = pacc |> alb |> "{" |> arb |> "}" 338 | (|>) pacc (JSExportClause alb s arb) = pacc |> alb |> "{" |> s |> arb |> "}" 339 | 340 | instance RenderJS JSExportSpecifier where 341 | (|>) pacc (JSExportSpecifier i) = pacc |> i 342 | (|>) pacc (JSExportSpecifierAs x1 annot x2) = pacc |> x1 |> annot |> "as" |> x2 343 | 344 | instance RenderJS a => RenderJS (JSCommaList a) where 345 | (|>) pacc (JSLCons pl a i) = pacc |> pl |> a |> "," |> i 346 | (|>) pacc (JSLOne i) = pacc |> i 347 | (|>) pacc JSLNil = pacc 348 | 349 | instance RenderJS a => RenderJS (JSCommaTrailingList a) where 350 | (|>) pacc (JSCTLComma xs a) = pacc |> xs |> a |> "," 351 | (|>) pacc (JSCTLNone xs) = pacc |> xs 352 | 353 | instance RenderJS JSIdent where 354 | (|>) pacc (JSIdentName a s) = pacc |> a |> s 355 | (|>) pacc JSIdentNone = pacc 356 | 357 | instance RenderJS (Maybe JSExpression) where 358 | (|>) pacc (Just e) = pacc |> e 359 | (|>) pacc Nothing = pacc 360 | 361 | instance RenderJS JSVarInitializer where 362 | (|>) pacc (JSVarInit a x) = pacc |> a |> "=" |> x 363 | (|>) pacc JSVarInitNone = pacc 364 | 365 | instance RenderJS [JSTemplatePart] where 366 | (|>) = foldl' (|>) 367 | 368 | instance RenderJS JSTemplatePart where 369 | (|>) pacc (JSTemplatePart e a s) = pacc |> e |> a |> s 370 | 371 | instance RenderJS JSClassHeritage where 372 | (|>) pacc (JSExtends a e) = pacc |> a |> "extends" |> e 373 | (|>) pacc JSExtendsNone = pacc 374 | 375 | instance RenderJS [JSClassElement] where 376 | (|>) = foldl' (|>) 377 | 378 | instance RenderJS JSClassElement where 379 | (|>) pacc (JSClassInstanceMethod m) = pacc |> m 380 | (|>) pacc (JSClassStaticMethod a m) = pacc |> a |> "static" |> m 381 | (|>) pacc (JSClassSemi a) = pacc |> a |> ";" 382 | 383 | -- EOF 384 | -------------------------------------------------------------------------------- /src/Language/JavaScript/Process/Minify.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP, FlexibleInstances #-} 2 | 3 | module Language.JavaScript.Process.Minify 4 | ( -- * Minify 5 | minifyJS 6 | ) where 7 | 8 | #if ! MIN_VERSION_base(4,13,0) 9 | import Control.Applicative ((<$>)) 10 | #endif 11 | 12 | import Language.JavaScript.Parser.AST 13 | import Language.JavaScript.Parser.SrcLocation 14 | import Language.JavaScript.Parser.Token 15 | 16 | -- --------------------------------------------------------------------- 17 | 18 | minifyJS :: JSAST -> JSAST 19 | minifyJS (JSAstProgram xs _) = JSAstProgram (fixStatementList noSemi xs) emptyAnnot 20 | minifyJS (JSAstModule xs _) = JSAstModule (map (fix emptyAnnot) xs) emptyAnnot 21 | minifyJS (JSAstStatement (JSStatementBlock _ [s] _ _) _) = JSAstStatement (fixStmtE noSemi s) emptyAnnot 22 | minifyJS (JSAstStatement s _) = JSAstStatement (fixStmtE noSemi s) emptyAnnot 23 | minifyJS (JSAstExpression e _) = JSAstExpression (fixEmpty e) emptyAnnot 24 | minifyJS (JSAstLiteral s _) = JSAstLiteral (fixEmpty s) emptyAnnot 25 | 26 | -- --------------------------------------------------------------------- 27 | 28 | class MinifyJS a where 29 | fix :: JSAnnot -> a -> a 30 | 31 | 32 | fixEmpty :: MinifyJS a => a -> a 33 | fixEmpty = fix emptyAnnot 34 | 35 | fixSpace :: MinifyJS a => a -> a 36 | fixSpace = fix spaceAnnot 37 | 38 | -- ----------------------------------------------------------------------------- 39 | -- During minification, Javascript statements may need to have explicit 40 | -- semicolons inserted between them, so that simply adding a JSStatement 41 | -- instance for the MinifyJS typeclass would not be sufficient. 42 | 43 | fixStmt :: JSAnnot -> JSSemi -> JSStatement -> JSStatement 44 | fixStmt a s (JSStatementBlock _lb ss _rb _) = fixStatementBlock a s ss 45 | fixStmt a s (JSBreak _ i _) = JSBreak a (fixSpace i) s 46 | fixStmt a s (JSClass _ n h _ ms _ _) = JSClass a (fixSpace n) (fixSpace h) emptyAnnot (fixEmpty ms) emptyAnnot s 47 | fixStmt a s (JSConstant _ ss _) = JSConstant a (fixVarList ss) s 48 | fixStmt a s (JSContinue _ i _) = JSContinue a (fixSpace i) s 49 | fixStmt a s (JSDoWhile _ st _ _ e _ _) = JSDoWhile a (mkStatementBlock noSemi st) emptyAnnot emptyAnnot (fixEmpty e) emptyAnnot s 50 | fixStmt a s (JSFor _ _ el1 _ el2 _ el3 _ st) = JSFor a emptyAnnot (fixEmpty el1) emptyAnnot (fixEmpty el2) emptyAnnot (fixEmpty el3) emptyAnnot (fixStmtE s st) 51 | fixStmt a s (JSForIn _ _ e1 op e2 _ st) = JSForIn a emptyAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) 52 | fixStmt a s (JSForVar _ _ _ el1 _ el2 _ el3 _ st) = JSForVar a emptyAnnot spaceAnnot (fixEmpty el1) emptyAnnot (fixEmpty el2) emptyAnnot (fixEmpty el3) emptyAnnot (fixStmtE s st) 53 | fixStmt a s (JSForVarIn _ _ _ e1 op e2 _ st) = JSForVarIn a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) 54 | fixStmt a s (JSForLet _ _ _ el1 _ el2 _ el3 _ st) = JSForLet a emptyAnnot spaceAnnot (fixEmpty el1) emptyAnnot (fixEmpty el2) emptyAnnot (fixEmpty el3) emptyAnnot (fixStmtE s st) 55 | fixStmt a s (JSForLetIn _ _ _ e1 op e2 _ st) = JSForLetIn a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) 56 | fixStmt a s (JSForLetOf _ _ _ e1 op e2 _ st) = JSForLetOf a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) 57 | fixStmt a s (JSForConst _ _ _ el1 _ el2 _ el3 _ st) = JSForConst a emptyAnnot spaceAnnot (fixEmpty el1) emptyAnnot (fixEmpty el2) emptyAnnot (fixEmpty el3) emptyAnnot (fixStmtE s st) 58 | fixStmt a s (JSForConstIn _ _ _ e1 op e2 _ st) = JSForConstIn a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) 59 | fixStmt a s (JSForConstOf _ _ _ e1 op e2 _ st) = JSForConstOf a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) 60 | fixStmt a s (JSForOf _ _ e1 op e2 _ st) = JSForOf a emptyAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) 61 | fixStmt a s (JSForVarOf _ _ _ e1 op e2 _ st) = JSForVarOf a emptyAnnot spaceAnnot (fixEmpty e1) (fixSpace op) (fixSpace e2) emptyAnnot (fixStmtE s st) 62 | fixStmt a s (JSAsyncFunction _ _ n _ ps _ blk _) = JSAsyncFunction a spaceAnnot (fixSpace n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty blk) s 63 | fixStmt a s (JSFunction _ n _ ps _ blk _) = JSFunction a (fixSpace n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty blk) s 64 | fixStmt a s (JSGenerator _ _ n _ ps _ blk _) = JSGenerator a emptyAnnot (fixEmpty n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty blk) s 65 | fixStmt a s (JSIf _ _ e _ st) = JSIf a emptyAnnot (fixEmpty e) emptyAnnot (fixIfElseBlock emptyAnnot s st) 66 | fixStmt a s (JSIfElse _ _ e _ (JSEmptyStatement _) _ sf) = JSIfElse a emptyAnnot (fixEmpty e) emptyAnnot (JSEmptyStatement emptyAnnot) emptyAnnot (fixStmt spaceAnnot s sf) 67 | fixStmt a s (JSIfElse _ _ e _ st _ sf) = JSIfElse a emptyAnnot (fixEmpty e) emptyAnnot (mkStatementBlock noSemi st) emptyAnnot (fixIfElseBlock spaceAnnot s sf) 68 | fixStmt a s (JSLabelled e _ st) = JSLabelled (fix a e) emptyAnnot (fixStmtE s st) 69 | fixStmt a s (JSLet _ xs _) = JSLet a (fixVarList xs) s 70 | fixStmt _ _ (JSEmptyStatement _) = JSEmptyStatement emptyAnnot 71 | fixStmt a s (JSExpressionStatement e _) = JSExpressionStatement (fix a e) s 72 | fixStmt a s (JSAssignStatement lhs op rhs _) = JSAssignStatement (fix a lhs) (fixEmpty op) (fixEmpty rhs) s 73 | fixStmt a s (JSMethodCall e _ args _ _) = JSMethodCall (fix a e) emptyAnnot (fixEmpty args) emptyAnnot s 74 | fixStmt a s (JSReturn _ me _) = JSReturn a (fixSpace me) s 75 | fixStmt a s (JSSwitch _ _ e _ _ sps _ _) = JSSwitch a emptyAnnot (fixEmpty e) emptyAnnot emptyAnnot (fixSwitchParts sps) emptyAnnot s 76 | fixStmt a s (JSThrow _ e _) = JSThrow a (fixSpace e) s 77 | fixStmt a _ (JSTry _ b tc tf) = JSTry a (fixEmpty b) (map fixEmpty tc) (fixEmpty tf) 78 | fixStmt a s (JSVariable _ ss _) = JSVariable a (fixVarList ss) s 79 | fixStmt a s (JSWhile _ _ e _ st) = JSWhile a emptyAnnot (fixEmpty e) emptyAnnot (fixStmt a s st) 80 | fixStmt a s (JSWith _ _ e _ st _) = JSWith a emptyAnnot (fixEmpty e) emptyAnnot (fixStmtE noSemi st) s 81 | 82 | 83 | fixIfElseBlock :: JSAnnot -> JSSemi -> JSStatement -> JSStatement 84 | fixIfElseBlock _ _ (JSStatementBlock _ [] _ _) = JSEmptyStatement emptyAnnot 85 | fixIfElseBlock a s st = fixStmt a s st 86 | 87 | fixStmtE :: JSSemi -> JSStatement -> JSStatement 88 | fixStmtE = fixStmt emptyAnnot 89 | 90 | -- Turn a single JSStatement into a JSStatementBlock. 91 | mkStatementBlock :: JSSemi -> JSStatement -> JSStatement 92 | mkStatementBlock s (JSStatementBlock _ blk _ _) = JSStatementBlock emptyAnnot (fixStatementList noSemi blk) emptyAnnot s 93 | mkStatementBlock s x = JSStatementBlock emptyAnnot [fixStmtE noSemi x] emptyAnnot s 94 | 95 | -- Filter a list of JSStatment, dropping JSEmptyStatement and empty 96 | -- JSStatementBlocks. If the resulting list contains only a single element, 97 | -- remove the enclosing JSStatementBlock and return the inner JSStatement. 98 | fixStatementBlock :: JSAnnot -> JSSemi -> [JSStatement] -> JSStatement 99 | fixStatementBlock a s ss = 100 | case filter (not . isEmpty) ss of 101 | [] -> JSStatementBlock emptyAnnot [] emptyAnnot s 102 | [sx] -> fixStmt a s sx 103 | sss -> JSStatementBlock emptyAnnot (fixStatementList noSemi sss) emptyAnnot s 104 | where 105 | isEmpty (JSEmptyStatement _) = True 106 | isEmpty (JSStatementBlock _ [] _ _) = True 107 | isEmpty _ = False 108 | 109 | -- Force semi-colons between statements, and make sure the last statement in a 110 | -- block has no semi-colon. 111 | fixStatementList :: JSSemi -> [JSStatement] -> [JSStatement] 112 | fixStatementList trailingSemi = 113 | fixList emptyAnnot trailingSemi . filter (not . isRedundant) 114 | where 115 | isRedundant (JSStatementBlock _ [] _ _) = True 116 | isRedundant (JSEmptyStatement _) = True 117 | isRedundant _ = False 118 | 119 | fixList _ _ [] = [] 120 | fixList a s [JSStatementBlock _ blk _ _] = fixList a s blk 121 | fixList a s [x] = [fixStmt a s x] 122 | fixList _ s (JSStatementBlock _ blk _ _:xs) = fixList emptyAnnot semi (filter (not . isRedundant) blk) ++ fixList emptyAnnot s xs 123 | fixList a s (JSConstant _ vs1 _:JSConstant _ vs2 _: xs) = fixList a s (JSConstant spaceAnnot (concatCommaList vs1 vs2) s : xs) 124 | fixList a s (JSVariable _ vs1 _:JSVariable _ vs2 _: xs) = fixList a s (JSVariable spaceAnnot (concatCommaList vs1 vs2) s : xs) 125 | fixList a s (x1@JSFunction{}:x2@JSFunction{}:xs) = fixStmt a noSemi x1 : fixList newlineAnnot s (x2:xs) 126 | fixList a s (x:xs) = fixStmt a semi x : fixList emptyAnnot s xs 127 | 128 | concatCommaList :: JSCommaList a -> JSCommaList a -> JSCommaList a 129 | concatCommaList xs JSLNil = xs 130 | concatCommaList JSLNil ys = ys 131 | concatCommaList xs (JSLOne y) = JSLCons xs emptyAnnot y 132 | concatCommaList xs ys = 133 | let recurse (z, zs) = concatCommaList (JSLCons xs emptyAnnot z) zs 134 | in maybe xs recurse $ headCommaList ys 135 | 136 | headCommaList :: JSCommaList a -> Maybe (a, JSCommaList a) 137 | headCommaList JSLNil = Nothing 138 | headCommaList (JSLOne x) = Just (x, JSLNil) 139 | headCommaList (JSLCons (JSLOne x) _ y) = Just (x, JSLOne y) 140 | headCommaList (JSLCons xs _ y) = 141 | let rebuild (x, ys) = (x, JSLCons ys emptyAnnot y) 142 | in rebuild <$> headCommaList xs 143 | 144 | -- ----------------------------------------------------------------------------- 145 | -- JSExpression and the rest can use the MinifyJS typeclass. 146 | 147 | instance MinifyJS JSExpression where 148 | -- Terminals 149 | fix a (JSIdentifier _ s) = JSIdentifier a s 150 | fix a (JSDecimal _ s) = JSDecimal a s 151 | fix a (JSLiteral _ s) = JSLiteral a s 152 | fix a (JSHexInteger _ s) = JSHexInteger a s 153 | fix a (JSOctal _ s) = JSOctal a s 154 | fix _ (JSStringLiteral _ s) = JSStringLiteral emptyAnnot s 155 | fix _ (JSRegEx _ s) = JSRegEx emptyAnnot s 156 | 157 | -- Non-Terminals 158 | fix _ (JSArrayLiteral _ xs _) = JSArrayLiteral emptyAnnot (map fixEmpty xs) emptyAnnot 159 | fix a (JSArrowExpression ps _ ss) = JSArrowExpression (fix a ps) emptyAnnot (fixStmt emptyAnnot noSemi ss) 160 | fix a (JSAssignExpression lhs op rhs) = JSAssignExpression (fix a lhs) (fixEmpty op) (fixEmpty rhs) 161 | fix a (JSAwaitExpression _ ex) = JSAwaitExpression a (fixSpace ex) 162 | fix a (JSCallExpression ex _ xs _) = JSCallExpression (fix a ex) emptyAnnot (fixEmpty xs) emptyAnnot 163 | fix a (JSCallExpressionDot ex _ xs) = JSCallExpressionDot (fix a ex) emptyAnnot (fixEmpty xs) 164 | fix a (JSCallExpressionSquare ex _ xs _) = JSCallExpressionSquare (fix a ex) emptyAnnot (fixEmpty xs) emptyAnnot 165 | fix a (JSClassExpression _ n h _ ms _) = JSClassExpression a (fixSpace n) (fixSpace h) emptyAnnot (fixEmpty ms) emptyAnnot 166 | fix a (JSCommaExpression le _ re) = JSCommaExpression (fix a le) emptyAnnot (fixEmpty re) 167 | fix a (JSExpressionBinary lhs op rhs) = fixBinOpExpression a op lhs rhs 168 | fix _ (JSExpressionParen _ e _) = JSExpressionParen emptyAnnot (fixEmpty e) emptyAnnot 169 | fix a (JSExpressionPostfix e op) = JSExpressionPostfix (fix a e) (fixEmpty op) 170 | fix a (JSExpressionTernary cond _ v1 _ v2) = JSExpressionTernary (fix a cond) emptyAnnot (fixEmpty v1) emptyAnnot (fixEmpty v2) 171 | fix a (JSFunctionExpression _ n _ x2s _ x3) = JSFunctionExpression a (fixSpace n) emptyAnnot (fixEmpty x2s) emptyAnnot (fixEmpty x3) 172 | fix a (JSGeneratorExpression _ _ n _ x2s _ x3) = JSGeneratorExpression a emptyAnnot (fixEmpty n) emptyAnnot (fixEmpty x2s) emptyAnnot (fixEmpty x3) 173 | fix a (JSMemberDot xs _ n) = JSMemberDot (fix a xs) emptyAnnot (fixEmpty n) 174 | fix a (JSMemberExpression e _ args _) = JSMemberExpression (fix a e) emptyAnnot (fixEmpty args) emptyAnnot 175 | fix a (JSMemberNew _ n _ s _) = JSMemberNew a (fix spaceAnnot n) emptyAnnot (fixEmpty s) emptyAnnot 176 | fix a (JSMemberSquare xs _ e _) = JSMemberSquare (fix a xs) emptyAnnot (fixEmpty e) emptyAnnot 177 | fix a (JSNewExpression _ e) = JSNewExpression a (fixSpace e) 178 | fix _ (JSObjectLiteral _ xs _) = JSObjectLiteral emptyAnnot (fixEmpty xs) emptyAnnot 179 | fix a (JSTemplateLiteral t _ s ps) = JSTemplateLiteral (fmap (fix a) t) emptyAnnot s (map fixEmpty ps) 180 | fix a (JSUnaryExpression op x) = let (ta, fop) = fixUnaryOp a op in JSUnaryExpression fop (fix ta x) 181 | fix a (JSVarInitExpression x1 x2) = JSVarInitExpression (fix a x1) (fixEmpty x2) 182 | fix a (JSYieldExpression _ x) = JSYieldExpression a (fixSpace x) 183 | fix a (JSYieldFromExpression _ _ x) = JSYieldFromExpression a emptyAnnot (fixEmpty x) 184 | fix a (JSSpreadExpression _ e) = JSSpreadExpression a (fixEmpty e) 185 | 186 | instance MinifyJS JSArrowParameterList where 187 | fix _ (JSUnparenthesizedArrowParameter p) = JSUnparenthesizedArrowParameter (fixEmpty p) 188 | fix _ (JSParenthesizedArrowParameterList _ ps _) = JSParenthesizedArrowParameterList emptyAnnot (fixEmpty ps) emptyAnnot 189 | 190 | fixVarList :: JSCommaList JSExpression -> JSCommaList JSExpression 191 | fixVarList (JSLCons h _ v) = JSLCons (fixVarList h) emptyAnnot (fixEmpty v) 192 | fixVarList (JSLOne a) = JSLOne (fixSpace a) 193 | fixVarList JSLNil = JSLNil 194 | 195 | fixBinOpExpression :: JSAnnot -> JSBinOp -> JSExpression -> JSExpression -> JSExpression 196 | fixBinOpExpression a (JSBinOpPlus _) lhs rhs = fixBinOpPlus a lhs rhs 197 | fixBinOpExpression a (JSBinOpIn _) lhs rhs = JSExpressionBinary (fix a lhs) (JSBinOpIn spaceAnnot) (fix spaceAnnot rhs) 198 | fixBinOpExpression a (JSBinOpInstanceOf _) lhs rhs = JSExpressionBinary (fix a lhs) (JSBinOpInstanceOf spaceAnnot) (fix spaceAnnot rhs) 199 | fixBinOpExpression a op lhs rhs = JSExpressionBinary (fix a lhs) (fixEmpty op) (fixEmpty rhs) 200 | 201 | fixBinOpPlus :: JSAnnot -> JSExpression -> JSExpression -> JSExpression 202 | fixBinOpPlus a lhs rhs = 203 | case (fix a lhs, fixEmpty rhs) of 204 | (JSStringLiteral _ s1, JSStringLiteral _ s2) -> stringLitConcat (normalizeToSQ s1) (normalizeToSQ s2) 205 | (nlhs, nrhs) -> JSExpressionBinary nlhs (JSBinOpPlus emptyAnnot) nrhs 206 | 207 | -- Concatenate two JSStringLiterals. Since the strings will include the string 208 | -- terminators (either single or double quotes) we use whatever terminator is 209 | -- used by the first string. 210 | stringLitConcat :: String -> String -> JSExpression 211 | stringLitConcat xs [] = JSStringLiteral emptyAnnot xs 212 | stringLitConcat [] ys = JSStringLiteral emptyAnnot ys 213 | stringLitConcat xall (_:yss) = 214 | JSStringLiteral emptyAnnot (init xall ++ init yss ++ "'") 215 | 216 | -- Normalize a String. If its single quoted, just return it and its double quoted 217 | -- convert it to single quoted. 218 | normalizeToSQ :: String -> String 219 | normalizeToSQ str = 220 | case str of 221 | [] -> [] 222 | ('\'' : _) -> str 223 | ('"' : xs) -> '\'' : convertSQ xs 224 | other -> other -- Should not happen. 225 | where 226 | convertSQ [] = [] 227 | convertSQ [_] = "'" 228 | convertSQ ('\'':xs) = '\\' : '\'' : convertSQ xs 229 | convertSQ ('\\':'\"':xs) = '"' : convertSQ xs 230 | convertSQ (x:xs) = x : convertSQ xs 231 | 232 | 233 | instance MinifyJS JSBinOp where 234 | fix _ (JSBinOpAnd _) = JSBinOpAnd emptyAnnot 235 | fix _ (JSBinOpBitAnd _) = JSBinOpBitAnd emptyAnnot 236 | fix _ (JSBinOpBitOr _) = JSBinOpBitOr emptyAnnot 237 | fix _ (JSBinOpBitXor _) = JSBinOpBitXor emptyAnnot 238 | fix _ (JSBinOpDivide _) = JSBinOpDivide emptyAnnot 239 | fix _ (JSBinOpEq _) = JSBinOpEq emptyAnnot 240 | fix _ (JSBinOpGe _) = JSBinOpGe emptyAnnot 241 | fix _ (JSBinOpGt _) = JSBinOpGt emptyAnnot 242 | fix a (JSBinOpIn _) = JSBinOpIn a 243 | fix a (JSBinOpInstanceOf _) = JSBinOpInstanceOf a 244 | fix _ (JSBinOpLe _) = JSBinOpLe emptyAnnot 245 | fix _ (JSBinOpLsh _) = JSBinOpLsh emptyAnnot 246 | fix _ (JSBinOpLt _) = JSBinOpLt emptyAnnot 247 | fix _ (JSBinOpMinus _) = JSBinOpMinus emptyAnnot 248 | fix _ (JSBinOpMod _) = JSBinOpMod emptyAnnot 249 | fix _ (JSBinOpNeq _) = JSBinOpNeq emptyAnnot 250 | fix a (JSBinOpOf _) = JSBinOpOf a 251 | fix _ (JSBinOpOr _) = JSBinOpOr emptyAnnot 252 | fix _ (JSBinOpPlus _) = JSBinOpPlus emptyAnnot 253 | fix _ (JSBinOpRsh _) = JSBinOpRsh emptyAnnot 254 | fix _ (JSBinOpStrictEq _) = JSBinOpStrictEq emptyAnnot 255 | fix _ (JSBinOpStrictNeq _) = JSBinOpStrictNeq emptyAnnot 256 | fix _ (JSBinOpTimes _) = JSBinOpTimes emptyAnnot 257 | fix _ (JSBinOpUrsh _) = JSBinOpUrsh emptyAnnot 258 | 259 | 260 | instance MinifyJS JSUnaryOp where 261 | fix _ (JSUnaryOpDecr _) = JSUnaryOpDecr emptyAnnot 262 | fix _ (JSUnaryOpDelete _) = JSUnaryOpDelete emptyAnnot 263 | fix _ (JSUnaryOpIncr _) = JSUnaryOpIncr emptyAnnot 264 | fix _ (JSUnaryOpMinus _) = JSUnaryOpMinus emptyAnnot 265 | fix _ (JSUnaryOpNot _) = JSUnaryOpNot emptyAnnot 266 | fix _ (JSUnaryOpPlus _) = JSUnaryOpPlus emptyAnnot 267 | fix _ (JSUnaryOpTilde _) = JSUnaryOpTilde emptyAnnot 268 | fix _ (JSUnaryOpTypeof _) = JSUnaryOpTypeof emptyAnnot 269 | fix _ (JSUnaryOpVoid _) = JSUnaryOpVoid emptyAnnot 270 | 271 | fixUnaryOp :: JSAnnot -> JSUnaryOp -> (JSAnnot, JSUnaryOp) 272 | fixUnaryOp a (JSUnaryOpDelete _) = (spaceAnnot, JSUnaryOpDelete a) 273 | fixUnaryOp a (JSUnaryOpTypeof _) = (spaceAnnot, JSUnaryOpTypeof a) 274 | fixUnaryOp a (JSUnaryOpVoid _) = (spaceAnnot, JSUnaryOpVoid a) 275 | fixUnaryOp a x = (emptyAnnot, fix a x) 276 | 277 | 278 | instance MinifyJS JSAssignOp where 279 | fix a (JSAssign _) = JSAssign a 280 | fix a (JSTimesAssign _) = JSTimesAssign a 281 | fix a (JSDivideAssign _) = JSDivideAssign a 282 | fix a (JSModAssign _) = JSModAssign a 283 | fix a (JSPlusAssign _) = JSPlusAssign a 284 | fix a (JSMinusAssign _) = JSMinusAssign a 285 | fix a (JSLshAssign _) = JSLshAssign a 286 | fix a (JSRshAssign _) = JSRshAssign a 287 | fix a (JSUrshAssign _) = JSUrshAssign a 288 | fix a (JSBwAndAssign _) = JSBwAndAssign a 289 | fix a (JSBwXorAssign _) = JSBwXorAssign a 290 | fix a (JSBwOrAssign _) = JSBwOrAssign a 291 | 292 | instance MinifyJS JSModuleItem where 293 | fix _ (JSModuleImportDeclaration _ x1) = JSModuleImportDeclaration emptyAnnot (fixEmpty x1) 294 | fix _ (JSModuleExportDeclaration _ x1) = JSModuleExportDeclaration emptyAnnot (fixEmpty x1) 295 | fix a (JSModuleStatementListItem s) = JSModuleStatementListItem (fixStmt a noSemi s) 296 | 297 | instance MinifyJS JSImportDeclaration where 298 | fix _ (JSImportDeclaration imps from _) = JSImportDeclaration (fixEmpty imps) (fix annot from) noSemi 299 | where 300 | annot = case imps of 301 | JSImportClauseDefault {} -> spaceAnnot 302 | JSImportClauseNameSpace {} -> spaceAnnot 303 | JSImportClauseNamed {} -> emptyAnnot 304 | JSImportClauseDefaultNameSpace {} -> spaceAnnot 305 | JSImportClauseDefaultNamed {} -> emptyAnnot 306 | fix a (JSImportDeclarationBare _ m _) = JSImportDeclarationBare a m noSemi 307 | 308 | instance MinifyJS JSImportClause where 309 | fix _ (JSImportClauseDefault n) = JSImportClauseDefault (fixSpace n) 310 | fix _ (JSImportClauseNameSpace ns) = JSImportClauseNameSpace (fixSpace ns) 311 | fix _ (JSImportClauseNamed named) = JSImportClauseNamed (fixEmpty named) 312 | fix _ (JSImportClauseDefaultNameSpace def _ ns) = JSImportClauseDefaultNameSpace (fixSpace def) emptyAnnot (fixEmpty ns) 313 | fix _ (JSImportClauseDefaultNamed def _ ns) = JSImportClauseDefaultNamed (fixSpace def) emptyAnnot (fixEmpty ns) 314 | 315 | instance MinifyJS JSFromClause where 316 | fix a (JSFromClause _ _ m) = JSFromClause a emptyAnnot m 317 | 318 | instance MinifyJS JSImportNameSpace where 319 | fix a (JSImportNameSpace _ _ ident) = JSImportNameSpace (JSBinOpTimes a) spaceAnnot (fixSpace ident) 320 | 321 | instance MinifyJS JSImportsNamed where 322 | fix _ (JSImportsNamed _ imps _) = JSImportsNamed emptyAnnot (fixEmpty imps) emptyAnnot 323 | 324 | instance MinifyJS JSImportSpecifier where 325 | fix _ (JSImportSpecifier x1) = JSImportSpecifier (fixEmpty x1) 326 | fix _ (JSImportSpecifierAs x1 _ x2) = JSImportSpecifierAs (fixEmpty x1) spaceAnnot (fixSpace x2) 327 | 328 | instance MinifyJS JSExportDeclaration where 329 | fix a (JSExportFrom x1 from _) = JSExportFrom (fix a x1) (fix a from) noSemi 330 | fix _ (JSExportLocals x1 _) = JSExportLocals (fix emptyAnnot x1) noSemi 331 | fix _ (JSExport x1 _) = JSExport (fixStmt spaceAnnot noSemi x1) noSemi 332 | 333 | instance MinifyJS JSExportClause where 334 | fix a (JSExportClause _ x1 _) = JSExportClause emptyAnnot (fixEmpty x1) a 335 | 336 | instance MinifyJS JSExportSpecifier where 337 | fix _ (JSExportSpecifier x1) = JSExportSpecifier (fixEmpty x1) 338 | fix _ (JSExportSpecifierAs x1 _ x2) = JSExportSpecifierAs (fixEmpty x1) spaceAnnot (fixSpace x2) 339 | 340 | instance MinifyJS JSTryCatch where 341 | fix a (JSCatch _ _ x1 _ x3) = JSCatch a emptyAnnot (fixEmpty x1) emptyAnnot (fixEmpty x3) 342 | fix a (JSCatchIf _ _ x1 _ ex _ x3) = JSCatchIf a emptyAnnot (fixEmpty x1) spaceAnnot (fixSpace ex) emptyAnnot (fixEmpty x3) 343 | 344 | 345 | instance MinifyJS JSTryFinally where 346 | fix a (JSFinally _ x) = JSFinally a (fixEmpty x) 347 | fix _ JSNoFinally = JSNoFinally 348 | 349 | 350 | fixSwitchParts :: [JSSwitchParts] -> [JSSwitchParts] 351 | fixSwitchParts parts = 352 | case parts of 353 | [] -> [] 354 | [x] -> [fixPart noSemi x] 355 | (x:xs) -> fixPart semi x : fixSwitchParts xs 356 | where 357 | fixPart s (JSCase _ e _ ss) = JSCase emptyAnnot (fixCase e) emptyAnnot (fixStatementList s ss) 358 | fixPart s (JSDefault _ _ ss) = JSDefault emptyAnnot emptyAnnot (fixStatementList s ss) 359 | 360 | fixCase :: JSExpression -> JSExpression 361 | fixCase (JSStringLiteral _ s) = JSStringLiteral emptyAnnot s 362 | fixCase e = fix spaceAnnot e 363 | 364 | 365 | instance MinifyJS JSBlock where 366 | fix _ (JSBlock _ ss _) = JSBlock emptyAnnot (fixStatementList noSemi ss) emptyAnnot 367 | 368 | 369 | instance MinifyJS JSObjectProperty where 370 | fix a (JSPropertyNameandValue n _ vs) = JSPropertyNameandValue (fix a n) emptyAnnot (map fixEmpty vs) 371 | fix a (JSPropertyIdentRef _ s) = JSPropertyIdentRef a s 372 | fix a (JSObjectMethod m) = JSObjectMethod (fix a m) 373 | 374 | instance MinifyJS JSMethodDefinition where 375 | fix a (JSMethodDefinition n _ ps _ b) = JSMethodDefinition (fix a n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty b) 376 | fix _ (JSGeneratorMethodDefinition _ n _ ps _ b) = JSGeneratorMethodDefinition emptyAnnot (fixEmpty n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty b) 377 | fix a (JSPropertyAccessor s n _ ps _ b) = JSPropertyAccessor (fix a s) (fixSpace n) emptyAnnot (fixEmpty ps) emptyAnnot (fixEmpty b) 378 | 379 | instance MinifyJS JSPropertyName where 380 | fix a (JSPropertyIdent _ s) = JSPropertyIdent a s 381 | fix a (JSPropertyString _ s) = JSPropertyString a s 382 | fix a (JSPropertyNumber _ s) = JSPropertyNumber a s 383 | fix _ (JSPropertyComputed _ x _) = JSPropertyComputed emptyAnnot (fixEmpty x) emptyAnnot 384 | 385 | instance MinifyJS JSAccessor where 386 | fix a (JSAccessorGet _) = JSAccessorGet a 387 | fix a (JSAccessorSet _) = JSAccessorSet a 388 | 389 | 390 | instance MinifyJS JSArrayElement where 391 | fix _ (JSArrayElement e) = JSArrayElement (fixEmpty e) 392 | fix _ (JSArrayComma _) = JSArrayComma emptyAnnot 393 | 394 | 395 | instance MinifyJS a => MinifyJS (JSCommaList a) where 396 | fix _ (JSLCons xs _ x) = JSLCons (fixEmpty xs) emptyAnnot (fixEmpty x) 397 | fix _ (JSLOne a) = JSLOne (fixEmpty a) 398 | fix _ JSLNil = JSLNil 399 | 400 | 401 | instance MinifyJS a => MinifyJS (JSCommaTrailingList a) where 402 | fix _ (JSCTLComma xs _) = JSCTLNone (fixEmpty xs) 403 | fix _ (JSCTLNone xs) = JSCTLNone (fixEmpty xs) 404 | 405 | 406 | instance MinifyJS JSIdent where 407 | fix a (JSIdentName _ n) = JSIdentName a n 408 | fix _ JSIdentNone = JSIdentNone 409 | 410 | 411 | instance MinifyJS (Maybe JSExpression) where 412 | fix a me = fix a <$> me 413 | 414 | 415 | instance MinifyJS JSVarInitializer where 416 | fix a (JSVarInit _ x) = JSVarInit a (fix emptyAnnot x) 417 | fix _ JSVarInitNone = JSVarInitNone 418 | 419 | 420 | instance MinifyJS JSTemplatePart where 421 | fix _ (JSTemplatePart e _ s) = JSTemplatePart (fixEmpty e) emptyAnnot s 422 | 423 | 424 | instance MinifyJS JSClassHeritage where 425 | fix _ JSExtendsNone = JSExtendsNone 426 | fix a (JSExtends _ e) = JSExtends a (fixSpace e) 427 | 428 | 429 | instance MinifyJS [JSClassElement] where 430 | fix _ [] = [] 431 | fix a (JSClassInstanceMethod m:t) = JSClassInstanceMethod (fix a m) : fixEmpty t 432 | fix a (JSClassStaticMethod _ m:t) = JSClassStaticMethod a (fixSpace m) : fixEmpty t 433 | fix a (JSClassSemi _:t) = fix a t 434 | 435 | 436 | spaceAnnot :: JSAnnot 437 | spaceAnnot = JSAnnot tokenPosnEmpty [WhiteSpace tokenPosnEmpty " "] 438 | 439 | emptyAnnot :: JSAnnot 440 | emptyAnnot = JSNoAnnot 441 | 442 | newlineAnnot :: JSAnnot 443 | newlineAnnot = JSAnnot tokenPosnEmpty [WhiteSpace tokenPosnEmpty "\n"] 444 | 445 | semi :: JSSemi 446 | semi = JSSemi emptyAnnot 447 | 448 | noSemi :: JSSemi 449 | noSemi = JSSemiAuto 450 | -------------------------------------------------------------------------------- /test/Test/Language/Javascript/ExpressionParser.hs: -------------------------------------------------------------------------------- 1 | module Test.Language.Javascript.ExpressionParser 2 | ( testExpressionParser 3 | ) where 4 | 5 | import Test.Hspec 6 | 7 | import Language.JavaScript.Parser 8 | import Language.JavaScript.Parser.Grammar7 9 | import Language.JavaScript.Parser.Parser 10 | 11 | 12 | testExpressionParser :: Spec 13 | testExpressionParser = describe "Parse expressions:" $ do 14 | it "this" $ 15 | testExpr "this" `shouldBe` "Right (JSAstExpression (JSLiteral 'this'))" 16 | it "regex" $ do 17 | testExpr "/blah/" `shouldBe` "Right (JSAstExpression (JSRegEx '/blah/'))" 18 | testExpr "/$/g" `shouldBe` "Right (JSAstExpression (JSRegEx '/$/g'))" 19 | testExpr "/\\n/g" `shouldBe` "Right (JSAstExpression (JSRegEx '/\\n/g'))" 20 | testExpr "/(\\/)/" `shouldBe` "Right (JSAstExpression (JSRegEx '/(\\/)/'))" 21 | testExpr "/a[/]b/" `shouldBe` "Right (JSAstExpression (JSRegEx '/a[/]b/'))" 22 | testExpr "/[/\\]/" `shouldBe` "Right (JSAstExpression (JSRegEx '/[/\\]/'))" 23 | testExpr "/(\\/|\\)/" `shouldBe` "Right (JSAstExpression (JSRegEx '/(\\/|\\)/'))" 24 | testExpr "/a\\[|\\]$/g" `shouldBe` "Right (JSAstExpression (JSRegEx '/a\\[|\\]$/g'))" 25 | testExpr "/[(){}\\[\\]]/g" `shouldBe` "Right (JSAstExpression (JSRegEx '/[(){}\\[\\]]/g'))" 26 | testExpr "/^\"(?:\\.|[^\"])*\"|^'(?:[^']|\\.)*'/" `shouldBe` "Right (JSAstExpression (JSRegEx '/^\"(?:\\.|[^\"])*\"|^'(?:[^']|\\.)*'/'))" 27 | 28 | it "identifier" $ do 29 | testExpr "_$" `shouldBe` "Right (JSAstExpression (JSIdentifier '_$'))" 30 | testExpr "this_" `shouldBe` "Right (JSAstExpression (JSIdentifier 'this_'))" 31 | it "array literal" $ do 32 | testExpr "[]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral []))" 33 | testExpr "[,]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral [JSComma]))" 34 | testExpr "[,,]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral [JSComma,JSComma]))" 35 | testExpr "[,,x]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral [JSComma,JSComma,JSIdentifier 'x']))" 36 | testExpr "[,,x]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral [JSComma,JSComma,JSIdentifier 'x']))" 37 | testExpr "[,x,,x]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral [JSComma,JSIdentifier 'x',JSComma,JSComma,JSIdentifier 'x']))" 38 | testExpr "[x]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral [JSIdentifier 'x']))" 39 | testExpr "[x,]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral [JSIdentifier 'x',JSComma]))" 40 | testExpr "[,,,]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral [JSComma,JSComma,JSComma]))" 41 | testExpr "[a,,]" `shouldBe` "Right (JSAstExpression (JSArrayLiteral [JSIdentifier 'a',JSComma,JSComma]))" 42 | it "operator precedence" $ 43 | testExpr "2+3*4+5" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('+',JSExpressionBinary ('+',JSDecimal '2',JSExpressionBinary ('*',JSDecimal '3',JSDecimal '4')),JSDecimal '5')))" 44 | it "parentheses" $ 45 | testExpr "(56)" `shouldBe` "Right (JSAstExpression (JSExpressionParen (JSDecimal '56')))" 46 | it "string concatenation" $ do 47 | testExpr "'ab' + 'bc'" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('+',JSStringLiteral 'ab',JSStringLiteral 'bc')))" 48 | testExpr "'bc' + \"cd\"" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('+',JSStringLiteral 'bc',JSStringLiteral \"cd\")))" 49 | it "object literal" $ do 50 | testExpr "{}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral []))" 51 | testExpr "{x:1}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'x') [JSDecimal '1']]))" 52 | testExpr "{x:1,y:2}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'x') [JSDecimal '1'],JSPropertyNameandValue (JSIdentifier 'y') [JSDecimal '2']]))" 53 | testExpr "{x:1,}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'x') [JSDecimal '1'],JSComma]))" 54 | testExpr "{yield:1}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'yield') [JSDecimal '1']]))" 55 | testExpr "{x}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyIdentRef 'x']))" 56 | testExpr "{x,}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyIdentRef 'x',JSComma]))" 57 | testExpr "{set x([a,b]=y) {this.a=a;this.b=b}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyAccessor JSAccessorSet (JSIdentifier 'x') (JSOpAssign ('=',JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b'],JSIdentifier 'y')) (JSBlock [JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'a'),JSIdentifier 'a'),JSSemicolon,JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'b'),JSIdentifier 'b')])]))" 58 | testExpr "a={if:1,interface:2}" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'a',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'if') [JSDecimal '1'],JSPropertyNameandValue (JSIdentifier 'interface') [JSDecimal '2']])))" 59 | testExpr "a={\n values: 7,\n}\n" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'a',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'values') [JSDecimal '7'],JSComma])))" 60 | testExpr "x={get foo() {return 1},set foo(a) {x=a}}" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'x',JSObjectLiteral [JSPropertyAccessor JSAccessorGet (JSIdentifier 'foo') () (JSBlock [JSReturn JSDecimal '1' ]),JSPropertyAccessor JSAccessorSet (JSIdentifier 'foo') (JSIdentifier 'a') (JSBlock [JSOpAssign ('=',JSIdentifier 'x',JSIdentifier 'a')])])))" 61 | testExpr "{evaluate:evaluate,load:function load(s){if(x)return s;1}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'evaluate') [JSIdentifier 'evaluate'],JSPropertyNameandValue (JSIdentifier 'load') [JSFunctionExpression 'load' (JSIdentifier 's') (JSBlock [JSIf (JSIdentifier 'x') (JSReturn JSIdentifier 's' JSSemicolon),JSDecimal '1'])]]))" 62 | testExpr "obj = { name : 'A', 'str' : 'B', 123 : 'C', }" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'obj',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'name') [JSStringLiteral 'A'],JSPropertyNameandValue (JSIdentifier ''str'') [JSStringLiteral 'B'],JSPropertyNameandValue (JSIdentifier '123') [JSStringLiteral 'C'],JSComma])))" 63 | testExpr "{[x]:1}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSPropertyNameandValue (JSPropertyComputed (JSIdentifier 'x')) [JSDecimal '1']]))" 64 | testExpr "{ a(x,y) {}, 'blah blah'() {} }" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock []),JSMethodDefinition (JSIdentifier ''blah blah'') () (JSBlock [])]))" 65 | testExpr "{[x]() {}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSMethodDefinition (JSPropertyComputed (JSIdentifier 'x')) () (JSBlock [])]))" 66 | testExpr "{*a(x,y) {yield y;}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSGeneratorMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock [JSYieldExpression (JSIdentifier 'y'),JSSemicolon])]))" 67 | testExpr "{*[x]({y},...z) {}}" `shouldBe` "Right (JSAstExpression (JSObjectLiteral [JSGeneratorMethodDefinition (JSPropertyComputed (JSIdentifier 'x')) (JSObjectLiteral [JSPropertyIdentRef 'y'],JSSpreadExpression (JSIdentifier 'z')) (JSBlock [])]))" 68 | 69 | it "unary expression" $ do 70 | testExpr "delete y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('delete',JSIdentifier 'y')))" 71 | testExpr "void y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('void',JSIdentifier 'y')))" 72 | testExpr "typeof y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('typeof',JSIdentifier 'y')))" 73 | testExpr "++y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('++',JSIdentifier 'y')))" 74 | testExpr "--y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('--',JSIdentifier 'y')))" 75 | testExpr "+y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('+',JSIdentifier 'y')))" 76 | testExpr "-y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('-',JSIdentifier 'y')))" 77 | testExpr "~y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('~',JSIdentifier 'y')))" 78 | testExpr "!y" `shouldBe` "Right (JSAstExpression (JSUnaryExpression ('!',JSIdentifier 'y')))" 79 | testExpr "y++" `shouldBe` "Right (JSAstExpression (JSExpressionPostfix ('++',JSIdentifier 'y')))" 80 | testExpr "y--" `shouldBe` "Right (JSAstExpression (JSExpressionPostfix ('--',JSIdentifier 'y')))" 81 | testExpr "...y" `shouldBe` "Right (JSAstExpression (JSSpreadExpression (JSIdentifier 'y')))" 82 | 83 | 84 | it "new expression" $ do 85 | testExpr "new x()" `shouldBe` "Right (JSAstExpression (JSMemberNew (JSIdentifier 'x',JSArguments ())))" 86 | testExpr "new x.y" `shouldBe` "Right (JSAstExpression (JSNewExpression JSMemberDot (JSIdentifier 'x',JSIdentifier 'y')))" 87 | 88 | it "binary expression" $ do 89 | testExpr "x||y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('||',JSIdentifier 'x',JSIdentifier 'y')))" 90 | testExpr "x&&y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('&&',JSIdentifier 'x',JSIdentifier 'y')))" 91 | testExpr "x|y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('|',JSIdentifier 'x',JSIdentifier 'y')))" 92 | testExpr "x^y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('^',JSIdentifier 'x',JSIdentifier 'y')))" 93 | testExpr "x&y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('&',JSIdentifier 'x',JSIdentifier 'y')))" 94 | 95 | testExpr "x==y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('==',JSIdentifier 'x',JSIdentifier 'y')))" 96 | testExpr "x!=y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('!=',JSIdentifier 'x',JSIdentifier 'y')))" 97 | testExpr "x===y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('===',JSIdentifier 'x',JSIdentifier 'y')))" 98 | testExpr "x!==y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('!==',JSIdentifier 'x',JSIdentifier 'y')))" 99 | 100 | testExpr "xy" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('>',JSIdentifier 'x',JSIdentifier 'y')))" 102 | testExpr "x<=y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('<=',JSIdentifier 'x',JSIdentifier 'y')))" 103 | testExpr "x>=y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('>=',JSIdentifier 'x',JSIdentifier 'y')))" 104 | 105 | testExpr "x<>y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('>>',JSIdentifier 'x',JSIdentifier 'y')))" 107 | testExpr "x>>>y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('>>>',JSIdentifier 'x',JSIdentifier 'y')))" 108 | 109 | testExpr "x+y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('+',JSIdentifier 'x',JSIdentifier 'y')))" 110 | testExpr "x-y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('-',JSIdentifier 'x',JSIdentifier 'y')))" 111 | 112 | testExpr "x*y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('*',JSIdentifier 'x',JSIdentifier 'y')))" 113 | testExpr "x/y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('/',JSIdentifier 'x',JSIdentifier 'y')))" 114 | testExpr "x%y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('%',JSIdentifier 'x',JSIdentifier 'y')))" 115 | testExpr "x instanceof y" `shouldBe` "Right (JSAstExpression (JSExpressionBinary ('instanceof',JSIdentifier 'x',JSIdentifier 'y')))" 116 | 117 | it "assign expression" $ do 118 | testExpr "x=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1')))" 119 | testExpr "x*=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('*=',JSIdentifier 'x',JSDecimal '1')))" 120 | testExpr "x/=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('/=',JSIdentifier 'x',JSDecimal '1')))" 121 | testExpr "x%=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('%=',JSIdentifier 'x',JSDecimal '1')))" 122 | testExpr "x+=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('+=',JSIdentifier 'x',JSDecimal '1')))" 123 | testExpr "x-=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('-=',JSIdentifier 'x',JSDecimal '1')))" 124 | testExpr "x<<=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('<<=',JSIdentifier 'x',JSDecimal '1')))" 125 | testExpr "x>>=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('>>=',JSIdentifier 'x',JSDecimal '1')))" 126 | testExpr "x>>>=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('>>>=',JSIdentifier 'x',JSDecimal '1')))" 127 | testExpr "x&=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('&=',JSIdentifier 'x',JSDecimal '1')))" 128 | testExpr "x^=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('^=',JSIdentifier 'x',JSDecimal '1')))" 129 | testExpr "x|=1" `shouldBe` "Right (JSAstExpression (JSOpAssign ('|=',JSIdentifier 'x',JSDecimal '1')))" 130 | 131 | it "function expression" $ do 132 | testExpr "function(){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' () (JSBlock [])))" 133 | testExpr "function(a){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSIdentifier 'a') (JSBlock [])))" 134 | testExpr "function(a,b){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSIdentifier 'a',JSIdentifier 'b') (JSBlock [])))" 135 | testExpr "function(...a){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSSpreadExpression (JSIdentifier 'a')) (JSBlock [])))" 136 | testExpr "function(a=1){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSOpAssign ('=',JSIdentifier 'a',JSDecimal '1')) (JSBlock [])))" 137 | testExpr "function([a,b]){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b']) (JSBlock [])))" 138 | testExpr "function([a,...b]){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSArrayLiteral [JSIdentifier 'a',JSComma,JSSpreadExpression (JSIdentifier 'b')]) (JSBlock [])))" 139 | testExpr "function({a,b}){}" `shouldBe` "Right (JSAstExpression (JSFunctionExpression '' (JSObjectLiteral [JSPropertyIdentRef 'a',JSPropertyIdentRef 'b']) (JSBlock [])))" 140 | testExpr "a => {}" `shouldBe` "Right (JSAstExpression (JSArrowExpression (JSIdentifier 'a') => JSStatementBlock []))" 141 | testExpr "(a) => { a + 2 }" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a')) => JSStatementBlock [JSExpressionBinary ('+',JSIdentifier 'a',JSDecimal '2')]))" 142 | testExpr "(a, b) => {}" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSIdentifier 'b')) => JSStatementBlock []))" 143 | testExpr "(a, b) => a + b" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSIdentifier 'b')) => JSExpressionBinary ('+',JSIdentifier 'a',JSIdentifier 'b')))" 144 | testExpr "() => { 42 }" `shouldBe` "Right (JSAstExpression (JSArrowExpression (()) => JSStatementBlock [JSDecimal '42']))" 145 | testExpr "(a, ...b) => b" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSSpreadExpression (JSIdentifier 'b'))) => JSIdentifier 'b'))" 146 | testExpr "(a,b=1) => a + b" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSIdentifier 'a',JSOpAssign ('=',JSIdentifier 'b',JSDecimal '1'))) => JSExpressionBinary ('+',JSIdentifier 'a',JSIdentifier 'b')))" 147 | testExpr "([a,b]) => a + b" `shouldBe` "Right (JSAstExpression (JSArrowExpression ((JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b'])) => JSExpressionBinary ('+',JSIdentifier 'a',JSIdentifier 'b')))" 148 | 149 | it "generator expression" $ do 150 | testExpr "function*(){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression '' () (JSBlock [])))" 151 | testExpr "function*(a){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression '' (JSIdentifier 'a') (JSBlock [])))" 152 | testExpr "function*(a,b){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression '' (JSIdentifier 'a',JSIdentifier 'b') (JSBlock [])))" 153 | testExpr "function*(a,...b){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression '' (JSIdentifier 'a',JSSpreadExpression (JSIdentifier 'b')) (JSBlock [])))" 154 | testExpr "function*f(){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression 'f' () (JSBlock [])))" 155 | testExpr "function*f(a){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression 'f' (JSIdentifier 'a') (JSBlock [])))" 156 | testExpr "function*f(a,b){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression 'f' (JSIdentifier 'a',JSIdentifier 'b') (JSBlock [])))" 157 | testExpr "function*f(a,...b){}" `shouldBe` "Right (JSAstExpression (JSGeneratorExpression 'f' (JSIdentifier 'a',JSSpreadExpression (JSIdentifier 'b')) (JSBlock [])))" 158 | 159 | it "member expression" $ do 160 | testExpr "x[y]" `shouldBe` "Right (JSAstExpression (JSMemberSquare (JSIdentifier 'x',JSIdentifier 'y')))" 161 | testExpr "x[y][z]" `shouldBe` "Right (JSAstExpression (JSMemberSquare (JSMemberSquare (JSIdentifier 'x',JSIdentifier 'y'),JSIdentifier 'z')))" 162 | testExpr "x.y" `shouldBe` "Right (JSAstExpression (JSMemberDot (JSIdentifier 'x',JSIdentifier 'y')))" 163 | testExpr "x.y.z" `shouldBe` "Right (JSAstExpression (JSMemberDot (JSMemberDot (JSIdentifier 'x',JSIdentifier 'y'),JSIdentifier 'z')))" 164 | 165 | it "call expression" $ do 166 | testExpr "x()" `shouldBe` "Right (JSAstExpression (JSMemberExpression (JSIdentifier 'x',JSArguments ())))" 167 | testExpr "x()()" `shouldBe` "Right (JSAstExpression (JSCallExpression (JSMemberExpression (JSIdentifier 'x',JSArguments ()),JSArguments ())))" 168 | testExpr "x()[4]" `shouldBe` "Right (JSAstExpression (JSCallExpressionSquare (JSMemberExpression (JSIdentifier 'x',JSArguments ()),JSDecimal '4')))" 169 | testExpr "x().x" `shouldBe` "Right (JSAstExpression (JSCallExpressionDot (JSMemberExpression (JSIdentifier 'x',JSArguments ()),JSIdentifier 'x')))" 170 | testExpr "x(a,b=2).x" `shouldBe` "Right (JSAstExpression (JSCallExpressionDot (JSMemberExpression (JSIdentifier 'x',JSArguments (JSIdentifier 'a',JSOpAssign ('=',JSIdentifier 'b',JSDecimal '2'))),JSIdentifier 'x')))" 171 | testExpr "foo (56.8379100, 60.5806664)" `shouldBe` "Right (JSAstExpression (JSMemberExpression (JSIdentifier 'foo',JSArguments (JSDecimal '56.8379100',JSDecimal '60.5806664'))))" 172 | 173 | it "spread expression" $ 174 | testExpr "... x" `shouldBe` "Right (JSAstExpression (JSSpreadExpression (JSIdentifier 'x')))" 175 | 176 | it "template literal" $ do 177 | testExpr "``" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'``',[])))" 178 | testExpr "`$`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`$`',[])))" 179 | testExpr "`$\\n`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`$\\n`',[])))" 180 | testExpr "`\\${x}`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`\\${x}`',[])))" 181 | testExpr "`$ {x}`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`$ {x}`',[])))" 182 | testExpr "`\n\n`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`\n\n`',[])))" 183 | testExpr "`${x+y} ${z}`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`${',[(JSExpressionBinary ('+',JSIdentifier 'x',JSIdentifier 'y'),'} ${'),(JSIdentifier 'z','}`')])))" 184 | testExpr "`<${x} ${y}>`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((),'`<${',[(JSIdentifier 'x','} ${'),(JSIdentifier 'y','}>`')])))" 185 | testExpr "tag `xyz`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((JSIdentifier 'tag'),'`xyz`',[])))" 186 | testExpr "tag()`xyz`" `shouldBe` "Right (JSAstExpression (JSTemplateLiteral ((JSMemberExpression (JSIdentifier 'tag',JSArguments ())),'`xyz`',[])))" 187 | 188 | it "yield" $ do 189 | testExpr "yield" `shouldBe` "Right (JSAstExpression (JSYieldExpression ()))" 190 | testExpr "yield a + b" `shouldBe` "Right (JSAstExpression (JSYieldExpression (JSExpressionBinary ('+',JSIdentifier 'a',JSIdentifier 'b'))))" 191 | testExpr "yield* g()" `shouldBe` "Right (JSAstExpression (JSYieldFromExpression (JSMemberExpression (JSIdentifier 'g',JSArguments ()))))" 192 | 193 | it "class expression" $ do 194 | testExpr "class Foo extends Bar { a(x,y) {} *b() {} }" `shouldBe` "Right (JSAstExpression (JSClassExpression 'Foo' (JSIdentifier 'Bar') [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock []),JSGeneratorMethodDefinition (JSIdentifier 'b') () (JSBlock [])]))" 195 | testExpr "class { static get [a]() {}; }" `shouldBe` "Right (JSAstExpression (JSClassExpression '' () [JSClassStaticMethod (JSPropertyAccessor JSAccessorGet (JSPropertyComputed (JSIdentifier 'a')) () (JSBlock [])),JSClassSemi]))" 196 | testExpr "class Foo extends Bar { a(x,y) { super(x); } }" `shouldBe` "Right (JSAstExpression (JSClassExpression 'Foo' (JSIdentifier 'Bar') [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock [JSCallExpression (JSLiteral 'super',JSArguments (JSIdentifier 'x')),JSSemicolon])]))" 197 | 198 | 199 | testExpr :: String -> String 200 | testExpr str = showStrippedMaybe (parseUsing parseExpression str "src") 201 | -------------------------------------------------------------------------------- /test/Test/Language/Javascript/Lexer.hs: -------------------------------------------------------------------------------- 1 | module Test.Language.Javascript.Lexer 2 | ( testLexer 3 | ) where 4 | 5 | import Test.Hspec 6 | 7 | import Data.List (intercalate) 8 | 9 | import Language.JavaScript.Parser.Lexer 10 | 11 | 12 | testLexer :: Spec 13 | testLexer = describe "Lexer:" $ do 14 | it "comments" $ do 15 | testLex "// 𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡 " `shouldBe` "[CommentToken]" 16 | testLex "/* 𝟘𝟙𝟚𝟛𝟜𝟝𝟞𝟟𝟠𝟡 */" `shouldBe` "[CommentToken]" 17 | 18 | it "numbers" $ do 19 | testLex "123" `shouldBe` "[DecimalToken 123]" 20 | testLex "037" `shouldBe` "[OctalToken 037]" 21 | testLex "0xab" `shouldBe` "[HexIntegerToken 0xab]" 22 | testLex "0xCD" `shouldBe` "[HexIntegerToken 0xCD]" 23 | 24 | it "invalid numbers" $ do 25 | testLex "089" `shouldBe` "[DecimalToken 0,DecimalToken 89]" 26 | testLex "0xGh" `shouldBe` "[DecimalToken 0,IdentifierToken 'xGx']" 27 | 28 | it "string" $ do 29 | testLex "'cat'" `shouldBe` "[StringToken 'cat']" 30 | testLex "\"dog\"" `shouldBe` "[StringToken \"dog\"]" 31 | 32 | it "strings with escape chars" $ do 33 | testLex "'\t'" `shouldBe` "[StringToken '\t']" 34 | testLex "'\\n'" `shouldBe` "[StringToken '\\n']" 35 | testLex "'\\\\n'" `shouldBe` "[StringToken '\\\\n']" 36 | testLex "'\\\\'" `shouldBe` "[StringToken '\\\\']" 37 | testLex "'\\0'" `shouldBe` "[StringToken '\\0']" 38 | testLex "'\\12'" `shouldBe` "[StringToken '\\12']" 39 | testLex "'\\s'" `shouldBe` "[StringToken '\\s']" 40 | testLex "'\\-'" `shouldBe` "[StringToken '\\-']" 41 | 42 | it "strings with non-escaped chars" $ 43 | testLex "'\\/'" `shouldBe` "[StringToken '\\/']" 44 | 45 | it "strings with escaped quotes" $ do 46 | testLex "'\"'" `shouldBe` "[StringToken '\"']" 47 | testLex "\"\\\"\"" `shouldBe` "[StringToken \"\\\\\"\"]" 48 | testLex "'\\\''" `shouldBe` "[StringToken '\\\\'']" 49 | testLex "'\"'" `shouldBe` "[StringToken '\"']" 50 | testLex "\"\\'\"" `shouldBe` "[StringToken \"\\'\"]" 51 | 52 | it "spread token" $ do 53 | testLex "...a" `shouldBe` "[SpreadToken,IdentifierToken 'a']" 54 | 55 | it "assignment" $ do 56 | testLex "x=1" `shouldBe` "[IdentifierToken 'x',SimpleAssignToken,DecimalToken 1]" 57 | testLex "x=1\ny=2" `shouldBe` "[IdentifierToken 'x',SimpleAssignToken,DecimalToken 1,WsToken,IdentifierToken 'y',SimpleAssignToken,DecimalToken 2]" 58 | 59 | it "break/continue/return" $ do 60 | testLex "break\nx=1" `shouldBe` "[BreakToken,WsToken,IdentifierToken 'x',SimpleAssignToken,DecimalToken 1]" 61 | testLex "continue\nx=1" `shouldBe` "[ContinueToken,WsToken,IdentifierToken 'x',SimpleAssignToken,DecimalToken 1]" 62 | testLex "return\nx=1" `shouldBe` "[ReturnToken,WsToken,IdentifierToken 'x',SimpleAssignToken,DecimalToken 1]" 63 | 64 | it "var/let" $ do 65 | testLex "var\n" `shouldBe` "[VarToken,WsToken]" 66 | testLex "let\n" `shouldBe` "[LetToken,WsToken]" 67 | 68 | it "in/of" $ do 69 | testLex "in\n" `shouldBe` "[InToken,WsToken]" 70 | testLex "of\n" `shouldBe` "[OfToken,WsToken]" 71 | 72 | it "function" $ do 73 | testLex "async function\n" `shouldBe` "[AsyncToken,WsToken,FunctionToken,WsToken]" 74 | 75 | 76 | testLex :: String -> String 77 | testLex str = 78 | either id stringify $ alexTestTokeniser str 79 | where 80 | stringify xs = "[" ++ intercalate "," (map showToken xs) ++ "]" 81 | 82 | showToken :: Token -> String 83 | showToken (StringToken _ lit _) = "StringToken " ++ stringEscape lit 84 | showToken (IdentifierToken _ lit _) = "IdentifierToken '" ++ stringEscape lit ++ "'" 85 | showToken (DecimalToken _ lit _) = "DecimalToken " ++ lit 86 | showToken (OctalToken _ lit _) = "OctalToken " ++ lit 87 | showToken (HexIntegerToken _ lit _) = "HexIntegerToken " ++ lit 88 | showToken token = takeWhile (/= ' ') $ show token 89 | 90 | stringEscape [] = [] 91 | stringEscape (term:rest) = 92 | let escapeTerm [] = [] 93 | escapeTerm [_] = [term] 94 | escapeTerm (x:xs) 95 | | term == x = "\\" ++ x : escapeTerm xs 96 | | otherwise = x : escapeTerm xs 97 | in term : escapeTerm rest 98 | -------------------------------------------------------------------------------- /test/Test/Language/Javascript/LiteralParser.hs: -------------------------------------------------------------------------------- 1 | module Test.Language.Javascript.LiteralParser 2 | ( testLiteralParser 3 | ) where 4 | 5 | import Test.Hspec 6 | 7 | import Control.Monad (forM_) 8 | import Data.Char (chr, isPrint) 9 | 10 | import Language.JavaScript.Parser 11 | import Language.JavaScript.Parser.Grammar7 12 | import Language.JavaScript.Parser.Parser 13 | 14 | 15 | testLiteralParser :: Spec 16 | testLiteralParser = describe "Parse literals:" $ do 17 | it "null/true/false" $ do 18 | testLiteral "null" `shouldBe` "Right (JSAstLiteral (JSLiteral 'null'))" 19 | testLiteral "false" `shouldBe` "Right (JSAstLiteral (JSLiteral 'false'))" 20 | testLiteral "true" `shouldBe` "Right (JSAstLiteral (JSLiteral 'true'))" 21 | it "hex numbers" $ do 22 | testLiteral "0x1234fF" `shouldBe` "Right (JSAstLiteral (JSHexInteger '0x1234fF'))" 23 | testLiteral "0X1234fF" `shouldBe` "Right (JSAstLiteral (JSHexInteger '0X1234fF'))" 24 | it "decimal numbers" $ do 25 | testLiteral "1.0e4" `shouldBe` "Right (JSAstLiteral (JSDecimal '1.0e4'))" 26 | testLiteral "2.3E6" `shouldBe` "Right (JSAstLiteral (JSDecimal '2.3E6'))" 27 | testLiteral "4.5" `shouldBe` "Right (JSAstLiteral (JSDecimal '4.5'))" 28 | testLiteral "0.7e8" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.7e8'))" 29 | testLiteral "0.7E8" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.7E8'))" 30 | testLiteral "10" `shouldBe` "Right (JSAstLiteral (JSDecimal '10'))" 31 | testLiteral "0" `shouldBe` "Right (JSAstLiteral (JSDecimal '0'))" 32 | testLiteral "0.03" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.03'))" 33 | testLiteral "0.7e+8" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.7e+8'))" 34 | testLiteral "0.7e-18" `shouldBe` "Right (JSAstLiteral (JSDecimal '0.7e-18'))" 35 | testLiteral "1.0e+4" `shouldBe` "Right (JSAstLiteral (JSDecimal '1.0e+4'))" 36 | testLiteral "1.0e-4" `shouldBe` "Right (JSAstLiteral (JSDecimal '1.0e-4'))" 37 | testLiteral "1e18" `shouldBe` "Right (JSAstLiteral (JSDecimal '1e18'))" 38 | testLiteral "1e+18" `shouldBe` "Right (JSAstLiteral (JSDecimal '1e+18'))" 39 | testLiteral "1e-18" `shouldBe` "Right (JSAstLiteral (JSDecimal '1e-18'))" 40 | testLiteral "1E-01" `shouldBe` "Right (JSAstLiteral (JSDecimal '1E-01'))" 41 | it "octal numbers" $ do 42 | testLiteral "070" `shouldBe` "Right (JSAstLiteral (JSOctal '070'))" 43 | testLiteral "010234567" `shouldBe` "Right (JSAstLiteral (JSOctal '010234567'))" 44 | it "strings" $ do 45 | testLiteral "'cat'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral 'cat'))" 46 | testLiteral "\"cat\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"cat\"))" 47 | testLiteral "'\\u1234'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral '\\u1234'))" 48 | testLiteral "'\\uabcd'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral '\\uabcd'))" 49 | testLiteral "\"\\r\\n\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\r\\n\"))" 50 | testLiteral "\"\\b\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\b\"))" 51 | testLiteral "\"\\f\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\f\"))" 52 | testLiteral "\"\\t\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\t\"))" 53 | testLiteral "\"\\v\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\v\"))" 54 | testLiteral "\"\\0\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\0\"))" 55 | testLiteral "\"hello\\nworld\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"hello\\nworld\"))" 56 | testLiteral "'hello\\nworld'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral 'hello\\nworld'))" 57 | 58 | testLiteral "'char \n'" `shouldBe` "Left (\"lexical error @ line 1 and column 7\")" 59 | 60 | forM_ (mkTestStrings SingleQuote) $ \ str -> 61 | testLiteral str `shouldBe` ("Right (JSAstLiteral (JSStringLiteral " ++ str ++ "))") 62 | 63 | forM_ (mkTestStrings DoubleQuote) $ \ str -> 64 | testLiteral str `shouldBe` ("Right (JSAstLiteral (JSStringLiteral " ++ str ++ "))") 65 | 66 | it "strings with escaped quotes" $ do 67 | testLiteral "'\"'" `shouldBe` "Right (JSAstLiteral (JSStringLiteral '\"'))" 68 | testLiteral "\"\\\"\"" `shouldBe` "Right (JSAstLiteral (JSStringLiteral \"\\\"\"))" 69 | 70 | 71 | data Quote 72 | = SingleQuote 73 | | DoubleQuote 74 | deriving Eq 75 | 76 | 77 | mkTestStrings :: Quote -> [String] 78 | mkTestStrings quote = 79 | map mkString [0 .. 255] 80 | where 81 | mkString :: Int -> String 82 | mkString i = 83 | quoteString $ "char #" ++ show i ++ " " ++ showCh i 84 | 85 | showCh :: Int -> String 86 | showCh ch 87 | | ch == 34 = if quote == DoubleQuote then "\\\"" else "\"" 88 | | ch == 39 = if quote == SingleQuote then "\\\'" else "'" 89 | | ch == 92 = "\\\\" 90 | | ch < 127 && isPrint (chr ch) = [chr ch] 91 | | otherwise = 92 | let str = "000" ++ show ch 93 | slen = length str 94 | in "\\" ++ drop (slen - 3) str 95 | 96 | quoteString s = 97 | if quote == SingleQuote 98 | then '\'' : (s ++ "'") 99 | else '"' : (s ++ ['"']) 100 | 101 | 102 | testLiteral :: String -> String 103 | testLiteral str = showStrippedMaybe $ parseUsing parseLiteral str "src" 104 | -------------------------------------------------------------------------------- /test/Test/Language/Javascript/Minify.hs: -------------------------------------------------------------------------------- 1 | module Test.Language.Javascript.Minify 2 | ( testMinifyExpr 3 | , testMinifyStmt 4 | , testMinifyProg 5 | , testMinifyModule 6 | ) where 7 | 8 | import Control.Monad (forM_) 9 | import Test.Hspec 10 | 11 | import Language.JavaScript.Parser hiding (parseModule) 12 | import Language.JavaScript.Parser.Grammar7 13 | import Language.JavaScript.Parser.Lexer (Alex) 14 | import Language.JavaScript.Parser.Parser hiding (parseModule) 15 | import Language.JavaScript.Process.Minify 16 | import qualified Language.JavaScript.Parser.AST as AST 17 | 18 | 19 | testMinifyExpr :: Spec 20 | testMinifyExpr = describe "Minify expressions:" $ do 21 | it "terminals" $ do 22 | minifyExpr " identifier " `shouldBe` "identifier" 23 | minifyExpr " 1 " `shouldBe` "1" 24 | minifyExpr " this " `shouldBe` "this" 25 | minifyExpr " 0x12ab " `shouldBe` "0x12ab" 26 | minifyExpr " 0567 " `shouldBe` "0567" 27 | minifyExpr " 'helo' " `shouldBe` "'helo'" 28 | minifyExpr " \"good bye\" " `shouldBe` "\"good bye\"" 29 | minifyExpr " /\\n/g " `shouldBe` "/\\n/g" 30 | 31 | it "array literals" $ do 32 | minifyExpr " [ ] " `shouldBe` "[]" 33 | minifyExpr " [ , ] " `shouldBe` "[,]" 34 | minifyExpr " [ , , ] " `shouldBe` "[,,]" 35 | minifyExpr " [ x ] " `shouldBe` "[x]" 36 | minifyExpr " [ x , y ] " `shouldBe` "[x,y]" 37 | 38 | it "object literals" $ do 39 | minifyExpr " { } " `shouldBe` "{}" 40 | minifyExpr " { a : 1 } " `shouldBe` "{a:1}" 41 | minifyExpr " { b : 2 , } " `shouldBe` "{b:2}" 42 | minifyExpr " { c : 3 , d : 4 , } " `shouldBe` "{c:3,d:4}" 43 | minifyExpr " { 'str' : true , 42 : false , } " `shouldBe` "{'str':true,42:false}" 44 | minifyExpr " { x , } " `shouldBe` "{x}" 45 | minifyExpr " { [ x + y ] : 1 } " `shouldBe` "{[x+y]:1}" 46 | minifyExpr " { a ( x, y ) { } } " `shouldBe` "{a(x,y){}}" 47 | minifyExpr " { [ x + y ] ( ) { } } " `shouldBe` "{[x+y](){}}" 48 | minifyExpr " { * a ( x, y ) { } } " `shouldBe` "{*a(x,y){}}" 49 | 50 | it "parentheses" $ do 51 | minifyExpr " ( 'hello' ) " `shouldBe` "('hello')" 52 | minifyExpr " ( 12 ) " `shouldBe` "(12)" 53 | minifyExpr " ( 1 + 2 ) " `shouldBe` "(1+2)" 54 | 55 | it "unary" $ do 56 | minifyExpr " a -- " `shouldBe` "a--" 57 | minifyExpr " delete b " `shouldBe` "delete b" 58 | minifyExpr " c ++ " `shouldBe` "c++" 59 | minifyExpr " - d " `shouldBe` "-d" 60 | minifyExpr " ! e " `shouldBe` "!e" 61 | minifyExpr " + f " `shouldBe` "+f" 62 | minifyExpr " ~ g " `shouldBe` "~g" 63 | minifyExpr " typeof h " `shouldBe` "typeof h" 64 | minifyExpr " void i " `shouldBe` "void i" 65 | 66 | it "binary" $ do 67 | minifyExpr " a && z " `shouldBe` "a&&z" 68 | minifyExpr " b & z " `shouldBe` "b&z" 69 | minifyExpr " c | z " `shouldBe` "c|z" 70 | minifyExpr " d ^ z " `shouldBe` "d^z" 71 | minifyExpr " e / z " `shouldBe` "e/z" 72 | minifyExpr " f == z " `shouldBe` "f==z" 73 | minifyExpr " g >= z " `shouldBe` "g>=z" 74 | minifyExpr " h > z " `shouldBe` "h>z" 75 | minifyExpr " i in z " `shouldBe` "i in z" 76 | minifyExpr " j instanceof z " `shouldBe` "j instanceof z" 77 | minifyExpr " k <= z " `shouldBe` "k<=z" 78 | minifyExpr " l << z " `shouldBe` "l<> z " `shouldBe` "s>>z" 86 | minifyExpr " t === z " `shouldBe` "t===z" 87 | minifyExpr " u !== z " `shouldBe` "u!==z" 88 | minifyExpr " v * z " `shouldBe` "v*z" 89 | minifyExpr " w >>> z " `shouldBe` "w>>>z" 90 | 91 | it "ternary" $ do 92 | minifyExpr " true ? 1 : 2 " `shouldBe` "true?1:2" 93 | minifyExpr " x ? y + 1 : j - 1 " `shouldBe` "x?y+1:j-1" 94 | 95 | it "member access" $ do 96 | minifyExpr " a . b " `shouldBe` "a.b" 97 | minifyExpr " c . d . e " `shouldBe` "c.d.e" 98 | 99 | it "new" $ do 100 | minifyExpr " new f ( ) " `shouldBe` "new f()" 101 | minifyExpr " new g ( 1 ) " `shouldBe` "new g(1)" 102 | minifyExpr " new h ( 1 , 2 ) " `shouldBe` "new h(1,2)" 103 | minifyExpr " new k . x " `shouldBe` "new k.x" 104 | 105 | it "array access" $ do 106 | minifyExpr " i [ a ] " `shouldBe` "i[a]" 107 | minifyExpr " j [ a ] [ b ]" `shouldBe` "j[a][b]" 108 | 109 | it "function" $ do 110 | minifyExpr " function ( ) { } " `shouldBe` "function(){}" 111 | minifyExpr " function ( a ) { } " `shouldBe` "function(a){}" 112 | minifyExpr " function ( a , b ) { return a + b ; } " `shouldBe` "function(a,b){return a+b}" 113 | minifyExpr " function ( a , ...b ) { return b ; } " `shouldBe` "function(a,...b){return b}" 114 | minifyExpr " function ( a = 1 , b = 2 ) { return a + b ; } " `shouldBe` "function(a=1,b=2){return a+b}" 115 | minifyExpr " function ( [ a , b ] ) { return b ; } " `shouldBe` "function([a,b]){return b}" 116 | minifyExpr " function ( { a , b , } ) { return a + b ; } " `shouldBe` "function({a,b}){return a+b}" 117 | 118 | minifyExpr "a => {}" `shouldBe` "a=>{}" 119 | minifyExpr "(a) => {}" `shouldBe` "(a)=>{}" 120 | minifyExpr "( a ) => { a + 2 }" `shouldBe` "(a)=>a+2" 121 | minifyExpr "(a, b) => a + b" `shouldBe` "(a,b)=>a+b" 122 | minifyExpr "() => { 42 }" `shouldBe` "()=>42" 123 | minifyExpr "(a, ...b) => b" `shouldBe` "(a,...b)=>b" 124 | minifyExpr "(a = 1, b = 2) => a + b" `shouldBe` "(a=1,b=2)=>a+b" 125 | minifyExpr "( [ a , b ] ) => a + b" `shouldBe` "([a,b])=>a+b" 126 | minifyExpr "( { a , b , } ) => a + b" `shouldBe` "({a,b})=>a+b" 127 | 128 | it "generator" $ do 129 | minifyExpr " function * ( ) { } " `shouldBe` "function*(){}" 130 | minifyExpr " function * ( a ) { yield * a ; } " `shouldBe` "function*(a){yield*a}" 131 | minifyExpr " function * ( a , b ) { yield a + b ; } " `shouldBe` "function*(a,b){yield a+b}" 132 | 133 | it "calls" $ do 134 | minifyExpr " a ( ) " `shouldBe` "a()" 135 | minifyExpr " b ( ) ( ) " `shouldBe` "b()()" 136 | minifyExpr " c ( ) [ x ] " `shouldBe` "c()[x]" 137 | minifyExpr " d ( ) . y " `shouldBe` "d().y" 138 | 139 | it "property accessor" $ do 140 | minifyExpr " { get foo ( ) { return x } } " `shouldBe` "{get foo(){return x}}" 141 | minifyExpr " { set foo ( a ) { x = a } } " `shouldBe` "{set foo(a){x=a}}" 142 | minifyExpr " { set foo ( [ a , b ] ) { x = a } } " `shouldBe` "{set foo([a,b]){x=a}}" 143 | 144 | it "string concatenation" $ do 145 | minifyExpr " 'ab' + \"cd\" " `shouldBe` "'abcd'" 146 | minifyExpr " \"bc\" + 'de' " `shouldBe` "'bcde'" 147 | minifyExpr " \"cd\" + 'ef' + 'gh' " `shouldBe` "'cdefgh'" 148 | 149 | minifyExpr " 'de' + '\"fg\"' + 'hi' " `shouldBe` "'de\"fg\"hi'" 150 | minifyExpr " 'ef' + \"'gh'\" + 'ij' " `shouldBe` "'ef\\'gh\\'ij'" 151 | 152 | -- minifyExpr " 'de' + '\"fg\"' + 'hi' " `shouldBe` "'de\"fg\"hi'" 153 | -- minifyExpr " 'ef' + \"'gh'\" + 'ij' " `shouldBe` "'ef'gh'ij'" 154 | 155 | it "spread exporession" $ 156 | minifyExpr " ... x " `shouldBe` "...x" 157 | 158 | it "template literal" $ do 159 | minifyExpr " ` a + b + ${ c + d } + ... ` " `shouldBe` "` a + b + ${c+d} + ... `" 160 | minifyExpr " tagger () ` a + b ` " `shouldBe` "tagger()` a + b `" 161 | 162 | it "class" $ do 163 | minifyExpr " class Foo {\n a() {\n return 0;\n };\n static [ b ] ( x ) {}\n } " `shouldBe` "class Foo{a(){return 0}static[b](x){}}" 164 | minifyExpr " class { static get a() { return 0; } static set a(v) {} } " `shouldBe` "class{static get a(){return 0}static set a(v){}}" 165 | minifyExpr " class { ; ; ; } " `shouldBe` "class{}" 166 | minifyExpr " class Foo extends Bar {} " `shouldBe` "class Foo extends Bar{}" 167 | minifyExpr " class extends (getBase()) {} " `shouldBe` "class extends(getBase()){}" 168 | minifyExpr " class extends [ Bar1, Bar2 ][getBaseIndex()] {} " `shouldBe` "class extends[Bar1,Bar2][getBaseIndex()]{}" 169 | 170 | 171 | testMinifyStmt :: Spec 172 | testMinifyStmt = describe "Minify statements:" $ do 173 | forM_ [ "break", "continue", "return" ] $ \kw -> 174 | it kw $ do 175 | minifyStmt (" " ++ kw ++ " ; ") `shouldBe` kw 176 | minifyStmt (" {" ++ kw ++ " ;} ") `shouldBe` kw 177 | minifyStmt (" " ++ kw ++ " x ; ") `shouldBe` (kw ++ " x") 178 | minifyStmt ("\n\n" ++ kw ++ " x ;\n") `shouldBe` (kw ++ " x") 179 | 180 | it "block" $ do 181 | minifyStmt "\n{ a = 1\nb = 2\n } " `shouldBe` "{a=1;b=2}" 182 | minifyStmt " { c = 3 ; d = 4 ; } " `shouldBe` "{c=3;d=4}" 183 | minifyStmt " { ; e = 1 } " `shouldBe` "e=1" 184 | minifyStmt " { { } ; f = 1 ; { } ; } ; " `shouldBe` "f=1" 185 | 186 | it "if" $ do 187 | minifyStmt " if ( 1 ) return ; " `shouldBe` "if(1)return" 188 | minifyStmt " if ( 1 ) ; " `shouldBe` "if(1);" 189 | 190 | it "if/else" $ do 191 | minifyStmt " if ( a ) ; else break ; " `shouldBe` "if(a);else break" 192 | minifyStmt " if ( b ) break ; else break ; " `shouldBe` "if(b){break}else break" 193 | minifyStmt " if ( c ) continue ; else continue ; " `shouldBe` "if(c){continue}else continue" 194 | minifyStmt " if ( d ) return ; else return ; " `shouldBe` "if(d){return}else return" 195 | minifyStmt " if ( e ) { b = 1 } else c = 2 ;" `shouldBe` "if(e){b=1}else c=2" 196 | minifyStmt " if ( f ) { b = 1 } else { c = 2 ; d = 4 ; } ;" `shouldBe` "if(f){b=1}else{c=2;d=4}" 197 | minifyStmt " if ( g ) { ex ; } else { ex ; } ; " `shouldBe` "if(g){ex}else ex" 198 | minifyStmt " if ( h ) ; else if ( 2 ){ 3 ; } " `shouldBe` "if(h);else if(2)3" 199 | 200 | it "while" $ do 201 | minifyStmt " while ( x < 2 ) x ++ ; " `shouldBe` "while(x<2)x++" 202 | minifyStmt " while ( x < 0x12 && y > 1 ) { x *= 3 ; y += 1 ; } ; " `shouldBe` "while(x<0x12&&y>1){x*=3;y+=1}" 203 | 204 | it "do/while" $ do 205 | minifyStmt " do x = foo (y) ; while ( x < y ) ; " `shouldBe` "do{x=foo(y)}while(x y ) ; " `shouldBe` "do{x=foo(x,y);y--}while(x>y)" 207 | 208 | it "for" $ do 209 | minifyStmt " for ( ; ; ) ; " `shouldBe` "for(;;);" 210 | minifyStmt " for ( k = 0 ; k <= 10 ; k ++ ) ; " `shouldBe` "for(k=0;k<=10;k++);" 211 | minifyStmt " for ( k = 0, j = 1 ; k <= 10 && j < 10 ; k ++ , j -- ) ; " `shouldBe` "for(k=0,j=1;k<=10&&j<10;k++,j--);" 212 | minifyStmt " for (var x ; y ; z) { } " `shouldBe` "for(var x;y;z){}" 213 | minifyStmt " for ( x in 5 ) foo (x) ;" `shouldBe` "for(x in 5)foo(x)" 214 | minifyStmt " for ( var x in 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(var x in 5){foo(x++);y++}" 215 | minifyStmt " for (let x ; y ; z) { } " `shouldBe` "for(let x;y;z){}" 216 | minifyStmt " for ( let x in 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(let x in 5){foo(x++);y++}" 217 | minifyStmt " for ( let x of 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(let x of 5){foo(x++);y++}" 218 | minifyStmt " for (const x ; y ; z) { } " `shouldBe` "for(const x;y;z){}" 219 | minifyStmt " for ( const x in 5 ) { foo ( x ); y ++ ; } ;" `shouldBe` "for(const x in 5){foo(x);y++}" 220 | minifyStmt " for ( const x of 5 ) { foo ( x ); y ++ ; } ;" `shouldBe` "for(const x of 5){foo(x);y++}" 221 | minifyStmt " for ( x of 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(x of 5){foo(x++);y++}" 222 | minifyStmt " for ( var x of 5 ) { foo ( x++ ); y ++ ; } ;" `shouldBe` "for(var x of 5){foo(x++);y++}" 223 | it "labelled" $ do 224 | minifyStmt " start : while ( true ) { if ( i ++ < 3 ) continue start ; break ; } ; " `shouldBe` "start:while(true){if(i++<3)continue start;break}" 225 | minifyStmt " { k ++ ; start : while ( true ) { if ( i ++ < 3 ) continue start ; break ; } ; } ; " `shouldBe` "{k++;start:while(true){if(i++<3)continue start;break}}" 226 | 227 | it "function" $ do 228 | minifyStmt " function f ( ) { } ; " `shouldBe` "function f(){}" 229 | minifyStmt " function f ( a ) { } ; " `shouldBe` "function f(a){}" 230 | minifyStmt " function f ( a , b ) { return a + b ; } ; " `shouldBe` "function f(a,b){return a+b}" 231 | minifyStmt " function f ( a , ... b ) { return b ; } ; " `shouldBe` "function f(a,...b){return b}" 232 | minifyStmt " function f ( a = 1 , b = 2 ) { return a + b ; } ; " `shouldBe` "function f(a=1,b=2){return a+b}" 233 | minifyStmt " function f ( [ a , b ] ) { return a + b ; } ; " `shouldBe` "function f([a,b]){return a+b}" 234 | minifyStmt " function f ( { a , b , } ) { return a + b ; } ; " `shouldBe` "function f({a,b}){return a+b}" 235 | minifyStmt " async function f ( ) { } " `shouldBe` "async function f(){}" 236 | 237 | it "generator" $ do 238 | minifyStmt " function * f ( ) { } ; " `shouldBe` "function*f(){}" 239 | minifyStmt " function * f ( a ) { yield * a ; } ; " `shouldBe` "function*f(a){yield*a}" 240 | minifyStmt " function * f ( a , b ) { yield a + b ; } ; " `shouldBe` "function*f(a,b){yield a+b}" 241 | 242 | it "with" $ do 243 | minifyStmt " with ( x ) { } ; " `shouldBe` "with(x){}" 244 | minifyStmt " with ({ first: 'John' }) { foo ('Hello '+first); }" `shouldBe` "with({first:'John'})foo('Hello '+first)" 245 | 246 | it "throw" $ do 247 | minifyStmt " throw a " `shouldBe` "throw a" 248 | minifyStmt " throw b ; " `shouldBe` "throw b" 249 | minifyStmt " { throw c ; } ;" `shouldBe` "throw c" 250 | 251 | it "switch" $ do 252 | minifyStmt " switch ( a ) { } ; " `shouldBe` "switch(a){}" 253 | minifyStmt " switch ( b ) { case 1 : 1 ; case 2 : 2 ; } ;" `shouldBe` "switch(b){case 1:1;case 2:2}" 254 | minifyStmt " switch ( c ) { case 1 : case 'a': case \"b\" : break ; default : break ; } ; " `shouldBe` "switch(c){case 1:case'a':case\"b\":break;default:break}" 255 | minifyStmt " switch ( d ) { default : if (a) {x} else y ; if (b) { x } else y ; }" `shouldBe` "switch(d){default:if(a){x}else y;if(b){x}else y}" 256 | 257 | it "try/catch/finally" $ do 258 | minifyStmt " try { } catch ( a ) { } " `shouldBe` "try{}catch(a){}" 259 | minifyStmt " try { b } finally { } " `shouldBe` "try{b}finally{}" 260 | minifyStmt " try { } catch ( c ) { } finally { } " `shouldBe` "try{}catch(c){}finally{}" 261 | minifyStmt " try { } catch ( d ) { } catch ( x ){ } finally { } " `shouldBe` "try{}catch(d){}catch(x){}finally{}" 262 | minifyStmt " try { } catch ( e ) { } catch ( y ) { } " `shouldBe` "try{}catch(e){}catch(y){}" 263 | minifyStmt " try { } catch ( f if f == x ) { } catch ( z ) { } " `shouldBe` "try{}catch(f if f==x){}catch(z){}" 264 | 265 | it "variable declaration" $ do 266 | minifyStmt " var a " `shouldBe` "var a" 267 | minifyStmt " var b ; " `shouldBe` "var b" 268 | minifyStmt " var c = 1 ; " `shouldBe` "var c=1" 269 | minifyStmt " var d = 1, x = 2 ; " `shouldBe` "var d=1,x=2" 270 | minifyStmt " let c = 1 ; " `shouldBe` "let c=1" 271 | minifyStmt " let d = 1, x = 2 ; " `shouldBe` "let d=1,x=2" 272 | minifyStmt " const { a : [ b , c ] } = d; " `shouldBe` "const{a:[b,c]}=d" 273 | 274 | it "string concatenation" $ 275 | minifyStmt " f (\"ab\"+\"cd\") " `shouldBe` "f('abcd')" 276 | 277 | it "class" $ do 278 | minifyStmt " class Foo {\n a() {\n return 0;\n }\n static b ( x ) {}\n } " `shouldBe` "class Foo{a(){return 0}static b(x){}}" 279 | minifyStmt " class Foo extends Bar {} " `shouldBe` "class Foo extends Bar{}" 280 | minifyStmt " class Foo extends (getBase()) {} " `shouldBe` "class Foo extends(getBase()){}" 281 | minifyStmt " class Foo extends [ Bar1, Bar2 ][getBaseIndex()] {} " `shouldBe` "class Foo extends[Bar1,Bar2][getBaseIndex()]{}" 282 | 283 | it "miscellaneous" $ 284 | minifyStmt " let r = await p ; " `shouldBe` "let r=await p" 285 | 286 | testMinifyProg :: Spec 287 | testMinifyProg = describe "Minify programs:" $ do 288 | it "simple" $ do 289 | minifyProg " a = f ? e : g ; " `shouldBe` "a=f?e:g" 290 | minifyProg " for ( i = 0 ; ; ) { ; var t = 1 ; } " `shouldBe` "for(i=0;;)var t=1" 291 | it "if" $ 292 | minifyProg " if ( x ) { } ; t ; " `shouldBe` "if(x);t" 293 | it "if/else" $ do 294 | minifyProg " if ( a ) { } else { } ; break ; " `shouldBe` "if(a){}else;break" 295 | minifyProg " if ( b ) {x = 1} else {x = 2} f () ; " `shouldBe` "if(b){x=1}else x=2;f()" 296 | it "empty block" $ do 297 | minifyProg " a = 1 ; { } ; " `shouldBe` "a=1" 298 | minifyProg " { } ; b = 1 ; " `shouldBe` "b=1" 299 | it "empty statement" $ do 300 | minifyProg " a = 1 + b ; c ; ; { d ; } ; " `shouldBe` "a=1+b;c;d" 301 | minifyProg " b = a + 2 ; c ; { d ; } ; ; " `shouldBe` "b=a+2;c;d" 302 | it "nested block" $ do 303 | minifyProg "{a;;x;};y;z;;" `shouldBe` "a;x;y;z" 304 | minifyProg "{b;;{x;y;};};z;;" `shouldBe` "b;x;y;z" 305 | it "functions" $ 306 | minifyProg " function f() {} ; function g() {} ;" `shouldBe` "function f(){}\nfunction g(){}" 307 | it "variable declaration" $ do 308 | minifyProg " var a = 1 ; var b = 2 ;" `shouldBe` "var a=1,b=2" 309 | minifyProg " var c=1;var d=2;var e=3;" `shouldBe` "var c=1,d=2,e=3" 310 | minifyProg " const f = 1 ; const g = 2 ;" `shouldBe` "const f=1,g=2" 311 | minifyProg " var h = 1 ; const i = 2 ;" `shouldBe` "var h=1;const i=2" 312 | it "try/catch/finally" $ 313 | minifyProg " try { } catch (a) {} finally {} ; try { } catch ( b ) { } ; " `shouldBe` "try{}catch(a){}finally{}try{}catch(b){}" 314 | 315 | testMinifyModule :: Spec 316 | testMinifyModule = describe "Minify modules:" $ do 317 | it "import" $ do 318 | minifyModule "import def from 'mod' ; " `shouldBe` "import def from'mod'" 319 | minifyModule "import * as foo from \"mod\" ; " `shouldBe` "import * as foo from\"mod\"" 320 | minifyModule "import def, * as foo from \"mod\" ; " `shouldBe` "import def,* as foo from\"mod\"" 321 | minifyModule "import { baz, bar as foo } from \"mod\" ; " `shouldBe` "import{baz,bar as foo}from\"mod\"" 322 | minifyModule "import def, { baz, bar as foo } from \"mod\" ; " `shouldBe` "import def,{baz,bar as foo}from\"mod\"" 323 | minifyModule "import \"mod\" ; " `shouldBe` "import\"mod\"" 324 | 325 | it "export" $ do 326 | minifyModule " export { } ; " `shouldBe` "export{}" 327 | minifyModule " export { a } ; " `shouldBe` "export{a}" 328 | minifyModule " export { a, b } ; " `shouldBe` "export{a,b}" 329 | minifyModule " export { a, b as c , d } ; " `shouldBe` "export{a,b as c,d}" 330 | minifyModule " export { } from \"mod\" ; " `shouldBe` "export{}from\"mod\"" 331 | minifyModule " export const a = 1 ; " `shouldBe` "export const a=1" 332 | minifyModule " export function f () { } ; " `shouldBe` "export function f(){}" 333 | minifyModule " export function * f () { } ; " `shouldBe` "export function*f(){}" 334 | 335 | -- ----------------------------------------------------------------------------- 336 | -- Minify test helpers. 337 | 338 | minifyExpr :: String -> String 339 | minifyExpr = minifyWith parseExpression 340 | 341 | minifyStmt :: String -> String 342 | minifyStmt = minifyWith parseStatement 343 | 344 | minifyProg :: String -> String 345 | minifyProg = minifyWith parseProgram 346 | 347 | minifyModule :: String -> String 348 | minifyModule = minifyWith parseModule 349 | 350 | minifyWith :: (Alex AST.JSAST) -> String -> String 351 | minifyWith p str = either id (renderToString . minifyJS) (parseUsing p str "src") 352 | -------------------------------------------------------------------------------- /test/Test/Language/Javascript/ModuleParser.hs: -------------------------------------------------------------------------------- 1 | module Test.Language.Javascript.ModuleParser 2 | ( testModuleParser 3 | ) where 4 | 5 | import Test.Hspec 6 | 7 | import Language.JavaScript.Parser 8 | 9 | 10 | testModuleParser :: Spec 11 | testModuleParser = describe "Parse modules:" $ do 12 | it "as" $ 13 | test "as" 14 | `shouldBe` 15 | "Right (JSAstModule [JSModuleStatementListItem (JSIdentifier 'as')])" 16 | 17 | it "import" $ do 18 | -- Not yet supported 19 | -- test "import 'a';" `shouldBe` "" 20 | 21 | test "import def from 'mod';" 22 | `shouldBe` 23 | "Right (JSAstModule [JSModuleImportDeclaration (JSImportDeclaration (JSImportClauseDefault (JSIdentifier 'def'),JSFromClause ''mod''))])" 24 | test "import def from \"mod\";" 25 | `shouldBe` 26 | "Right (JSAstModule [JSModuleImportDeclaration (JSImportDeclaration (JSImportClauseDefault (JSIdentifier 'def'),JSFromClause '\"mod\"'))])" 27 | test "import * as thing from 'mod';" 28 | `shouldBe` 29 | "Right (JSAstModule [JSModuleImportDeclaration (JSImportDeclaration (JSImportClauseNameSpace (JSImportNameSpace (JSIdentifier 'thing')),JSFromClause ''mod''))])" 30 | test "import { foo, bar, baz as quux } from 'mod';" 31 | `shouldBe` 32 | "Right (JSAstModule [JSModuleImportDeclaration (JSImportDeclaration (JSImportClauseNameSpace (JSImportsNamed ((JSImportSpecifier (JSIdentifier 'foo'),JSImportSpecifier (JSIdentifier 'bar'),JSImportSpecifierAs (JSIdentifier 'baz',JSIdentifier 'quux')))),JSFromClause ''mod''))])" 33 | test "import def, * as thing from 'mod';" 34 | `shouldBe` 35 | "Right (JSAstModule [JSModuleImportDeclaration (JSImportDeclaration (JSImportClauseDefaultNameSpace (JSIdentifier 'def',JSImportNameSpace (JSIdentifier 'thing')),JSFromClause ''mod''))])" 36 | test "import def, { foo, bar, baz as quux } from 'mod';" 37 | `shouldBe` 38 | "Right (JSAstModule [JSModuleImportDeclaration (JSImportDeclaration (JSImportClauseDefaultNamed (JSIdentifier 'def',JSImportsNamed ((JSImportSpecifier (JSIdentifier 'foo'),JSImportSpecifier (JSIdentifier 'bar'),JSImportSpecifierAs (JSIdentifier 'baz',JSIdentifier 'quux')))),JSFromClause ''mod''))])" 39 | 40 | it "export" $ do 41 | test "export {}" 42 | `shouldBe` 43 | "Right (JSAstModule [JSModuleExportDeclaration (JSExportLocals (JSExportClause (())))])" 44 | test "export {};" 45 | `shouldBe` 46 | "Right (JSAstModule [JSModuleExportDeclaration (JSExportLocals (JSExportClause (())))])" 47 | test "export const a = 1;" 48 | `shouldBe` 49 | "Right (JSAstModule [JSModuleExportDeclaration (JSExport (JSConstant (JSVarInitExpression (JSIdentifier 'a') [JSDecimal '1'])))])" 50 | test "export function f() {};" 51 | `shouldBe` 52 | "Right (JSAstModule [JSModuleExportDeclaration (JSExport (JSFunction 'f' () (JSBlock [])))])" 53 | test "export { a };" 54 | `shouldBe` 55 | "Right (JSAstModule [JSModuleExportDeclaration (JSExportLocals (JSExportClause ((JSExportSpecifier (JSIdentifier 'a')))))])" 56 | test "export { a as b };" 57 | `shouldBe` 58 | "Right (JSAstModule [JSModuleExportDeclaration (JSExportLocals (JSExportClause ((JSExportSpecifierAs (JSIdentifier 'a',JSIdentifier 'b')))))])" 59 | test "export {} from 'mod'" 60 | `shouldBe` 61 | "Right (JSAstModule [JSModuleExportDeclaration (JSExportFrom (JSExportClause (()),JSFromClause ''mod''))])" 62 | 63 | 64 | test :: String -> String 65 | test str = showStrippedMaybe (parseModule str "src") 66 | -------------------------------------------------------------------------------- /test/Test/Language/Javascript/ProgramParser.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | module Test.Language.Javascript.ProgramParser 3 | ( testProgramParser 4 | ) where 5 | 6 | #if ! MIN_VERSION_base(4,13,0) 7 | import Control.Applicative ((<$>)) 8 | #endif 9 | import Test.Hspec 10 | 11 | import Language.JavaScript.Parser 12 | import Language.JavaScript.Parser.Grammar7 13 | import Language.JavaScript.Parser.Parser 14 | 15 | 16 | testProgramParser :: Spec 17 | testProgramParser = describe "Program parser:" $ do 18 | it "function" $ do 19 | testProg "function a(){}" `shouldBe` "Right (JSAstProgram [JSFunction 'a' () (JSBlock [])])" 20 | testProg "function a(b,c){}" `shouldBe` "Right (JSAstProgram [JSFunction 'a' (JSIdentifier 'b',JSIdentifier 'c') (JSBlock [])])" 21 | it "comments" $ do 22 | testProg "//blah\nx=1;//foo\na" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon,JSIdentifier 'a'])" 23 | testProg "/*x=1\ny=2\n*/z=2;//foo\na" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'z',JSDecimal '2'),JSSemicolon,JSIdentifier 'a'])" 24 | testProg "/* */\nfunction f() {\n/* */\n}\n" `shouldBe` "Right (JSAstProgram [JSFunction 'f' () (JSBlock [])])" 25 | testProg "/* **/\nfunction f() {\n/* */\n}\n" `shouldBe` "Right (JSAstProgram [JSFunction 'f' () (JSBlock [])])" 26 | 27 | it "if" $ do 28 | testProg "if(x);x=1" `shouldBe` "Right (JSAstProgram [JSIf (JSIdentifier 'x') (JSEmptyStatement),JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1')])" 29 | testProg "if(a)x=1;y=2" `shouldBe` "Right (JSAstProgram [JSIf (JSIdentifier 'a') (JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon),JSOpAssign ('=',JSIdentifier 'y',JSDecimal '2')])" 30 | testProg "if(a)x=a()y=2" `shouldBe` "Right (JSAstProgram [JSIf (JSIdentifier 'a') (JSOpAssign ('=',JSIdentifier 'x',JSMemberExpression (JSIdentifier 'a',JSArguments ()))),JSOpAssign ('=',JSIdentifier 'y',JSDecimal '2')])" 31 | testProg "if(true)break \nfoo();" `shouldBe` "Right (JSAstProgram [JSIf (JSLiteral 'true') (JSBreak),JSMethodCall (JSIdentifier 'foo',JSArguments ()),JSSemicolon])" 32 | testProg "if(true)continue \nfoo();" `shouldBe` "Right (JSAstProgram [JSIf (JSLiteral 'true') (JSContinue),JSMethodCall (JSIdentifier 'foo',JSArguments ()),JSSemicolon])" 33 | testProg "if(true)break \nfoo();" `shouldBe` "Right (JSAstProgram [JSIf (JSLiteral 'true') (JSBreak),JSMethodCall (JSIdentifier 'foo',JSArguments ()),JSSemicolon])" 34 | 35 | it "assign" $ 36 | testProg "x = 1\n y=2;" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSOpAssign ('=',JSIdentifier 'y',JSDecimal '2'),JSSemicolon])" 37 | 38 | it "regex" $ do 39 | testProg "x=/\\n/g" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSRegEx '/\\n/g')])" 40 | testProg "x=i(/^$/g,\"\\\\$&\")" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSMemberExpression (JSIdentifier 'i',JSArguments (JSRegEx '/^$/g',JSStringLiteral \"\\\\$&\")))])" 41 | testProg "x=i(/[?|^&(){}\\[\\]+\\-*\\/\\.]/g,\"\\\\$&\")" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSMemberExpression (JSIdentifier 'i',JSArguments (JSRegEx '/[?|^&(){}\\[\\]+\\-*\\/\\.]/g',JSStringLiteral \"\\\\$&\")))])" 42 | testProg "(match = /^\"(?:\\\\.|[^\"])*\"|^'(?:[^']|\\\\.)*'/(input))" `shouldBe` "Right (JSAstProgram [JSExpressionParen (JSOpAssign ('=',JSIdentifier 'match',JSMemberExpression (JSRegEx '/^\"(?:\\\\.|[^\"])*\"|^'(?:[^']|\\\\.)*'/',JSArguments (JSIdentifier 'input'))))])" 43 | testProg "if(/^[a-z]/.test(t)){consts+=t.toUpperCase();keywords[t]=i}else consts+=(/^\\W/.test(t)?opTypeNames[t]:t);" 44 | `shouldBe` "Right (JSAstProgram [JSIfElse (JSMemberExpression (JSMemberDot (JSRegEx '/^[a-z]/',JSIdentifier 'test'),JSArguments (JSIdentifier 't'))) (JSStatementBlock [JSOpAssign ('+=',JSIdentifier 'consts',JSMemberExpression (JSMemberDot (JSIdentifier 't',JSIdentifier 'toUpperCase'),JSArguments ())),JSSemicolon,JSOpAssign ('=',JSMemberSquare (JSIdentifier 'keywords',JSIdentifier 't'),JSIdentifier 'i')]) (JSOpAssign ('+=',JSIdentifier 'consts',JSExpressionParen (JSExpressionTernary (JSMemberExpression (JSMemberDot (JSRegEx '/^\\W/',JSIdentifier 'test'),JSArguments (JSIdentifier 't')),JSMemberSquare (JSIdentifier 'opTypeNames',JSIdentifier 't'),JSIdentifier 't'))),JSSemicolon)])" 45 | 46 | it "unicode" $ do 47 | testProg "àáâãäå = 1;" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier '\224\225\226\227\228\229',JSDecimal '1'),JSSemicolon])" 48 | testProg "//comment\x000Ax=1;" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon])" 49 | testProg "//comment\x000Dx=1;" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon])" 50 | testProg "//comment\x2028x=1;" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon])" 51 | testProg "//comment\x2029x=1;" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon])" 52 | testProg "$aà = 1;_b=2;\0065a=2" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier '$a\224',JSDecimal '1'),JSSemicolon,JSOpAssign ('=',JSIdentifier '_b',JSDecimal '2'),JSSemicolon,JSOpAssign ('=',JSIdentifier 'Aa',JSDecimal '2')])" 53 | testProg "x=\"àáâãäå\";y='\3012a\0068'" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSStringLiteral \"\224\225\226\227\228\229\"),JSSemicolon,JSOpAssign ('=',JSIdentifier 'y',JSStringLiteral '\3012aD')])" 54 | 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;" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'a',JSDecimal '1'),JSSemicolon])" 55 | testProg "/* * geolocation. пытаемся определить свое местоположение * если не получается то используем defaultLocation * @Param {object} map экземпляр карты * @Param {object LatLng} defaultLocation Координаты центра по умолчанию * @Param {function} callbackAfterLocation Фу-ия которая вызывается после * геолокации. Т.к запрос геолокации асинхронен */x" `shouldBe` "Right (JSAstProgram [JSIdentifier 'x'])" 56 | testFileUtf8 "./test/Unicode.js" `shouldReturn` "JSAstProgram [JSOpAssign ('=',JSIdentifier '\224\225\226\227\228\229',JSDecimal '1'),JSSemicolon]" 57 | 58 | it "strings" $ do 59 | -- Working in ECMASCRIPT 5.1 changes 60 | testProg "x='abc\\ndef';" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSStringLiteral 'abc\\ndef'),JSSemicolon])" 61 | testProg "x=\"abc\\ndef\";" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSStringLiteral \"abc\\ndef\"),JSSemicolon])" 62 | testProg "x=\"abc\\rdef\";" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSStringLiteral \"abc\\rdef\"),JSSemicolon])" 63 | testProg "x=\"abc\\r\\ndef\";" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSStringLiteral \"abc\\r\\ndef\"),JSSemicolon])" 64 | testProg "x=\"abc\\x2028 def\";" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSStringLiteral \"abc\\x2028 def\"),JSSemicolon])" 65 | testProg "x=\"abc\\x2029 def\";" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSStringLiteral \"abc\\x2029 def\"),JSSemicolon])" 66 | 67 | it "object literal" $ do 68 | testProg "x = { y: 1e8 }" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'y') [JSDecimal '1e8']])])" 69 | testProg "{ y: 1e8 }" `shouldBe` "Right (JSAstProgram [JSStatementBlock [JSLabelled (JSIdentifier 'y') (JSDecimal '1e8')]])" 70 | testProg "{ y: 18 }" `shouldBe` "Right (JSAstProgram [JSStatementBlock [JSLabelled (JSIdentifier 'y') (JSDecimal '18')]])" 71 | testProg "x = { y: 18 }" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'x',JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'y') [JSDecimal '18']])])" 72 | testProg "var k = {\ny: somename\n}" `shouldBe` "Right (JSAstProgram [JSVariable (JSVarInitExpression (JSIdentifier 'k') [JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'y') [JSIdentifier 'somename']]])])" 73 | testProg "var k = {\ny: code\n}" `shouldBe` "Right (JSAstProgram [JSVariable (JSVarInitExpression (JSIdentifier 'k') [JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'y') [JSIdentifier 'code']]])])" 74 | testProg "var k = {\ny: mode\n}" `shouldBe` "Right (JSAstProgram [JSVariable (JSVarInitExpression (JSIdentifier 'k') [JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'y') [JSIdentifier 'mode']]])])" 75 | 76 | it "programs" $ do 77 | testProg "newlines=spaces.match(/\\n/g)" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'newlines',JSMemberExpression (JSMemberDot (JSIdentifier 'spaces',JSIdentifier 'match'),JSArguments (JSRegEx '/\\n/g')))])" 78 | testProg "Animal=function(){return this.name};" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'Animal',JSFunctionExpression '' () (JSBlock [JSReturn JSMemberDot (JSLiteral 'this',JSIdentifier 'name') ])),JSSemicolon])" 79 | testProg "$(img).click(function(){alert('clicked!')});" `shouldBe` "Right (JSAstProgram [JSCallExpression (JSCallExpressionDot (JSMemberExpression (JSIdentifier '$',JSArguments (JSIdentifier 'img')),JSIdentifier 'click'),JSArguments (JSFunctionExpression '' () (JSBlock [JSMethodCall (JSIdentifier 'alert',JSArguments (JSStringLiteral 'clicked!'))]))),JSSemicolon])" 80 | testProg "function() {\nz = function z(o) {\nreturn r;\n};}" `shouldBe` "Right (JSAstProgram [JSFunctionExpression '' () (JSBlock [JSOpAssign ('=',JSIdentifier 'z',JSFunctionExpression 'z' (JSIdentifier 'o') (JSBlock [JSReturn JSIdentifier 'r' JSSemicolon])),JSSemicolon])])" 81 | testProg "function() {\nz = function /*z*/(o) {\nreturn r;\n};}" `shouldBe` "Right (JSAstProgram [JSFunctionExpression '' () (JSBlock [JSOpAssign ('=',JSIdentifier 'z',JSFunctionExpression '' (JSIdentifier 'o') (JSBlock [JSReturn JSIdentifier 'r' JSSemicolon])),JSSemicolon])])" 82 | testProg "{zero}\nget;two\n{three\nfour;set;\n{\nsix;{seven;}\n}\n}" `shouldBe` "Right (JSAstProgram [JSStatementBlock [JSIdentifier 'zero'],JSIdentifier 'get',JSSemicolon,JSIdentifier 'two',JSStatementBlock [JSIdentifier 'three',JSIdentifier 'four',JSSemicolon,JSIdentifier 'set',JSSemicolon,JSStatementBlock [JSIdentifier 'six',JSSemicolon,JSStatementBlock [JSIdentifier 'seven',JSSemicolon]]]])" 83 | testProg "{zero}\none1;two\n{three\nfour;five;\n{\nsix;{seven;}\n}\n}" `shouldBe` "Right (JSAstProgram [JSStatementBlock [JSIdentifier 'zero'],JSIdentifier 'one1',JSSemicolon,JSIdentifier 'two',JSStatementBlock [JSIdentifier 'three',JSIdentifier 'four',JSSemicolon,JSIdentifier 'five',JSSemicolon,JSStatementBlock [JSIdentifier 'six',JSSemicolon,JSStatementBlock [JSIdentifier 'seven',JSSemicolon]]]])" 84 | testProg "v = getValue(execute(n[0], x)) in getValue(execute(n[1], x));" `shouldBe` "Right (JSAstProgram [JSOpAssign ('=',JSIdentifier 'v',JSExpressionBinary ('in',JSMemberExpression (JSIdentifier 'getValue',JSArguments (JSMemberExpression (JSIdentifier 'execute',JSArguments (JSMemberSquare (JSIdentifier 'n',JSDecimal '0'),JSIdentifier 'x')))),JSMemberExpression (JSIdentifier 'getValue',JSArguments (JSMemberExpression (JSIdentifier 'execute',JSArguments (JSMemberSquare (JSIdentifier 'n',JSDecimal '1'),JSIdentifier 'x')))))),JSSemicolon])" 85 | 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\"" 86 | `shouldBe` "Right (JSAstProgram [JSFunction 'Animal' (JSIdentifier 'name') (JSBlock [JSIf (JSUnaryExpression ('!',JSIdentifier 'name')) (JSThrow (JSMemberNew (JSIdentifier 'Error',JSArguments (JSStringLiteral 'Must specify an animal name')))),JSOpAssign ('=',JSMemberDot (JSLiteral 'this',JSIdentifier 'name'),JSIdentifier 'name')]),JSOpAssign ('=',JSMemberDot (JSMemberDot (JSIdentifier 'Animal',JSIdentifier 'prototype'),JSIdentifier 'toString'),JSFunctionExpression '' () (JSBlock [JSReturn JSMemberDot (JSLiteral 'this',JSIdentifier 'name') ])),JSSemicolon,JSOpAssign ('=',JSIdentifier 'o',JSMemberNew (JSIdentifier 'Animal',JSArguments (JSStringLiteral \"bob\"))),JSSemicolon,JSExpressionBinary ('==',JSMemberExpression (JSMemberDot (JSIdentifier 'o',JSIdentifier 'toString'),JSArguments ()),JSStringLiteral \"bob\")])" 87 | 88 | 89 | testProg :: String -> String 90 | testProg str = showStrippedMaybe (parseUsing parseProgram str "src") 91 | 92 | testFileUtf8 :: FilePath -> IO String 93 | testFileUtf8 fileName = showStripped <$> parseFileUtf8 fileName 94 | 95 | -------------------------------------------------------------------------------- /test/Test/Language/Javascript/RoundTrip.hs: -------------------------------------------------------------------------------- 1 | module Test.Language.Javascript.RoundTrip 2 | ( testRoundTrip 3 | ) where 4 | 5 | import Test.Hspec 6 | 7 | import Language.JavaScript.Parser 8 | import qualified Language.JavaScript.Parser.AST as AST 9 | 10 | 11 | testRoundTrip :: Spec 12 | testRoundTrip = describe "Roundtrip:" $ do 13 | it "multi comment" $ do 14 | testRT "/*a*/\n//foo\nnull" 15 | testRT "/*a*/x" 16 | testRT "/*a*/null" 17 | testRT "/*b*/false" 18 | testRT "true/*c*/" 19 | testRT "/*c*/true" 20 | testRT "/*d*/0x1234fF" 21 | testRT "/*e*/1.0e4" 22 | testRT "/*x*/011" 23 | testRT "/*f*/\"hello\\nworld\"" 24 | testRT "/*g*/'hello\\nworld'" 25 | testRT "/*h*/this" 26 | testRT "/*i*//blah/" 27 | testRT "//j\nthis_" 28 | 29 | it "arrays" $ do 30 | testRT "/*a*/[/*b*/]" 31 | testRT "/*a*/[/*b*/,/*c*/]" 32 | testRT "/*a*/[/*b*/,/*c*/,/*d*/]" 33 | testRT "/*a*/[/*b/*,/*c*/,/*d*/x/*e*/]" 34 | testRT "/*a*/[/*b*/,/*c*/,/*d*/x/*e*/]" 35 | testRT "/*a*/[/*b*/,/*c*/x/*d*/,/*e*/,/*f*/x/*g*/]" 36 | testRT "/*a*/[/*b*/x/*c*/]" 37 | testRT "/*a*/[/*b*/x/*c*/,/*d*/]" 38 | 39 | it "object literals" $ do 40 | testRT "/*a*/{/*b*/}" 41 | testRT "/*a*/{/*b*/x/*c*/:/*d*/1/*e*/}" 42 | testRT "/*a*/{/*b*/x/*c*/}" 43 | testRT "/*a*/{/*b*/of/*c*/}" 44 | testRT "x=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/}" 45 | testRT "x=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/y/*g*/:/*h*/2/*i*/,/*j*/z/*k*/:/*l*/3/*m*/}" 46 | testRT "a=/*a*/{/*b*/x/*c*/:/*d*/1/*e*/,/*f*/}" 47 | testRT "/*a*/{/*b*/[/*c*/x/*d*/+/*e*/y/*f*/]/*g*/:/*h*/1/*i*/}" 48 | testRT "/*a*/{/*b*/a/*c*/(/*d*/x/*e*/,/*f*/y/*g*/)/*h*/{/*i*/}/*j*/}" 49 | testRT "/*a*/{/*b*/[/*c*/x/*d*/+/*e*/y/*f*/]/*g*/(/*h*/)/*i*/{/*j*/}/*k*/}" 50 | testRT "/*a*/{/*b*/*/*c*/a/*d*/(/*e*/x/*f*/,/*g*/y/*h*/)/*i*/{/*j*/}/*k*/}" 51 | 52 | it "miscellaneous" $ do 53 | testRT "/*a*/(/*b*/56/*c*/)" 54 | testRT "/*a*/true/*b*/?/*c*/1/*d*/:/*e*/2" 55 | testRT "/*a*/x/*b*/||/*c*/y" 56 | testRT "/*a*/x/*b*/&&/*c*/y" 57 | testRT "/*a*/x/*b*/|/*c*/y" 58 | testRT "/*a*/x/*b*/^/*c*/y" 59 | testRT "/*a*/x/*b*/&/*c*/y" 60 | testRT "/*a*/x/*b*/==/*c*/y" 61 | testRT "/*a*/x/*b*/!=/*c*/y" 62 | testRT "/*a*/x/*b*/===/*c*/y" 63 | testRT "/*a*/x/*b*/!==/*c*/y" 64 | testRT "/*a*/x/*b*//*c*/y" 66 | testRT "/*a*/x/*b*/<=/*c*/y" 67 | testRT "/*a*/x/*b*/>=/*c*/y" 68 | testRT "/*a*/x /*b*/instanceof /*c*/y" 69 | testRT "/*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*/}" 70 | testRT "x = { set foo(/*a*/[/*b*/a/*c*/,/*d*/b/*e*/]/*f*/=/*g*/y/*h*/) {} }" 71 | testRT "... /*a*/ x" 72 | 73 | testRT "a => {}" 74 | testRT "(a) => { a + 2 }" 75 | testRT "(a, b) => {}" 76 | testRT "(a, b) => a + b" 77 | testRT "() => { 42 }" 78 | testRT "(...a) => a" 79 | testRT "(a=1, b=2) => a + b" 80 | testRT "([a, b]) => a + b" 81 | testRT "({a, b}) => a + b" 82 | 83 | testRT "function (...a) {}" 84 | testRT "function (a=1, b=2) {}" 85 | testRT "function ([a, ...b]) {}" 86 | testRT "function ({a, b: c}) {}" 87 | 88 | testRT "/*a*/function/*b*/*/*c*/f/*d*/(/*e*/)/*f*/{/*g*/yield/*h*/a/*i*/}/*j*/" 89 | testRT "function*(a, b) { yield a ; yield b ; }" 90 | 91 | testRT "/*a*/`<${/*b*/x/*c*/}>`/*d*/" 92 | testRT "`\\${}`" 93 | testRT "`\n\n`" 94 | testRT "{}+``" 95 | -- ^ https://github.com/erikd/language-javascript/issues/104 96 | 97 | 98 | it "statement" $ do 99 | testRT "if (1) {}" 100 | testRT "if (1) {} else {}" 101 | testRT "if (1) x=1; else {}" 102 | testRT "do {x=1} while (true);" 103 | testRT "do x=x+1;while(x<4);" 104 | testRT "while(true);" 105 | testRT "for(;;);" 106 | testRT "for(x=1;x<10;x++);" 107 | testRT "for(var x;;);" 108 | testRT "for(var x=1;;);" 109 | testRT "for(var x;y;z){}" 110 | testRT "for(x in 5){}" 111 | testRT "for(var x in 5){}" 112 | testRT "for(let x;y;z){}" 113 | testRT "for(let x in 5){}" 114 | testRT "for(let x of 5){}" 115 | testRT "for(const x;y;z){}" 116 | testRT "for(const x in 5){}" 117 | testRT "for(const x of 5){}" 118 | testRT "for(x of 5){}" 119 | testRT "for(var x of 5){}" 120 | testRT "var x=1;" 121 | testRT "const x=1,y=2;" 122 | testRT "continue;" 123 | testRT "continue x;" 124 | testRT "break;" 125 | testRT "break x;" 126 | testRT "return;" 127 | testRT "return x;" 128 | testRT "with (x) {};" 129 | testRT "abc:x=1" 130 | testRT "switch (x) {}" 131 | testRT "switch (x) {case 1:break;}" 132 | testRT "switch (x) {case 0:\ncase 1:break;}" 133 | testRT "switch (x) {default:break;}" 134 | testRT "switch (x) {default:\ncase 1:break;}" 135 | testRT "var x=1;let y=2;" 136 | testRT "var [x, y]=z;" 137 | testRT "let {x: [y]}=z;" 138 | testRT "let yield=1" 139 | 140 | it "module" $ do 141 | testRTModule "import def from 'mod'" 142 | testRTModule "import def from \"mod\";" 143 | testRTModule "import * as foo from \"mod\" ; " 144 | testRTModule "import def, * as foo from \"mod\" ; " 145 | testRTModule "import { baz, bar as foo } from \"mod\" ; " 146 | testRTModule "import def, { baz, bar as foo } from \"mod\" ; " 147 | 148 | testRTModule "export {};" 149 | testRTModule " export {} ; " 150 | testRTModule "export { a , b , c };" 151 | testRTModule "export { a, X as B, c }" 152 | testRTModule "export {} from \"mod\";" 153 | testRTModule "export const a = 1 ; " 154 | testRTModule "export function f () { } ; " 155 | testRTModule "export function * f () { } ; " 156 | testRTModule "export class Foo\nextends Bar\n{ get a () { return 1 ; } static b ( x,y ) {} ; } ; " 157 | 158 | 159 | testRT :: String -> Expectation 160 | testRT = testRTWith readJs 161 | 162 | testRTModule :: String -> Expectation 163 | testRTModule = testRTWith readJsModule 164 | 165 | testRTWith :: (String -> AST.JSAST) -> String -> Expectation 166 | testRTWith f str = renderToString (f str) `shouldBe` str 167 | -------------------------------------------------------------------------------- /test/Test/Language/Javascript/StatementParser.hs: -------------------------------------------------------------------------------- 1 | module Test.Language.Javascript.StatementParser 2 | ( testStatementParser 3 | ) where 4 | 5 | 6 | import Test.Hspec 7 | 8 | import Language.JavaScript.Parser 9 | import Language.JavaScript.Parser.Grammar7 10 | import Language.JavaScript.Parser.Parser 11 | 12 | 13 | testStatementParser :: Spec 14 | testStatementParser = describe "Parse statements:" $ do 15 | it "simple" $ do 16 | testStmt "x" `shouldBe` "Right (JSAstStatement (JSIdentifier 'x'))" 17 | testStmt "null" `shouldBe` "Right (JSAstStatement (JSLiteral 'null'))" 18 | testStmt "true?1:2" `shouldBe` "Right (JSAstStatement (JSExpressionTernary (JSLiteral 'true',JSDecimal '1',JSDecimal '2')))" 19 | 20 | it "block" $ do 21 | testStmt "{}" `shouldBe` "Right (JSAstStatement (JSStatementBlock []))" 22 | testStmt "{x=1}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1')]))" 23 | testStmt "{x=1;y=2}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon,JSOpAssign ('=',JSIdentifier 'y',JSDecimal '2')]))" 24 | testStmt "{{}}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSStatementBlock []]))" 25 | testStmt "{{{}}}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSStatementBlock [JSStatementBlock []]]))" 26 | 27 | it "if" $ 28 | testStmt "if (1) {}" `shouldBe` "Right (JSAstStatement (JSIf (JSDecimal '1') (JSStatementBlock [])))" 29 | 30 | it "if/else" $ do 31 | testStmt "if (1) {} else {}" `shouldBe` "Right (JSAstStatement (JSIfElse (JSDecimal '1') (JSStatementBlock []) (JSStatementBlock [])))" 32 | testStmt "if (1) x=1; else {}" `shouldBe` "Right (JSAstStatement (JSIfElse (JSDecimal '1') (JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'),JSSemicolon) (JSStatementBlock [])))" 33 | testStmt " if (1);else break" `shouldBe` "Right (JSAstStatement (JSIfElse (JSDecimal '1') (JSEmptyStatement) (JSBreak)))" 34 | 35 | it "while" $ 36 | testStmt "while(true);" `shouldBe` "Right (JSAstStatement (JSWhile (JSLiteral 'true') (JSEmptyStatement)))" 37 | 38 | it "do/while" $ do 39 | testStmt "do {x=1} while (true);" `shouldBe` "Right (JSAstStatement (JSDoWhile (JSStatementBlock [JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1')]) (JSLiteral 'true') (JSSemicolon)))" 40 | testStmt "do x=x+1;while(x<4);" `shouldBe` "Right (JSAstStatement (JSDoWhile (JSOpAssign ('=',JSIdentifier 'x',JSExpressionBinary ('+',JSIdentifier 'x',JSDecimal '1')),JSSemicolon) (JSExpressionBinary ('<',JSIdentifier 'x',JSDecimal '4')) (JSSemicolon)))" 41 | 42 | it "for" $ do 43 | testStmt "for(;;);" `shouldBe` "Right (JSAstStatement (JSFor () () () (JSEmptyStatement)))" 44 | testStmt "for(x=1;x<10;x++);" `shouldBe` "Right (JSAstStatement (JSFor (JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1')) (JSExpressionBinary ('<',JSIdentifier 'x',JSDecimal '10')) (JSExpressionPostfix ('++',JSIdentifier 'x')) (JSEmptyStatement)))" 45 | 46 | testStmt "for(var x;;);" `shouldBe` "Right (JSAstStatement (JSForVar (JSVarInitExpression (JSIdentifier 'x') ) () () (JSEmptyStatement)))" 47 | testStmt "for(var x=1;;);" `shouldBe` "Right (JSAstStatement (JSForVar (JSVarInitExpression (JSIdentifier 'x') [JSDecimal '1']) () () (JSEmptyStatement)))" 48 | testStmt "for(var x;y;z){}" `shouldBe` "Right (JSAstStatement (JSForVar (JSVarInitExpression (JSIdentifier 'x') ) (JSIdentifier 'y') (JSIdentifier 'z') (JSStatementBlock [])))" 49 | 50 | testStmt "for(x in 5){}" `shouldBe` "Right (JSAstStatement (JSForIn JSIdentifier 'x' (JSDecimal '5') (JSStatementBlock [])))" 51 | 52 | testStmt "for(var x in 5){}" `shouldBe` "Right (JSAstStatement (JSForVarIn (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" 53 | 54 | testStmt "for(let x;y;z){}" `shouldBe` "Right (JSAstStatement (JSForLet (JSVarInitExpression (JSIdentifier 'x') ) (JSIdentifier 'y') (JSIdentifier 'z') (JSStatementBlock [])))" 55 | testStmt "for(let x in 5){}" `shouldBe` "Right (JSAstStatement (JSForLetIn (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" 56 | testStmt "for(let x of 5){}" `shouldBe` "Right (JSAstStatement (JSForLetOf (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" 57 | testStmt "for(const x;y;z){}" `shouldBe` "Right (JSAstStatement (JSForConst (JSVarInitExpression (JSIdentifier 'x') ) (JSIdentifier 'y') (JSIdentifier 'z') (JSStatementBlock [])))" 58 | testStmt "for(const x in 5){}" `shouldBe` "Right (JSAstStatement (JSForConstIn (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" 59 | testStmt "for(const x of 5){}" `shouldBe` "Right (JSAstStatement (JSForConstOf (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" 60 | testStmt "for(x of 5){}" `shouldBe` "Right (JSAstStatement (JSForOf JSIdentifier 'x' (JSDecimal '5') (JSStatementBlock [])))" 61 | testStmt "for(var x of 5){}" `shouldBe` "Right (JSAstStatement (JSForVarOf (JSVarInitExpression (JSIdentifier 'x') ) (JSDecimal '5') (JSStatementBlock [])))" 62 | 63 | it "variable/constant/let declaration" $ do 64 | testStmt "var x=1;" `shouldBe` "Right (JSAstStatement (JSVariable (JSVarInitExpression (JSIdentifier 'x') [JSDecimal '1'])))" 65 | testStmt "const x=1,y=2;" `shouldBe` "Right (JSAstStatement (JSConstant (JSVarInitExpression (JSIdentifier 'x') [JSDecimal '1'],JSVarInitExpression (JSIdentifier 'y') [JSDecimal '2'])))" 66 | testStmt "let x=1,y=2;" `shouldBe` "Right (JSAstStatement (JSLet (JSVarInitExpression (JSIdentifier 'x') [JSDecimal '1'],JSVarInitExpression (JSIdentifier 'y') [JSDecimal '2'])))" 67 | testStmt "var [a,b]=x" `shouldBe` "Right (JSAstStatement (JSVariable (JSVarInitExpression (JSArrayLiteral [JSIdentifier 'a',JSComma,JSIdentifier 'b']) [JSIdentifier 'x'])))" 68 | testStmt "const {a:b}=x" `shouldBe` "Right (JSAstStatement (JSConstant (JSVarInitExpression (JSObjectLiteral [JSPropertyNameandValue (JSIdentifier 'a') [JSIdentifier 'b']]) [JSIdentifier 'x'])))" 69 | 70 | it "break" $ do 71 | testStmt "break;" `shouldBe` "Right (JSAstStatement (JSBreak,JSSemicolon))" 72 | testStmt "break x;" `shouldBe` "Right (JSAstStatement (JSBreak 'x',JSSemicolon))" 73 | testStmt "{break}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSBreak]))" 74 | 75 | it "continue" $ do 76 | testStmt "continue;" `shouldBe` "Right (JSAstStatement (JSContinue,JSSemicolon))" 77 | testStmt "continue x;" `shouldBe` "Right (JSAstStatement (JSContinue 'x',JSSemicolon))" 78 | testStmt "{continue}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSContinue]))" 79 | 80 | it "return" $ do 81 | testStmt "return;" `shouldBe` "Right (JSAstStatement (JSReturn JSSemicolon))" 82 | testStmt "return x;" `shouldBe` "Right (JSAstStatement (JSReturn JSIdentifier 'x' JSSemicolon))" 83 | testStmt "return 123;" `shouldBe` "Right (JSAstStatement (JSReturn JSDecimal '123' JSSemicolon))" 84 | testStmt "{return}" `shouldBe` "Right (JSAstStatement (JSStatementBlock [JSReturn ]))" 85 | 86 | it "with" $ 87 | testStmt "with (x) {};" `shouldBe` "Right (JSAstStatement (JSWith (JSIdentifier 'x') (JSStatementBlock [])))" 88 | 89 | it "assign" $ 90 | testStmt "var z = x[i] / y;" `shouldBe` "Right (JSAstStatement (JSVariable (JSVarInitExpression (JSIdentifier 'z') [JSExpressionBinary ('/',JSMemberSquare (JSIdentifier 'x',JSIdentifier 'i'),JSIdentifier 'y')])))" 91 | 92 | it "label" $ 93 | testStmt "abc:x=1" `shouldBe` "Right (JSAstStatement (JSLabelled (JSIdentifier 'abc') (JSOpAssign ('=',JSIdentifier 'x',JSDecimal '1'))))" 94 | 95 | it "throw" $ 96 | testStmt "throw 1" `shouldBe` "Right (JSAstStatement (JSThrow (JSDecimal '1')))" 97 | 98 | it "switch" $ do 99 | testStmt "switch (x) {}" `shouldBe` "Right (JSAstStatement (JSSwitch (JSIdentifier 'x') []))" 100 | testStmt "switch (x) {case 1:break;}" `shouldBe` "Right (JSAstStatement (JSSwitch (JSIdentifier 'x') [JSCase (JSDecimal '1') ([JSBreak,JSSemicolon])]))" 101 | testStmt "switch (x) {case 0:\ncase 1:break;}" `shouldBe` "Right (JSAstStatement (JSSwitch (JSIdentifier 'x') [JSCase (JSDecimal '0') ([]),JSCase (JSDecimal '1') ([JSBreak,JSSemicolon])]))" 102 | testStmt "switch (x) {default:break;}" `shouldBe` "Right (JSAstStatement (JSSwitch (JSIdentifier 'x') [JSDefault ([JSBreak,JSSemicolon])]))" 103 | testStmt "switch (x) {default:\ncase 1:break;}" `shouldBe` "Right (JSAstStatement (JSSwitch (JSIdentifier 'x') [JSDefault ([]),JSCase (JSDecimal '1') ([JSBreak,JSSemicolon])]))" 104 | 105 | it "try/cathc/finally" $ do 106 | testStmt "try{}catch(a){}" `shouldBe` "Right (JSAstStatement (JSTry (JSBlock [],[JSCatch (JSIdentifier 'a',JSBlock [])],JSFinally ())))" 107 | testStmt "try{}finally{}" `shouldBe` "Right (JSAstStatement (JSTry (JSBlock [],[],JSFinally (JSBlock []))))" 108 | testStmt "try{}catch(a){}finally{}" `shouldBe` "Right (JSAstStatement (JSTry (JSBlock [],[JSCatch (JSIdentifier 'a',JSBlock [])],JSFinally (JSBlock []))))" 109 | testStmt "try{}catch(a){}catch(b){}finally{}" `shouldBe` "Right (JSAstStatement (JSTry (JSBlock [],[JSCatch (JSIdentifier 'a',JSBlock []),JSCatch (JSIdentifier 'b',JSBlock [])],JSFinally (JSBlock []))))" 110 | testStmt "try{}catch(a){}catch(b){}" `shouldBe` "Right (JSAstStatement (JSTry (JSBlock [],[JSCatch (JSIdentifier 'a',JSBlock []),JSCatch (JSIdentifier 'b',JSBlock [])],JSFinally ())))" 111 | testStmt "try{}catch(a if true){}catch(b){}" `shouldBe` "Right (JSAstStatement (JSTry (JSBlock [],[JSCatch (JSIdentifier 'a') if JSLiteral 'true' (JSBlock []),JSCatch (JSIdentifier 'b',JSBlock [])],JSFinally ())))" 112 | 113 | it "function" $ do 114 | testStmt "function x(){}" `shouldBe` "Right (JSAstStatement (JSFunction 'x' () (JSBlock [])))" 115 | testStmt "function x(a){}" `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSIdentifier 'a') (JSBlock [])))" 116 | testStmt "function x(a,b){}" `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSIdentifier 'a',JSIdentifier 'b') (JSBlock [])))" 117 | testStmt "function x(...a){}" `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSSpreadExpression (JSIdentifier 'a')) (JSBlock [])))" 118 | testStmt "function x(a=1){}" `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSOpAssign ('=',JSIdentifier 'a',JSDecimal '1')) (JSBlock [])))" 119 | testStmt "function x([a]){}" `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSArrayLiteral [JSIdentifier 'a']) (JSBlock [])))" 120 | testStmt "function x({a}){}" `shouldBe` "Right (JSAstStatement (JSFunction 'x' (JSObjectLiteral [JSPropertyIdentRef 'a']) (JSBlock [])))" 121 | 122 | it "generator" $ do 123 | testStmt "function* x(){}" `shouldBe` "Right (JSAstStatement (JSGenerator 'x' () (JSBlock [])))" 124 | testStmt "function* x(a){}" `shouldBe` "Right (JSAstStatement (JSGenerator 'x' (JSIdentifier 'a') (JSBlock [])))" 125 | testStmt "function* x(a,b){}" `shouldBe` "Right (JSAstStatement (JSGenerator 'x' (JSIdentifier 'a',JSIdentifier 'b') (JSBlock [])))" 126 | testStmt "function* x(a,...b){}" `shouldBe` "Right (JSAstStatement (JSGenerator 'x' (JSIdentifier 'a',JSSpreadExpression (JSIdentifier 'b')) (JSBlock [])))" 127 | 128 | it "class" $ do 129 | testStmt "class Foo extends Bar { a(x,y) {} *b() {} }" `shouldBe` "Right (JSAstStatement (JSClass 'Foo' (JSIdentifier 'Bar') [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock []),JSGeneratorMethodDefinition (JSIdentifier 'b') () (JSBlock [])]))" 130 | testStmt "class Foo { static get [a]() {}; }" `shouldBe` "Right (JSAstStatement (JSClass 'Foo' () [JSClassStaticMethod (JSPropertyAccessor JSAccessorGet (JSPropertyComputed (JSIdentifier 'a')) () (JSBlock [])),JSClassSemi]))" 131 | testStmt "class Foo extends Bar { a(x,y) { super[x](y); } }" `shouldBe` "Right (JSAstStatement (JSClass 'Foo' (JSIdentifier 'Bar') [JSMethodDefinition (JSIdentifier 'a') (JSIdentifier 'x',JSIdentifier 'y') (JSBlock [JSMethodCall (JSMemberSquare (JSLiteral 'super',JSIdentifier 'x'),JSArguments (JSIdentifier 'y')),JSSemicolon])]))" 132 | 133 | 134 | testStmt :: String -> String 135 | testStmt str = showStrippedMaybe (parseUsing parseStatement str "src") 136 | -------------------------------------------------------------------------------- /test/Unicode.js: -------------------------------------------------------------------------------- 1 | // -*- coding: utf-8 -*- 2 | 3 | àáâãäå = 1; 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/k.js: -------------------------------------------------------------------------------- 1 | function f() {} 2 | -------------------------------------------------------------------------------- /test/testsuite.hs: -------------------------------------------------------------------------------- 1 | 2 | import Control.Monad (when) 3 | import System.Exit 4 | import Test.Hspec 5 | import Test.Hspec.Runner 6 | 7 | 8 | import Test.Language.Javascript.ExpressionParser 9 | import Test.Language.Javascript.Lexer 10 | import Test.Language.Javascript.LiteralParser 11 | import Test.Language.Javascript.Minify 12 | import Test.Language.Javascript.ModuleParser 13 | import Test.Language.Javascript.ProgramParser 14 | import Test.Language.Javascript.RoundTrip 15 | import Test.Language.Javascript.StatementParser 16 | 17 | 18 | main :: IO () 19 | main = do 20 | summary <- hspecWithResult defaultConfig testAll 21 | when (summaryFailures summary == 0) 22 | exitSuccess 23 | exitFailure 24 | 25 | 26 | testAll :: Spec 27 | testAll = do 28 | testLexer 29 | testLiteralParser 30 | testExpressionParser 31 | testStatementParser 32 | testProgramParser 33 | testModuleParser 34 | testRoundTrip 35 | testMinifyExpr 36 | testMinifyStmt 37 | testMinifyProg 38 | testMinifyModule 39 | -------------------------------------------------------------------------------- /test/unicode.txt: -------------------------------------------------------------------------------- 1 | -*- coding: utf-8; mode: xub -*- 2 | ¢ € ₠ £ ¥ ¤ 3 | ° © ® ™ § ¶ † ‡ ※ 4 | •◦ ‣ ✓ ●■◆ ○□◇ ★☆ ♠♣♥♦ ♤♧♡♢ 5 | “” ‘’ ¿¡ «» ‹› ¶§ª - ‐ ‑ ‒ – — ― … 6 | àáâãäåæç èéêë ìíîï ðñòóôõö øùúûüýþÿ ÀÁÂÃÄÅ Ç ÈÉÊË ÌÍÎÏ ÐÑ ÒÓÔÕÖ ØÙÚÛÜÝÞß 7 | Æ ᴁ ᴂ ᴈ 8 | ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω 9 | ⌈⌉ ⌊⌋ ∏ ∑ ∫ ×÷ ⊕ ⊖ ⊗ ⊘ ⊙ ∙ ∘ ′ ″ ‴ ∼ ∂ √ ≔ × ⁱ ⁰ ¹ ² ³ ₀ ₁ ₂ 10 | π ∞ ± ∎ 11 | ∀¬∧∨∃⊦∵∴∅∈∉⊂⊃⊆⊇⊄⋂⋃ 12 | ≠≤≥≮≯≫≪≈≡ 13 | ℕℤℚℝℂ 14 | ←→↑↓ ↔ ↖↗↙↘ ⇐⇒⇑⇓ ⇔⇗ ⇦⇨⇧⇩ ↞↠↟↡ ↺↻ ☞☜☝☟ 15 | λ ƒ Ɱ 16 | ⌘ ⌥ ‸ ⇧ ⌤ ↑ ↓ → ← ⇞ ⇟ ↖ ↘ ⌫ ⌦ ⎋⏏ ↶↷ ◀▶▲▼ ◁▷△▽ ⇄ ⇤⇥ ↹ ↵↩⏎ ⌧ ⌨ ␣ ⌶ ⎗⎘⎙⎚ ⌚⌛ ✂✄ ✉✍ 17 | 18 | ♩♪♫♬♭♮♯ 19 | ➀➁➂➃➄➅➆➇➈➉ 20 | 卐卍✝✚✡☥⎈☭☪☮☺☹ ☯☰☱☲☳☴☵☶☷ ☠☢☣☤♲♳⌬♨♿ ☉☼☾☽ ♀♂ ♔♕♖ ♗♘♙ ♚♛ ♜♝♞♟ 21 | ❦ 22 |  、。!,:「」『』〈〉《》〖〗【】〔〕 23 | 24 | ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ 25 | 26 | 林花謝了春紅 太匆匆, 無奈朝來寒雨 晚來風 27 | 胭脂淚 留人醉 幾時重, 自是人生長恨 水長東 28 | 29 | http://xahlee.org/emacs/unicode-browser.html 30 | http://xahlee.org/Periodic_dosage_dir/t1/20040505_unicode.html 31 | -------------------------------------------------------------------------------- /unicode/combiningmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # UnicodeCombiningMark 4 | # any character in the Unicode categories “Non-spacing mark (Mn)” or “Combining spacing mark (Mc)” 5 | 6 | wget -c 'http://www.fileformat.info/info/unicode/category/Mn/list.htm?mode=print' -O uc-mn.htm 7 | wget -c 'http://www.fileformat.info/info/unicode/category/Mc/list.htm?mode=print' -O uc-mc.htm 8 | 9 | grep --no-filename -o -E "U\+[0-9a-fA-F]+" uc-m*.htm | sort > list-cm.txt 10 | -------------------------------------------------------------------------------- /unicode/connector-punctuation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | # UnicodeConnectorPunctuation 5 | # any character in the Unicode category “Connector punctuation (Pc)” 6 | 7 | wget -c 'http://www.fileformat.info/info/unicode/category/Pc/list.htm?mode=print' -O uc-pc.htm 8 | 9 | grep --no-filename -o -E "U\+[0-9a-fA-F]+" uc-pc.htm | sort > list-pc.txt 10 | -------------------------------------------------------------------------------- /unicode/digit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # UnicodeDigit 4 | # any character in the Unicode category “Decimal number (Nd)” 5 | 6 | wget -c 'http://www.fileformat.info/info/unicode/category/Nd/list.htm?mode=print' -O uc-nd.htm 7 | 8 | grep --no-filename -o -E "U\+[0-9a-fA-F]+" uc-nd.htm | sort > list-nd.txt 9 | -------------------------------------------------------------------------------- /unicode/doit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Identifier characters 4 | # UnicodeLetter 5 | # any character in the Unicode categories “Uppercase letter (Lu)”, “Lowercase letter (Ll)”, 6 | # “Titlecase letter (Lt)”, “Modifier letter (Lm)”, “Other letter (Lo)”, or “Letter number (Nl)”. 7 | 8 | wget -c 'http://www.fileformat.info/info/unicode/category/Lu/list.htm?mode=print' -O uc-lu.htm 9 | wget -c 'http://www.fileformat.info/info/unicode/category/Ll/list.htm?mode=print' -O uc-ll.htm 10 | wget -c 'http://www.fileformat.info/info/unicode/category/Lt/list.htm?mode=print' -O uc-lt.htm 11 | wget -c 'http://www.fileformat.info/info/unicode/category/Lm/list.htm?mode=print' -O uc-lm.htm 12 | wget -c 'http://www.fileformat.info/info/unicode/category/Lo/list.htm?mode=print' -O uc-lo.htm 13 | wget -c 'http://www.fileformat.info/info/unicode/category/Nl/list.htm?mode=print' -O uc-nl.htm 14 | 15 | grep --no-filename -o -E "U\+[0-9a-fA-F]+" uc-*.htm | sort > list.txt 16 | -------------------------------------------------------------------------------- /unicode/list-cm.txt: -------------------------------------------------------------------------------- 1 | U+0300 2 | U+0301 3 | U+0302 4 | U+0303 5 | U+0304 6 | U+0305 7 | U+0306 8 | U+0307 9 | U+0308 10 | U+0309 11 | U+030A 12 | U+030B 13 | U+030C 14 | U+030D 15 | U+030E 16 | U+030F 17 | U+0310 18 | U+0311 19 | U+0312 20 | U+0313 21 | U+0314 22 | U+0315 23 | U+0316 24 | U+0317 25 | U+0318 26 | U+0319 27 | U+031A 28 | U+031B 29 | U+031C 30 | U+031D 31 | U+031E 32 | U+031F 33 | U+0320 34 | U+0321 35 | U+0322 36 | U+0323 37 | U+0324 38 | U+0325 39 | U+0326 40 | U+0327 41 | U+0328 42 | U+0329 43 | U+032A 44 | U+032B 45 | U+032C 46 | U+032D 47 | U+032E 48 | U+032F 49 | U+0330 50 | U+0331 51 | U+0332 52 | U+0333 53 | U+0334 54 | U+0335 55 | U+0336 56 | U+0337 57 | U+0338 58 | U+0339 59 | U+033A 60 | U+033B 61 | U+033C 62 | U+033D 63 | U+033E 64 | U+033F 65 | U+0340 66 | U+0341 67 | U+0342 68 | U+0343 69 | U+0344 70 | U+0345 71 | U+0346 72 | U+0347 73 | U+0348 74 | U+0349 75 | U+034A 76 | U+034B 77 | U+034C 78 | U+034D 79 | U+034E 80 | U+034F 81 | U+0350 82 | U+0351 83 | U+0352 84 | U+0353 85 | U+0354 86 | U+0355 87 | U+0356 88 | U+0357 89 | U+0358 90 | U+0359 91 | U+035A 92 | U+035B 93 | U+035C 94 | U+035D 95 | U+035E 96 | U+035F 97 | U+0360 98 | U+0361 99 | U+0362 100 | U+0363 101 | U+0364 102 | U+0365 103 | U+0366 104 | U+0367 105 | U+0368 106 | U+0369 107 | U+036A 108 | U+036B 109 | U+036C 110 | U+036D 111 | U+036E 112 | U+036F 113 | U+0483 114 | U+0484 115 | U+0485 116 | U+0486 117 | U+0487 118 | U+0591 119 | U+0592 120 | U+0593 121 | U+0594 122 | U+0595 123 | U+0596 124 | U+0597 125 | U+0598 126 | U+0599 127 | U+059A 128 | U+059B 129 | U+059C 130 | U+059D 131 | U+059E 132 | U+059F 133 | U+05A0 134 | U+05A1 135 | U+05A2 136 | U+05A3 137 | U+05A4 138 | U+05A5 139 | U+05A6 140 | U+05A7 141 | U+05A8 142 | U+05A9 143 | U+05AA 144 | U+05AB 145 | U+05AC 146 | U+05AD 147 | U+05AE 148 | U+05AF 149 | U+05B0 150 | U+05B1 151 | U+05B2 152 | U+05B3 153 | U+05B4 154 | U+05B5 155 | U+05B6 156 | U+05B7 157 | U+05B8 158 | U+05B9 159 | U+05BA 160 | U+05BB 161 | U+05BC 162 | U+05BD 163 | U+05BF 164 | U+05C1 165 | U+05C2 166 | U+05C4 167 | U+05C5 168 | U+05C7 169 | U+0610 170 | U+0611 171 | U+0612 172 | U+0613 173 | U+0614 174 | U+0615 175 | U+0616 176 | U+0617 177 | U+0618 178 | U+0619 179 | U+061A 180 | U+064B 181 | U+064C 182 | U+064D 183 | U+064E 184 | U+064F 185 | U+0650 186 | U+0651 187 | U+0652 188 | U+0653 189 | U+0654 190 | U+0655 191 | U+0656 192 | U+0657 193 | U+0658 194 | U+0659 195 | U+065A 196 | U+065B 197 | U+065C 198 | U+065D 199 | U+065E 200 | U+065F 201 | U+0670 202 | U+06D6 203 | U+06D7 204 | U+06D8 205 | U+06D9 206 | U+06DA 207 | U+06DB 208 | U+06DC 209 | U+06DF 210 | U+06E0 211 | U+06E1 212 | U+06E2 213 | U+06E3 214 | U+06E4 215 | U+06E7 216 | U+06E8 217 | U+06EA 218 | U+06EB 219 | U+06EC 220 | U+06ED 221 | U+0711 222 | U+0730 223 | U+0731 224 | U+0732 225 | U+0733 226 | U+0734 227 | U+0735 228 | U+0736 229 | U+0737 230 | U+0738 231 | U+0739 232 | U+073A 233 | U+073B 234 | U+073C 235 | U+073D 236 | U+073E 237 | U+073F 238 | U+0740 239 | U+0741 240 | U+0742 241 | U+0743 242 | U+0744 243 | U+0745 244 | U+0746 245 | U+0747 246 | U+0748 247 | U+0749 248 | U+074A 249 | U+07A6 250 | U+07A7 251 | U+07A8 252 | U+07A9 253 | U+07AA 254 | U+07AB 255 | U+07AC 256 | U+07AD 257 | U+07AE 258 | U+07AF 259 | U+07B0 260 | U+07EB 261 | U+07EC 262 | U+07ED 263 | U+07EE 264 | U+07EF 265 | U+07F0 266 | U+07F1 267 | U+07F2 268 | U+07F3 269 | U+0816 270 | U+0817 271 | U+0818 272 | U+0819 273 | U+081B 274 | U+081C 275 | U+081D 276 | U+081E 277 | U+081F 278 | U+0820 279 | U+0821 280 | U+0822 281 | U+0823 282 | U+0825 283 | U+0826 284 | U+0827 285 | U+0829 286 | U+082A 287 | U+082B 288 | U+082C 289 | U+082D 290 | U+0859 291 | U+085A 292 | U+085B 293 | U+0900 294 | U+0901 295 | U+0902 296 | U+0903 297 | U+093A 298 | U+093B 299 | U+093C 300 | U+093E 301 | U+093F 302 | U+0940 303 | U+0941 304 | U+0942 305 | U+0943 306 | U+0944 307 | U+0945 308 | U+0946 309 | U+0947 310 | U+0948 311 | U+0949 312 | U+094A 313 | U+094B 314 | U+094C 315 | U+094D 316 | U+094E 317 | U+094F 318 | U+0951 319 | U+0952 320 | U+0953 321 | U+0954 322 | U+0955 323 | U+0956 324 | U+0957 325 | U+0962 326 | U+0963 327 | U+0981 328 | U+0982 329 | U+0983 330 | U+09BC 331 | U+09BE 332 | U+09BF 333 | U+09C0 334 | U+09C1 335 | U+09C2 336 | U+09C3 337 | U+09C4 338 | U+09C7 339 | U+09C8 340 | U+09CB 341 | U+09CC 342 | U+09CD 343 | U+09D7 344 | U+09E2 345 | U+09E3 346 | U+0A01 347 | U+0A02 348 | U+0A03 349 | U+0A3C 350 | U+0A3E 351 | U+0A3F 352 | U+0A40 353 | U+0A41 354 | U+0A42 355 | U+0A47 356 | U+0A48 357 | U+0A4B 358 | U+0A4C 359 | U+0A4D 360 | U+0A51 361 | U+0A70 362 | U+0A71 363 | U+0A75 364 | U+0A81 365 | U+0A82 366 | U+0A83 367 | U+0ABC 368 | U+0ABE 369 | U+0ABF 370 | U+0AC0 371 | U+0AC1 372 | U+0AC2 373 | U+0AC3 374 | U+0AC4 375 | U+0AC5 376 | U+0AC7 377 | U+0AC8 378 | U+0AC9 379 | U+0ACB 380 | U+0ACC 381 | U+0ACD 382 | U+0AE2 383 | U+0AE3 384 | U+0B01 385 | U+0B02 386 | U+0B03 387 | U+0B3C 388 | U+0B3E 389 | U+0B3F 390 | U+0B40 391 | U+0B41 392 | U+0B42 393 | U+0B43 394 | U+0B44 395 | U+0B47 396 | U+0B48 397 | U+0B4B 398 | U+0B4C 399 | U+0B4D 400 | U+0B56 401 | U+0B57 402 | U+0B62 403 | U+0B63 404 | U+0B82 405 | U+0BBE 406 | U+0BBF 407 | U+0BC0 408 | U+0BC1 409 | U+0BC2 410 | U+0BC6 411 | U+0BC7 412 | U+0BC8 413 | U+0BCA 414 | U+0BCB 415 | U+0BCC 416 | U+0BCD 417 | U+0BD7 418 | U+0C01 419 | U+0C02 420 | U+0C03 421 | U+0C3E 422 | U+0C3F 423 | U+0C40 424 | U+0C41 425 | U+0C42 426 | U+0C43 427 | U+0C44 428 | U+0C46 429 | U+0C47 430 | U+0C48 431 | U+0C4A 432 | U+0C4B 433 | U+0C4C 434 | U+0C4D 435 | U+0C55 436 | U+0C56 437 | U+0C62 438 | U+0C63 439 | U+0C82 440 | U+0C83 441 | U+0CBC 442 | U+0CBE 443 | U+0CBF 444 | U+0CC0 445 | U+0CC1 446 | U+0CC2 447 | U+0CC3 448 | U+0CC4 449 | U+0CC6 450 | U+0CC7 451 | U+0CC8 452 | U+0CCA 453 | U+0CCB 454 | U+0CCC 455 | U+0CCD 456 | U+0CD5 457 | U+0CD6 458 | U+0CE2 459 | U+0CE3 460 | U+0D02 461 | U+0D03 462 | U+0D3E 463 | U+0D3F 464 | U+0D40 465 | U+0D41 466 | U+0D42 467 | U+0D43 468 | U+0D44 469 | U+0D46 470 | U+0D47 471 | U+0D48 472 | U+0D4A 473 | U+0D4B 474 | U+0D4C 475 | U+0D4D 476 | U+0D57 477 | U+0D62 478 | U+0D63 479 | U+0D82 480 | U+0D83 481 | U+0DCA 482 | U+0DCF 483 | U+0DD0 484 | U+0DD1 485 | U+0DD2 486 | U+0DD3 487 | U+0DD4 488 | U+0DD6 489 | U+0DD8 490 | U+0DD9 491 | U+0DDA 492 | U+0DDB 493 | U+0DDC 494 | U+0DDD 495 | U+0DDE 496 | U+0DDF 497 | U+0DF2 498 | U+0DF3 499 | U+0E31 500 | U+0E34 501 | U+0E35 502 | U+0E36 503 | U+0E37 504 | U+0E38 505 | U+0E39 506 | U+0E3A 507 | U+0E47 508 | U+0E48 509 | U+0E49 510 | U+0E4A 511 | U+0E4B 512 | U+0E4C 513 | U+0E4D 514 | U+0E4E 515 | U+0EB1 516 | U+0EB4 517 | U+0EB5 518 | U+0EB6 519 | U+0EB7 520 | U+0EB8 521 | U+0EB9 522 | U+0EBB 523 | U+0EBC 524 | U+0EC8 525 | U+0EC9 526 | U+0ECA 527 | U+0ECB 528 | U+0ECC 529 | U+0ECD 530 | U+0F18 531 | U+0F19 532 | U+0F35 533 | U+0F37 534 | U+0F39 535 | U+0F3E 536 | U+0F3F 537 | U+0F71 538 | U+0F72 539 | U+0F73 540 | U+0F74 541 | U+0F75 542 | U+0F76 543 | U+0F77 544 | U+0F78 545 | U+0F79 546 | U+0F7A 547 | U+0F7B 548 | U+0F7C 549 | U+0F7D 550 | U+0F7E 551 | U+0F7F 552 | U+0F80 553 | U+0F81 554 | U+0F82 555 | U+0F83 556 | U+0F84 557 | U+0F86 558 | U+0F87 559 | U+0F8D 560 | U+0F8E 561 | U+0F8F 562 | U+0F90 563 | U+0F91 564 | U+0F92 565 | U+0F93 566 | U+0F94 567 | U+0F95 568 | U+0F96 569 | U+0F97 570 | U+0F99 571 | U+0F9A 572 | U+0F9B 573 | U+0F9C 574 | U+0F9D 575 | U+0F9E 576 | U+0F9F 577 | U+0FA0 578 | U+0FA1 579 | U+0FA2 580 | U+0FA3 581 | U+0FA4 582 | U+0FA5 583 | U+0FA6 584 | U+0FA7 585 | U+0FA8 586 | U+0FA9 587 | U+0FAA 588 | U+0FAB 589 | U+0FAC 590 | U+0FAD 591 | U+0FAE 592 | U+0FAF 593 | U+0FB0 594 | U+0FB1 595 | U+0FB2 596 | U+0FB3 597 | U+0FB4 598 | U+0FB5 599 | U+0FB6 600 | U+0FB7 601 | U+0FB8 602 | U+0FB9 603 | U+0FBA 604 | U+0FBB 605 | U+0FBC 606 | U+0FC6 607 | U+101FD 608 | U+102B 609 | U+102C 610 | U+102D 611 | U+102E 612 | U+102F 613 | U+1030 614 | U+1031 615 | U+1032 616 | U+1033 617 | U+1034 618 | U+1035 619 | U+1036 620 | U+1037 621 | U+1038 622 | U+1039 623 | U+103A 624 | U+103B 625 | U+103C 626 | U+103D 627 | U+103E 628 | U+1056 629 | U+1057 630 | U+1058 631 | U+1059 632 | U+105E 633 | U+105F 634 | U+1060 635 | U+1062 636 | U+1063 637 | U+1064 638 | U+1067 639 | U+1068 640 | U+1069 641 | U+106A 642 | U+106B 643 | U+106C 644 | U+106D 645 | U+1071 646 | U+1072 647 | U+1073 648 | U+1074 649 | U+1082 650 | U+1083 651 | U+1084 652 | U+1085 653 | U+1086 654 | U+1087 655 | U+1088 656 | U+1089 657 | U+108A 658 | U+108B 659 | U+108C 660 | U+108D 661 | U+108F 662 | U+109A 663 | U+109B 664 | U+109C 665 | U+109D 666 | U+10A01 667 | U+10A02 668 | U+10A03 669 | U+10A05 670 | U+10A06 671 | U+10A0C 672 | U+10A0D 673 | U+10A0E 674 | U+10A0F 675 | U+10A38 676 | U+10A39 677 | U+10A3A 678 | U+10A3F 679 | U+11000 680 | U+11001 681 | U+11002 682 | U+11038 683 | U+11039 684 | U+1103A 685 | U+1103B 686 | U+1103C 687 | U+1103D 688 | U+1103E 689 | U+1103F 690 | U+11040 691 | U+11041 692 | U+11042 693 | U+11043 694 | U+11044 695 | U+11045 696 | U+11046 697 | U+11080 698 | U+11081 699 | U+11082 700 | U+110B0 701 | U+110B1 702 | U+110B2 703 | U+110B3 704 | U+110B4 705 | U+110B5 706 | U+110B6 707 | U+110B7 708 | U+110B8 709 | U+110B9 710 | U+110BA 711 | U+135D 712 | U+135E 713 | U+135F 714 | U+1712 715 | U+1713 716 | U+1714 717 | U+1732 718 | U+1733 719 | U+1734 720 | U+1752 721 | U+1753 722 | U+1772 723 | U+1773 724 | U+17B6 725 | U+17B7 726 | U+17B8 727 | U+17B9 728 | U+17BA 729 | U+17BB 730 | U+17BC 731 | U+17BD 732 | U+17BE 733 | U+17BF 734 | U+17C0 735 | U+17C1 736 | U+17C2 737 | U+17C3 738 | U+17C4 739 | U+17C5 740 | U+17C6 741 | U+17C7 742 | U+17C8 743 | U+17C9 744 | U+17CA 745 | U+17CB 746 | U+17CC 747 | U+17CD 748 | U+17CE 749 | U+17CF 750 | U+17D0 751 | U+17D1 752 | U+17D2 753 | U+17D3 754 | U+17DD 755 | U+180B 756 | U+180C 757 | U+180D 758 | U+18A9 759 | U+1920 760 | U+1921 761 | U+1922 762 | U+1923 763 | U+1924 764 | U+1925 765 | U+1926 766 | U+1927 767 | U+1928 768 | U+1929 769 | U+192A 770 | U+192B 771 | U+1930 772 | U+1931 773 | U+1932 774 | U+1933 775 | U+1934 776 | U+1935 777 | U+1936 778 | U+1937 779 | U+1938 780 | U+1939 781 | U+193A 782 | U+193B 783 | U+19B0 784 | U+19B1 785 | U+19B2 786 | U+19B3 787 | U+19B4 788 | U+19B5 789 | U+19B6 790 | U+19B7 791 | U+19B8 792 | U+19B9 793 | U+19BA 794 | U+19BB 795 | U+19BC 796 | U+19BD 797 | U+19BE 798 | U+19BF 799 | U+19C0 800 | U+19C8 801 | U+19C9 802 | U+1A17 803 | U+1A18 804 | U+1A19 805 | U+1A1A 806 | U+1A1B 807 | U+1A55 808 | U+1A56 809 | U+1A57 810 | U+1A58 811 | U+1A59 812 | U+1A5A 813 | U+1A5B 814 | U+1A5C 815 | U+1A5D 816 | U+1A5E 817 | U+1A60 818 | U+1A61 819 | U+1A62 820 | U+1A63 821 | U+1A64 822 | U+1A65 823 | U+1A66 824 | U+1A67 825 | U+1A68 826 | U+1A69 827 | U+1A6A 828 | U+1A6B 829 | U+1A6C 830 | U+1A6D 831 | U+1A6E 832 | U+1A6F 833 | U+1A70 834 | U+1A71 835 | U+1A72 836 | U+1A73 837 | U+1A74 838 | U+1A75 839 | U+1A76 840 | U+1A77 841 | U+1A78 842 | U+1A79 843 | U+1A7A 844 | U+1A7B 845 | U+1A7C 846 | U+1A7F 847 | U+1B00 848 | U+1B01 849 | U+1B02 850 | U+1B03 851 | U+1B04 852 | U+1B34 853 | U+1B35 854 | U+1B36 855 | U+1B37 856 | U+1B38 857 | U+1B39 858 | U+1B3A 859 | U+1B3B 860 | U+1B3C 861 | U+1B3D 862 | U+1B3E 863 | U+1B3F 864 | U+1B40 865 | U+1B41 866 | U+1B42 867 | U+1B43 868 | U+1B44 869 | U+1B6B 870 | U+1B6C 871 | U+1B6D 872 | U+1B6E 873 | U+1B6F 874 | U+1B70 875 | U+1B71 876 | U+1B72 877 | U+1B73 878 | U+1B80 879 | U+1B81 880 | U+1B82 881 | U+1BA1 882 | U+1BA2 883 | U+1BA3 884 | U+1BA4 885 | U+1BA5 886 | U+1BA6 887 | U+1BA7 888 | U+1BA8 889 | U+1BA9 890 | U+1BAA 891 | U+1BE6 892 | U+1BE7 893 | U+1BE8 894 | U+1BE9 895 | U+1BEA 896 | U+1BEB 897 | U+1BEC 898 | U+1BED 899 | U+1BEE 900 | U+1BEF 901 | U+1BF0 902 | U+1BF1 903 | U+1BF2 904 | U+1BF3 905 | U+1C24 906 | U+1C25 907 | U+1C26 908 | U+1C27 909 | U+1C28 910 | U+1C29 911 | U+1C2A 912 | U+1C2B 913 | U+1C2C 914 | U+1C2D 915 | U+1C2E 916 | U+1C2F 917 | U+1C30 918 | U+1C31 919 | U+1C32 920 | U+1C33 921 | U+1C34 922 | U+1C35 923 | U+1C36 924 | U+1C37 925 | U+1CD0 926 | U+1CD1 927 | U+1CD2 928 | U+1CD4 929 | U+1CD5 930 | U+1CD6 931 | U+1CD7 932 | U+1CD8 933 | U+1CD9 934 | U+1CDA 935 | U+1CDB 936 | U+1CDC 937 | U+1CDD 938 | U+1CDE 939 | U+1CDF 940 | U+1CE0 941 | U+1CE1 942 | U+1CE2 943 | U+1CE3 944 | U+1CE4 945 | U+1CE5 946 | U+1CE6 947 | U+1CE7 948 | U+1CE8 949 | U+1CED 950 | U+1CF2 951 | U+1D165 952 | U+1D166 953 | U+1D167 954 | U+1D168 955 | U+1D169 956 | U+1D16D 957 | U+1D16E 958 | U+1D16F 959 | U+1D170 960 | U+1D171 961 | U+1D172 962 | U+1D17B 963 | U+1D17C 964 | U+1D17D 965 | U+1D17E 966 | U+1D17F 967 | U+1D180 968 | U+1D181 969 | U+1D182 970 | U+1D185 971 | U+1D186 972 | U+1D187 973 | U+1D188 974 | U+1D189 975 | U+1D18A 976 | U+1D18B 977 | U+1D1AA 978 | U+1D1AB 979 | U+1D1AC 980 | U+1D1AD 981 | U+1D242 982 | U+1D243 983 | U+1D244 984 | U+1DC0 985 | U+1DC1 986 | U+1DC2 987 | U+1DC3 988 | U+1DC4 989 | U+1DC5 990 | U+1DC6 991 | U+1DC7 992 | U+1DC8 993 | U+1DC9 994 | U+1DCA 995 | U+1DCB 996 | U+1DCC 997 | U+1DCD 998 | U+1DCE 999 | U+1DCF 1000 | U+1DD0 1001 | U+1DD1 1002 | U+1DD2 1003 | U+1DD3 1004 | U+1DD4 1005 | U+1DD5 1006 | U+1DD6 1007 | U+1DD7 1008 | U+1DD8 1009 | U+1DD9 1010 | U+1DDA 1011 | U+1DDB 1012 | U+1DDC 1013 | U+1DDD 1014 | U+1DDE 1015 | U+1DDF 1016 | U+1DE0 1017 | U+1DE1 1018 | U+1DE2 1019 | U+1DE3 1020 | U+1DE4 1021 | U+1DE5 1022 | U+1DE6 1023 | U+1DFC 1024 | U+1DFD 1025 | U+1DFE 1026 | U+1DFF 1027 | U+20D0 1028 | U+20D1 1029 | U+20D2 1030 | U+20D3 1031 | U+20D4 1032 | U+20D5 1033 | U+20D6 1034 | U+20D7 1035 | U+20D8 1036 | U+20D9 1037 | U+20DA 1038 | U+20DB 1039 | U+20DC 1040 | U+20E1 1041 | U+20E5 1042 | U+20E6 1043 | U+20E7 1044 | U+20E8 1045 | U+20E9 1046 | U+20EA 1047 | U+20EB 1048 | U+20EC 1049 | U+20ED 1050 | U+20EE 1051 | U+20EF 1052 | U+20F0 1053 | U+2CEF 1054 | U+2CF0 1055 | U+2CF1 1056 | U+2D7F 1057 | U+2DE0 1058 | U+2DE1 1059 | U+2DE2 1060 | U+2DE3 1061 | U+2DE4 1062 | U+2DE5 1063 | U+2DE6 1064 | U+2DE7 1065 | U+2DE8 1066 | U+2DE9 1067 | U+2DEA 1068 | U+2DEB 1069 | U+2DEC 1070 | U+2DED 1071 | U+2DEE 1072 | U+2DEF 1073 | U+2DF0 1074 | U+2DF1 1075 | U+2DF2 1076 | U+2DF3 1077 | U+2DF4 1078 | U+2DF5 1079 | U+2DF6 1080 | U+2DF7 1081 | U+2DF8 1082 | U+2DF9 1083 | U+2DFA 1084 | U+2DFB 1085 | U+2DFC 1086 | U+2DFD 1087 | U+2DFE 1088 | U+2DFF 1089 | U+302A 1090 | U+302B 1091 | U+302C 1092 | U+302D 1093 | U+302E 1094 | U+302F 1095 | U+3099 1096 | U+309A 1097 | U+A66F 1098 | U+A67C 1099 | U+A67D 1100 | U+A6F0 1101 | U+A6F1 1102 | U+A802 1103 | U+A806 1104 | U+A80B 1105 | U+A823 1106 | U+A824 1107 | U+A825 1108 | U+A826 1109 | U+A827 1110 | U+A880 1111 | U+A881 1112 | U+A8B4 1113 | U+A8B5 1114 | U+A8B6 1115 | U+A8B7 1116 | U+A8B8 1117 | U+A8B9 1118 | U+A8BA 1119 | U+A8BB 1120 | U+A8BC 1121 | U+A8BD 1122 | U+A8BE 1123 | U+A8BF 1124 | U+A8C0 1125 | U+A8C1 1126 | U+A8C2 1127 | U+A8C3 1128 | U+A8C4 1129 | U+A8E0 1130 | U+A8E1 1131 | U+A8E2 1132 | U+A8E3 1133 | U+A8E4 1134 | U+A8E5 1135 | U+A8E6 1136 | U+A8E7 1137 | U+A8E8 1138 | U+A8E9 1139 | U+A8EA 1140 | U+A8EB 1141 | U+A8EC 1142 | U+A8ED 1143 | U+A8EE 1144 | U+A8EF 1145 | U+A8F0 1146 | U+A8F1 1147 | U+A926 1148 | U+A927 1149 | U+A928 1150 | U+A929 1151 | U+A92A 1152 | U+A92B 1153 | U+A92C 1154 | U+A92D 1155 | U+A947 1156 | U+A948 1157 | U+A949 1158 | U+A94A 1159 | U+A94B 1160 | U+A94C 1161 | U+A94D 1162 | U+A94E 1163 | U+A94F 1164 | U+A950 1165 | U+A951 1166 | U+A952 1167 | U+A953 1168 | U+A980 1169 | U+A981 1170 | U+A982 1171 | U+A983 1172 | U+A9B3 1173 | U+A9B4 1174 | U+A9B5 1175 | U+A9B6 1176 | U+A9B7 1177 | U+A9B8 1178 | U+A9B9 1179 | U+A9BA 1180 | U+A9BB 1181 | U+A9BC 1182 | U+A9BD 1183 | U+A9BE 1184 | U+A9BF 1185 | U+A9C0 1186 | U+AA29 1187 | U+AA2A 1188 | U+AA2B 1189 | U+AA2C 1190 | U+AA2D 1191 | U+AA2E 1192 | U+AA2F 1193 | U+AA30 1194 | U+AA31 1195 | U+AA32 1196 | U+AA33 1197 | U+AA34 1198 | U+AA35 1199 | U+AA36 1200 | U+AA43 1201 | U+AA4C 1202 | U+AA4D 1203 | U+AA7B 1204 | U+AAB0 1205 | U+AAB2 1206 | U+AAB3 1207 | U+AAB4 1208 | U+AAB7 1209 | U+AAB8 1210 | U+AABE 1211 | U+AABF 1212 | U+AAC1 1213 | U+ABE3 1214 | U+ABE4 1215 | U+ABE5 1216 | U+ABE6 1217 | U+ABE7 1218 | U+ABE8 1219 | U+ABE9 1220 | U+ABEA 1221 | U+ABEC 1222 | U+ABED 1223 | U+E0100 1224 | U+E0101 1225 | U+E0102 1226 | U+E0103 1227 | U+E0104 1228 | U+E0105 1229 | U+E0106 1230 | U+E0107 1231 | U+E0108 1232 | U+E0109 1233 | U+E010A 1234 | U+E010B 1235 | U+E010C 1236 | U+E010D 1237 | U+E010E 1238 | U+E010F 1239 | U+E0110 1240 | U+E0111 1241 | U+E0112 1242 | U+E0113 1243 | U+E0114 1244 | U+E0115 1245 | U+E0116 1246 | U+E0117 1247 | U+E0118 1248 | U+E0119 1249 | U+E011A 1250 | U+E011B 1251 | U+E011C 1252 | U+E011D 1253 | U+E011E 1254 | U+E011F 1255 | U+E0120 1256 | U+E0121 1257 | U+E0122 1258 | U+E0123 1259 | U+E0124 1260 | U+E0125 1261 | U+E0126 1262 | U+E0127 1263 | U+E0128 1264 | U+E0129 1265 | U+E012A 1266 | U+E012B 1267 | U+E012C 1268 | U+E012D 1269 | U+E012E 1270 | U+E012F 1271 | U+E0130 1272 | U+E0131 1273 | U+E0132 1274 | U+E0133 1275 | U+E0134 1276 | U+E0135 1277 | U+E0136 1278 | U+E0137 1279 | U+E0138 1280 | U+E0139 1281 | U+E013A 1282 | U+E013B 1283 | U+E013C 1284 | U+E013D 1285 | U+E013E 1286 | U+E013F 1287 | U+E0140 1288 | U+E0141 1289 | U+E0142 1290 | U+E0143 1291 | U+E0144 1292 | U+E0145 1293 | U+E0146 1294 | U+E0147 1295 | U+E0148 1296 | U+E0149 1297 | U+E014A 1298 | U+E014B 1299 | U+E014C 1300 | U+E014D 1301 | U+E014E 1302 | U+E014F 1303 | U+E0150 1304 | U+E0151 1305 | U+E0152 1306 | U+E0153 1307 | U+E0154 1308 | U+E0155 1309 | U+E0156 1310 | U+E0157 1311 | U+E0158 1312 | U+E0159 1313 | U+E015A 1314 | U+E015B 1315 | U+E015C 1316 | U+E015D 1317 | U+E015E 1318 | U+E015F 1319 | U+E0160 1320 | U+E0161 1321 | U+E0162 1322 | U+E0163 1323 | U+E0164 1324 | U+E0165 1325 | U+E0166 1326 | U+E0167 1327 | U+E0168 1328 | U+E0169 1329 | U+E016A 1330 | U+E016B 1331 | U+E016C 1332 | U+E016D 1333 | U+E016E 1334 | U+E016F 1335 | U+E0170 1336 | U+E0171 1337 | U+E0172 1338 | U+E0173 1339 | U+E0174 1340 | U+E0175 1341 | U+E0176 1342 | U+E0177 1343 | U+E0178 1344 | U+E0179 1345 | U+E017A 1346 | U+E017B 1347 | U+E017C 1348 | U+E017D 1349 | U+E017E 1350 | U+E017F 1351 | U+E0180 1352 | U+E0181 1353 | U+E0182 1354 | U+E0183 1355 | U+E0184 1356 | U+E0185 1357 | U+E0186 1358 | U+E0187 1359 | U+E0188 1360 | U+E0189 1361 | U+E018A 1362 | U+E018B 1363 | U+E018C 1364 | U+E018D 1365 | U+E018E 1366 | U+E018F 1367 | U+E0190 1368 | U+E0191 1369 | U+E0192 1370 | U+E0193 1371 | U+E0194 1372 | U+E0195 1373 | U+E0196 1374 | U+E0197 1375 | U+E0198 1376 | U+E0199 1377 | U+E019A 1378 | U+E019B 1379 | U+E019C 1380 | U+E019D 1381 | U+E019E 1382 | U+E019F 1383 | U+E01A0 1384 | U+E01A1 1385 | U+E01A2 1386 | U+E01A3 1387 | U+E01A4 1388 | U+E01A5 1389 | U+E01A6 1390 | U+E01A7 1391 | U+E01A8 1392 | U+E01A9 1393 | U+E01AA 1394 | U+E01AB 1395 | U+E01AC 1396 | U+E01AD 1397 | U+E01AE 1398 | U+E01AF 1399 | U+E01B0 1400 | U+E01B1 1401 | U+E01B2 1402 | U+E01B3 1403 | U+E01B4 1404 | U+E01B5 1405 | U+E01B6 1406 | U+E01B7 1407 | U+E01B8 1408 | U+E01B9 1409 | U+E01BA 1410 | U+E01BB 1411 | U+E01BC 1412 | U+E01BD 1413 | U+E01BE 1414 | U+E01BF 1415 | U+E01C0 1416 | U+E01C1 1417 | U+E01C2 1418 | U+E01C3 1419 | U+E01C4 1420 | U+E01C5 1421 | U+E01C6 1422 | U+E01C7 1423 | U+E01C8 1424 | U+E01C9 1425 | U+E01CA 1426 | U+E01CB 1427 | U+E01CC 1428 | U+E01CD 1429 | U+E01CE 1430 | U+E01CF 1431 | U+E01D0 1432 | U+E01D1 1433 | U+E01D2 1434 | U+E01D3 1435 | U+E01D4 1436 | U+E01D5 1437 | U+E01D6 1438 | U+E01D7 1439 | U+E01D8 1440 | U+E01D9 1441 | U+E01DA 1442 | U+E01DB 1443 | U+E01DC 1444 | U+E01DD 1445 | U+E01DE 1446 | U+E01DF 1447 | U+E01E0 1448 | U+E01E1 1449 | U+E01E2 1450 | U+E01E3 1451 | U+E01E4 1452 | U+E01E5 1453 | U+E01E6 1454 | U+E01E7 1455 | U+E01E8 1456 | U+E01E9 1457 | U+E01EA 1458 | U+E01EB 1459 | U+E01EC 1460 | U+E01ED 1461 | U+E01EE 1462 | U+E01EF 1463 | U+FB1E 1464 | U+FE00 1465 | U+FE01 1466 | U+FE02 1467 | U+FE03 1468 | U+FE04 1469 | U+FE05 1470 | U+FE06 1471 | U+FE07 1472 | U+FE08 1473 | U+FE09 1474 | U+FE0A 1475 | U+FE0B 1476 | U+FE0C 1477 | U+FE0D 1478 | U+FE0E 1479 | U+FE0F 1480 | U+FE20 1481 | U+FE21 1482 | U+FE22 1483 | U+FE23 1484 | U+FE24 1485 | U+FE25 1486 | U+FE26 1487 | -------------------------------------------------------------------------------- /unicode/list-nd.txt: -------------------------------------------------------------------------------- 1 | U+0030 2 | U+0031 3 | U+0032 4 | U+0033 5 | U+0034 6 | U+0035 7 | U+0036 8 | U+0037 9 | U+0038 10 | U+0039 11 | U+0660 12 | U+0661 13 | U+0662 14 | U+0663 15 | U+0664 16 | U+0665 17 | U+0666 18 | U+0667 19 | U+0668 20 | U+0669 21 | U+06F0 22 | U+06F1 23 | U+06F2 24 | U+06F3 25 | U+06F4 26 | U+06F5 27 | U+06F6 28 | U+06F7 29 | U+06F8 30 | U+06F9 31 | U+07C0 32 | U+07C1 33 | U+07C2 34 | U+07C3 35 | U+07C4 36 | U+07C5 37 | U+07C6 38 | U+07C7 39 | U+07C8 40 | U+07C9 41 | U+0966 42 | U+0967 43 | U+0968 44 | U+0969 45 | U+096A 46 | U+096B 47 | U+096C 48 | U+096D 49 | U+096E 50 | U+096F 51 | U+09E6 52 | U+09E7 53 | U+09E8 54 | U+09E9 55 | U+09EA 56 | U+09EB 57 | U+09EC 58 | U+09ED 59 | U+09EE 60 | U+09EF 61 | U+0A66 62 | U+0A67 63 | U+0A68 64 | U+0A69 65 | U+0A6A 66 | U+0A6B 67 | U+0A6C 68 | U+0A6D 69 | U+0A6E 70 | U+0A6F 71 | U+0AE6 72 | U+0AE7 73 | U+0AE8 74 | U+0AE9 75 | U+0AEA 76 | U+0AEB 77 | U+0AEC 78 | U+0AED 79 | U+0AEE 80 | U+0AEF 81 | U+0B66 82 | U+0B67 83 | U+0B68 84 | U+0B69 85 | U+0B6A 86 | U+0B6B 87 | U+0B6C 88 | U+0B6D 89 | U+0B6E 90 | U+0B6F 91 | U+0BE6 92 | U+0BE7 93 | U+0BE8 94 | U+0BE9 95 | U+0BEA 96 | U+0BEB 97 | U+0BEC 98 | U+0BED 99 | U+0BEE 100 | U+0BEF 101 | U+0C66 102 | U+0C67 103 | U+0C68 104 | U+0C69 105 | U+0C6A 106 | U+0C6B 107 | U+0C6C 108 | U+0C6D 109 | U+0C6E 110 | U+0C6F 111 | U+0CE6 112 | U+0CE7 113 | U+0CE8 114 | U+0CE9 115 | U+0CEA 116 | U+0CEB 117 | U+0CEC 118 | U+0CED 119 | U+0CEE 120 | U+0CEF 121 | U+0D66 122 | U+0D67 123 | U+0D68 124 | U+0D69 125 | U+0D6A 126 | U+0D6B 127 | U+0D6C 128 | U+0D6D 129 | U+0D6E 130 | U+0D6F 131 | U+0E50 132 | U+0E51 133 | U+0E52 134 | U+0E53 135 | U+0E54 136 | U+0E55 137 | U+0E56 138 | U+0E57 139 | U+0E58 140 | U+0E59 141 | U+0ED0 142 | U+0ED1 143 | U+0ED2 144 | U+0ED3 145 | U+0ED4 146 | U+0ED5 147 | U+0ED6 148 | U+0ED7 149 | U+0ED8 150 | U+0ED9 151 | U+0F20 152 | U+0F21 153 | U+0F22 154 | U+0F23 155 | U+0F24 156 | U+0F25 157 | U+0F26 158 | U+0F27 159 | U+0F28 160 | U+0F29 161 | U+1040 162 | U+1041 163 | U+1042 164 | U+1043 165 | U+1044 166 | U+1045 167 | U+1046 168 | U+1047 169 | U+1048 170 | U+1049 171 | U+104A0 172 | U+104A1 173 | U+104A2 174 | U+104A3 175 | U+104A4 176 | U+104A5 177 | U+104A6 178 | U+104A7 179 | U+104A8 180 | U+104A9 181 | U+1090 182 | U+1091 183 | U+1092 184 | U+1093 185 | U+1094 186 | U+1095 187 | U+1096 188 | U+1097 189 | U+1098 190 | U+1099 191 | U+11066 192 | U+11067 193 | U+11068 194 | U+11069 195 | U+1106A 196 | U+1106B 197 | U+1106C 198 | U+1106D 199 | U+1106E 200 | U+1106F 201 | U+17E0 202 | U+17E1 203 | U+17E2 204 | U+17E3 205 | U+17E4 206 | U+17E5 207 | U+17E6 208 | U+17E7 209 | U+17E8 210 | U+17E9 211 | U+1810 212 | U+1811 213 | U+1812 214 | U+1813 215 | U+1814 216 | U+1815 217 | U+1816 218 | U+1817 219 | U+1818 220 | U+1819 221 | U+1946 222 | U+1947 223 | U+1948 224 | U+1949 225 | U+194A 226 | U+194B 227 | U+194C 228 | U+194D 229 | U+194E 230 | U+194F 231 | U+19D0 232 | U+19D1 233 | U+19D2 234 | U+19D3 235 | U+19D4 236 | U+19D5 237 | U+19D6 238 | U+19D7 239 | U+19D8 240 | U+19D9 241 | U+1A80 242 | U+1A81 243 | U+1A82 244 | U+1A83 245 | U+1A84 246 | U+1A85 247 | U+1A86 248 | U+1A87 249 | U+1A88 250 | U+1A89 251 | U+1A90 252 | U+1A91 253 | U+1A92 254 | U+1A93 255 | U+1A94 256 | U+1A95 257 | U+1A96 258 | U+1A97 259 | U+1A98 260 | U+1A99 261 | U+1B50 262 | U+1B51 263 | U+1B52 264 | U+1B53 265 | U+1B54 266 | U+1B55 267 | U+1B56 268 | U+1B57 269 | U+1B58 270 | U+1B59 271 | U+1BB0 272 | U+1BB1 273 | U+1BB2 274 | U+1BB3 275 | U+1BB4 276 | U+1BB5 277 | U+1BB6 278 | U+1BB7 279 | U+1BB8 280 | U+1BB9 281 | U+1C40 282 | U+1C41 283 | U+1C42 284 | U+1C43 285 | U+1C44 286 | U+1C45 287 | U+1C46 288 | U+1C47 289 | U+1C48 290 | U+1C49 291 | U+1C50 292 | U+1C51 293 | U+1C52 294 | U+1C53 295 | U+1C54 296 | U+1C55 297 | U+1C56 298 | U+1C57 299 | U+1C58 300 | U+1C59 301 | U+1D7CE 302 | U+1D7CF 303 | U+1D7D0 304 | U+1D7D1 305 | U+1D7D2 306 | U+1D7D3 307 | U+1D7D4 308 | U+1D7D5 309 | U+1D7D6 310 | U+1D7D7 311 | U+1D7D8 312 | U+1D7D9 313 | U+1D7DA 314 | U+1D7DB 315 | U+1D7DC 316 | U+1D7DD 317 | U+1D7DE 318 | U+1D7DF 319 | U+1D7E0 320 | U+1D7E1 321 | U+1D7E2 322 | U+1D7E3 323 | U+1D7E4 324 | U+1D7E5 325 | U+1D7E6 326 | U+1D7E7 327 | U+1D7E8 328 | U+1D7E9 329 | U+1D7EA 330 | U+1D7EB 331 | U+1D7EC 332 | U+1D7ED 333 | U+1D7EE 334 | U+1D7EF 335 | U+1D7F0 336 | U+1D7F1 337 | U+1D7F2 338 | U+1D7F3 339 | U+1D7F4 340 | U+1D7F5 341 | U+1D7F6 342 | U+1D7F7 343 | U+1D7F8 344 | U+1D7F9 345 | U+1D7FA 346 | U+1D7FB 347 | U+1D7FC 348 | U+1D7FD 349 | U+1D7FE 350 | U+1D7FF 351 | U+A620 352 | U+A621 353 | U+A622 354 | U+A623 355 | U+A624 356 | U+A625 357 | U+A626 358 | U+A627 359 | U+A628 360 | U+A629 361 | U+A8D0 362 | U+A8D1 363 | U+A8D2 364 | U+A8D3 365 | U+A8D4 366 | U+A8D5 367 | U+A8D6 368 | U+A8D7 369 | U+A8D8 370 | U+A8D9 371 | U+A900 372 | U+A901 373 | U+A902 374 | U+A903 375 | U+A904 376 | U+A905 377 | U+A906 378 | U+A907 379 | U+A908 380 | U+A909 381 | U+A9D0 382 | U+A9D1 383 | U+A9D2 384 | U+A9D3 385 | U+A9D4 386 | U+A9D5 387 | U+A9D6 388 | U+A9D7 389 | U+A9D8 390 | U+A9D9 391 | U+AA50 392 | U+AA51 393 | U+AA52 394 | U+AA53 395 | U+AA54 396 | U+AA55 397 | U+AA56 398 | U+AA57 399 | U+AA58 400 | U+AA59 401 | U+ABF0 402 | U+ABF1 403 | U+ABF2 404 | U+ABF3 405 | U+ABF4 406 | U+ABF5 407 | U+ABF6 408 | U+ABF7 409 | U+ABF8 410 | U+ABF9 411 | U+FF10 412 | U+FF11 413 | U+FF12 414 | U+FF13 415 | U+FF14 416 | U+FF15 417 | U+FF16 418 | U+FF17 419 | U+FF18 420 | U+FF19 421 | -------------------------------------------------------------------------------- /unicode/list-pc.txt: -------------------------------------------------------------------------------- 1 | U+005F 2 | U+203F 3 | U+2040 4 | U+2054 5 | U+FE33 6 | U+FE34 7 | U+FE4D 8 | U+FE4E 9 | U+FE4F 10 | U+FF3F 11 | --------------------------------------------------------------------------------