jmacro-0.6.15: QuasiQuotation library for programmatic generation of Javascript code.

Copyright(c) Gershom Bazerman 2010
LicenseBSD 3 Clause
Maintainergershomb@gmail.com
Stabilityexperimental
Safe HaskellNone
LanguageHaskell98

Language.Javascript.JMacro

Contents

Description

Simple DSL for lightweight (untyped) programmatic generation of Javascript.

A number of examples are available in the source of Language.Javascript.JMacro.Prelude.

Functions to generate generic RPC wrappers (using json serialization) are available in Language.Javascript.JMacro.Rpc.

usage:

renderJs [jmacro|fun id x -> x|]

The above produces the id function at the top level.

renderJs [jmacro|var id = \x -> x;|]

So does the above here. However, as id is brought into scope by the keyword var, you do not get a variable named id in the generated javascript, but a variable with an arbitrary unique identifier.

renderJs [jmacro|var !id = \x -> x;|]

The above, by using the bang special form in a var declaration, produces a variable that really is named id.

renderJs [jmacro|function id(x) {return x;}|]

The above is also id.

renderJs [jmacro|function !id(x) {return x;}|]

As is the above (with the correct name).

renderJs [jmacro|fun id x {return x;}|]

As is the above.

renderJs [jmacroE|foo(x,y)|]

The above is an expression representing the application of foo to x and y.

renderJs [jmacroE|foo x y|]]

As is the above.

renderJs [jmacroE|foo (x,y)|]

While the above is an error. (i.e. standard javascript function application cannot seperate the leading parenthesis of the argument from the function being applied)

\x -> [jmacroE|foo `(x)`|]

The above is a haskell expression that provides a function that takes an x, and yields an expression representing the application of foo to the value of x as transformed to a Javascript expression.

[jmacroE|\x ->`(foo x)`|]

Meanwhile, the above lambda is in Javascript, and brings the variable into scope both in javascript and in the enclosed antiquotes. The expression is a Javascript function that takes an x, and yields an expression produced by the application of the Haskell function foo as applied to the identifier x (which is of type JExpr -- i.e. a Javascript expression).

Other than that, the language is essentially Javascript (1.5). Note however that one must use semicolons in a principled fashion -- i.e. to end statements consistently. Otherwise, the parser will mistake the whitespace for a whitespace application, and odd things will occur. A further gotcha exists in regex literals, whicch cannot begin with a space. x 5 4 parses as ((x 5) 4). However, x 5 4 will parse as x(5 , 4). Such are the perils of operators used as delimeters in the presence of whitespace application.

Additional features in jmacro (documented on the wiki) include an infix application operator, and an enhanced destructuring bind.

Additional datatypes can be marshalled to Javascript by proper instance declarations for the ToJExpr class.

An experimental typechecker is available in the Language.Javascript.JMacro.Typed module.

Synopsis

Documentation

jmacro :: QuasiQuoter Source #

QuasiQuoter for a block of JMacro statements.

jmacroE :: QuasiQuoter Source #

QuasiQuoter for a JMacro expression.

ADT

data JStat Source #

Statements

Instances

Eq JStat Source # 

Methods

(==) :: JStat -> JStat -> Bool #

(/=) :: JStat -> JStat -> Bool #

Data JStat Source # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> JStat -> c JStat #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c JStat #

toConstr :: JStat -> Constr #

dataTypeOf :: JStat -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c JStat) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c JStat) #

gmapT :: (forall b. Data b => b -> b) -> JStat -> JStat #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> JStat -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> JStat -> r #

gmapQ :: (forall d. Data d => d -> u) -> JStat -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> JStat -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> JStat -> m JStat #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> JStat -> m JStat #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> JStat -> m JStat #

Ord JStat Source # 

Methods

compare :: JStat -> JStat -> Ordering #

(<) :: JStat -> JStat -> Bool #

(<=) :: JStat -> JStat -> Bool #

(>) :: JStat -> JStat -> Bool #

(>=) :: JStat -> JStat -> Bool #

max :: JStat -> JStat -> JStat #

min :: JStat -> JStat -> JStat #

Show JStat Source # 

Methods

showsPrec :: Int -> JStat -> ShowS #

show :: JStat -> String #

showList :: [JStat] -> ShowS #

Semigroup JStat Source # 

Methods

(<>) :: JStat -> JStat -> JStat #

sconcat :: NonEmpty JStat -> JStat #

stimes :: Integral b => b -> JStat -> JStat #

Monoid JStat Source # 

Methods

mempty :: JStat #

mappend :: JStat -> JStat -> JStat #

