on 442ac09 help sign in
elk/src/Generate/JavaScript/Variable.hs
178 lines 4.5 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Generate.JavaScript.Variable
4 ( fresh
5 , canonical
6 , qualified
7 , native
8 , coreNative
9 , staticProgram
10 , define
11 , safe
12 )
13 where
15import qualified Control.Monad.State as State
16import Data.Monoid
17import qualified Data.Set as Set
18import qualified Data.Text as Text
19import Data.Text (Text)
21import qualified AST.Helpers as Help
22import qualified AST.Module.Name as ModuleName
23import qualified AST.Variable as Var
24import qualified Elm.Package as Pkg
25import qualified Generate.JavaScript.Builder as JS
26import qualified Generate.JavaScript.Helpers as JS
30-- FRESH NAMES
33fresh :: State.State Int Text
34fresh =
35 do n <- State.get
36 State.modify (+1)
37 return (Text.pack ("_v" ++ show n))
41-- DEF NAMES
44define :: Maybe ModuleName.Canonical -> Text -> JS.Expr -> [JS.Stmt]
45define maybeHome name body =
46 if not (Help.isOp name) then
47 let
48 jsName =
49 maybe unqualified qualified maybeHome name
50 in
51 [ JS.VarDeclStmt [ JS.varDecl jsName body ] ]
53 else
54 case maybeHome of
55 Nothing ->
56 error "can only define infix operators at the top level"
58 Just home ->
59 let
60 opsDictName =
61 getOpsDictName (Var.TopLevel home)
63 lvalue =
64 JS.LBracket (JS.ref opsDictName) (JS.String name)
65 in
66 [ JS.VarDeclStmt [ JS.varDecl opsDictName (JS.refOrObject opsDictName) ]
67 , JS.ExprStmt (JS.Assign JS.OpAssign lvalue body)
68 ]
72-- INSTANTIATE VARIABLES
75canonical :: Var.Canonical -> JS.Expr
76canonical (Var.Canonical home name) =
77 if Help.isOp name then
78 JS.BracketRef (JS.ref (getOpsDictName home)) (JS.String name)
80 else
81 case home of
82 Var.Local ->
83 JS.ref (unqualified name)
85 Var.BuiltIn ->
86 JS.ref (unqualified name)
88 Var.Module moduleName@(ModuleName.Canonical _ rawName) ->
89 if ModuleName.isNative rawName then
90 native moduleName name
92 else
93 JS.ref (qualified moduleName name)
95 Var.TopLevel moduleName ->
96 JS.ref (qualified moduleName name)
99unqualified :: Text -> Text
100unqualified =
101 safe
104qualified :: ModuleName.Canonical -> Text -> Text
105qualified moduleName name =
106 moduleToText moduleName <> "$" <> name
109native :: ModuleName.Canonical -> Text -> JS.Expr
110native moduleName name =
111 JS.obj [ moduleToText moduleName, name ]
114coreNative :: Text -> Text -> JS.Expr
115coreNative moduleName name =
116 native (ModuleName.inCore ("Native." <> moduleName)) name
119staticProgram :: JS.Expr
120staticProgram =
121 native (ModuleName.inVirtualDom "Native.VirtualDom") "staticProgram"
124getOpsDictName :: Var.Home -> Text
125getOpsDictName home =
126 let
127 moduleName =
128 case home of
129 Var.Local -> error "infix operators should only be defined in top-level declarations"
130 Var.BuiltIn -> error "there should be no built-in infix operators"
131 Var.Module name -> name
132 Var.TopLevel name -> name
133 in
134 moduleToText moduleName <> "_ops"
137moduleToText :: ModuleName.Canonical -> Text
138moduleToText (ModuleName.Canonical (Pkg.Name user project) moduleName) =
139 let
140 safeUser =
141 Text.replace "-" "_" user
143 safeProject =
144 Text.replace "-" "_" project
146 safeModuleName =
147 Text.replace "." "_" moduleName
148 in
149 "_" <> safeUser <> "$" <> safeProject <> "$" <> safeModuleName
153-- SAFE NAMES
156safe :: Text -> Text
157safe name =
158 if Set.member name jsReserveds then "$" <> name else name
161jsReserveds :: Set.Set Text
162jsReserveds =
163 Set.fromList
164 -- JS reserved words
165 [ "null", "undefined", "Nan", "Infinity", "true", "false", "eval"
166 , "arguments", "int", "byte", "char", "goto", "long", "final", "float"
167 , "short", "double", "native", "throws", "boolean", "abstract", "volatile"
168 , "transient", "synchronized", "function", "break", "case", "catch"
169 , "continue", "debugger", "default", "delete", "do", "else", "finally"
170 , "for", "function", "if", "in", "instanceof", "new", "return", "switch"
171 , "this", "throw", "try", "typeof", "var", "void", "while", "with", "class"
172 , "const", "enum", "export", "extends", "import", "super", "implements"
173 , "interface", "let", "package", "private", "protected", "public"
174 , "static", "yield"
175 -- reserved by the Elm runtime system
176 , "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"
177 , "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9"
178 ]