-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBuiltin.hs
140 lines (111 loc) · 4.31 KB
/
Builtin.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
module Builtin where
import Prelude hiding (lookup)
import Data.List hiding (delete, lookup, insert)
import Data.Map hiding (map, foldr)
import Data.IORef
import System.Directory
import System.Environment
import System.Exit
import System.IO
import System.Posix.Process
import System.Posix.IO
import System.Posix.Types
data Value = Int Integer | Str String | List [Value]
data Result = Result {
out :: IO String,
err :: IO String,
stat :: IO [ProcessStatus]
}
-- extract ∷ (Archive a) => a -> ()
data Type = TypeList [Type] -- [TypeVar "a", TypeVar "b"]: a → b
| Type String -- "Tar", "Raw", "PDF", ...
| TypeVar String -- a in a → a
| Unit -- ()
-- A Utility gets the Environment, Input, Arguments and returns the Result
type UtilityType = Env -> String -> [Value] -> IO Result
data Utility = Utility {
fn :: UtilityType,
typ :: [Type]
}
instance Show Value where
show (Int a) = show a
show (Str s) = s
show (List v) = unwords (map show v)
instance Show Type where
show (Type typ) = typ
show (TypeList types) = intercalate " → " (map show types)
show (TypeVar var) = var
show Unit = "()"
------------------------------------------------------------------------------
-- Utilities
------------------------------------------------------------------------------
builtin = fromList [
("set", Utility set [Unit, Unit])
,("unset", Utility unset [Unit, Unit])
,("get", Utility get [Unit, TypeVar "a"])
,("map", Utility map' [])
,("cd", Utility cd [Type "String", Unit])
,("ls", Utility ls [Unit, Type "List"])
,("cat", Utility cat [TypeVar "a", TypeVar "a"])
]
ret out err stat = return (Result (return out) (return err) (return [stat]))
retSuc out = ret out "" (Exited ExitSuccess)
retErr err = ret "" err (Exited (ExitFailure 2))
void = retSuc ""
set env _ [Str id, val] = setVar env id val >> void
-- set env "" [Str id] = unset env "" [Str id]
set env input [Str id] = setVar env id (Str input) >> void
set _ _ _ = retErr "usage: set id [value]"
unset env input [Str id] = unsetVar env id >> void
unset _ _ _ = retErr "usage: unset id"
get env _ [Str id] = getVar env id >>= \out -> case out of
Just value -> retSuc (show value)
Nothing -> void
get env _ _ = retErr "usage: get id"
map' env _ [Int 1, _ ] = void
cd env "" [] = getHomeDirectory >>= \dir -> cd env "" [Str dir]
cd env "" [Str dir] = setCurrentDirectory dir >> setVar env "PWD" (Str dir) >> void
cd env input [] = cd env "" [Str input]
cd _ _ _ = retErr "usage: cd [dir]"
ls env _ _ = getCurrentDirectory >>= getDirectoryContents >>= retSuc . unwords . sort
cat env input [] = retSuc input
cat env input [Str "-"] = retSuc input
cat env input [Str file] = readFile file >>= retSuc
cat _ _ _ = retErr "usage: cat [files]"
------------------------------------------------------------------------------
-- Environment
------------------------------------------------------------------------------
type Env = IORef (Map String Value)
freshEnv :: IO Env
freshEnv = newIORef empty
isBound :: Env -> String -> IO Bool
isBound envRef id = readIORef envRef >>= return . member id
getVar :: Env -> String -> IO (Maybe Value)
getVar envRef id = readIORef envRef >>= return . lookup id
setVar :: Env -> String -> Value -> IO Value
setVar envRef id value = do
env <- readIORef envRef
writeIORef envRef (insert id value env)
return value
unsetVar :: Env -> String -> IO ()
unsetVar envRef id = do
env <- readIORef envRef
writeIORef envRef (delete id env)
return ()
getDefault :: Env -> String -> Value -> IO Value
getDefault envRef id def = do
env <- readIORef envRef
return (findWithDefault def id env)
envInit :: Env -> IO ()
envInit env = do
setVar env "PS1" (Str "TySh>")
getHomeDirectory >>= setVar env "HOME" . Str
getEnv "USER" >>= setVar env "USER" . Str
getEnv "PATH" >>= setVar env "PATH" . List . map Str . splitBy ':'
getEnv "PWD" >>= setVar env "PWD" . Str
return ()
-- From:
-- http://stackoverflow.com/questions/4503958/what-is-the-best-way-to-split-string-by-delimiter-funcionally
splitBy del = foldr f [[]]
where f c l@(x:xs) | c == del = []:l
| otherwise = (c:x):xs