mconcat :: [JStat] -> JStat #

ToStat JStat Source # 

Methods

toStat :: JStat -> JStat Source #

JsToDoc JStat Source # 

Methods

jsToDoc :: JStat -> Doc Source #

JMacro JStat Source # 
JTypeCheck JStat Source # 
ToStat [JStat] Source # 

Methods

toStat :: [JStat] -> JStat Source #

JsToDoc [JStat] Source # 

Methods

jsToDoc :: [JStat] -> Doc Source #

data JExpr Source #

Expressions

Instances

Eq JExpr Source # 

Methods

(==) :: JExpr -> JExpr -> Bool #

(/=) :: JExpr -> JExpr -> Bool #

Data JExpr Source # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> JExpr -> c JExpr #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c JExpr #

toConstr :: JExpr -> Constr #

dataTypeOf :: JExpr -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c JExpr) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c JExpr) #

gmapT :: (forall b. Data b => b -> b) -> JExpr -> JExpr #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> JExpr -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> JExpr -> r #

gmapQ :: (forall d. Data d => d -> u) -> JExpr -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> JExpr -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> JExpr -> m JExpr #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> JExpr -> m JExpr #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> JExpr -> m JExpr #

Num JExpr Source # 
Ord JExpr Source # 

Methods

compare :: JExpr -> JExpr -> Ordering #

(<) :: JExpr -> JExpr -> Bool #

(<=) :: JExpr -> JExpr -> Bool #

(>) :: JExpr -> JExpr -> Bool #

(>=) :: JExpr -> JExpr -> Bool #

max :: JExpr -> JExpr -> JExpr #

min :: JExpr -> JExpr -> JExpr #

Show JExpr Source # 

Methods

showsPrec :: Int -> JExpr -> ShowS #

show :: JExpr -> String #

showList :: [JExpr] -> ShowS #

ToStat JExpr Source # 

Methods

toStat :: JExpr -> JStat Source #

ToJExpr JExpr Source # 
JsToDoc JExpr Source # 

Methods

jsToDoc :: JExpr -> Doc Source #

JMacro JExpr Source # 
JTypeCheck JExpr Source # 
ToStat [JExpr] Source # 

Methods

toStat :: [JExpr] -> JStat Source #

JsToDoc [JExpr] Source # 

Methods

jsToDoc :: [JExpr] -> Doc Source #

data JVal Source #

Values

Instances

Eq JVal Source # 

Methods

(==) :: JVal -> JVal -> Bool #

(/=) :: JVal -> JVal -> Bool #

Data JVal Source # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> JVal -> c JVal #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c JVal #

toConstr :: JVal -> Constr #

dataTypeOf :: JVal -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c JVal) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c JVal) #

gmapT :: (forall b. Data b => b -> b) -> JVal -> JVal #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> JVal -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> JVal -> r #

gmapQ :: (forall d. Data d => d -> u) -> JVal -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> JVal -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> JVal -> m JVal #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> JVal -> m JVal #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> JVal -> m JVal #

Ord JVal Source # 

Methods

compare :: JVal -> JVal -> Ordering #

(<) :: JVal -> JVal -> Bool #

(<=) :: JVal -> JVal -> Bool #

(>) :: JVal -> JVal -> Bool #

(>=) :: JVal -> JVal -> Bool #

max :: JVal -> JVal -> JVal #

min :: JVal -> JVal -> JVal #

Show JVal Source # 

Methods

showsPrec :: Int -> JVal -> ShowS #

show :: JVal -> String #

showList :: [JVal] -> ShowS #

ToJExpr JVal Source # 
JsToDoc JVal Source # 

Methods

jsToDoc :: JVal -> Doc Source #

JMacro JVal Source # 
JTypeCheck JVal Source # 

newtype Ident Source #

Identifiers

Constructors

StrI String 

Instances

Eq Ident Source # 

Methods

(==) :: Ident -> Ident -> Bool #

(/=) :: Ident -> Ident -> Bool #

Data Ident Source # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Ident -> c Ident #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Ident #

toConstr :: Ident -> Constr #

dataTypeOf :: Ident -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c Ident) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Ident) #

gmapT :: (forall b. Data b => b -> b) -> Ident -> Ident #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Ident -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Ident -> r #

gmapQ :: (forall d. Data d => d -> u) -> Ident -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> Ident -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> Ident -> m Ident #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Ident -> m Ident #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Ident -> m Ident #

Ord Ident Source # 

Methods

compare :: Ident -> Ident -> Ordering #

(<) :: Ident -> Ident -> Bool #

(<=) :: Ident -> Ident -> Bool #

