Skip to content

Commit dc615b4

Browse files
committed
Don't use capitalized names on record creation to prevent name clashes with modules (fixes #368)
1 parent f14e083 commit dc615b4

File tree

6 files changed

+41
-5
lines changed

6 files changed

+41
-5
lines changed

src/Fay/Compiler/Exp.hs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import Fay.Types
2828
import Control.Applicative
2929
import Control.Monad.Error
3030
import Control.Monad.RWS
31+
import qualified Data.Char as Char
3132
import Language.Haskell.Exts.Annotated
3233
import Language.Haskell.Names
3334

@@ -276,18 +277,18 @@ compileEnumFromThenTo a b z = do
276277
compileRecConstr :: S.QName -> [S.FieldUpdate] -> Compile JsExp
277278
compileRecConstr name fieldUpdates = do
278279
-- var obj = new $_Type()
279-
let unQualName = unQualify $ unAnn name
280+
let unQualName = withIdent lowerFirst . unQualify $ unAnn name
280281
qname <- unsafeResolveName name
281282
let record = JsVar (JsNameVar unQualName) (JsNew (JsConstructor qname) [])
282283
setFields <- liftM concat (forM fieldUpdates (updateStmt name))
283-
return $ JsApp (JsFun Nothing [] (record:setFields) (Just $ JsName $ JsNameVar $ unQualify $ unAnn name)) []
284+
return $ JsApp (JsFun Nothing [] (record:setFields) (Just . JsName . JsNameVar . withIdent lowerFirst . unQualify $ unAnn name)) []
284285
where
285286
-- updateStmt :: QName a -> S.FieldUpdate -> Compile [JsStmt]
286287
updateStmt (unAnn -> o) (FieldUpdate _ (unAnn -> field) value) = do
287288
exp <- compileExp value
288-
return [JsSetProp (JsNameVar $ unQualify o) (JsNameVar $ unQualify field) exp]
289-
updateStmt name (FieldWildcard (wildcardFields -> fields)) = do
290-
return $ for fields $ \fieldName -> JsSetProp (JsNameVar $ unAnn name)
289+
return [JsSetProp (JsNameVar $ withIdent lowerFirst $ unQualify o) (JsNameVar $ unQualify field) exp]
290+
updateStmt o (FieldWildcard (wildcardFields -> fields)) = do
291+
return $ for fields $ \fieldName -> JsSetProp (JsNameVar . withIdent lowerFirst . unQualify . unAnn $ o)
291292
(JsNameVar fieldName)
292293
(JsName $ JsNameVar fieldName)
293294
-- I couldn't find a code that generates (FieldUpdate (FieldPun ..))
@@ -296,6 +297,9 @@ compileRecConstr name fieldUpdates = do
296297
wildcardFields l = case l of
297298
Scoped (RecExpWildcard es) _ -> map (unQualify . origName2QName) . map fst $ es
298299
_ -> []
300+
lowerFirst :: String -> String
301+
lowerFirst "" = ""
302+
lowerFirst (x:xs) = '_' : Char.toLower x : xs
299303

300304
-- | Compile a record update.
301305
compileRecUpdate :: S.Exp -> [S.FieldUpdate] -> Compile JsExp

src/Fay/Compiler/QName.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@ changeModule' :: (String -> String) -> QName a -> QName a
3030
changeModule' f (Qual l (ModuleName ml mn) n) = Qual l (ModuleName ml $ f mn) n
3131
changeModule' _ x = x
3232

33+
withIdent :: (String -> String) -> QName a -> QName a
34+
withIdent f q = case q of
35+
Qual l m n -> Qual l m $ withIdent' f n
36+
UnQual l n -> UnQual l $ withIdent' f n
37+
Special{} -> q
38+
where
39+
withIdent' :: (String -> String) -> Name a -> Name a
40+
withIdent' f' n' = case n' of
41+
Symbol{} -> n'
42+
Ident l s -> Ident l (f' s)
43+
3344
-- | Extract the string from a Name.
3445
unname :: Name a -> String
3546
unname (Ident _ s) = s

tests/ModuleRecordClash2.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module Main where
2+
3+
import FFI
4+
import ModuleRecordClash2_Hello
5+
import Prelude
6+
7+
alert :: String -> Fay ()
8+
alert = ffi "console.log(%1)"
9+
10+
main = do
11+
alert (greeting defaultHello)

tests/ModuleRecordClash2.res

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hello, world!

tests/ModuleRecordClash2_Hello.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- This module needs to be top level to do the intended test.
2+
module ModuleRecordClash2_Hello where
3+
4+
import Prelude
5+
6+
defaultHello :: ModuleRecordClash2_Hello
7+
defaultHello = ModuleRecordClash2_Hello { greeting = "Hello, world!" }
8+
9+
data ModuleRecordClash2_Hello = ModuleRecordClash2_Hello { greeting :: String }

tests/ModuleRecordClash2_Hello.res

Whitespace-only changes.

0 commit comments

Comments
 (0)