on 72da9da 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 , define
9 , safe
10 )
11 where
13import qualified Control.Monad.State as State
14import qualified Data.List as List
15import qualified Data.Set as Set
16import qualified Language.ECMAScript3.Syntax as JS
18import qualified AST.Helpers as Help
19import qualified AST.Module.Name as ModuleName
20import qualified AST.Variable as Var
21import qualified Elm.Package as Pkg
22import qualified Generate.JavaScript.Helpers as JS
26-- FRESH NAMES
29fresh :: State.State Int String
30fresh =
31 do n <- State.get
32 State.modify (+1)
33 return ("_v" ++ show n)
37-- DEF NAMES
40define :: Maybe ModuleName.Canonical -> String -> JS.Expression () -> [JS.Statement ()]
41define maybeHome name body =
42 if not (Help.isOp name) then
43 let
44 jsName =
45 maybe unqualified qualified maybeHome name
46 in
47 [ JS.VarDeclStmt () [ JS.varDecl jsName body ] ]
49 else
50 case maybeHome of
51 Nothing ->
52 error "can only define infix operators at the top level"
54 Just home ->
55 let
56 opsDictName =
57 getOpsDictName (Var.TopLevel home)
59 lvalue =
60 JS.LBracket () (JS.ref opsDictName) (JS.StringLit () name)
61 in
62 [ JS.VarDeclStmt () [ JS.varDecl opsDictName (JS.refOrObject opsDictName) ]
63 , JS.ExprStmt () (JS.AssignExpr () JS.OpAssign lvalue body)
64 ]
68-- INSTANTIATE VARIABLES
71canonical :: Var.Canonical -> JS.Expression ()
72canonical (Var.Canonical home name) =
73 if Help.isOp name then
74 JS.BracketRef () (JS.ref (getOpsDictName home)) (JS.StringLit () name)
76 else
77 case home of
78 Var.Local ->
79 JS.ref (unqualified name)
81 Var.BuiltIn ->
82 JS.ref (unqualified name)
84 Var.Module moduleName@(ModuleName.Canonical _ rawName) ->
85 if ModuleName.isNative rawName then
86 native moduleName name
88 else
89 JS.ref (qualified moduleName name)
91 Var.TopLevel moduleName ->
92 JS.ref (qualified moduleName name)
95unqualified :: String -> String
96unqualified =
97 safe
100qualified :: ModuleName.Canonical -> String -> String
101qualified moduleName name =
102 moduleToString moduleName ++ "$" ++ removePrimes name
105native :: ModuleName.Canonical -> String -> JS.Expression ()
106native moduleName name =
107 JS.obj [ moduleToString moduleName, name ]
110coreNative :: String -> String -> JS.Expression ()
111coreNative moduleName name =
112 native (ModuleName.inCore ["Native",moduleName]) name
115getOpsDictName :: Var.Home -> String
116getOpsDictName home =
117 let
118 moduleName =
119 case home of
120 Var.Local -> error "infix operators should only be defined in top-level declarations"
121 Var.BuiltIn -> error "there should be no built-in infix operators"
122 Var.Module name -> name
123 Var.TopLevel name -> name
124 in
125 moduleToString moduleName ++ "_ops"
128moduleToString :: ModuleName.Canonical -> String
129moduleToString (ModuleName.Canonical (Pkg.Name user project) moduleName) =
130 let
131 safeUser =
132 map (swap '-' '_') user
134 safeProject =
135 map (swap '-' '_') project
137 safeModuleName =
138 List.intercalate "_" moduleName
139 in
140 '_' : safeUser ++ "$" ++ safeProject ++ "$" ++ safeModuleName
143swap :: Char -> Char -> Char -> Char
144swap from to c =
145 if c == from then to else c
149-- SAFE NAMES
152safe :: String -> String
153safe name =
154 removePrimes $
155 if Set.member name jsReserveds then '$' : name else name
158removePrimes :: String -> String
159removePrimes name =
160 map (swap '\'' '$') 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 ]