js-good-parts 0.0.1 → 0.0.2
raw patch · 4 files changed
+386/−210 lines, 4 files
Files
- js-good-parts.cabal +4/−3
- src/Language/JavaScript/AST.hs +352/−199
- src/Language/JavaScript/NonEmptyList.hs +30/−0
- src/Language/JavaScript/Pretty.hs +0/−8
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