@@ -9,15 +9,20 @@ module Generate.JavaScript.Variable
10 , globalName
10 , globalName
11 , globalToName
11 , globalToName
16import qualified Control.Monad.State.Strict as State
17import qualified Control.Monad.State.Strict as State
18+import qualified Data.ByteString as BS
17import Data.Monoid ((<>))
19import Data.Monoid ((<>))
20+import qualified Data.Map as Map
18import qualified Data.Set as Set
21import qualified Data.Set as Set
19−import qualified Data.Text as Text
20import Data.Text (Text)
22import Data.Text (Text)
23+import qualified Data.Text as Text
24+import qualified Data.Text.Encoding as Text (encodeUtf8)
25+import Data.Word (Word8)
22import qualified AST.Helpers as Help
27import qualified AST.Helpers as Help
23import qualified AST.Module.Name as ModuleName
28import qualified AST.Module.Name as ModuleName
@@ -61,28 +66,41 @@ local name =
62safe :: Text -> Text
67safe :: Text -> Text
63safe name =
68safe name =
64− if Set.member name reservedWords then
69+ if Set.member name reservedNames then
65 "_" <> name
70 "_" <> name
79+reservedNames :: Set.Set Text
81+ Set.union jsReservedWords elmReservedWords
70−reservedWords :: Set.Set Text
84+jsReservedWords :: Set.Set Text
71−reservedWords =
85+jsReservedWords =
72 Set.fromList
86 Set.fromList
73− -- reserved by JavaScript
87+ [ "do", "if", "in"
74− [ "null", "undefined", "NaN", "Infinity", "true", "false", "eval"
88+ , "NaN", "int", "for", "new", "try", "var", "let"
75− , "arguments", "int", "byte", "char", "goto", "long", "final", "float"
89+ , "null", "true", "eval", "byte", "char", "goto", "long", "case", "else", "this", "void", "with", "enum"
76− , "short", "double", "native", "throws", "boolean", "abstract", "volatile"
90+ , "false", "final", "float", "short", "break", "catch", "throw", "while", "class", "const", "super", "yield"
77− , "transient", "synchronized", "function", "break", "case", "catch"
91+ , "double", "native", "throws", "delete", "return", "switch", "typeof", "export", "import", "public", "static"
78− , "continue", "debugger", "default", "delete", "do", "else", "finally"
92+ , "boolean", "default", "finally", "extends", "package", "private"
79− , "for", "function", "if", "in", "instanceof", "new", "return", "switch"
93+ , "Infinity", "abstract", "volatile", "function", "continue", "debugger", "function"
80− , "this", "throw", "try", "typeof", "var", "void", "while", "with", "class"
94+ , "undefined", "arguments", "transient", "interface", "protected"
81− , "const", "enum", "export", "extends", "import", "super", "implements"
95+ , "instanceof", "implements"
82− , "interface", "let", "package", "private", "protected", "public"
96+ , "synchronized"
83− , "static", "yield"
97+ ]
84− -- reserved by Elm
98+
100+elmReservedWords :: Set.Set Text
85− , "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"
103+ [ "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"
86 , "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9"
104 , "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9"
@@ -119,3 +137,113 @@ globalToName (ModuleName.Canonical (Pkg.Name user project) moduleName) name =
119 <> "$" <> Text.replace "." "_" moduleName
137 <> "$" <> Text.replace "." "_" moduleName
120 <> "$" <> revisedName
138 <> "$" <> revisedName
145+intToAscii :: Int -> BS.ByteString
147+ if n < 53 then -- skip $ as a standalone name
148+ BS.singleton (toByte n)
151+ intToAsciiHelp (numStartBytes * numInnerBytes) allBadFields (n - 53)
154+intToAsciiHelp :: Int -> [BadFields] -> Int -> BS.ByteString
155+intToAsciiHelp blockSize badFields n =
158+ if n < blockSize then
161+ intToAsciiHelp (blockSize * numInnerBytes) [] (n - blockSize)
163+ BadFields renamings : biggerBadFields ->
164+ if n < blockSize - Map.size renamings then
165+ let name = unsafeIntToAscii n in
166+ Map.findWithDefault name name renamings
168+ intToAsciiHelp (blockSize * numInnerBytes) biggerBadFields (n - blockSize)
172+-- UNSAFE INT TO ASCII
175+unsafeIntToAscii :: Int -> BS.ByteString
178+ (quotient, remainder) =
179+ quotRem n numStartBytes
181+ BS.pack $ toByte remainder : unsafeIntToAsciiHelp quotient
184+unsafeIntToAsciiHelp :: Int -> [Word8]
185+unsafeIntToAsciiHelp n =
189+ let (quotient, remainder) = quotRem n numInnerBytes in
190+ toByte remainder : unsafeIntToAsciiHelp quotient
207+toByte :: Int -> Word8
209+ | n < 26 = fromIntegral (97 + n ) {- lower -}
210+ | n < 52 = fromIntegral (65 + n - 26) {- upper -}
211+ | n == 53 = 95 {- _ -}
212+ | n == 54 = 36 {- $ -}
213+ | n < 64 = fromIntegral (48 + n - 54) {- digit -}
214+ | True = error $ "cannot convert int " ++ show n ++ " to ASCII"
222+ BadFields { _renamings :: Renamings }
226+ Map.Map BS.ByteString BS.ByteString
229+allBadFields :: [BadFields]
233+ Map.alter (Just . addRenaming keyword) (Text.length keyword) dict
235+ Map.elems $ Set.foldr add Map.empty jsReservedWords
238+addRenaming :: Text -> Maybe BadFields -> BadFields
239+addRenaming keyword maybeBadFields =
242+ numStartBytes * numInnerBytes ^ (Text.length keyword - 1) - 1
244+ case maybeBadFields of
246+ BadFields $ Map.singleton (Text.encodeUtf8 keyword) (unsafeIntToAscii maxName)
248+ Just (BadFields renamings) ->
249+ BadFields $ Map.insert (Text.encodeUtf8 keyword) (unsafeIntToAscii (maxName - Map.size renamings)) renamings