(>) :: Ident -> Ident -> Bool #

(>=) :: Ident -> Ident -> Bool #

max :: Ident -> Ident -> Ident #

min :: Ident -> Ident -> Ident #

Show Ident Source # 

Methods

showsPrec :: Int -> Ident -> ShowS #

show :: Ident -> String #

showList :: [Ident] -> ShowS #

JsToDoc Ident Source # 

Methods

jsToDoc :: Ident -> Doc Source #

JMacro Ident Source # 

newtype IdentSupply a Source #

Constructors

IS 

Fields

Instances

Functor IdentSupply Source # 

Methods

fmap :: (a -> b) -> IdentSupply a -> IdentSupply b #

(<$) :: a -> IdentSupply b -> IdentSupply a #

Eq a => Eq (IdentSupply a) Source # 
Data a => Data (IdentSupply a) Source # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> IdentSupply a -> c (IdentSupply a) #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (IdentSupply a) #

toConstr :: IdentSupply a -> Constr #

dataTypeOf :: IdentSupply a -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c (IdentSupply a)) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (IdentSupply a)) #

gmapT :: (forall b. Data b => b -> b) -> IdentSupply a -> IdentSupply a #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> IdentSupply a -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> IdentSupply a -> r #

gmapQ :: (forall d. Data d => d -> u) -> IdentSupply a -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> IdentSupply a -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> IdentSupply a -> m (IdentSupply a) #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> IdentSupply a -> m (IdentSupply a) #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> IdentSupply a -> m (IdentSupply a) #

Ord a => Ord (IdentSupply a) Source # 
Show a => Show (IdentSupply a) Source # 

Generic traversal (via compos)

class JMacro a where Source #

Compos and ops for generic traversal as defined over the JMacro ADT.

Utility class to coerce the ADT into a regular structure.

Minimal complete definition

jtoGADT, jfromGADT

Methods

jtoGADT :: a -> JMGadt a Source #

jfromGADT :: JMGadt a -> a Source #

data JMGadt a where Source #

Union type to allow regular traversal by compos.

Instances

Compos JMGadt Source # 

Methods

compos :: (forall a. a -> m a) -> (forall a b. m (a -> b) -> m a -> m b) -> (forall a. JMGadt a -> m (JMGadt a)) -> JMGadt c -> m (JMGadt c) Source #

class Compos t where Source #

Minimal complete definition

compos

Methods

compos :: (forall a. a -> m a) -> (forall a b. m (a -> b) -> m a -> m b) -> (forall a. t a -> m (t a)) -> t c -> m (t c) Source #

Instances

Compos JMGadt Source # 

Methods

compos :: (forall a. a -> m a) -> (forall a b. m (a -> b) -> m a -> m b) -> (forall a. JMGadt a -> m (JMGadt a)) -> JMGadt c -> m (JMGadt c) Source #

composOp :: Compos t => (forall a. t a -> t a) -> t b -> t b Source #

composOpM :: (Compos t, Monad m) => (forall a. t a -> m (t a)) -> t b -> m (t b) Source #

composOpM_ :: (Compos t, Monad m) => (forall a. t a -> m ()) -> t b -> m () Source #

composOpFold :: Compos t => b -> (b -> b -> b) -> (forall a. t a -> b) -> t c -> b Source #

Hygienic transformation

withHygiene :: JMacro a => (a -> a) -> a -> a Source #

Apply a transformation to a fully saturated syntax tree, taking care to return any free variables back to their free state following the transformation. As the transformation preserves free variables, it is hygienic.

scopify :: JStat -> JStat Source #

Takes a fully saturated expression and transforms it to use unique variables that respect scope.

Display/Output

renderJs :: (JsToDoc a, JMacro a) => a -> Doc Source #

Render a syntax tree as a pretty-printable document (simply showing the resultant doc produces a nice, well formatted String).

renderPrefixJs :: (JsToDoc a, JMacro a) => String -> a -> Doc Source #

Render a syntax tree as a pretty-printable document, using a given prefix to all generated names. Use this with distinct prefixes to ensure distinct generated names between independent calls to render(Prefix)Js.

class JsToDoc a where Source #

Minimal complete definition

jsToDoc

Methods

jsToDoc :: a -> Doc Source #

Ad-hoc data marshalling

class ToJExpr a where Source #

Things that can be marshalled into javascript values. Instantiate for any necessary data structures.

Minimal complete definition

toJExpr

Methods

toJExpr :: a -> JExpr Source #

toJExprFromList :: [a] -> JExpr Source #

Instances

