Copyright | (c) The University of Glasgow 2001 |
---|---|
License | BSD-style (see the file LICENSE) |
Maintainer | Jeffrey Young <jeffrey.young@iohk.io> Luite Stegeman <luite.stegeman@iohk.io> Sylvain Henry <sylvain.henry@iohk.io> Josh Meredith <josh.meredith@iohk.io> |
Stability | experimental |
Safe Haskell | None |
Language | GHC2021 |
Domain and Purpose
GHC.JS.Make defines helper functions to ease the creation of JavaScript ASTs as defined in
Syntax
. Its purpose is twofold: make the EDSL more ergonomic to program in, and make errors in the EDSL look obvious because the EDSL is untyped. It is primarily concerned with injecting terms into the domain of the EDSL to construct JS programs in Haskell.Strategy
The strategy for this module comes straight from gentzen; where we have two types of helper functions. Functions which inject terms into the EDSL, and combinator functions which operate on terms in the EDSL to construct new terms in the EDSL. Crucially, missing from this module are corresponding elimination or destructing functions which would project information from the EDSL back to Haskell. See
Utils
for such functions.Introduction functions
We define various primitive helpers which introduce terms in the EDSL, for example
jVar
,jLam
, andvar
andjString
. Similarly this module exports four typeclassesToExpr
,ToStat
,JVarMagic
,JSArgument
.ToExpr
injects values as a JS expression into the EDSL.ToStat
injects values as JS statements into the EDSL.JVarMagic
provides a polymorphic way to introduce a new name into the EDSL andJSArgument
provides a polymorphic way to bind variable names for use in JS functions with different arities.Combinator functions
The rest of the module defines combinators which create terms in the EDSL from terms in the EDSL. Notable examples are
|=
and||=
,|=
is sugar forAssignStat
, it is a binding form that declaresfoo = bar
assuming foo has been already declared.||=
is more sugar on top of|=
, it is also a binding form that declares the LHS of|=
before calling|=
to bind a value, bar, to a variable foo. Other common examples are theif_
andmath_
helpers such asmath_cos
.
Consumers
The entire JS backend consumes this module, e.g., the modules in GHC.StgToJS.*.
Notation
In this module we use
==>
in docstrings to show the translation from the JS EDSL domain to JS code. For example,foo ||= bar ==> var foo; foo = bar;
should be read asfoo ||= bar
is in the EDSL domain and results in the JS codevar foo; foo = bar;
when compiled.In most cases functions prefixed with a
j
are monadic because the observably allocate. Notable exceptions arejwhenS
,jString
and the helpers for HashMaps.
Synopsis
- class ToJExpr a where
- toJExpr :: a -> JStgExpr
- toJExprFromList :: [a] -> JStgExpr
- class ToStat a where
- class JVarMagic a where
- class JSArgument args where
- jString :: FastString -> JStgExpr
- jLam :: JSArgument args => (args -> JSM JStgStat) -> JSM JStgExpr
- jLam' :: JStgStat -> JStgExpr
- jFunction :: JSArgument args => Ident -> (args -> JSM JStgStat) -> JSM JStgStat
- jFunctionSized :: Ident -> Int -> ([JStgExpr] -> JSM JStgStat) -> JSM JStgStat
- jFunction' :: Ident -> JSM JStgStat -> JSM JStgStat
- jVar :: (JVarMagic t, ToJExpr t) => (t -> JSM JStgStat) -> JSM JStgStat
- jVars :: JSArgument args => (args -> JSM JStgStat) -> JSM JStgStat
- jFor :: (JStgExpr -> JStgStat) -> (JStgExpr -> JStgExpr) -> (JStgExpr -> JStgStat) -> (JStgExpr -> JStgStat) -> JSM JStgStat
- jForIn :: JStgExpr -> (JStgExpr -> JStgStat) -> JSM JStgStat
- jForEachIn :: JStgExpr -> (JStgExpr -> JStgStat) -> JSM JStgStat
- jTryCatchFinally :: (Ident -> JStgStat) -> (Ident -> JStgStat) -> (Ident -> JStgStat) -> JSM JStgStat
- (||=) :: Ident -> JStgExpr -> JStgStat
- (|=) :: JStgExpr -> JStgExpr -> JStgStat
- (.==.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.===.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.!=.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.!==.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.!) :: JStgExpr -> JStgExpr -> JStgExpr
- (.>.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.>=.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.<.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.<=.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.<<.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.>>.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.>>>.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.|.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.||.) :: JStgExpr -> JStgExpr -> JStgExpr
- (.&&.) :: JStgExpr -> JStgExpr -> JStgExpr
- if_ :: JStgExpr -> JStgExpr -> JStgExpr -> JStgExpr
- if10 :: JStgExpr -> JStgExpr
- if01 :: JStgExpr -> JStgExpr
- ifS :: JStgExpr -> JStgStat -> JStgStat -> JStgStat
- ifBlockS :: JStgExpr -> [JStgStat] -> [JStgStat] -> JStgStat
- jBlock :: Monoid a => [JSM a] -> JSM a
- jIf :: JStgExpr -> JSM JStgStat -> JSM JStgStat -> JSM JStgStat
- jwhenS :: JStgExpr -> JStgStat -> JStgStat
- app :: FastString -> [JStgExpr] -> JStgExpr
- appS :: FastString -> [JStgExpr] -> JStgStat
- returnS :: JStgExpr -> JStgStat
- loop :: JStgExpr -> (JStgExpr -> JStgExpr) -> (JStgExpr -> JSM JStgStat) -> JSM JStgStat
- loopBlockS :: JStgExpr -> (JStgExpr -> JStgExpr) -> (JStgExpr -> [JStgStat]) -> JSM JStgStat
- preIncrS :: JStgExpr -> JStgStat
- postIncrS :: JStgExpr -> JStgStat
- preDecrS :: JStgExpr -> JStgStat
- postDecrS :: JStgExpr -> JStgStat
- off8 :: JStgExpr -> JStgExpr -> JStgExpr
- off16 :: JStgExpr -> JStgExpr -> JStgExpr
- off32 :: JStgExpr -> JStgExpr -> JStgExpr
- off64 :: JStgExpr -> JStgExpr -> JStgExpr
- mask8 :: JStgExpr -> JStgExpr
- mask16 :: JStgExpr -> JStgExpr
- signExtend8 :: JStgExpr -> JStgExpr
- signExtend16 :: JStgExpr -> JStgExpr
- typeof :: JStgExpr -> JStgExpr
- returnStack :: JStgStat
- assignAllEqual :: HasDebugCallStack => [JStgExpr] -> [JStgExpr] -> JStgStat
- assignAll :: [JStgExpr] -> [JStgExpr] -> JStgStat
- assignAllReverseOrder :: [JStgExpr] -> [JStgExpr] -> JStgStat
- declAssignAll :: [Ident] -> [JStgExpr] -> JStgStat
- nullStat :: JStgStat
- (.^) :: JStgExpr -> FastString -> JStgExpr
- trace :: ToJExpr a => a -> JStgStat
- jhEmpty :: Map k JStgExpr
- jhSingle :: (Ord k, ToJExpr a) => k -> a -> Map k JStgExpr
- jhAdd :: (Ord k, ToJExpr a) => k -> a -> Map k JStgExpr -> Map k JStgExpr
- jhFromList :: [(FastString, JStgExpr)] -> JVal
- null_ :: JStgExpr
- undefined_ :: JStgExpr
- false_ :: JStgExpr
- true_ :: JStgExpr
- zero_ :: JStgExpr
- one_ :: JStgExpr
- two_ :: JStgExpr
- three_ :: JStgExpr
- math_log :: [JStgExpr] -> JStgExpr
- math_sin :: [JStgExpr] -> JStgExpr
- math_cos :: [JStgExpr] -> JStgExpr
- math_tan :: [JStgExpr] -> JStgExpr
- math_exp :: [JStgExpr] -> JStgExpr
- math_acos :: [JStgExpr] -> JStgExpr
- math_asin :: [JStgExpr] -> JStgExpr
- math_atan :: [JStgExpr] -> JStgExpr
- math_abs :: [JStgExpr] -> JStgExpr
- math_pow :: [JStgExpr] -> JStgExpr
- math_sqrt :: [JStgExpr] -> JStgExpr
- math_asinh :: [JStgExpr] -> JStgExpr
- math_acosh :: [JStgExpr] -> JStgExpr
- math_atanh :: [JStgExpr] -> JStgExpr
- math_cosh :: [JStgExpr] -> JStgExpr
- math_sinh :: [JStgExpr] -> JStgExpr
- math_tanh :: [JStgExpr] -> JStgExpr
- math_expm1 :: [JStgExpr] -> JStgExpr
- math_log1p :: [JStgExpr] -> JStgExpr
- math_fround :: [JStgExpr] -> JStgExpr
- data Solo a where
- decl :: Ident -> JStgStat
Injection Type classes
The ToJExpr
class handles injection of of things into the EDSL as a JS
expression
class ToJExpr a where Source #
Things that can be marshalled into javascript values. Instantiate for any necessary data structures.
Instances
The ToStat
class handles injection of of things into the EDSL as a JS
statement. This ends up being polymorphic sugar for JS blocks, see helper
function expr2stat
. Instantiate for any necessary data
structures.
class JVarMagic a where Source #
Type class that generates fresh a
's for the JS backend. You should almost
never need to use this directly. Instead use JSArgument
, for examples of
how to employ these classes please see jVar
, jFunction
and call sites in
the Rts.
class JSArgument args where Source #
Type class that finds the form of arguments required for a JS syntax
object. This class gives us a single interface to generate variables for
functions that have different arities. Thus with it, we can have only one
jFunction
which is polymorphic over its arity, instead of jFunction2
,
jFunction3
and so on.
Instances
Introduction functions
jString :: FastString -> JStgExpr Source #
Convert a ShortText to a Javascript String
jLam :: JSArgument args => (args -> JSM JStgStat) -> JSM JStgExpr Source #
Create a new anonymous function. The result is a JExpr
expression.
Usage:
jLam $ \x -> jVar x + one_ jLam $ \f -> (jLam $ \x -> (f `app` (x `app` x))) `app` (jLam $ \x -> (f `app` (x `app` x)))
jLam' :: JStgStat -> JStgExpr Source #
Special case of jLam
where the anonymous function requires no fresh
arguments.
:: JSArgument args | |
=> Ident | global name |
-> (args -> JSM JStgStat) | function body, input is locally unique generated variables |
-> JSM JStgStat |
Construct a top-level function subject to JS hoisting. This combinator is
polymorphic over function arity so you can you use to define a JS syntax
object in Haskell, which is a function in JS that takes 2 or 4 or whatever
arguments. For a singleton function use the Solo
constructor MkSolo
.
Usage:
an example from the Rts that defines a 1-arity JS function > jFunction (global "h$getReg") ((MkSolo n) -> return $ SwitchStat n getRegCases mempty)
an example of a two argument function from the Rts > jFunction (global "h$bh_lne") ((x, frameSize) -> bhLneStats s x frameSize)
:: Ident | global name |
-> Int | Arity |
-> ([JStgExpr] -> JSM JStgStat) | function body, input is locally unique generated variables |
-> JSM JStgStat |
Construct a top-level function subject to JS hoisting. Special case where
the arity cannot be deduced from the args
parameter (atleast not without
dependent types).
:: Ident | global name |
-> JSM JStgStat | function body, input is locally unique generated variables |
-> JSM JStgStat |
Construct a top-level function subject to JS hoisting. Special case where the function binds no parameters
jVar :: (JVarMagic t, ToJExpr t) => (t -> JSM JStgStat) -> JSM JStgStat Source #
Introduce only one new variable into scope for the duration of the enclosed expression. The result is a block statement. Usage:
'jVar $ x -> mconcat [jVar x ||= one_, ...'
jVars :: JSArgument args => (args -> JSM JStgStat) -> JSM JStgStat Source #
Introduce one or many new variables into scope for the duration of the enclosed expression. This function reifies the number of arguments based on the container of the input function. We intentionally avoid lists and instead opt for tuples because lists are not sized in general. The result is a block statement. Usage:
jVars $ (x,y) -> mconcat [ x |= one_, y |= two_, x + y]
:: (JStgExpr -> JStgStat) | initialization function |
-> (JStgExpr -> JStgExpr) | predicate |
-> (JStgExpr -> JStgStat) | step function |
-> (JStgExpr -> JStgStat) | body |
-> JSM JStgStat |
Create a for
statement given a function for initialization, a predicate
to step to, a step and a body
Usage:
jFor (|= zero_) (.<. Int 65536) preIncrS (j -> ...something with the counter j...)
jForIn :: JStgExpr -> (JStgExpr -> JStgStat) -> JSM JStgStat Source #
Create a 'for in' statement. Usage:
jForIn {expression} $ x -> {block involving x}
jForEachIn :: JStgExpr -> (JStgExpr -> JStgStat) -> JSM JStgStat Source #
As with "jForIn" but creating a "for each in" statement.
jTryCatchFinally :: (Ident -> JStgStat) -> (Ident -> JStgStat) -> (Ident -> JStgStat) -> JSM JStgStat Source #
As with "jForIn" but creating a "for each in" statement.
Combinators
Combinators operate on terms in the JS EDSL domain to create new terms in the EDSL domain.
(||=) :: Ident -> JStgExpr -> JStgStat infixl 2 Source #
Declare a variable and then Assign the variable to an expression
foo |= expr ==> var foo; foo = expr;
(|=) :: JStgExpr -> JStgExpr -> JStgStat infixl 2 Source #
Assign a variable to an expression
foo |= expr ==> var foo = expr;
(.!) :: JStgExpr -> JStgExpr -> JStgExpr infixl 8 Source #
return the expression at idx of obj
obj .! idx ==> obj[idx]
if_ :: JStgExpr -> JStgExpr -> JStgExpr -> JStgExpr Source #
JS if-expression
if_ e1 e2 e3 ==> e1 ? e2 : e3
if10 :: JStgExpr -> JStgExpr Source #
if-expression that returns 1 if condition = true, 0 otherwise
if10 e ==> e ? 1 : 0
if01 :: JStgExpr -> JStgExpr Source #
if-expression that returns 0 if condition = true, 1 otherwise
if01 e ==> e ? 0 : 1
ifS :: JStgExpr -> JStgStat -> JStgStat -> JStgStat Source #
If-expression which returns statements, see related ifBlockS
if e s1 s2 ==> if(e) { s1 } else { s2 }
ifBlockS :: JStgExpr -> [JStgStat] -> [JStgStat] -> JStgStat Source #
If-expression which returns blocks
ifBlockS e s1 s2 ==> if(e) { s1 } else { s2 }
jIf :: JStgExpr -> JSM JStgStat -> JSM JStgStat -> JSM JStgStat Source #
Version of a JS if-expression which admits monadic actions in its branches
jwhenS :: JStgExpr -> JStgStat -> JStgStat Source #
A when-statement as syntactic sugar via ifS
jwhenS cond block ==> if(cond) { block } else { }
app :: FastString -> [JStgExpr] -> JStgExpr Source #
an expression application, see related appS
app f xs ==> f(xs)
appS :: FastString -> [JStgExpr] -> JStgStat Source #
A statement application, see the expression form app
loop :: JStgExpr -> (JStgExpr -> JStgExpr) -> (JStgExpr -> JSM JStgStat) -> JSM JStgStat Source #
"for" loop with increment at end of body
loopBlockS :: JStgExpr -> (JStgExpr -> JStgExpr) -> (JStgExpr -> [JStgStat]) -> JSM JStgStat Source #
"for" loop with increment at end of body
signExtend8 :: JStgExpr -> JStgExpr Source #
Sign-extend/narrow a 8-bit value
signExtend16 :: JStgExpr -> JStgExpr Source #
Sign-extend/narrow a 16-bit value
assignAllEqual :: HasDebugCallStack => [JStgExpr] -> [JStgExpr] -> JStgStat Source #
(.^) :: JStgExpr -> FastString -> JStgExpr infixl 8 Source #
Select a property prop
, from and object obj
obj .^ prop ==> obj.prop
Hash combinators
jhAdd :: (Ord k, ToJExpr a) => k -> a -> Map k JStgExpr -> Map k JStgExpr Source #
insert a key-value pair into a JS HashMap
jhFromList :: [(FastString, JStgExpr)] -> JVal Source #
Construct a JS HashMap from a list of key-value pairs
Literals
Literals in the JS EDSL are constants in the Haskell domain. These are useful helper values and never change
undefined_ :: JStgExpr Source #
The JS literal undefined
Math functions
Math functions in the EDSL are literals, with the exception of math_
which
is the sole math introduction function.
math_asinh :: [JStgExpr] -> JStgExpr Source #
math_acosh :: [JStgExpr] -> JStgExpr Source #
math_atanh :: [JStgExpr] -> JStgExpr Source #
math_expm1 :: [JStgExpr] -> JStgExpr Source #
math_log1p :: [JStgExpr] -> JStgExpr Source #
math_fround :: [JStgExpr] -> JStgExpr Source #
Statement helpers
MkSolo a |
Instances
MonadZip Solo | Since: base-4.15.0.0 | ||||
Foldable1 Solo | Since: base-4.18.0.0 | ||||
Defined in Data.Foldable1 fold1 :: Semigroup m => Solo m -> m Source # foldMap1 :: Semigroup m => (a -> m) -> Solo a -> m Source # foldMap1' :: Semigroup m => (a -> m) -> Solo a -> m Source # toNonEmpty :: Solo a -> NonEmpty a Source # maximum :: Ord a => Solo a -> a Source # minimum :: Ord a => Solo a -> a Source # foldrMap1 :: (a -> b) -> (a -> b -> b) -> Solo a -> b Source # foldlMap1' :: (a -> b) -> (b -> a -> b) -> Solo a -> b Source # foldlMap1 :: (a -> b) -> (b -> a -> b) -> Solo a -> b Source # foldrMap1' :: (a -> b) -> (a -> b -> b) -> Solo a -> b Source # | |||||
Eq1 Solo | Since: base-4.15 | ||||
Ord1 Solo | Since: base-4.15 | ||||
Defined in Data.Functor.Classes | |||||
Read1 Solo | Since: base-4.15 | ||||
Defined in Data.Functor.Classes liftReadsPrec :: (Int -> ReadS a) -> ReadS [a] -> Int -> ReadS (Solo a) Source # liftReadList :: (Int -> ReadS a) -> ReadS [a] -> ReadS [Solo a] Source # liftReadPrec :: ReadPrec a -> ReadPrec [a] -> ReadPrec (Solo a) Source # liftReadListPrec :: ReadPrec a -> ReadPrec [a] -> ReadPrec [Solo a] Source # | |||||
Show1 Solo | Since: base-4.15 | ||||
NFData1 Solo | Since: deepseq-1.4.6.0 | ||||
Defined in Control.DeepSeq | |||||
Applicative Solo | |||||
Functor Solo | |||||
Monad Solo | |||||
MonadFix Solo | |||||
Defined in GHC.Internal.Control.Monad.Fix | |||||
Foldable Solo | |||||
Defined in GHC.Internal.Data.Foldable fold :: Monoid m => Solo m -> m # foldMap :: Monoid m => (a -> m) -> Solo a -> m # foldMap' :: Monoid m => (a -> m) -> Solo a -> m # foldr :: (a -> b -> b) -> b -> Solo a -> b # foldr' :: (a -> b -> b) -> b -> Solo a -> b # foldl :: (b -> a -> b) -> b -> Solo a -> b # foldl' :: (b -> a -> b) -> b -> Solo a -> b # foldr1 :: (a -> a -> a) -> Solo a -> a # foldl1 :: (a -> a -> a) -> Solo a -> a # elem :: Eq a => a -> Solo a -> Bool # maximum :: Ord a => Solo a -> a # | |||||
Traversable Solo | |||||
Generic1 Solo | |||||
Defined in GHC.Internal.Generics
| |||||
NFData a => NFData (Solo a) | Since: deepseq-1.4.6.0 | ||||
Defined in Control.DeepSeq | |||||
(JVarMagic a, ToJExpr a) => JSArgument (Solo a) Source # | |||||
Monoid a => Monoid (Solo a) | |||||
Semigroup a => Semigroup (Solo a) | |||||
Data a => Data (Solo a) | |||||
Defined in GHC.Internal.Data.Data gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Solo a -> c (Solo a) # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Solo a) # toConstr :: Solo a -> Constr # dataTypeOf :: Solo a -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (Solo a)) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (Solo a)) # gmapT :: (forall b. Data b => b -> b) -> Solo a -> Solo a # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Solo a -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Solo a -> r # gmapQ :: (forall d. Data d => d -> u) -> Solo a -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> Solo a -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> Solo a -> m (Solo a) # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Solo a -> m (Solo a) # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Solo a -> m (Solo a) # | |||||
Bounded a => Bounded (Solo a) | |||||
Enum a => Enum (Solo a) | |||||
Defined in GHC.Internal.Enum | |||||
Generic (Solo a) | |||||
Defined in GHC.Internal.Generics
| |||||
Ix a => Ix (Solo a) | |||||
Read a => Read (Solo a) | |||||
Show a => Show (Solo a) | |||||
Eq a => Eq (Solo a) | |||||
Ord a => Ord (Solo a) | |||||
type Rep1 Solo | |||||
Defined in GHC.Internal.Generics | |||||
type Rep (Solo a) | |||||
Defined in GHC.Internal.Generics |