1{-# LANGUAGE OverloadedStrings #-}
2module Generate.JavaScript.Expression
15import qualified Data.IntMap as IntMap
16import qualified Data.List as List
18import qualified Data.Map as Map
19import qualified Data.Text.Encoding as Text
21import qualified AST.Canonical as Can
22import qualified AST.Optimized as Opt
23import qualified AST.Module.Name as ModuleName
24import qualified Data.Index as Index
25import qualified Elm.Compiler.Type as Type
26import qualified Elm.Compiler.Type.Extract as Extract
27import qualified Elm.Name as N
28import qualified Elm.Package as Pkg
29import qualified Elm.Compiler.Version as Version
30import qualified Generate.JavaScript.Builder as JS
31import qualified Generate.JavaScript.Mode as Mode
32import qualified Generate.JavaScript.Name as Name
33import qualified Json.Encode as Encode
34import qualified Optimize.DecisionTree as DT
35import qualified Reporting.Region as R
42generateJsExpr :: Mode.Mode -> Opt.Expr -> JS.Expr
43generateJsExpr mode expression =
44 codeToExpr (generate mode expression)
47generate :: Mode.Mode -> Opt.Expr -> Code
48generate mode expression =
57 JS.Call toChar [ JS.String (Text.encodeUtf8Builder char) ]
60 JS.String (Text.encodeUtf8Builder char)
63 JsExpr $ JS.String (Text.encodeUtf8Builder string)
69 JsExpr $ JS.Float float
72 JsExpr $ JS.Ref (Name.fromLocal name)
74 Opt.VarGlobal (Opt.Global home name) ->
75 JsExpr $ JS.Ref (Name.fromGlobal home name)
77 Opt.VarEnum (Opt.Global home name) index ->
80 JsExpr $ JS.Ref (Name.fromGlobal home name)
83 JsExpr $ JS.Int (Index.toMachine index)
85 Opt.VarBox (Opt.Global home name) ->
88 Mode.Dev _ _ -> Name.fromGlobal home name
89 Mode.Prod _ _ -> Name.fromGlobal ModuleName.basics N.identity
91 Opt.VarCycle home name ->
92 JsExpr $ JS.Call (JS.Ref (Name.fromCycle home name)) []
94 Opt.VarDebug name home region unhandledValueName ->
95 JsExpr $ generateDebug name home region unhandledValueName
97 Opt.VarKernel home name ->
98 JsExpr $ JS.Ref (Name.fromKernel home name)
103 JsExpr $ JS.Ref (Name.fromKernel N.list "Nil")
108 (JS.Ref (Name.fromKernel N.list "fromArray"))
109 [ JS.Array $ map (generateJsExpr mode) entries
112 Opt.Function args body ->
113 generateFunction (map Name.fromLocal args) (generate mode body)
115 Opt.Call func args ->
116 JsExpr $ generateCall mode func args
118 Opt.TailCall name args ->
119 JsBlock $ generateTailCall mode name args
121 Opt.If branches final ->
122 generateIf mode branches final
126 generateDef mode def : codeToStmtList (generate mode body)
128 Opt.Destruct (Opt.Destructor name path) body ->
130 pathExpr = generatePath mode path
131 pathDef = JS.Var [ (Name.fromLocal name, Just pathExpr) ]
133 JsBlock $ pathDef : codeToStmtList (generate mode body)
135 Opt.Case label root decider jumps ->
136 JsBlock $ generateCase mode label root decider jumps
138 Opt.Accessor field ->
139 JsExpr $ JS.Function Nothing [Name.dollar]
141 JS.Access (JS.Ref Name.dollar) (generateField mode field)
144 Opt.Access record field ->
145 JsExpr $ JS.Access (generateJsExpr mode record) (generateField mode field)
147 Opt.Update record fields ->
149 JS.Call (JS.Ref (Name.fromKernel N.utils "update"))
150 [ generateJsExpr mode record
151 , generateRecord mode fields
155 JsExpr $ generateRecord mode fields
160 JsExpr $ JS.Ref (Name.fromKernel N.utils "Tuple0")
165 Opt.Tuple a b maybeC ->
169 JS.Call (JS.Ref (Name.fromKernel N.utils "Tuple2"))
170 [ generateJsExpr mode a
171 , generateJsExpr mode b
175 JS.Call (JS.Ref (Name.fromKernel N.utils "Tuple3"))
176 [ generateJsExpr mode a
177 , generateJsExpr mode b
178 , generateJsExpr mode c
182 let string = JS.String (Text.encodeUtf8Builder src) in
183 JsExpr $ JS.Object [ ( Name.fromLocal "src", string ) ]
195codeToExpr :: Code -> JS.Expr
201 JsBlock [ JS.Return (Just expr) ] ->
205 JS.Call (JS.Function Nothing [] stmts) []
208codeToStmtList :: Code -> [JS.Stmt]
211 JsExpr (JS.Call (JS.Function Nothing [] stmts) []) ->
215 [ JS.Return (Just expr) ]
221codeToStmt :: Code -> JS.Stmt
224 JsExpr (JS.Call (JS.Function Nothing [] stmts) []) ->
228 JS.Return (Just expr)
241{-# NOINLINE toChar #-}
244 JS.Ref (Name.fromKernel N.utils "chr")
251generateCtor :: Mode.Mode -> N.Name -> Index.ZeroBased -> Int -> Code
252generateCtor mode name index arity =
255 Index.indexedMap (\i _ -> Name.fromIndex i) [1 .. arity]
259 Mode.Dev _ _ -> JS.String (N.toBuilder name)
260 Mode.Prod _ _ -> JS.Int (Index.toMachine index)
262 generateFunction argNames $ JsExpr $ JS.Object $
263 (Name.dollar, ctorTag) : map (\n -> (n, JS.Ref n)) argNames
270generateRecord :: Mode.Mode -> Map.Map N.Name Opt.Expr -> JS.Expr
271generateRecord mode fields =
273 toPair (field, value) =
274 (generateField mode field, generateJsExpr mode value)
276 JS.Object (map toPair (Map.toList fields))
279generateField :: Mode.Mode -> N.Name -> Name.Name
280generateField mode name =
285 Mode.Prod _ fields ->
294generateDebug :: N.Name -> ModuleName.Canonical -> R.Region -> Maybe N.Name -> JS.Expr
295generateDebug name (ModuleName.Canonical _ home) region unhandledValueName =
296 if name /= "todo" then
297 JS.Ref (Name.fromGlobal ModuleName.debug name)
299 case unhandledValueName of
301 JS.Call (JS.Ref (Name.fromKernel N.debug "todo")) $
302 [ JS.String (N.toBuilder home)
303 , regionToJsExpr region
307 JS.Call (JS.Ref (Name.fromKernel N.debug "todoCase")) $
308 [ JS.String (N.toBuilder home)
309 , regionToJsExpr region
310 , JS.Ref (Name.fromLocal valueName)
314regionToJsExpr :: R.Region -> JS.Expr
315regionToJsExpr (R.Region start end) =
317 [ ( Name.fromLocal "start", positionToJsExpr start )
318 , ( Name.fromLocal "end", positionToJsExpr end )
322positionToJsExpr :: R.Position -> JS.Expr
323positionToJsExpr (R.Position line column) =
325 [ ( Name.fromLocal "line", JS.Int line )
326 , ( Name.fromLocal "column", JS.Int column )
334generateFunction :: [Name.Name] -> Code -> Code
335generateFunction args body =
336 case IntMap.lookup (length args) funcHelpers of
340 [ JS.Function Nothing args $
347 JsExpr $ JS.Function Nothing [arg] $
350 foldr addArg body args
353{-# NOINLINE funcHelpers #-}
354funcHelpers :: IntMap.IntMap JS.Expr
357 map (\n -> (n, JS.Ref (Name.makeF n))) [2..9]
364generateCall :: Mode.Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
365generateCall mode func args =
367 Opt.VarGlobal global@(Opt.Global (ModuleName.Canonical pkg _) _) | pkg == Pkg.core ->
368 generateCoreCall mode global args
373 generateCallHelp mode func args
378 generateJsExpr mode arg
381 generateCallHelp mode func args
384 generateCallHelp mode func args
387generateCallHelp :: Mode.Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
388generateCallHelp mode func args =
390 (generateJsExpr mode func)
391 (map (generateJsExpr mode) args)
394generateGlobalCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
395generateGlobalCall home name args =
396 generateNormalCall (JS.Ref (Name.fromGlobal home name)) args
399generateNormalCall :: JS.Expr -> [JS.Expr] -> JS.Expr
400generateNormalCall func args =
401 case IntMap.lookup (length args) callHelpers of
403 JS.Call helper (func:args)
406 List.foldl' (\f a -> JS.Call f [a]) func args
409{-# NOINLINE callHelpers #-}
410callHelpers :: IntMap.IntMap JS.Expr
413 map (\n -> (n, JS.Ref (Name.makeA n))) [2..9]
420generateCoreCall :: Mode.Mode -> Opt.Global -> [Opt.Expr] -> JS.Expr
421generateCoreCall mode (Opt.Global home@(ModuleName.Canonical _ moduleName) name) args =
422 if moduleName == N.basics then
423 generateBasicsCall mode home name args
425 else if moduleName == N.bitwise then
426 generateBitwiseCall home name (map (generateJsExpr mode) args)
428 else if moduleName == N.tuple then
429 generateTupleCall home name (map (generateJsExpr mode) args)
431 else if moduleName == N.jsArray then
432 generateJsArrayCall home name (map (generateJsExpr mode) args)
435 generateGlobalCall home name (map (generateJsExpr mode) args)
438generateTupleCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
439generateTupleCall home name args =
443 "first" -> JS.Access value (Name.fromLocal "a")
444 "second" -> JS.Access value (Name.fromLocal "b")
445 _ -> generateGlobalCall home name args
448 generateGlobalCall home name args
451generateJsArrayCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
452generateJsArrayCall home name args =
454 [entry] | name == "singleton" -> JS.Array [entry]
455 [index, array] | name == "unsafeGet" -> JS.Index array index
456 _ -> generateGlobalCall home name args
459generateBitwiseCall :: ModuleName.Canonical -> N.Name -> [JS.Expr] -> JS.Expr
460generateBitwiseCall home name args =
464 "complement" -> JS.Prefix JS.PrefixBNot arg
465 _ -> generateGlobalCall home name args
469 "and" -> JS.Infix JS.OpBAnd left right
470 "or" -> JS.Infix JS.OpBOr left right
471 "xor" -> JS.Infix JS.OpBXor left right
472 "shiftLeftBy" -> JS.Infix JS.OpLShift right left
473 "shiftRightBy" -> JS.Infix JS.OpSpRShift right left
474 "shiftRightZfBy" -> JS.Infix JS.OpZfRShift right left
475 _ -> generateGlobalCall home name args
478 generateGlobalCall home name args
481generateBasicsCall :: Mode.Mode -> ModuleName.Canonical -> N.Name -> [Opt.Expr] -> JS.Expr
482generateBasicsCall mode home name args =
485 let arg = generateJsExpr mode elmArg in
487 "not" -> JS.Prefix JS.PrefixLNot arg
488 "negate" -> JS.Prefix JS.PrefixMinus arg
490 "truncate" -> JS.Infix JS.OpBOr arg (JS.Int 0)
491 _ -> generateGlobalCall home name [arg]
493 [elmLeft, elmRight] ->
495 "composeL" -> decomposeL mode elmLeft [elmRight]
496 "composeR" -> decomposeR mode [elmLeft] elmRight
497 "append" -> append mode elmLeft elmRight
498 "apL" -> generateJsExpr mode $ apply elmLeft elmRight
499 "apR" -> generateJsExpr mode $ apply elmRight elmLeft
502 left = generateJsExpr mode elmLeft
503 right = generateJsExpr mode elmRight
506 "add" -> JS.Infix JS.OpAdd left right
507 "sub" -> JS.Infix JS.OpSub left right
508 "mul" -> JS.Infix JS.OpMul left right
509 "fdiv" -> JS.Infix JS.OpDiv left right
510 "idiv" -> JS.Infix JS.OpBOr (JS.Infix JS.OpDiv left right) (JS.Int 0)
511 "eq" -> equal left right
512 "neq" -> notEqual left right
513 "lt" -> cmp JS.OpLT JS.OpLT 0 left right
514 "gt" -> cmp JS.OpGT JS.OpGT 0 left right
515 "le" -> cmp JS.OpLEq JS.OpLT 1 left right
516 "ge" -> cmp JS.OpGEq JS.OpGT (-1) left right
517 "or" -> JS.Infix JS.OpLOr left right
518 "and" -> JS.Infix JS.OpLAnd left right
519 "xor" -> JS.Infix JS.OpStrictNEq left right
520 "remainderBy" -> JS.Infix JS.OpMod right left
521 _ -> generateGlobalCall home name [left, right]
524 generateGlobalCall home name (map (generateJsExpr mode) args)
527equal :: JS.Expr -> JS.Expr -> JS.Expr
529 if isLiteral left || isLiteral right then
532 JS.Call (JS.Ref (Name.fromKernel N.utils "eq")) [left, right]
535notEqual :: JS.Expr -> JS.Expr -> JS.Expr
537 if isLiteral left || isLiteral right then
540 JS.Prefix JS.PrefixLNot $
541 JS.Call (JS.Ref (Name.fromKernel N.utils "eq")) [left, right]
544cmp :: JS.InfixOp -> JS.InfixOp -> Int -> JS.Expr -> JS.Expr -> JS.Expr
545cmp idealOp backupOp backupInt left right =
546 if isLiteral left || isLiteral right then
547 JS.Infix idealOp left right
550 (JS.Call (JS.Ref (Name.fromKernel N.utils "cmp")) [left, right])
554isLiteral :: JS.Expr -> Bool
573decomposeL :: Mode.Mode -> Opt.Expr -> [Opt.Expr] -> JS.Expr
574decomposeL mode expr funcs =
576 Opt.Call (Opt.VarGlobal (Opt.Global home "composeL")) [left, func]
577 | home == ModuleName.basics ->
578 decomposeL mode left (func:funcs)
581 generateJsExpr mode $
582 Opt.Function [N.dollar] (foldr apply (Opt.VarLocal N.dollar) (expr:funcs))
585decomposeR :: Mode.Mode -> [Opt.Expr] -> Opt.Expr -> JS.Expr
586decomposeR mode funcs expr =
588 Opt.Call (Opt.VarGlobal (Opt.Global home "composeR")) [func, right]
589 | home == ModuleName.basics ->
590 decomposeR mode (func:funcs) right
593 generateJsExpr mode $
594 Opt.Function [N.dollar] (foldr apply (Opt.VarLocal N.dollar) (expr:funcs))
597apply :: Opt.Expr -> Opt.Expr -> Opt.Expr
600 Opt.Accessor field ->
601 Opt.Access value field
604 Opt.Call f (args ++ [value])
607 Opt.Call func [value]
610append :: Mode.Mode -> Opt.Expr -> Opt.Expr -> JS.Expr
611append mode left right =
612 let seqs = generateJsExpr mode left : toSeqs mode right in
613 if any isStringLiteral seqs then
614 foldr1 (JS.Infix JS.OpAdd) seqs
619jsAppend :: JS.Expr -> JS.Expr -> JS.Expr
621 JS.Call (JS.Ref (Name.fromKernel N.utils "ap")) [a, b]
624toSeqs :: Mode.Mode -> Opt.Expr -> [JS.Expr]
627 Opt.Call (Opt.VarGlobal (Opt.Global home "append")) [left, right]
628 | home == ModuleName.basics ->
629 generateJsExpr mode left : toSeqs mode right
632 [generateJsExpr mode expr]
635isStringLiteral :: JS.Expr -> Bool
636isStringLiteral expr =
646-- SIMPLIFY INFIX OPERATORS
649strictEq :: JS.Expr -> JS.Expr -> JS.Expr
653 JS.Prefix JS.PrefixLNot right
656 if bool then right else JS.Prefix JS.PrefixLNot right
661 JS.Prefix JS.PrefixLNot left
664 if bool then left else JS.Prefix JS.PrefixLNot left
667 JS.Infix JS.OpStrictEq left right
670strictNEq :: JS.Expr -> JS.Expr -> JS.Expr
671strictNEq left right =
677 if bool then JS.Prefix JS.PrefixLNot right else right
685 if bool then JS.Prefix JS.PrefixLNot left else left
688 JS.Infix JS.OpStrictNEq left right
695-- TODO check if JS minifiers collapse unnecessary temporary variables
697generateTailCall :: Mode.Mode -> N.Name -> [(N.Name, Opt.Expr)] -> [JS.Stmt]
698generateTailCall mode name args =
700 toTempVars (argName, arg) =
701 ( Name.makeTemp argName, Just (generateJsExpr mode arg) )
703 toRealVars (argName, _) =
705 JS.Assign (JS.LRef (Name.fromLocal argName)) (JS.Ref (Name.makeTemp argName))
707 JS.Var (map toTempVars args)
708 : map toRealVars args
709 ++ [ JS.Continue (Just (Name.fromLocal name)) ]
716generateDef :: Mode.Mode -> Opt.Def -> JS.Stmt
717generateDef mode def =
720 JS.Var [ (Name.fromLocal name, Just (generateJsExpr mode body)) ]
722 Opt.TailDef name argNames body ->
723 JS.Var [ (Name.fromLocal name, Just (codeToExpr (generateTailDef mode name argNames body))) ]
726generateTailDef :: Mode.Mode -> N.Name -> [N.Name] -> Opt.Expr -> Code
727generateTailDef mode name argNames body =
728 generateFunction (map Name.fromLocal argNames) $ JsBlock $
729 [ JS.Labelled (Name.fromLocal name) $
730 JS.While (JS.Bool True) $
731 codeToStmt $ generate mode body
739generatePath :: Mode.Mode -> Opt.Path -> JS.Expr
740generatePath mode path =
742 Opt.Index index subPath ->
743 JS.Access (generatePath mode subPath) (Name.fromIndex index)
746 JS.Ref (Name.fromLocal name)
748 Opt.Field field subPath ->
749 JS.Access (generatePath mode subPath) (generateField mode field)
754 JS.Access (generatePath mode subPath) (Name.fromIndex Index.first)
757 generatePath mode subPath
764generateIf :: Mode.Mode -> [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> Code
765generateIf mode givenBranches givenFinal =
768 crushIfs givenBranches givenFinal
770 convertBranch (condition, expr) =
771 ( generateJsExpr mode condition
775 branchExprs = map convertBranch branches
776 finalCode = generate mode final
778 if isBlock finalCode || any (isBlock . snd) branchExprs then
779 JsBlock [ foldr addStmtIf (codeToStmt finalCode) branchExprs ]
781 JsExpr $ foldr addExprIf (codeToExpr finalCode) branchExprs
784addExprIf :: (JS.Expr, Code) -> JS.Expr -> JS.Expr
785addExprIf (condition, branch) final =
786 JS.If condition (codeToExpr branch) final
789addStmtIf :: (JS.Expr, Code) -> JS.Stmt -> JS.Stmt
790addStmtIf (condition, branch) final =
791 JS.IfStmt condition (codeToStmt branch) final
794isBlock :: Code -> Bool
801crushIfs :: [(Opt.Expr, Opt.Expr)] -> Opt.Expr -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
802crushIfs branches final =
803 crushIfsHelp [] branches final
807 :: [(Opt.Expr, Opt.Expr)]
808 -> [(Opt.Expr, Opt.Expr)]
810 -> ([(Opt.Expr, Opt.Expr)], Opt.Expr)
811crushIfsHelp visitedBranches unvisitedBranches final =
812 case unvisitedBranches of
815 Opt.If subBranches subFinal ->
816 crushIfsHelp visitedBranches subBranches subFinal
819 (reverse visitedBranches, final)
821 visiting : unvisited ->
822 crushIfsHelp (visiting : visitedBranches) unvisited final
829generateCase :: Mode.Mode -> N.Name -> N.Name -> Opt.Decider Opt.Choice -> [(Int, Opt.Expr)] -> [JS.Stmt]
830generateCase mode label root decider jumps =
831 foldr (goto mode label) (generateDecider mode label root decider) jumps
834goto :: Mode.Mode -> N.Name -> (Int, Opt.Expr) -> [JS.Stmt] -> [JS.Stmt]
835goto mode label (index, branch) stmts =
839 (Name.makeLabel label index)
840 (JS.While (JS.Bool True) (JS.Block stmts))
842 labeledDeciderStmt : codeToStmtList (generate mode branch)
845generateDecider :: Mode.Mode -> N.Name -> N.Name -> Opt.Decider Opt.Choice -> [JS.Stmt]
846generateDecider mode label root decisionTree =
848 Opt.Leaf (Opt.Inline branch) ->
849 codeToStmtList (generate mode branch)
851 Opt.Leaf (Opt.Jump index) ->
852 [ JS.Break (Just (Name.makeLabel label index)) ]
854 Opt.Chain testChain success failure ->
856 (List.foldl1' (JS.Infix JS.OpLAnd) (map (generateIfTest mode root) testChain))
857 (JS.Block $ generateDecider mode label root success)
858 (JS.Block $ generateDecider mode label root failure)
861 Opt.FanOut path edges fallback ->
863 (generateCaseTest mode root path (fst (head edges)))
865 (\edge cases -> generateCaseBranch mode label root edge : cases)
866 [ JS.Default (generateDecider mode label root fallback) ]
872generateIfTest :: Mode.Mode -> N.Name -> (DT.Path, DT.Test) -> JS.Expr
873generateIfTest mode root (path, test) =
875 value = pathToJsExpr mode root path
878 DT.IsCtor name index _ _ ->
879 strictEq (JS.Access value Name.dollar) $
881 Mode.Dev _ _ -> JS.String (N.toBuilder name)
882 Mode.Prod _ _ -> JS.Int (Index.toMachine index)
885 strictEq value (JS.Int int)
888 strictEq (JS.String (Text.encodeUtf8Builder char)) $
890 Mode.Dev _ _ -> JS.Call (JS.Access value (Name.fromLocal "valueOf")) []
891 Mode.Prod _ _ -> value
894 strictEq value (JS.String (Text.encodeUtf8Builder string))
897 JS.Access value (Name.fromLocal "b")
900 JS.Prefix JS.PrefixLNot $
901 JS.Access value (Name.fromLocal "b")
904 error "COMPILER BUG - there should never be tests on a tuple"
908generateCaseBranch :: Mode.Mode -> N.Name -> N.Name -> (DT.Test, Opt.Decider Opt.Choice) -> JS.Case
909generateCaseBranch mode label root (test, subTree) =
911 (generateCaseValue mode test)
912 (generateDecider mode label root subTree)
915generateCaseValue :: Mode.Mode -> DT.Test -> JS.Expr
916generateCaseValue mode test =
918 DT.IsCtor name index _ _ ->
920 Mode.Dev _ _ -> JS.String (N.toBuilder name)
921 Mode.Prod _ _ -> JS.Int (Index.toMachine index)
927 JS.String (Text.encodeUtf8Builder char)
930 JS.String (Text.encodeUtf8Builder string)
933 error "COMPILER BUG - there should never be three tests on a list"
936 error "COMPILER BUG - there should never be three tests on a list"
939 error "COMPILER BUG - there should never be three tests on a tuple"
942generateCaseTest :: Mode.Mode -> N.Name -> DT.Path -> DT.Test -> JS.Expr
943generateCaseTest mode root path exampleTest =
945 value = pathToJsExpr mode root path
948 DT.IsCtor _ _ _ opts ->
951 JS.Access value Name.dollar
956 JS.Access value Name.dollar
973 JS.Call (JS.Access value (Name.fromLocal "valueOf")) []
979 error "COMPILER BUG - there should never be three tests on a list"
982 error "COMPILER BUG - there should never be three tests on a list"
985 error "COMPILER BUG - there should never be three tests on a list"
992pathToJsExpr :: Mode.Mode -> N.Name -> DT.Path -> JS.Expr
993pathToJsExpr mode root path =
995 DT.Index index subPath ->
996 JS.Access (pathToJsExpr mode root subPath) (Name.fromIndex index)
1001 JS.Access (pathToJsExpr mode root subPath) (Name.fromIndex Index.first)
1004 pathToJsExpr mode root subPath
1007 JS.Ref (Name.fromLocal root)
1014generateMain :: Mode.Mode -> ModuleName.Canonical -> Opt.Main -> JS.Expr
1015generateMain mode home main =
1018 JS.Ref (Name.fromKernel N.virtualDom "init")
1019 # JS.Ref (Name.fromGlobal home "main")
1023 Opt.Dynamic msgType decoder ->
1024 JS.Ref (Name.fromGlobal home "main")
1025 # generateJsExpr mode decoder
1026 # toDebugMetadata mode msgType
1029(#) :: JS.Expr -> JS.Expr -> JS.Expr
1034toDebugMetadata :: Mode.Mode -> Can.Type -> JS.Expr
1035toDebugMetadata mode msgType =
1040 Mode.Dev _ Nothing ->
1043 Mode.Dev _ (Just interfaces) ->
1044 JS.Json $ Encode.object $
1045 [ ("versions", Encode.object [ ("elm", Pkg.encodeVersion Version.version) ])
1046 , ("types", Type.encodeMetadata (Extract.fromMsg interfaces msgType))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list