on master help sign in
Make sure that all names in a program are safe for use in JS code
commitf8bf89b48de7e8fd89d945ed342ebc708e03a92c authorEvan Czaplicki <info@elm-lang.org> dateSun 22 Dec 2013, 15:00 (13 years ago) parente690c42
4 files changed+90−13
Elm.cabal+2 compiler/Generate/JavaScript.hs+6−13 compiler/Parse/Helpers.hs+4 compiler/Transform/SafeNames.hs+78
Elm.cabal+2
@@ -54,6 +54,7 @@ Library
5454 Generate.Cases,
5555 Transform.Canonicalize,
5656 Transform.Check,
57+ Transform.SafeNames,
5758 Transform.SortDefinitions,
5859 Transform.Substitute,
5960 Transform.Optimize,
@@ -132,6 +133,7 @@ Executable elm
132133 Generate.Cases,
133134 Transform.Canonicalize,
134135 Transform.Check,
136+ Transform.SafeNames,
135137 Transform.SortDefinitions,
136138 Transform.Substitute,
137139 Transform.Optimize,
compiler/Generate/JavaScript.hs+6−13
@@ -1,4 +1,4 @@
1−module Generate.JavaScript where
1+module Generate.JavaScript (generate) where
22
33import Control.Arrow (first,(***))
44import Control.Applicative ((<$>),(<*>))
@@ -14,15 +14,7 @@ import SourceSyntax.Location
1414import qualified Transform.SortDefinitions as SD
1515import Language.ECMAScript3.Syntax
1616import Language.ECMAScript3.PrettyPrint
17−import Parse.Helpers (jsReserveds)
18−
19−makeSafe :: String -> String
20−makeSafe = List.intercalate "." . map dereserve . split . deprime
21− where
22− deprime = map (\c -> if c == '\'' then '$' else c)
23− dereserve x = case Set.member x jsReserveds of
24− False -> x
25− True -> "$" ++ x
17+import qualified Transform.SafeNames as MakeSafe
2618
2719split :: String -> [String]
2820split = go []
@@ -33,7 +25,7 @@ split = go []
3325 | otherwise -> go (vars ++ [x]) rest
3426 (x,[]) -> vars ++ [x]
3527
36−var name = Id () (makeSafe name)
28+var name = Id () name
3729ref name = VarRef () (var name)
3830prop name = PropId () (var name)
3931f <| x = CallExpr () f [x]
@@ -185,7 +177,7 @@ expression (L span expr) =
185177 do es' <- mapM expression es
186178 return $ ObjectLit () (ctor : fields es')
187179 where
188− ctor = (prop "ctor", string (makeSafe name))
180+ ctor = (prop "ctor", string name)
189181 fields = zipWith (\n e -> (prop ("_" ++ show n), e)) [0..]
190182
191183 Markdown uid doc es ->
@@ -291,10 +283,11 @@ clause span variable (Case.Clause value vars mtch) =
291283
292284
293285generate :: MetadataModule () () -> String
294−generate modul =
286+generate unsafeModule =
295287 show . prettyPrint $ setup (Just "Elm") (names modul ++ ["make"]) ++
296288 [ assign ("Elm" : names modul ++ ["make"]) (function ["_elm"] programStmts) ]
297289 where
290+ modul = MakeSafe.metadataModule unsafeModule
298291 thisModule = dotSep ("_elm" : names modul ++ ["values"])
299292 programStmts =
300293 concat [ setup (Just "_elm") (names modul ++ ["values"])
compiler/Parse/Helpers.hs+4
@@ -36,6 +36,10 @@ jsReserveds = Set.fromList
3636 , "const", "enum", "export", "extends", "import", "super", "implements"
3737 , "interface", "let", "package", "private", "protected", "public"
3838 , "static", "yield"
39+ -- reserved by the Elm runtime system
40+ , "Elm", "ElmRuntime"
41+ , "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"
42+ , "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9"
3943 ]
4044
4145expecting = flip (<?>)
compiler/Transform/SafeNames.hsnew file+78
@@ -0,0 +1,78 @@
1+{-# OPTIONS_GHC -Wall #-}
2+module Transform.SafeNames (metadataModule) where
3+
4+import Control.Arrow (first, (***))
5+import SourceSyntax.Expression
6+import SourceSyntax.Location
7+import SourceSyntax.Module
8+import SourceSyntax.Pattern
9+import qualified Data.Set as Set
10+import qualified Parse.Helpers as PHelp
11+
12+var :: String -> String
13+var = dereserve . deprime
14+ where
15+ deprime = map (\c -> if c == '\'' then '$' else c)
16+ dereserve x = case Set.member x PHelp.jsReserveds of
17+ False -> x
18+ True -> "$" ++ x
19+
20+pattern :: Pattern -> Pattern
21+pattern pat =
22+ case pat of
23+ PVar x -> PVar (var x)
24+ PLiteral _ -> pat
25+ PRecord fs -> PRecord (map var fs)
26+ PAnything -> pat
27+ PAlias x p -> PAlias (var x) (pattern p)
28+ PData name ps -> PData name (map pattern ps)
29+
30+expression :: LExpr t v -> LExpr t v
31+expression (L loc expr) =
32+ let f = expression in
33+ L loc $
34+ case expr of
35+ Literal _ -> expr
36+ Var x -> Var (var x)
37+ Range e1 e2 -> Range (f e1) (f e2)
38+ ExplicitList es -> ExplicitList (map f es)
39+ Binop op e1 e2 -> Binop op (f e1) (f e2)
40+ Lambda p e -> Lambda (pattern p) (f e)
41+ App e1 e2 -> App (f e1) (f e2)
42+ MultiIf ps -> MultiIf (map (f *** f) ps)
43+ Let defs body -> Let (map definition defs) (f body)
44+ Case e cases -> Case (f e) $ map (pattern *** f) cases
45+ Data name es -> Data name (map f es)
46+ Access e x -> Access (f e) (var x)
47+ Remove e x -> Remove (f e) (var x)
48+ Insert e x v -> Insert (f e) (var x) (f v)
49+ Modify r fs -> Modify (f r) (map (var *** f) fs)
50+ Record fs -> Record (map (var *** f) fs)
51+ Markdown uid md es -> Markdown uid md (map f es)
52+
53+definition :: Def t v -> Def t v
54+definition def =
55+ case def of
56+ Def p e -> Def (pattern p) (expression e)
57+ TypeAnnotation name t -> TypeAnnotation (var name) t
58+
59+metadataModule :: MetadataModule t v -> MetadataModule t v
60+metadataModule modul =
61+ modul
62+ { names = map var (names modul)
63+ , exports = map var (exports modul)
64+ , imports = map (first var) (imports modul)
65+ , program = expression (program modul)
66+ , aliases =
67+ let makeSafe (name, tvars, tipe) = (var name, tvars, tipe)
68+ in map makeSafe (aliases modul)
69+ , datatypes =
70+ let makeSafe (name,tvars,ctors) = (var name, tvars, map (first var) ctors)
71+ in map makeSafe (datatypes modul)
72+ , foreignImports =
73+ let makeSafe (js,expr,elm,tipe) = (js, expression expr, var elm, tipe)
74+ in map makeSafe (foreignImports modul)
75+ , foreignExports =
76+ let makeSafe (js,elm,tipe) = (js, var elm, tipe)
77+ in map makeSafe (foreignExports modul)
78+ }