on 101709f help sign in
elk/src/Generate/JavaScript/Variable.hs
152 lines 3.4 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Generate.JavaScript.Variable
4 ( Generator
5 , run
6 , Table
7 , emptyTable
8 , fresh
9 , local
10 , safe
11 , global
12 , globalName
13 , globalToName
14 )
15 where
18import qualified Control.Monad.State as State
19import Data.Monoid ((<>))
20import qualified Data.Map as Map
21import qualified Data.Set as Set
22import qualified Data.Text as Text
23import Data.Text (Text)
25import qualified AST.Helpers as Help
26import qualified AST.Module.Name as ModuleName
27import qualified AST.Variable as Var
28import qualified Elm.Package as Pkg
29import qualified Generate.JavaScript.Builder as JS
30import qualified Generate.JavaScript.Helpers as JS
34-- GENERATOR
37type Generator = State.State Table
40run :: Table -> Generator a -> ( a, Table )
41run table generator =
42 State.runState generator table
46-- STATE
49data Table =
50 Table
51 { _uid :: !Int
52 , _names :: Map.Map Var.Global Text
53 }
56emptyTable :: Table
57emptyTable =
58 Table 0 Map.empty
62-- FRESH NAMES
65fresh :: Generator Text
66fresh =
67 do (Table uid names) <- State.get
68 State.put (Table (uid + 1) names)
69 return (Text.pack ("_v" ++ show uid))
73-- LOCAL NAMES
76local :: Text -> JS.Expr
77local name =
78 JS.ref (safe name)
81safe :: Text -> Text
82safe name =
83 if Set.member name reservedWords then
84 "_" <> name
85 else
86 name
89reservedWords :: Set.Set Text
90reservedWords =
91 Set.fromList
92 -- reserved by JavaScript
93 [ "null", "undefined", "Nan", "Infinity", "true", "false", "eval"
94 , "arguments", "int", "byte", "char", "goto", "long", "final", "float"
95 , "short", "double", "native", "throws", "boolean", "abstract", "volatile"
96 , "transient", "synchronized", "function", "break", "case", "catch"
97 , "continue", "debugger", "default", "delete", "do", "else", "finally"
98 , "for", "function", "if", "in", "instanceof", "new", "return", "switch"
99 , "this", "throw", "try", "typeof", "var", "void", "while", "with", "class"
100 , "const", "enum", "export", "extends", "import", "super", "implements"
101 , "interface", "let", "package", "private", "protected", "public"
102 , "static", "yield"
103 -- reserved by Elm
104 , "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"
105 , "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9"
106 , "ctor"
107 ]
111-- GLOBAL NAMES
114global :: Var.Global -> Generator JS.Expr
115global var =
116 JS.ref <$> globalName var
119globalName :: Var.Global -> Generator Text
120globalName var =
121 do table <- State.get
122 globalNameHelp var table
125globalNameHelp :: Var.Global -> Table -> Generator Text
126globalNameHelp var@(Var.Global home name) (Table uid names) =
127 case Help.isOp name of
128 False ->
129 return $ globalToName home name
131 True ->
132 case Map.lookup var names of
133 Just jsName ->
134 return jsName
136 Nothing ->
137 do let jsName = globalToName home ("_op" <> Text.pack (show uid))
138 State.put (Table (uid + 1) (Map.insert var jsName names))
139 return jsName
142globalToName :: ModuleName.Canonical -> Text -> Text
143globalToName (ModuleName.Canonical (Pkg.Name user project) moduleName) name =
144 if ModuleName.isKernel moduleName then
145 "_" <> ModuleName.getKernel moduleName <> "_" <> name
147 else
148 Text.replace "-" "_" user
149 <> "$" <> Text.replace "-" "_" project
150 <> "$" <> Text.replace "." "_" moduleName
151 <> "$" <> name