on 41df71f help sign in
elk/src/Generate/JavaScript/Variable.hs
181 lines 4.6 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2module Generate.JavaScript.Variable
3 ( fresh
4 , canonical
5 , qualified
6 , native
7 , coreNative
8 , staticProgram
9 , define
10 , safe
11 )
12 where
14import qualified Control.Monad.State as State
15import qualified Data.List as List
16import qualified Data.Set as Set
17import qualified Language.ECMAScript3.Syntax as JS
19import qualified AST.Helpers as Help
20import qualified AST.Module.Name as ModuleName
21import qualified AST.Variable as Var
22import qualified Elm.Package as Pkg
23import qualified Generate.JavaScript.Helpers as JS
27-- FRESH NAMES
30fresh :: State.State Int String
31fresh =
32 do n <- State.get
33 State.modify (+1)
34 return ("_v" ++ show n)
38-- DEF NAMES
41define :: Maybe ModuleName.Canonical -> String -> JS.Expression () -> [JS.Statement ()]
42define maybeHome name body =
43 if not (Help.isOp name) then
44 let
45 jsName =
46 maybe unqualified qualified maybeHome name
47 in
48 [ JS.VarDeclStmt () [ JS.varDecl jsName body ] ]
50 else
51 case maybeHome of
52 Nothing ->
53 error "can only define infix operators at the top level"
55 Just home ->
56 let
57 opsDictName =
58 getOpsDictName (Var.TopLevel home)
60 lvalue =
61 JS.LBracket () (JS.ref opsDictName) (JS.StringLit () name)
62 in
63 [ JS.VarDeclStmt () [ JS.varDecl opsDictName (JS.refOrObject opsDictName) ]
64 , JS.ExprStmt () (JS.AssignExpr () JS.OpAssign lvalue body)
65 ]
69-- INSTANTIATE VARIABLES
72canonical :: Var.Canonical -> JS.Expression ()
73canonical (Var.Canonical home name) =
74 if Help.isOp name then
75 JS.BracketRef () (JS.ref (getOpsDictName home)) (JS.StringLit () name)
77 else
78 case home of
79 Var.Local ->
80 JS.ref (unqualified name)
82 Var.BuiltIn ->
83 JS.ref (unqualified name)
85 Var.Module moduleName@(ModuleName.Canonical _ rawName) ->
86 if ModuleName.isNative rawName then
87 native moduleName name
89 else
90 JS.ref (qualified moduleName name)
92 Var.TopLevel moduleName ->
93 JS.ref (qualified moduleName name)
96unqualified :: String -> String
97unqualified =
98 safe
101qualified :: ModuleName.Canonical -> String -> String
102qualified moduleName name =
103 moduleToString moduleName ++ "$" ++ name
106native :: ModuleName.Canonical -> String -> JS.Expression ()
107native moduleName name =
108 JS.obj [ moduleToString moduleName, name ]
111coreNative :: String -> String -> JS.Expression ()
112coreNative moduleName name =
113 native (ModuleName.inCore ["Native",moduleName]) name
116staticProgram :: JS.Expression ()
117staticProgram =
118 native (ModuleName.inVirtualDom ["Native","VirtualDom"]) "staticProgram"
121getOpsDictName :: Var.Home -> String
122getOpsDictName home =
123 let
124 moduleName =
125 case home of
126 Var.Local -> error "infix operators should only be defined in top-level declarations"
127 Var.BuiltIn -> error "there should be no built-in infix operators"
128 Var.Module name -> name
129 Var.TopLevel name -> name
130 in
131 moduleToString moduleName ++ "_ops"
134moduleToString :: ModuleName.Canonical -> String
135moduleToString (ModuleName.Canonical (Pkg.Name user project) moduleName) =
136 let
137 safeUser =
138 map (swap '-' '_') user
140 safeProject =
141 map (swap '-' '_') project
143 safeModuleName =
144 List.intercalate "_" moduleName
145 in
146 '_' : safeUser ++ "$" ++ safeProject ++ "$" ++ safeModuleName
149swap :: Char -> Char -> Char -> Char
150swap from to c =
151 if c == from then to else c
155-- SAFE NAMES
158safe :: String -> String
159safe name =
160 if Set.member name jsReserveds then '$' : name else name
163jsReserveds :: Set.Set String
164jsReserveds =
165 Set.fromList
166 -- JS reserved words
167 [ "null", "undefined", "Nan", "Infinity", "true", "false", "eval"
168 , "arguments", "int", "byte", "char", "goto", "long", "final", "float"
169 , "short", "double", "native", "throws", "boolean", "abstract", "volatile"
170 , "transient", "synchronized", "function", "break", "case", "catch"
171 , "continue", "debugger", "default", "delete", "do", "else", "finally"
172 , "for", "function", "if", "in", "instanceof", "new", "return", "switch"
173 , "this", "throw", "try", "typeof", "var", "void", "while", "with", "class"
174 , "const", "enum", "export", "extends", "import", "super", "implements"
175 , "interface", "let", "package", "private", "protected", "public"
176 , "static", "yield"
177 -- reserved by the Elm runtime system
178 , "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"
179 , "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9"
180 , JS.localRuntime
181 ]