switch StrV to use Data.Text
This commit is contained in:
parent
aab89f838b
commit
df693a83f7
79
Interp.hs
79
Interp.hs
|
@ -7,7 +7,10 @@ import Prelude hiding (lookup)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import qualified Data.ByteString.Char8 as BSC
|
import qualified Data.ByteString.Char8 as BSC
|
||||||
import qualified Network.Socket as SO
|
import qualified Network.Socket as SO
|
||||||
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.IO as TIO
|
||||||
import Data.List (intercalate)
|
import Data.List (intercalate)
|
||||||
|
import Control.Applicative ((<$>))
|
||||||
import Control.Exception (try, SomeException)
|
import Control.Exception (try, SomeException)
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
import Control.Monad.Trans.State (StateT, runStateT, evalStateT, get, put)
|
import Control.Monad.Trans.State (StateT, runStateT, evalStateT, get, put)
|
||||||
|
@ -27,7 +30,7 @@ instance Eq BIF where a == b = False
|
||||||
instance Ord BIF where compare a b = if a == b then EQ else LT
|
instance Ord BIF where compare a b = if a == b then EQ else LT
|
||||||
|
|
||||||
data Value = IntV Integer
|
data Value = IntV Integer
|
||||||
| StrV String
|
| StrV T.Text
|
||||||
| BoolV Bool
|
| BoolV Bool
|
||||||
| StreamV Handle
|
| StreamV Handle
|
||||||
| TupleV [Value]
|
| TupleV [Value]
|
||||||
|
@ -80,7 +83,7 @@ instance Show Value where
|
||||||
|
|
||||||
-- value operators
|
-- value operators
|
||||||
(IntV l) +$ (IntV r) = IntV (l + r)
|
(IntV l) +$ (IntV r) = IntV (l + r)
|
||||||
(StrV l) +$ (StrV r) = StrV (l ++ r)
|
(StrV l) +$ (StrV r) = StrV (l `T.append` r)
|
||||||
(ListV l) +$ (ListV r) = ListV (l ++ r)
|
(ListV l) +$ (ListV r) = ListV (l ++ r)
|
||||||
l +$ r = error $ "cannot + " ++ show l ++ " and " ++ show r
|
l +$ r = error $ "cannot + " ++ show l ++ " and " ++ show r
|
||||||
|
|
||||||
|
@ -104,40 +107,41 @@ l !=$ r = BoolV (l /= r)
|
||||||
|
|
||||||
toDict :: M.Map String Value -> Value
|
toDict :: M.Map String Value -> Value
|
||||||
toDict m =
|
toDict m =
|
||||||
let wrapped = map (\(k,v) -> (StrV k, v)) $ M.toAscList m in
|
let wrapped = map (\(k,v) -> (StrV (T.pack k), v)) $ M.toAscList m in
|
||||||
DictV $ M.fromAscList wrapped
|
DictV $ M.fromAscList wrapped
|
||||||
|
|
||||||
fromDict :: M.Map Value Value -> M.Map String Value
|
fromDict :: M.Map Value Value -> M.Map String Value
|
||||||
fromDict m =
|
fromDict m =
|
||||||
let unwrapped = map (\(StrV k,v) -> (k, v)) $ M.toAscList m in
|
let unwrapped = map (\(StrV k,v) -> (T.unpack k, v)) $ M.toAscList m in
|
||||||
M.fromAscList unwrapped
|
M.fromAscList unwrapped
|
||||||
|
|
||||||
-- some built-in functions
|
-- some built-in functions
|
||||||
|
|
||||||
_fputbytes (TupleV [StreamV handle, StrV str]) = do
|
_fputbytes (TupleV [StreamV handle, StrV str]) = do
|
||||||
io <- liftIO $ hPutStr handle str
|
io <- liftIO $ TIO.hPutStr handle str
|
||||||
return unitv
|
return unitv
|
||||||
|
|
||||||
_fputstr (TupleV [StreamV handle, StrV str]) = do
|
_fputstr (TupleV [StreamV handle, StrV str]) = do
|
||||||
io <- liftIO $ hPutStr handle str
|
io <- liftIO $ TIO.hPutStr handle str
|
||||||
return unitv
|
return unitv
|
||||||
|
|
||||||
_fgetline (StreamV handle) = do
|
_fgetline (StreamV handle) = do
|
||||||
str <- liftIO $ hGetLine handle
|
str <- liftIO $ TIO.hGetLine handle
|
||||||
if last str == '\r' then -- remove trailing CR
|
if T.last str == '\r' then -- remove trailing CR
|
||||||
return . StrV $ init str
|
return . StrV $ T.init str
|
||||||
else return $ StrV str
|
else return $ StrV str
|
||||||
|
|
||||||
_freadbytes (TupleV [StreamV handle, IntV n]) = do
|
_freadbytes (TupleV [StreamV handle, IntV n]) = do
|
||||||
str <- liftIO $ BSC.hGet handle (fromIntegral n :: Int)
|
--str <- liftIO $ BSC.hGet handle (fromIntegral n :: Int)
|
||||||
return . StrV $ BSC.unpack str
|
--return . StrV $ BSC.unpack str
|
||||||
|
liftIO $ StrV . T.take (fromIntegral n) <$> TIO.hGetContents handle
|
||||||
|
|
||||||
_fopen (TupleV [StrV path, StrV mode]) = do
|
_fopen (TupleV [StrV path, StrV mode]) = do
|
||||||
let mode' = case mode of
|
let mode' = case T.unpack mode of
|
||||||
"r" -> ReadMode
|
"r" -> ReadMode
|
||||||
"w" -> WriteMode
|
"w" -> WriteMode
|
||||||
"rw" -> ReadWriteMode
|
"rw" -> ReadWriteMode
|
||||||
handle <- liftIO $ openBinaryFile path mode'
|
handle <- liftIO $ openBinaryFile (T.unpack path) mode'
|
||||||
return $ StreamV handle
|
return $ StreamV handle
|
||||||
|
|
||||||
_feof (StreamV handle) = do
|
_feof (StreamV handle) = do
|
||||||
|
@ -150,7 +154,7 @@ _fclose (StreamV handle) = do
|
||||||
|
|
||||||
_sockopen (TupleV [StrV host, IntV port]) = do
|
_sockopen (TupleV [StrV host, IntV port]) = do
|
||||||
liftIO $ SO.withSocketsDo $ do
|
liftIO $ SO.withSocketsDo $ do
|
||||||
addr:_ <- SO.getAddrInfo Nothing (Just host) (Just $ show port)
|
addr:_ <- SO.getAddrInfo Nothing (Just $ T.unpack host) (Just $ show port)
|
||||||
sock <- SO.socket (SO.addrFamily addr) SO.Stream SO.defaultProtocol
|
sock <- SO.socket (SO.addrFamily addr) SO.Stream SO.defaultProtocol
|
||||||
SO.connect sock (SO.addrAddress addr)
|
SO.connect sock (SO.addrAddress addr)
|
||||||
handle <- SO.socketToHandle sock ReadWriteMode
|
handle <- SO.socketToHandle sock ReadWriteMode
|
||||||
|
@ -161,10 +165,10 @@ _putstr str@(StrV _) = _fputstr $ TupleV [StreamV stdout, str]
|
||||||
_putbytes str@(StrV _) = _fputbytes $ TupleV [StreamV stdout, str]
|
_putbytes str@(StrV _) = _fputbytes $ TupleV [StreamV stdout, str]
|
||||||
_getline (TupleV []) = _fgetline (StreamV stdin)
|
_getline (TupleV []) = _fgetline (StreamV stdin)
|
||||||
|
|
||||||
_print v = _putbytes $ StrV $ show v ++ "\n"
|
_print v = _putbytes $ StrV $ T.pack (show v) `T.snoc` '\n'
|
||||||
_repr v = return . StrV $ show v
|
_repr v = return . StrV $ T.pack $ show v
|
||||||
|
|
||||||
_itos (IntV i) = return $ StrV $ show i
|
_itos (IntV i) = return $ StrV $ T.pack $ show i
|
||||||
_itos v = error $ "itos: not an int: " ++ show v
|
_itos v = error $ "itos: not an int: " ++ show v
|
||||||
|
|
||||||
_ref v = do
|
_ref v = do
|
||||||
|
@ -189,9 +193,9 @@ _eval (TupleV [StrV code, DictV env]) = do
|
||||||
let trySome :: IO a -> IO (Either SomeException a)
|
let trySome :: IO a -> IO (Either SomeException a)
|
||||||
trySome = try
|
trySome = try
|
||||||
state = [fromDict env]
|
state = [fromDict env]
|
||||||
ret <- liftIO. trySome $ evalStateT (evalString code) state
|
ret <- liftIO . trySome $ evalStateT (evalString $ T.unpack code) state
|
||||||
case ret of
|
case ret of
|
||||||
Left err -> return $ TupleV [StrV "err", StrV (show err)]
|
Left err -> return $ TupleV [StrV (T.pack "err"), StrV $ T.pack (show err)]
|
||||||
Right v -> return v
|
Right v -> return v
|
||||||
_eval (TupleV [code@(StrV _), (ListV env)]) =
|
_eval (TupleV [code@(StrV _), (ListV env)]) =
|
||||||
let env' = map (\(TupleV [k,v]) -> (k,v)) env in
|
let env' = map (\(TupleV [k,v]) -> (k,v)) env in
|
||||||
|
@ -216,7 +220,7 @@ _locals (TupleV []) = do
|
||||||
_Import (StrV modname) = do
|
_Import (StrV modname) = do
|
||||||
env <- get -- save current state
|
env <- get -- save current state
|
||||||
put initialState
|
put initialState
|
||||||
(path,modname) <- liftIO $ findModule modname -- find the module file
|
(path,modname) <- liftIO $ findModule $ T.unpack modname -- find the module file
|
||||||
evalFile path -- evaluate the module file
|
evalFile path -- evaluate the module file
|
||||||
[modenv] <- get -- get the module env
|
[modenv] <- get -- get the module env
|
||||||
let [initialEnv] = initialState
|
let [initialEnv] = initialState
|
||||||
|
@ -251,7 +255,7 @@ initialState = [M.fromList [
|
||||||
("stdin", StreamV stdin),
|
("stdin", StreamV stdin),
|
||||||
("print", bif _print),
|
("print", bif _print),
|
||||||
("putstr", bif _putstr),
|
("putstr", bif _putstr),
|
||||||
("putstrln", bif (\x -> _putstr $ x +$ StrV "\n")),
|
("putstrln", bif (\x -> _putstr $ x +$ StrV (T.singleton '\n'))),
|
||||||
("getline", bif _getline),
|
("getline", bif _getline),
|
||||||
("fgetline", bif _fgetline),
|
("fgetline", bif _fgetline),
|
||||||
("putbytes", bif _putbytes),
|
("putbytes", bif _putbytes),
|
||||||
|
@ -272,7 +276,7 @@ initialState = [M.fromList [
|
||||||
eval :: AST -> InterpState Value
|
eval :: AST -> InterpState Value
|
||||||
|
|
||||||
eval (IntConst i) = return $ IntV i
|
eval (IntConst i) = return $ IntV i
|
||||||
eval (StrConst s) = return $ StrV s
|
eval (StrConst s) = return $ StrV $ T.pack s
|
||||||
eval (BoolConst b) = return $ BoolV b
|
eval (BoolConst b) = return $ BoolV b
|
||||||
|
|
||||||
eval (Block body) = foldr1 (>>) $ map eval body
|
eval (Block body) = foldr1 (>>) $ map eval body
|
||||||
|
@ -337,15 +341,15 @@ eval (Access left (Var right)) = do
|
||||||
lhs <- eval left
|
lhs <- eval left
|
||||||
case lhs of
|
case lhs of
|
||||||
DictV dict ->
|
DictV dict ->
|
||||||
case M.lookup (StrV right) dict of
|
case M.lookup (StrV $ T.pack right) dict of
|
||||||
Just (FnV [] fn) -> -- use the module's global scope
|
Just (FnV [] fn) -> -- use the module's global scope
|
||||||
return $ FnV (mapToEnv dict) fn
|
return $ FnV (mapToEnv dict) fn
|
||||||
Just v -> return v
|
Just v -> return v
|
||||||
Nothing -> return $ TupleV [StrV "nothing"]
|
Nothing -> return $ TupleV [StrV (T.pack "nothing")]
|
||||||
_ -> error $ "op/: need a dict, got " ++ show lhs
|
_ -> error $ "op/: need a dict, got " ++ show lhs
|
||||||
where
|
where
|
||||||
mapToEnv :: M.Map Value Value -> Env
|
mapToEnv :: M.Map Value Value -> Env
|
||||||
mapToEnv m = [M.fromAscList $ map (\(StrV k,v) -> (k,v)) (M.toAscList m)]
|
mapToEnv m = [M.fromAscList $ map (\(StrV k,v) -> (T.unpack k,v)) (M.toAscList m)]
|
||||||
eval (Access _ _) = error "op/: RHS must be an identifier"
|
eval (Access _ _) = error "op/: RHS must be an identifier"
|
||||||
|
|
||||||
eval (Call lhs arg) = do
|
eval (Call lhs arg) = do
|
||||||
|
@ -377,23 +381,30 @@ patternBindings (BoolP b) (BoolV v)
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
|
|
||||||
patternBindings (StrP x) (StrV y)
|
patternBindings (StrP x) (StrV y)
|
||||||
| x == y = Just M.empty
|
| T.pack x == y = Just M.empty
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
patternBindings (StrP _) _ = Nothing
|
patternBindings (StrP _) _ = Nothing
|
||||||
|
|
||||||
-- cons on strings
|
-- cons on strings
|
||||||
patternBindings (ConsP x (ListP [])) (StrV (y:[])) = patternBindings x (StrV [y])
|
-- x:[] matches with y:""
|
||||||
|
patternBindings (ConsP x (ListP [])) (StrV str) =
|
||||||
|
case T.uncons str of
|
||||||
|
Just (y, ys) | T.null ys -> -- str matches y:[]
|
||||||
|
patternBindings x (StrV $ T.singleton y)
|
||||||
|
_ -> Nothing
|
||||||
-- "xy":xs pattern
|
-- "xy":xs pattern
|
||||||
patternBindings (ConsP (StrP xp) xsp) (StrV str) =
|
patternBindings (ConsP (StrP xp) xsp) (StrV str) =
|
||||||
let len = length xp in
|
let len = length xp in
|
||||||
if take len str == xp then -- matches
|
if T.take len str == T.pack xp then -- matches
|
||||||
patternBindings xsp $ StrV (drop len str) -- match the rest of the string
|
patternBindings xsp $ StrV (T.drop len str) -- match the rest of the string
|
||||||
else Nothing -- no match
|
else Nothing -- no match
|
||||||
patternBindings (ConsP xp xsp) (StrV (x:xs)) =
|
patternBindings (ConsP xp xsp) (StrV str) =
|
||||||
do
|
case T.uncons str of
|
||||||
xe <- patternBindings xp (StrV [x])
|
Just (x, xs) -> do
|
||||||
xse <- patternBindings xsp $ StrV xs
|
xe <- patternBindings xp (StrV $ T.singleton x)
|
||||||
Just $ M.union xe xse
|
xse <- patternBindings xsp $ StrV xs
|
||||||
|
Just $ M.union xe xse
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
-- cons on lists
|
-- cons on lists
|
||||||
patternBindings (ConsP x (ListP [])) (ListV (y:[])) = patternBindings x y
|
patternBindings (ConsP x (ListP [])) (ListV (y:[])) = patternBindings x y
|
||||||
|
|
|
@ -7,6 +7,6 @@ cabal-version: >= 1.8
|
||||||
|
|
||||||
executable main
|
executable main
|
||||||
main-is: Lamb.hs
|
main-is: Lamb.hs
|
||||||
build-depends: base, peggy, containers, transformers, directory, filepath, bytestring, network
|
build-depends: base, peggy, containers, transformers, directory, filepath, bytestring, network, text
|
||||||
hs-source-dirs: .
|
hs-source-dirs: .
|
||||||
extensions: DoAndIfThenElse
|
extensions: DoAndIfThenElse
|
||||||
|
|
Loading…
Reference in New Issue