ToJExpr Bool Source # 
ToJExpr Char Source # 
ToJExpr Double Source # 
ToJExpr Int Source # 
ToJExpr Integer Source # 
ToJExpr () Source # 

Methods

toJExpr :: () -> JExpr Source #

toJExprFromList :: [()] -> JExpr Source #

ToJExpr Text Source # 
ToJExpr Value Source # 
ToJExpr Text Source # 
ToJExpr JVal Source # 
ToJExpr JExpr Source # 
ToJExpr a => ToJExpr [a] Source # 

Methods

toJExpr :: [a] -> JExpr Source #

toJExprFromList :: [[a]] -> JExpr Source #

(ToJExpr a, ToJExpr b) => ToJExpr (a, b) Source # 

Methods

toJExpr :: (a, b) -> JExpr Source #

toJExprFromList :: [(a, b)] -> JExpr Source #

ToJExpr a => ToJExpr (Map String a) Source # 
(ToJExpr a, ToJExpr b, ToJExpr c) => ToJExpr (a, b, c) Source # 

Methods

toJExpr :: (a, b, c) -> JExpr Source #

toJExprFromList :: [(a, b, c)] -> JExpr Source #

(ToJExpr a, ToJExpr b, ToJExpr c, ToJExpr d) => ToJExpr (a, b, c, d) Source # 

Methods

toJExpr :: (a, b, c, d) -> JExpr Source #

toJExprFromList :: [(a, b, c, d)] -> JExpr Source #

(ToJExpr a, ToJExpr b, ToJExpr c, ToJExpr d, ToJExpr e) => ToJExpr (a, b, c, d, e) Source # 

Methods

toJExpr :: (a, b, c, d, e) -> JExpr Source #

toJExprFromList :: [(a, b, c, d, e)] -> JExpr Source #

(ToJExpr a, ToJExpr b, ToJExpr c, ToJExpr d, ToJExpr e, ToJExpr f) => ToJExpr (a, b, c, d, e, f) Source # 

Methods

toJExpr :: (a, b, c, d, e, f) -> JExpr Source #

toJExprFromList :: [(a, b, c, d, e, f)] -> JExpr Source #

Literals

Occasionally helpful combinators

jLam :: ToSat a => a -> JExpr Source #

Create a new anonymous function. The result is an expression. Usage: jLam $ x y -> {JExpr involving x and y}

jVar :: ToSat a => a -> JStat Source #

Introduce a new variable into scope for the duration of the enclosed expression. The result is a block statement. Usage: jVar $ x y -> {JExpr involving x and y}

jVarTy :: ToSat a => a -> Maybe JLocalType -> JStat Source #

Introduce a new variable with optional type into scope for the duration of the enclosed expression. The result is a block statement. Usage: jVar $ x y -> {JExpr involving x and y}

jFor :: (ToJExpr a, ToStat b) => JStat -> a -> JStat -> b -> JStat Source #

jForIn :: ToSat a => JExpr -> (JExpr -> a) -> JStat Source #

Create a for in statement. Usage: jForIn {expression} $ x -> {block involving x}

jForEachIn :: ToSat a => JExpr -> (JExpr -> a) -> JStat Source #

As with "jForIn" but creating a "for each in" statement.

jTryCatchFinally :: ToSat a => JStat -> a -> JStat -> JStat Source #

class ToStat a where Source #

Minimal complete definition

toStat

Methods

toStat :: a -> JStat Source #

Hash combinators

Utility

jsSaturate :: JMacro a => Maybe String -> a -> a Source #

Given an optional prefix, fills in all free variable names with a supply of names generated by the prefix.

newtype SaneDouble Source #

Constructors

SaneDouble Double 

Instances

Eq SaneDouble Source # 
Fractional SaneDouble Source # 
Data SaneDouble Source # 

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> SaneDouble -> c SaneDouble #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c SaneDouble #

toConstr :: SaneDouble -> Constr #

dataTypeOf :: SaneDouble -> DataType #

dataCast1 :: Typeable (* -> *) t => (forall d. Data d => c (t d)) -> Maybe (c SaneDouble) #

dataCast2 :: Typeable (* -> * -> *) t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c SaneDouble) #

gmapT :: (forall b. Data b => b -> b) -> SaneDouble -> SaneDouble #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> SaneDouble -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> SaneDouble -> r #

gmapQ :: (forall d. Data d => d -> u) -> SaneDouble -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> SaneDouble -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> SaneDouble -> m SaneDouble #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> SaneDouble -> m SaneDouble #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> SaneDouble -> m SaneDouble #

Num SaneDouble Source # 
Ord SaneDouble Source # 
Show SaneDouble Source #