Skip to content

Commit ce4c1fc

Browse files
sebastiaanvisserbergmark
authored andcommitted
Implemented overloadable string literals using an in-scope fromString (closes #320).
Uses a combination of OverloadedStrings and RebindableSyntax.
1 parent 30b5079 commit ce4c1fc

File tree

14 files changed

+118
-13
lines changed

14 files changed

+118
-13
lines changed

fay.cabal

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,14 @@ extra-source-files:
136136
tests/Floating.res
137137
tests/fromInteger.hs
138138
tests/fromInteger.res
139+
tests/FromString/Dep.hs
140+
tests/FromString/Dep.res
141+
tests/FromString/DepDep.hs
142+
tests/FromString/DepDep.res
143+
tests/FromString/FayText.hs
144+
tests/FromString/FayText.res
145+
tests/FromString.hs
146+
tests/FromString.res
139147
tests/GADTs_without_records.hs
140148
tests/GADTs_without_records.res
141149
tests/guards.hs

src/Fay/Compiler.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ compileModuleFromAST (Module _ modulename _pragmas Nothing _exports imports decl
158158
imported <- fmap concat (mapM compileImport imports)
159159
modify $ \s -> s { stateModuleName = modulename
160160
, stateModuleScope = fromMaybe (error $ "Could not find stateModuleScope for " ++ show modulename) $ M.lookup modulename $ stateModuleScopes s
161+
, stateUseFromString = useFromString _pragmas
161162
}
162163
current <- compileDecls True decls
163164

@@ -175,6 +176,12 @@ compileModuleFromAST (Module _ modulename _pragmas Nothing _exports imports decl
175176
else stmts
176177
compileModuleFromAST mod = throwError (UnsupportedModuleSyntax mod)
177178

179+
useFromString :: [ModulePragma] -> Bool
180+
useFromString pragmas = any (hasPragma "OverloadedStrings") pragmas
181+
&& any (hasPragma "RebindableSyntax") pragmas
182+
where hasPragma p (LanguagePragma _ q) | p `elem` q = True
183+
hasPragma _ _ = False
184+
178185
instance CompilesTo Module [JsStmt] where compileTo = compileModuleFromAST
179186

180187

src/Fay/Compiler/Defaults.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ defaultCompileState = do
4141
, stateModuleScope = def
4242
, stateModuleScopes = M.empty
4343
, stateJsModulePaths = S.empty
44+
, stateUseFromString = False
4445
}

src/Fay/Compiler/Exp.hs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,11 @@ compileLit lit =
8484
Frac rational -> return (JsLit (JsFloating (fromRational rational)))
8585
-- TODO: Use real JS strings instead of array, probably it will
8686
-- lead to the same result.
87-
String string -> return (JsApp (JsName (JsBuiltIn "list"))
88-
[JsLit (JsStr string)])
87+
String string -> do
88+
fromString <- gets stateUseFromString
89+
if fromString
90+
then return (JsLit (JsStr string))
91+
else return (JsApp (JsName (JsBuiltIn "list")) [JsLit (JsStr string)])
8992
lit -> throwError (UnsupportedLiteral lit)
9093

9194
-- | Compile simple application.

src/Fay/FFI.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module Fay.FFI
1212
,ffi)
1313
where
1414

15+
import Data.String (IsString)
1516
import Fay.Types
1617
import Prelude (Bool, Char, Double, Int, Maybe, String, error)
1718

@@ -44,6 +45,7 @@ type Ptr a = a
4445
type Automatic a = a
4546

4647
-- | Declare a foreign action.
47-
ffi :: String -- ^ The foreign value.
48+
ffi :: IsString s
49+
=> s -- ^ The foreign value.
4850
-> a -- ^ Bottom.
4951
ffi = error "Fay.FFI.ffi: Used foreign function outside a JS engine context."

src/Fay/Types.hs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,18 @@ mkModulePathFromQName _ = error "mkModulePathFromQName: Not a qualified name"
108108

109109
-- | State of the compiler.
110110
data CompileState = CompileState
111-
{ _stateExports :: Map ModuleName (Set QName) -- ^ Collects exports from modules
112-
, stateRecordTypes :: [(QName,[QName])] -- ^ Map types to constructors
113-
, stateRecords :: [(QName,[QName])] -- ^ Map constructors to fields
114-
, stateNewtypes :: [(QName, Maybe QName, Type)] -- ^ Newtype constructor, destructor, wrapped type tuple
115-
, stateImported :: [(ModuleName,FilePath)] -- ^ Map of all imported modules and their source locations.
116-
, stateNameDepth :: Integer -- ^ Depth of the current lexical scope.
117-
, stateLocalScope :: Set Name -- ^ Names in the current lexical scope.
118-
, stateModuleScope :: ModuleScope -- ^ Names in the module scope.
119-
, stateModuleScopes :: Map ModuleName ModuleScope
120-
, stateModuleName :: ModuleName -- ^ Name of the module currently being compiled.
111+
{ _stateExports :: Map ModuleName (Set QName) -- ^ Collects exports from modules
112+
, stateRecordTypes :: [(QName,[QName])] -- ^ Map types to constructors
113+
, stateRecords :: [(QName,[QName])] -- ^ Map constructors to fields
114+
, stateNewtypes :: [(QName, Maybe QName, Type)] -- ^ Newtype constructor, destructor, wrapped type tuple
115+
, stateImported :: [(ModuleName,FilePath)] -- ^ Map of all imported modules and their source locations.
116+
, stateNameDepth :: Integer -- ^ Depth of the current lexical scope.
117+
, stateLocalScope :: Set Name -- ^ Names in the current lexical scope.
118+
, stateModuleScope :: ModuleScope -- ^ Names in the module scope.
119+
, stateModuleScopes :: Map ModuleName ModuleScope
120+
, stateModuleName :: ModuleName -- ^ Name of the module currently being compiled.
121121
, stateJsModulePaths :: Set ModulePath
122+
, stateUseFromString :: Bool
122123
} deriving (Show)
123124

124125
-- | Things written out by the compiler.

tests/FromString.hs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{-# LANGUAGE OverloadedStrings, RebindableSyntax #-}
2+
module FromString where
3+
4+
import Prelude
5+
import FromString.FayText
6+
import FromString.Dep (myString, depTest)
7+
8+
main :: Fay ()
9+
main = do
10+
print ("This is not a String" :: Text)
11+
print "This is not a String"
12+
putStrLn myString
13+
print myString
14+
depTest
15+

tests/FromString.res

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
This is not a String
2+
This is not a String
3+
test
4+
[ 't', 'e', 's', 't' ]
5+
This is also not a String

tests/FromString/Dep.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module FromString.Dep where
2+
3+
import Prelude
4+
import FromString.DepDep (myText)
5+
6+
myString :: String
7+
myString = "test"
8+
9+
depTest :: Fay ()
10+
depTest = print myText
11+

tests/FromString/Dep.res

Whitespace-only changes.

0 commit comments

Comments
 (0)