on 65a3af0 help sign in
elk/src/Generate/JavaScript/Variable.hs
151 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 )
14 where
17import qualified Control.Monad.State as State
18import Data.Monoid ((<>))
19import qualified Data.Map as Map
20import qualified Data.Set as Set
21import qualified Data.Text as Text
22import Data.Text (Text)
24import qualified AST.Helpers as Help
25import qualified AST.Module.Name as ModuleName
26import qualified AST.Variable as Var
27import qualified Elm.Package as Pkg
28import qualified Generate.JavaScript.Builder as JS
29import qualified Generate.JavaScript.Helpers as JS
33-- GENERATOR
36type Generator = State.State Table
39run :: Table -> Generator a -> ( a, Table )
40run table generator =
41 State.runState generator table
45-- STATE
48data Table =
49 Table
50 { _uid :: !Int
51 , _names :: Map.Map Var.Global Text
52 }
55emptyTable :: Table
56emptyTable =
57 Table 0 Map.empty
61-- FRESH NAMES
64fresh :: Generator Text
65fresh =
66 do (Table uid names) <- State.get
67 State.put (Table (uid + 1) names)
68 return (Text.pack ("_v" ++ show uid))
72-- LOCAL NAMES
75local :: Text -> JS.Expr
76local name =
77 JS.ref (safe name)
80safe :: Text -> Text
81safe name =
82 if Set.member name reservedWords then
83 "_" <> name
84 else
85 name
88reservedWords :: Set.Set Text
89reservedWords =
90 Set.fromList
91 -- reserved by JavaScript
92 [ "null", "undefined", "Nan", "Infinity", "true", "false", "eval"
93 , "arguments", "int", "byte", "char", "goto", "long", "final", "float"
94 , "short", "double", "native", "throws", "boolean", "abstract", "volatile"
95 , "transient", "synchronized", "function", "break", "case", "catch"
96 , "continue", "debugger", "default", "delete", "do", "else", "finally"
97 , "for", "function", "if", "in", "instanceof", "new", "return", "switch"
98 , "this", "throw", "try", "typeof", "var", "void", "while", "with", "class"
99 , "const", "enum", "export", "extends", "import", "super", "implements"
100 , "interface", "let", "package", "private", "protected", "public"
101 , "static", "yield"
102 -- reserved by Elm
103 , "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"
104 , "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9"
105 , "ctor"
106 ]
110-- GLOBAL NAMES
113global :: Var.Global -> Generator JS.Expr
114global var =
115 JS.ref <$> globalName var
118globalName :: Var.Global -> Generator Text
119globalName var =
120 do table <- State.get
121 globalNameHelp var table
124globalNameHelp :: Var.Global -> Table -> Generator Text
125globalNameHelp var@(Var.Global home name) (Table uid names) =
126 case Help.isOp name of
127 False ->
128 return $ globalToName home name
130 True ->
131 case Map.lookup var names of
132 Just jsName ->
133 return jsName
135 Nothing ->
136 do let jsName = globalToName home ("_op" <> Text.pack (show uid))
137 State.put (Table (uid + 1) (Map.insert var jsName names))
138 return jsName
141globalToName :: ModuleName.Canonical -> Text -> Text
142globalToName (ModuleName.Canonical (Pkg.Name user project) moduleName) name =
143 if ModuleName.isKernel moduleName then
144 "_" <> ModuleName.getKernel moduleName <> "_" <> name
146 else
147 Text.replace "-" "_" user
148 <> "$" <> Text.replace "-" "_" project
149 <> "$" <> Text.replace "." "_" moduleName
150 <> "$" <> name