packages feed

js-good-parts 0.0.1 → 0.0.2

raw patch · 4 files changed

+386/−210 lines, 4 files

Files

js-good-parts.cabal view
@@ -1,5 +1,5 @@ Name:                js-good-parts-Version:             0.0.1+Version:             0.0.2 Cabal-Version:       >= 1.6 Synopsis:            Javascript: The Good Parts -- AST & Pretty Printer Category:            Language, Javascript@@ -10,7 +10,7 @@  Author:              Sean Seefried Maintainer:          sean.seefried@gmail.com-Homepage:            http://github.com/sseefried/js-good-parts.git+Homepage:            https://github.com/sseefried/js-good-parts.git Copyright:           (c) by Sean Seefried License:             BSD3  License-File:        LICENSE@@ -18,7 +18,7 @@ build-type:          Simple Source-Repository head     type:         git-    location:     git://github.com/sseefried/js-tgp.git+    location:     https://github.com/sseefried/js-good-parts.git  Library   hs-Source-Dirs:      src@@ -27,3 +27,4 @@    Exposed-Modules:    Language.JavaScript.AST                       Language.JavaScript.Pretty+  Other-Modules:      Language.JavaScript.NonEmptyList
src/Language/JavaScript/AST.hs view
@@ -5,10 +5,10 @@ -- -- © 2012 ----- In Chapter 2 of "JavaScript: The Good Parts", Douglas Crockford presents a--- concrete grammar for "the good parts" of JavaScript.+-- | In Chapter 2 of \"JavaScript: The Good Parts\", Douglas Crockford presents a+-- concrete grammar for \"the good parts\" of JavaScript. ----- This module provides an abstract grammar for those good parts. We will abbreviate this+-- This module provides an abstract grammar for those good parts. Henceforth, we abbreviate this -- language to JS:TGP -- -- Crockford presents the grammar as a series of railroad diagrams.@@ -18,43 +18,40 @@ -- For each valid program produced by the concrete grammar there is a corresponding -- abstract syntax tree that when pretty printed will produce that program (modulo whitespace). ----- The abstract grammar:+-- /The abstract grammar/+-- --   * removes unnecessary characters such as parentheses (normal, curly and square)+-- --   * represents JavaScript's string, name and number literals directly in Haskell as --     'String', 'String' and 'Double' respectively. ----- Conventions for concrete syntax:---  -  Non-terminals appear in angle brackets e.g. <JSName>---  -  ? means zero or one. e.g. <JSExpression>?---  -  * means zero or more e.g. <JSStatement>*---  -  + means one  or more e.g. <JSStatement>+---  -  \( \) are meta-brackets used to enclose a concrete-syntax expression so that ?,* or +---     can be applied. e.g. \(= <JSExpression>\)*---     This means zero or more repetitions of: = <JsExpression>+-- /Conventions for concrete syntax/ ----- The data structure ensures no incorrect JS:TGP programs--- ---------------------------------------------------------- This library was designed so that it would be impossible, save for name, string literals--- to construct an incorrect JS:TGP program.+--  *  Non-terminals appear in angle brackets e.g. \<JSName\> ----- To this end some of the data structures may look like they contain redundancy.--- For instance, consider the 'JSESDelete' constructor which is defined+--  *  ? means zero or one. e.g. \<JSExpression\>? ----- JSESDelete JSExpression JSInvocation+--  *  * means zero or more e.g. \<JSStatement\>* ----- Why not just define it as 'JSESDelete JSExpression' since type 'JSExpression'--- has a constructor defined as 'JSExpressionInvocation JSExpression JSInvocation'?+--  *  + means one  or more e.g. \<JSStatement\>++--+--  *  \( \) are meta-brackets used to enclose a concrete-syntax expression so that ?,* or ++--     can be applied. e.g. \(= \<JSExpression\>\)*+--     This means zero or more repetitions of: = \<JsExpression\>+--+-- This library was designed so that it would be impossible, save for name, string literals+-- to construct an incorrect JS:TGP program. To this end some of the data structures may look like+-- they contain redundancy. For instance, consider the 'JSESDelete' constructor which is defined+--+-- @JSESDelete JSExpression JSInvocation@+--+-- Why not just define it as @JSESDelete JSExpression@ since type @JSExpression@+-- has a constructor defined as @JSExpressionInvocation JSExpression JSInvocation@? -- The reason is that this would allow incorrect programs. A 'JSExpression' is--- not necessarily an invocation.+-- not necessarily a 'JSInvocation'. ----- However, even though none of the programs are incorrect there are still some things--- it cannot check for. Although labels can appear before any statement, they should--- only be used on statements that interact with a switch, while, do, or for statement.--- This cannot be checked except by a second pass over the AST. This library does not--- provide this functionality.+-- /A note on precedence of JavaScript operators/ ----- A note on precedence of JavaScript operators--- -------------------------------------------- -- Interestingly, the precedence of JavaScript operators is -- not defined in the ECMAScript standard. The precedence used in this library comes from -- the Mozilla Developer's Network pages.@@ -66,51 +63,58 @@ -- have been normalised to what we are using in JS:TGP -- -- You will also note that we don't even consider the associativity/precedence of--- "=", "+=", "-=" etc. In JS:TGP the notion of expression statements is quite different+-- \"=\", \"+=\", \"-=\" etc. In JS:TGP the notion of expression statements is quite different -- to that of expressions. It simply isn't legal to write an expression statement like -----  (a += 2) -= 3---    OR---  a = (b = c) = (c = d)+--  @(a += 2) -= 3@ --+--    or+--+--  @a = (b = c) = (c = d)@+-- -- although it is perfectly legal to write -----  a = b = c = d += 2+--  @a = b = c = d += 2@ -- -- which if we add brackets to disambiguate is really ----- a = (b = (c = (d += 2)))+-- @a = (b = (c = (d += 2)))@ -- ----- Interesting aspects of "the good parts"--- ---------------------------------------+-- Interesting aspects of \"the good parts\": --+-- -- A JS:TGP program is a collection of statements. You'll note that there is no -- statement to declare a function in JS:TGP. However you can assign a function literal -- to a variable. ----- e.g. var fun = function(x) { return x + 1;}+-- e.g. --+-- @var fun = function(x) { return x + 1;}@+--+-- -- What about recursive functions then? There is the option to give the function a name which is -- local to the literal. ----- e.g. var factorial = function f(n) {---                        if ( n > 0 ) {---                          return n * f(n - 1);---                        } else {---                          return 1;---                        }---                      }+-- e.g. ----- 'f' is local. It will not be in scope outside of the function body.+-- @var factorial = function f(n) {+--                    if ( n > 0 ) {+--                      return n * f(n - 1);+--                    } else {+--                      return 1;+--                    }+--                  }@ --+-- @f@ is local. It will not be in scope outside of the function body.+-- module Language.JavaScript.AST (   -- JSString, JSName can't be create except with constructors   JSString, JSName,    unJSString, unJSName,   jsString, jsName,    -  -- Data types+  -- * Data types   JSNumber(..),   JSVarStatement(..), JSVarDecl(..), JSStatement(..),   JSDisruptiveStatement(..), JSIfStatement(..), JSSwitchStatement(..),@@ -129,7 +133,7 @@ data JSName = JSName { unJSName :: String }  ----- The only way you can create a JSName+-- | 'jsName' is the only way you can create a JSName -- jsName :: String -> Either String JSName jsName = Right . JSName -- FIXME: Return Left on error.@@ -137,9 +141,9 @@ data JSString = JSString { unJSString :: String }  ----- The only way you can create a Javascript string.--- This function needs to correctly encode all special characters.--- See p9 of "JavaScript: The Good Parts"+-- | The only way you can create a Javascript string.+--   This function needs to correctly encode all special characters.+--   See p9 of \"JavaScript: The Good Parts\" -- jsString :: String -> Either String JSString  jsString = Right . JSString -- FIXME: Return Left on error@@ -148,113 +152,163 @@ newtype JSNumber = JSNumber Double -- 64 bit floating point number  ----- Concrete syntax: var <VarDecl> [, <VarDecl>]* ;+-- | Concrete syntax: ----- e.g. var x = 1, y;+-- @var \<VarDecl\> [, \<VarDecl\>]* ;@ --+-- e.g. @var x = 1, y;@+-- data JSVarStatement = JSVarStatement (NonEmptyList JSVarDecl)  -- -- | Concrete syntax:---   1. <JSName> \(= <JSExpression>\)? --+--   1. @\<JSName\> \(= \<JSExpression\>\)?@+-- -- e.g.--- 1. x--- 2. x = 2 + y --+-- 1. @x@+--+-- 2. @x = 2 + y@+-- data JSVarDecl = JSVarDecl JSName (Maybe JSExpression) -- optional initialization  -- -- | The many different kinds of statements -- data JSStatement-  = JSStatementExpression   JSExpressionStatement -- ^ syntax: <JSExpressionStatement>;-  | JSStatementDisruptive  JSDisruptiveStatement -- ^ syntax: <JSDisruptiveStatement>-  | JSStatementTry         JSTryStatement        -- ^ syntax: <JSTryStatement>-  | JSStatementIf          JSIfStatement         -- ^ syntax: <JSIfStatement>-  -- | syntax: \(<JSName> : \) <JSSwitchStatement>+  = JSStatementExpression   JSExpressionStatement -- ^ @\<JSExpressionStatement\>;@+  | JSStatementDisruptive  JSDisruptiveStatement -- ^ @\<JSDisruptiveStatement\>@+  | JSStatementTry         JSTryStatement        -- ^ @\<JSTryStatement\>@+  | JSStatementIf          JSIfStatement         -- ^ @\<JSIfStatement\>@++  -- | @\(\<JSName\> : \) \<JSSwitchStatement\>@   | JSStatementSwitch      (Maybe JSName) JSSwitchStatement-  -- | syntax: \(<JSName> : \) <JSWhileStatement>+  -- | @\(\<JSName\> : \) \<JSWhileStatement\>@   | JSStatementWhile       (Maybe JSName) JSWhileStatement-  -- | syntax: \(<JSName> : \) <JSForStatement>+  -- | @\(\<JSName\> : \) \<JSForStatement\>@   | JSStatementFor         (Maybe JSName) JSForStatement-  -- | syntax: \(<JSName> : \) <JSDoStatement>+  -- | @\(\<JSName\> : \) \<JSDoStatement\>@   | JSStatementDo          (Maybe JSName) JSDoStatement  -- -- | Disruptive statements -- data JSDisruptiveStatement-  = JSDSBreak   JSBreakStatement  -- syntax: <JSBreakStatement>-  | JSDSReturn  JSReturnStatement -- syntax: <JSReturnStatement>-  | JSDSThrow   JSThrowStatement  -- syntax: <JSThrowStatement>+  = JSDSBreak   JSBreakStatement  -- ^ @\<JSBreakStatement\>@+  | JSDSReturn  JSReturnStatement -- ^ @syntax: \<JSReturnStatement\>@+  | JSDSThrow   JSThrowStatement  -- ^ @syntax: \<JSThrowStatement\>@  -- -- | Concrete syntax:---   if ( <JSExpression> ) { <JSStatement>* }                         -- for 'Nothing'---     OR---   if ( <JSExpression> ) { <JSStatement>* } else { <JSStatement>* } -- for 'Just . Left'---     OR---   if ( <JSExpression> ) { <JSStatement>* } else <JSIfStatement>    -- for 'Just . Right' --+-- @if ( \<JSExpression\> ) { \<JSStatement\>* }@                        -- for 'Nothing'+--+-- or+--+-- @if ( \<JSExpression\> ) { \<JSStatement\>* } else { \<JSStatement\>* }@ -- for 'Just . Left'+--+-- or+--+-- @if ( \<JSExpression\> ) { \<JSStatement\>* } else \<JSIfStatement\>@    -- for 'Just . Right'+-- --   e.g.---   if (x > 3) { y = 2; }---     OR---   if (x < 2) { y = 1; } else { y = 3; z = 2; }---     OR---   if (x > 0) { y = 20; } else if ( x > 10) { y = 30; } else { y = 10; } ---data JSIfStatement = JSIfStatement JSExpression [JSStatement] (Maybe (Either [JSStatement] JSIfStatement))+-- 1. @if (x > 3) { y = 2; }@+--+-- 2. @if (x < 2) { y = 1; } else { y = 3; z = 2; }@+--+-- 3. @if (x > 0) { y = 20; } else if ( x > 10) { y = 30; } else { y = 10; }@+--+data JSIfStatement = JSIfStatement JSExpression+                                   [JSStatement]+                                   (Maybe (Either [JSStatement] JSIfStatement)) + -- -- | Concrete syntax:---   switch ( <Expression> ) { <JSCaseClause> }---     OR---   switch ( <Expression> ) { <JSCaseAndDisruptive>+---                             default : <JSStatement>* }---   e.g.---   1. switch ( x ) {---        case 1:---          y = 2;---      }---   2. switch ( x ) {---        case 1:---          y = 2;---          break;---        case 2:---           y = 3;---           break;---        default:---           y = 4;---      } --+-- @switch ( \<JSExpression\> ) { \<JSCaseClause\> }@+--+-- or+--+-- @+-- switch ( \<JSExpression\> ) {+--  \<JSCaseAndDisruptive\>++--  default : \<JSStatement\>*+-- }+-- @+--+-- e.g.+--+-- 1.+--+-- @+-- switch ( x ) {+--   case 1:+--     y = 2;+--   }+-- @+--+-- 2.+--+-- @+-- switch ( x ) {+--   case 1:+--     y = 2;+--     break;+--   case 2:+--     y = 3;+--     break;+--   default:+--     y = 4;+-- }+-- @+-- data JSSwitchStatement   = JSSwitchStatementSingleCase JSExpression JSCaseClause   | JSSwitchStatement           JSExpression-                                (NonEmptyList JSCaseAndDisruptive) -- non-default case clauses-                                [JSStatement]                 -- default clause statements+                                (NonEmptyList JSCaseAndDisruptive)+                                --  ^ non-default case clauses+                                [JSStatement]+                                -- ^ default clause statements  -- -- | A case clause followed by a disruptive statement -- --   Concrete syntax:---     <JSCaseClause> <JSDisruptiveStatement>+--+--  @\<JSCaseClause\> \<JSDisruptiveStatement\>@+-- --   e.g.---   1. case 2:---        y = 2;---        break; --+-- 1.+-- @+-- case 2:+--   y = 2;+--   break;+-- @+-- data JSCaseAndDisruptive = JSCaseAndDisruptive JSCaseClause JSDisruptiveStatement  -- -- | Concrete syntax:---   case <JSExpression> : <JSStatement>* -----   e.g.---   1. case 2:   // zero statements following the case expression is valid.---   2. case 2:---        y = 1;+-- @case \<JSExpression\> : \<JSStatement\>*@ --+-- e.g.+--+-- 1.+--+-- @case 2:   \/\/ zero statements following the case expression is valid.@+--+-- 2.+--+-- @+-- case 2:+--   y = 1;+-- @+-- data JSCaseClause = JSCaseClause JSExpression [JSStatement]  --@@ -262,26 +316,43 @@ -- --   Concrete syntax: -----   1. for (<JSExpressionStatement>? ; <JSExpression>? ; <JSExpressionStatement>? ) {---        <JSStatement>*---      }---   2. for ( <JSName> in <JSExpression> ) {---        <JSStatement>*---      }+-- 1. --+-- @+-- for (\<JSExpressionStatement\>? ; \<JSExpression\>? ; \<JSExpressionStatement\>? ) {+--   \<JSStatement\>*+-- }+-- @+--+-- 2.+--+-- @+-- for ( \<JSName\> in \<JSExpression\> ) {+--   \<JSStatement\>*+-- }+-- @+-- --   e.g.---   1. for ( ; ; ) { }---   2. for ( ; x < 10 ;) { x += 1; }---   3. for (i = 0; i < 10; i += 1) {---         x += i;---      }---   4. for ( i in indices ) { a[i] = 66; } --+-- 1. @for ( ; ; ) { }@+--+-- 2. @for ( ; x < 10 ;) { x += 1; }@+--+-- 3.+--+-- @+-- for (i = 0; i < 10; i += 1) {+--   x += i;+-- }+-- @+--+-- 4. @for ( i in indices ) { a[i] = 66; }@+-- data JSForStatement = JSForStatementCStyle-                        (Maybe JSExpressionStatement) -- initialization-                        (Maybe JSExpression)          -- condition-                        (Maybe JSExpressionStatement) -- increment-                        [JSStatement]                 -- body+                        (Maybe JSExpressionStatement)+                        (Maybe JSExpression)+                        (Maybe JSExpressionStatement)+                        [JSStatement]                     | JSForStatementInStyle                         JSName                         JSExpression@@ -289,185 +360,267 @@  -- -- | Concrete syntax:---     do { <JSStatement>* } while ( <JSExpression> ); --+-- @do { \<JSStatement\>* } while ( \<JSExpression\> );@+-- data JSDoStatement = JSDoStatement [JSStatement] JSExpression  -- -- | Concrete syntax:---     while ( <JSExpression>) { <JSStatement>* } --+-- @while ( \<JSExpression\>) { \<JSStatement\>* }@+-- data JSWhileStatement = JSWhileStatement JSExpression [JSStatement]  -- -- | Concrete syntax:---     try { <JSStatement>* } catch ( <JSName> ) { <JSStatement>* } --+-- @try { \<JSStatement\>* } catch ( \<JSName\> ) { \<JSStatement\>* }@+-- data JSTryStatement = JSTryStatement [JSStatement] JSName [JSStatement]  -- -- | Concrete syntax:---     throw <JSExpression>; --+-- @throw \<JSExpression\>;@+-- data JSThrowStatement = JSThrowStatement JSExpression  -- -- | Concrete syntax:---     return <JSExpression>?;+--+-- @return \<JSExpression\>?;@+-- --   e.g.---   1. return;---   2. return 2 + x; --+--   1. @return;@+--+--   2. @return 2 + x;@+-- data JSReturnStatement = JSReturnStatement (Maybe JSExpression)  -- -- | Concrete syntax:---     break <JSName>?;---   e.g.---   1. break;---   2. break some_label; --+-- @break \<JSName\>?;@+--+-- e.g.+--+-- 1. @break;@+--+-- 2. @break some_label;@+-- data JSBreakStatement = JSBreakStatement (Maybe JSName)  -- -- | Concrete syntax: --+-- @\<JSValue\>+ \<JSRValue\>@ ---+-- or+--+-- @delete \<JSExpression\> \<JSRefinement\>@+-- data JSExpressionStatement   = JSESApply (NonEmptyList JSLValue) JSRValue   | JSESDelete JSExpression JSRefinement  -- -- | Concrete syntax:---     <JSName> \(<JSInvocation>* <JSRefinement>\)*+--+-- @\<JSName\> \(\<JSInvocation\>* \<JSRefinement\>\)*@+-- --   e.g.---   1. x---   2. x.field_1---   3. fun().field_1---   4. fun(1)(2)---   5. fun(1)(2).field_1---   5. x.fun_field_1(x+2).fun_field_2(y+3).field_3 --+--   1. @x@+--+--   2. @x.field_1@+--+--   3. @fun().field_1@+--+--   4. @fun(1)(2)@+--+--   5. @fun(1)(2).field_1@+--+--   6. @x.fun_field_1(x+2).fun_field_2(y+3).field_3@+-- data JSLValue = JSLValue JSName [([JSInvocation], JSRefinement)]  -- -- | Concrete syntax:---   1. =  <JSExpression>---   2. += <JSExpression>---   3. -= <JSExpression>---   4. <JSInvocation>+ -----   e.g.---   1. = 2---   2. += 3---   3. -= (4 + y)---   4a. ()---   4b. (1)---   4c. (x,y,z)+-- @=  \<JSExpression\>@ --+-- or+--+-- @+= \<JSExpression\>@+--+-- or+--+-- @-= \<JSExpression\>@+--+-- or+--+-- @\<JSInvocation\>+@+--+-- e.g.+--+-- 1. @= 2@+--+-- 2. @+= 3@+--+-- 3. @-= (4 + y)@+--+-- 4. @()@+--+-- 5. @(1)@+--+-- 6. @(x,y,z)@+-- data JSRValue   = JSRVAssign    JSExpression   | JSRVAddAssign JSExpression   | JSRVSubAssign JSExpression   | JSRVInvoke    (NonEmptyList JSInvocation) -data JSExpression = JSExpressionLiteral    JSLiteral-                  | JSExpressionName       JSName+data JSExpression = JSExpressionLiteral    JSLiteral -- ^ @\<JSLiteral\>@+                  | JSExpressionName       JSName    -- ^ @\<JSName\>@++                  -- | @\<JSPrefixOperator> \<JSExpression\>@                   | JSExpressionPrefix     JSPrefixOperator JSExpression++                  -- | @\<JSExpression\> \<JSInfixOperator\> \<JSExpression\>@                   | JSExpressionInfix      JSInfixOperator  JSExpression JSExpression++                  -- | @\<JSExpression\> ? \<JSExpression\> : \<JSExpression\>@                   | JSExpressionTernary    JSExpression     JSExpression JSExpression++                  -- | @\<JSExpression\>\<JSInvocation\>@                   | JSExpressionInvocation JSExpression     JSInvocation++                  -- | @\<JSExpression\>\<JSRefinement\>@                   | JSExpressionRefinement JSExpression     JSRefinement++                  -- | new @\<JSExpression\>\<JSInvocation\>@                   | JSExpressionNew        JSExpression     JSInvocation++                  -- | delete @\<JSExpression\>\<JSRefinement\>@                   | JSExpressionDelete     JSExpression     JSRefinement  data JSPrefixOperator-  = JSTypeOf   -- syntax: typeof-  | JSToNumber -- syntax: +-  | JSNegate   -- syntax: --  | JSNot      -- syntax: !+  = JSTypeOf   -- ^ @typeof@+  | JSToNumber -- ^ @+@+  | JSNegate   -- ^ @-@+  | JSNot      -- ^ @!@  data JSInfixOperator-  = JSMul  -- syntax: *-  | JSDiv  -- syntax: /-  | JSMod  -- syntax: %-  | JSAdd  -- syntax: +-  | JSSub  -- syntax: --  | JSGTE  -- syntax: >=-  | JSLTE  -- syntax: <=-  | JSGT   -- syntax: >-  | JSLT   -- syntax: <-  | JSEq   -- syntax: ===-  | JSNotEq-- syntax: !==-  | JSOr   -- syntax: ||-  | JSAnd  -- syntax: &&+  = JSMul  -- ^ @*@+  | JSDiv  -- ^ @/@+  | JSMod  -- ^ @%@+  | JSAdd  -- ^ @+@+  | JSSub  -- ^ @-@+  | JSGTE  -- ^ @>=@+  | JSLTE  -- ^ @<=@+  | JSGT   -- ^ @>@+  | JSLT   -- ^ @<@+  | JSEq   -- ^ @===@+  | JSNotEq-- ^ @!==@+  | JSOr   -- ^ @||@+  | JSAnd  -- ^ @&&@  -- -- | Concrete syntax:---     <JSExpression>*+--+-- @\<JSExpression\>*@+-- --   e.g.---   1. ()---   2. (1)---   3. (x,z,y) --+-- 1. @()@+--+-- 2. @(1)@+--+-- 3. @(x,z,y)@+-- data JSInvocation = JSInvocation [JSExpression] ---   e.g.---   1. .field_1---   2. [i+1]+-- | Concrete syntax: --+-- @.\<JSName\>@+--+-- or+--+-- @[\<JSExpression\>]@+--+-- e.g.+--+-- 1. @.field_1@+--+-- 2. @[i+1]@+-- data JSRefinement-  -- | syntax: .<JSName>-  --   e.g. .field_1   = JSProperty  JSName-  -- | syntax: [<JSExpression>]-  --   e.g. [x+3]   | JSSubscript JSExpression  data JSLiteral-  = JSLiteralNumber   JSNumber-  | JSLiteralString   JSString-  | JSLiteralObject   JSObjectLiteral-  | JSLiteralArray    JSArrayLiteral-  | JSLiteralFunction JSFunctionLiteral+  = JSLiteralNumber   JSNumber          -- ^ @\<JSNumber\>@+  | JSLiteralString   JSString          -- ^ @\<JSString\>@+  | JSLiteralObject   JSObjectLiteral   -- ^ @\<JSObjectLiteral\>@+  | JSLiteralArray    JSArrayLiteral    -- ^ @\<JSArrayLiteral\>@+  | JSLiteralFunction JSFunctionLiteral -- ^ @\<JSFunctionLiteral\>@ --  | JSLiteralRegexp   JSRegexpLiteral -- TODO: Add regexps  -- -- | Concrete syntax:---   1. {}                                          // no  fields---   2. {<JSObjectField> \(, <JSObjectField> \)*}   // one or more fields --+-- @{}@                                               -- no  fields+--+-- or+--+-- @\{\<JSObjectField\> \(, \<JSObjectField\> \)*\}@    -- one or more fields+-- data JSObjectLiteral = JSObjectLiteral [JSObjectField]  -- -- | Concrete syntax:---   1. <JSName>: <JSExpression>      // for Left---   2. <JSString>: <JSExpression>     // for Right --+-- @\<JSName\>: \<JSExpression\>        @ -- for Left+--+-- or+--+-- @\<JSString\>: \<JSExpression\>      @ -- for Right+-- --   e.g.---   1. x: y + 3---   2. "value": 3 - z --+--   1. @x: y + 3@+--+--   2. @\"value\": 3 - z@+-- data JSObjectField  = JSObjectField (Either JSName JSString) JSExpression  -- -- | Concrete syntax:---   1. []                             // empty array---   2. [<JSExpression> \(, <JSExpression>*\) ] --+-- @[]@ -- empty array+--+-- or+--+-- @[\<JSExpression\> \(, \<JSExpression\>*\) ]@ -- non empty array+-- data JSArrayLiteral = JSArrayLiteral [JSExpression]  -- -- | Concrete syntax:---   function <JSName>? <JSFunctionBody> --+-- @function \<JSName\>? \<JSFunctionBody\>@+-- data JSFunctionLiteral = JSFunctionLiteral (Maybe JSName) [JSName] JSFunctionBody  -- -- | Concrete syntax:---   { <JSVarStatement>+ <JSStatement>+ } --+-- @{ \<JSVarStatement\>+ \<JSStatement\>+ }@+-- data JSFunctionBody = JSFunctionBody [JSVarStatement] [JSStatement] +-- | Programs. All variable statements come first. data JSProgram = JSProgram [JSVarStatement] [JSStatement]
+ src/Language/JavaScript/NonEmptyList.hs view
@@ -0,0 +1,30 @@+--+--+-- Author: Sean Seefried+-- © 2012+--+-- Non-empty lists.+--+module Language.JavaScript.NonEmptyList (+ NonEmptyList,+ singleton, (<:>),+ toList++) where++-- A list of at least one element+data NonEmptyList a = Singleton a | Cons a (NonEmptyList a)++singleton :: a -> NonEmptyList a+singleton = Singleton++(<:>) :: a -> NonEmptyList a -> NonEmptyList a+x <:> xs = Cons x xs++instance Functor NonEmptyList where+  fmap f (Singleton a) = Singleton (f a)+  fmap f (Cons x xs)   = Cons (f x) (fmap f xs)++toList :: NonEmptyList a -> [a]+toList (Singleton a) = [a]+toList (Cons x xs) = x : toList xs
src/Language/JavaScript/Pretty.hs view
@@ -94,14 +94,6 @@   JSAnd   -> go 2 "&&"  where go i s = OpInfo i LeftToRight s -prefixOpInfo :: JSPrefixOperator -> OpInfo-prefixOpInfo op = case op of-  JSTypeOf   -> go 7 "typeof"-  JSToNumber -> go 7 "+"-  JSNegate   -> go 7 "-"-  JSNot      -> go 7 "!"-  where go i s = OpInfo i RightToLeft s- -----------------------------------------------------------------------  instance Pretty JSNumber where