Copyright | (c) Gershom Bazerman 2010 |
---|---|
License | BSD 3 Clause |
Maintainer | gershomb@gmail.com |
Stability | experimental |
Safe Haskell | None |
Language | Haskell98 |
Language.Javascript.JMacro
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
- jmacro :: QuasiQuoter
- jmacroE :: QuasiQuoter
- parseJM :: String -> Either ParseError JStat
- parseJME :: String -> Either ParseError JExpr
- class ToStat a where
- class ToJExpr a where
- toJExpr :: a -> JExpr
- toJExprFromList :: [a] -> JExpr
- class JsToDoc a where
- class Compos t where
- 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)
- data JMGadt a where
- class JMacro a where
- newtype Ident = StrI String
- newtype SaneDouble = SaneDouble Double
- data JVal
- data JExpr
- type JsLabel = String
- data JStat
- = DeclStat Ident (Maybe JLocalType)
- | ReturnStat JExpr
- | IfStat JExpr JStat JStat
- | WhileStat Bool JExpr JStat
- | ForInStat Bool Ident JExpr JStat
- | SwitchStat JExpr [(JExpr, JStat)] JStat
- | TryStat JStat Ident JStat JStat
- | BlockStat [JStat]
- | ApplStat JExpr [JExpr]
- | PPostStat Bool String JExpr
- | AssignStat JExpr JExpr
- | UnsatBlock (IdentSupply JStat)
- | AntiStat String
- | ForeignStat Ident JLocalType
- | LabelStat JsLabel JStat
- | BreakStat (Maybe JsLabel)
- | ContinueStat (Maybe JsLabel)
- newtype IdentSupply a = IS {
- runIdentSupply :: State [Ident] a
- composOp :: Compos t => (forall a. t a -> t a) -> t b -> t b
- composOpM :: (Compos t, Monad m) => (forall a. t a -> m (t a)) -> t b -> m (t b)
- composOpM_ :: (Compos t, Monad m) => (forall a. t a -> m ()) -> t b -> m ()
- composOpFold :: Compos t => b -> (b -> b -> b) -> (forall a. t a -> b) -> t c -> b
- jsSaturate :: JMacro a => Maybe String -> a -> a
- withHygiene :: JMacro a => (a -> a) -> a -> a
- scopify :: JStat -> JStat
- renderJs :: (JsToDoc a, JMacro a) => a -> Doc
- renderPrefixJs :: (JsToDoc a, JMacro a) => String -> a -> Doc
- jLam :: ToSat a => a -> JExpr
- jVar :: ToSat a => a -> JStat
- jVarTy :: ToSat a => a -> Maybe JLocalType -> JStat
- jForIn :: ToSat a => JExpr -> (JExpr -> a) -> JStat
- jForEachIn :: ToSat a => JExpr -> (JExpr -> a) -> JStat
- jTryCatchFinally :: ToSat a => JStat -> a -> JStat -> JStat
- jsv :: String -> JExpr
- jFor :: (ToJExpr a, ToStat b) => JStat -> a -> JStat -> b -> JStat
- jhEmpty :: Map String JExpr
- jhSingle :: ToJExpr a => String -> a -> Map String JExpr
- jhAdd :: ToJExpr a => String -> a -> Map String JExpr -> Map String JExpr
- jhFromList :: [(String, JExpr)] -> JVal
- jtFromList :: JType -> [(String, JType)] -> JType
- nullStat :: JStat
- module Language.Javascript.JMacro.Prelude
- data JType
Documentation
class ToJExpr a where Source #
Things that can be marshalled into javascript values. Instantiate for any necessary data structures.
Minimal complete definition
Instances
Union type to allow regular traversal by compos.
Compos and ops for generic traversal as defined over the JMacro ADT.
Utility class to coerce the ADT into a regular structure.
Identifiers
Constructors
StrI String |
Instances
Eq Ident Source # | |
Data Ident Source # | |
Defined in Language.Javascript.JMacro.Base 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 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 :: forall r r'. (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 # | |
Show Ident Source # | |
JsToDoc Ident Source # | |
JMacro Ident Source # | |
newtype SaneDouble Source #
Constructors
SaneDouble Double |
Instances
Eq SaneDouble Source # | |
Defined in Language.Javascript.JMacro.Base | |
Fractional SaneDouble Source # | |
Defined in Language.Javascript.JMacro.Base Methods (/) :: SaneDouble -> SaneDouble -> SaneDouble recip :: SaneDouble -> SaneDouble fromRational :: Rational -> SaneDouble | |
Data SaneDouble Source # | |
Defined in Language.Javascript.JMacro.Base 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 :: forall r r'. (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 # | |
Defined in Language.Javascript.JMacro.Base Methods (+) :: SaneDouble -> SaneDouble -> SaneDouble (-) :: SaneDouble -> SaneDouble -> SaneDouble (*) :: SaneDouble -> SaneDouble -> SaneDouble negate :: SaneDouble -> SaneDouble abs :: SaneDouble -> SaneDouble signum :: SaneDouble -> SaneDouble fromInteger :: Integer -> SaneDouble | |
Ord SaneDouble Source # | |
Defined in Language.Javascript.JMacro.Base Methods compare :: SaneDouble -> SaneDouble -> Ordering (<) :: SaneDouble -> SaneDouble -> Bool (<=) :: SaneDouble -> SaneDouble -> Bool (>) :: SaneDouble -> SaneDouble -> Bool (>=) :: SaneDouble -> SaneDouble -> Bool max :: SaneDouble -> SaneDouble -> SaneDouble min :: SaneDouble -> SaneDouble -> SaneDouble | |
Show SaneDouble Source # | |
Defined in Language.Javascript.JMacro.Base Methods showsPrec :: Int -> SaneDouble -> ShowS show :: SaneDouble -> String showList :: [SaneDouble] -> ShowS |
Values
Constructors
JVar Ident | |
JList [JExpr] | |
JDouble SaneDouble | |
JInt Integer | |
JStr String | |
JRegEx String | |
JHash (Map String JExpr) | |
JFunc [Ident] JStat | |
UnsatVal (IdentSupply JVal) |
Instances
Eq JVal Source # | |
Data JVal Source # | |
Defined in Language.Javascript.JMacro.Base 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 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 :: forall r r'. (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 # | |
Show JVal Source # | |
ToJExpr JVal Source # | |
JsToDoc JVal Source # | |
JMacro JVal Source # | |
JTypeCheck JVal Source # | |
Expressions
Constructors
ValExpr JVal | |
SelExpr JExpr Ident | |
IdxExpr JExpr JExpr | |
InfixExpr String JExpr JExpr | |
PPostExpr Bool String JExpr | |
IfExpr JExpr JExpr JExpr | |
NewExpr JExpr | |
ApplExpr JExpr [JExpr] | |
UnsatExpr (IdentSupply JExpr) | |
AntiExpr String | |
TypeExpr Bool JExpr JLocalType |
Instances
Eq JExpr Source # | |
Data JExpr Source # | |
Defined in Language.Javascript.JMacro.Base 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 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 :: forall r r'. (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 # | |
Show JExpr Source # | |
ToStat JExpr Source # | |
ToJExpr JExpr Source # | |
JsToDoc JExpr Source # | |
JMacro JExpr Source # | |
JTypeCheck JExpr Source # | |
ToStat [JExpr] Source # | |
JsToDoc [JExpr] Source # | |
Statements
Constructors
DeclStat Ident (Maybe JLocalType) | |
ReturnStat JExpr | |
IfStat JExpr JStat JStat | |
WhileStat Bool JExpr JStat | |
ForInStat Bool Ident JExpr JStat | |
SwitchStat JExpr [(JExpr, JStat)] JStat | |
TryStat JStat Ident JStat JStat | |
BlockStat [JStat] | |
ApplStat JExpr [JExpr] | |
PPostStat Bool String JExpr | |
AssignStat JExpr JExpr | |
UnsatBlock (IdentSupply JStat) | |
AntiStat String | |
ForeignStat Ident JLocalType | |
LabelStat JsLabel JStat | |
BreakStat (Maybe JsLabel) | |
ContinueStat (Maybe JsLabel) |
Instances
Eq JStat Source # | |
Data JStat Source # | |
Defined in Language.Javascript.JMacro.Base 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 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 :: forall r r'. (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 # | |
Show JStat Source # | |
Semigroup JStat Source # | |
Monoid JStat Source # | |
ToStat JStat Source # | |
JsToDoc JStat Source # | |
JMacro JStat Source # | |
JTypeCheck JStat Source # | |
ToStat [JStat] Source # | |
JsToDoc [JStat] Source # | |
newtype IdentSupply a Source #
Constructors
IS | |
Fields
|
Instances
Functor IdentSupply Source # | |
Defined in Language.Javascript.JMacro.Base Methods fmap :: (a -> b) -> IdentSupply a -> IdentSupply b (<$) :: a -> IdentSupply b -> IdentSupply a | |
Eq a => Eq (IdentSupply a) Source # | |
Defined in Language.Javascript.JMacro.Base | |
Data a => Data (IdentSupply a) Source # | |
Defined in Language.Javascript.JMacro.Base 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 :: forall r r'. (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 # | |
Defined in Language.Javascript.JMacro.Base Methods compare :: IdentSupply a -> IdentSupply a -> Ordering (<) :: IdentSupply a -> IdentSupply a -> Bool (<=) :: IdentSupply a -> IdentSupply a -> Bool (>) :: IdentSupply a -> IdentSupply a -> Bool (>=) :: IdentSupply a -> IdentSupply a -> Bool max :: IdentSupply a -> IdentSupply a -> IdentSupply a min :: IdentSupply a -> IdentSupply a -> IdentSupply a | |
Show a => Show (IdentSupply a) Source # | |
Defined in Language.Javascript.JMacro.Base Methods showsPrec :: Int -> IdentSupply a -> ShowS show :: IdentSupply a -> String showList :: [IdentSupply a] -> ShowS |
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 #
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.
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.
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.
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}
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.
jhFromList :: [(String, JExpr)] -> JVal Source #
Constructors
JTNum | |
JTString | |
JTBool | |
JTStat | |
JTFunc [JType] JType | |
JTList JType | |
JTMap JType | |
JTRecord JType (Map String JType) | |
JTRigid VarRef (Set Constraint) | |
JTImpossible | |
JTFree VarRef | |
JTForall [VarRef] JType |
Instances
Eq JType Source # | |
Data JType Source # | |
Defined in Language.Javascript.JMacro.Types Methods gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> JType -> c JType gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c JType dataTypeOf :: JType -> DataType dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c JType) dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c JType) gmapT :: (forall b. Data b => b -> b) -> JType -> JType gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> JType -> r gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> JType -> r gmapQ :: (forall d. Data d => d -> u) -> JType -> [u] gmapQi :: Int -> (forall d. Data d => d -> u) -> JType -> u gmapM :: Monad m => (forall d. Data d => d -> m d) -> JType -> m JType gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> JType -> m JType gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> JType -> m JType | |
Ord JType Source # | |
Read JType Source # | |
Defined in Language.Javascript.JMacro.Types | |
Show JType Source # | |
JsToDoc JLocalType Source # | |
Defined in Language.Javascript.JMacro.Base Methods jsToDoc :: JLocalType -> Doc Source # | |
JsToDoc JType Source # | |
Compos1 JType Source # | |