-
Notifications
You must be signed in to change notification settings - Fork 0
/
UEnvironment.hs
167 lines (147 loc) · 5.67 KB
/
UEnvironment.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
module UEnvironment where
import System.IO
import System.Environment
import Data.Char
import System.Process
import System.Exit
import Control.Monad.Trans.Class
import Control.Applicative
class UEnv e where
-- eExit :: Int -> e ()
-- eException :: [Char] -> e ()
-- eReturnResult :: [Char] -> e ()
eOpen :: [Int] -> Int -> e Int
eClose :: Int -> e Int
eGetChar :: Int -> e Int
ePeekChar :: Int -> e Int
ePutChar :: Int -> Int -> e Int
eGetArg :: e Int
eSystem :: [Int] -> e Int
data UEvalResult r a = URunning a | UExited Int | UExceptionHappened [Char] | UResultReturned r
newtype UEvalEnv r e a = UEvalEnv {runUEvalEnv :: e (UEvalResult r a)}
-- Strange code to make GHC 8.0.1 happy
instance (Functor e) => Functor (UEvalEnv r e) where
fmap f a = error "not implemented"
instance (Applicative e) => Applicative (UEvalEnv r e) where
(UEvalEnv f) <*> (UEvalEnv g) = error "not implemented"
pure a = UEvalEnv (pure (URunning a))
instance (Monad e) => Monad (UEvalEnv r e) where
(UEvalEnv f) >>= g = UEvalEnv (f >>= (\ret -> case (ret) of
URunning a -> runUEvalEnv (g a)
UExited a -> return$UExited a
UExceptionHappened a -> return$UExceptionHappened a
UResultReturned a -> return$UResultReturned a
))
return a = UEvalEnv (return (URunning a))
instance MonadTrans (UEvalEnv r) where
-- f :: e a
-- need: UEvalEnv r e a
lift f = UEvalEnv (f >>= (\a -> return$URunning a))
eExit :: (Monad e) => Int -> UEvalEnv r e ()
eExit a = UEvalEnv (return (UExited a))
eException :: (Monad e) => [Char] -> UEvalEnv r e ()
eException a = UEvalEnv (return (UExceptionHappened a))
eReturnResult :: (Monad e) => r -> UEvalEnv r e ()
eReturnResult a = UEvalEnv (return (UResultReturned a))
efOpenModes = [ReadMode,WriteMode,AppendMode,ReadWriteMode]
data UFileList h = UFileList [Maybe h] [Int] deriving Show
flAddHandle :: h -> UFileList h -> (Int,UFileList h)
flAddHandle h (UFileList hdls args) = findEmptySlot hdls id 0 where
findEmptySlot [] prefix curno = (curno,UFileList (prefix [Just h]) args)
findEmptySlot (Nothing:r) prefix curno = (curno,UFileList (prefix ((Just h):r)) args)
findEmptySlot (a:r) prefix curno = findEmptySlot r (\x -> prefix (a:x)) (curno+1)
flGetHandle :: Int -> UFileList h -> Maybe h
flGetHandle fno (UFileList hdls args)
| fno>=0 && fno<length hdls = hdls!!fno
| otherwise = Nothing
flCloseHandle :: Int -> UFileList h -> UFileList h
flCloseHandle fno (UFileList hdls args)
| fno>=0 && fno<length hdls = UFileList ((take fno hdls)++(Nothing:(drop (fno+1) hdls))) args
| otherwise = UFileList hdls args
flGetArg :: UFileList h -> (Int,UFileList h)
flGetArg (UFileList hdls []) = ((-1),UFileList hdls [])
flGetArg (UFileList hdls (a:ar)) = (a,UFileList hdls ar)
newtype URealWorldEnv a = URealWorldEnv {runRealWorldEnv :: UFileList Handle ->IO (a,UFileList Handle)}
liftUR :: IO a -> URealWorldEnv a
liftUR b = URealWorldEnv (\f -> (b>>=(\a -> return (a,f))))
-- Strange code to make GHC 8.0.1 happy
instance Functor URealWorldEnv where
fmap f a = error "not implemented"
instance Applicative URealWorldEnv where
f <*> g = error "not implemented"
pure a = URealWorldEnv (\f -> pure (a,f))
instance Monad URealWorldEnv where
(URealWorldEnv f) >>= g = URealWorldEnv (\initfiles ->
((f initfiles) >>= (\(va,files1) -> runRealWorldEnv (g va) files1)))
f >> g = (f >>= (const g))
return a = URealWorldEnv (\f -> return (a,f))
isValidCharInt :: Int -> Bool
isValidCharInt a = (a>=0 && a<1114112)
instance UEnv URealWorldEnv where
eOpen filename mode = URealWorldEnv (\initfiles ->
if (mode<0 || mode>=length efOpenModes) then
return ((-2),initfiles)
else if (any (not.isValidCharInt) filename) then
return ((-3),initfiles)
else
(openBinaryFile (map chr filename) (efOpenModes!!mode) >>=
(\handle -> ( let (fno,files1) = flAddHandle handle initfiles in
return (fno,files1)
)))
)
eClose fno = URealWorldEnv (\initfiles ->
case (flGetHandle fno initfiles) of
Nothing -> return ((-2),initfiles)
Just hdl -> ( hClose hdl >> (
return (0,(flCloseHandle fno initfiles))
))
)
eGetChar fno = URealWorldEnv (\initfiles ->
case (flGetHandle fno initfiles) of
Nothing -> return ((-2),initfiles)
Just hdl -> (hIsEOF hdl) >>= (\iseof -> case iseof of
False -> hGetChar hdl >>= (\c ->return ((ord c),initfiles))
True -> return ((-1),initfiles)
)
)
ePeekChar fno = URealWorldEnv (\initfiles ->
case (flGetHandle fno initfiles) of
Nothing -> return ((-2),initfiles)
Just hdl -> (hIsEOF hdl) >>= (\iseof -> case iseof of
False -> hLookAhead hdl >>= (\c -> return ((ord c),initfiles))
True -> return ((-1),initfiles)
)
)
ePutChar fno content = URealWorldEnv (\initfiles ->
if isValidCharInt content then
case (flGetHandle fno initfiles) of
Nothing -> return ((-2),initfiles)
Just hdl -> ( hPutChar hdl (chr content) >> (
return ((0),initfiles)
))
else
return ((-3),initfiles)
)
eGetArg = URealWorldEnv (\initfiles ->
let (ret,files1)=flGetArg initfiles in
return (ret,files1)
)
eSystem cmd_int = URealWorldEnv (\initfiles -> do
if (all isValidCharInt cmd_int) then do
let cmd = map chr cmd_int
exit_code <- system cmd
case exit_code of
ExitSuccess -> return (0,initfiles)
ExitFailure a -> return (a,initfiles)
else
return ((-3),initfiles)
)
initRealWorldEnv :: [[Char]] -> URealWorldEnv ()
initRealWorldEnv args = URealWorldEnv (\oldstate ->
let iargs = listjoin 0 (map (map ord) args) in
return ((),UFileList [Just stdin,Just stdout] iargs)) where
listjoin s [] = []
listjoin s (a:[]) = a
listjoin s (a:ar) = a++(s:(listjoin s ar))
runRealWorld :: [[Char]] -> URealWorldEnv a -> IO a
runRealWorld args f = (runRealWorldEnv (initRealWorldEnv args>>f)) (UFileList [] []) >>= (return.fst)