aboutsummaryrefslogtreecommitdiff
path: root/rip.hs
diff options
context:
space:
mode:
Diffstat (limited to 'rip.hs')
-rw-r--r--rip.hs167
1 files changed, 114 insertions, 53 deletions
diff --git a/rip.hs b/rip.hs
index 3ca7a29..3efd081 100644
--- a/rip.hs
+++ b/rip.hs
@@ -2,14 +2,18 @@ module Main where
import System.Environment
import System.Exit
+import System.IO
import System.IO.Error
import Control.Exception
import Control.Monad
import Data.Char
import Data.Either
import Data.Maybe
-import Data.List as List
-import Data.Map.Strict as Map
+import Data.List
+import qualified Data.Map.Strict as Map
+import Data.Map.Strict ((!))
+import Network.Socket
+import Numeric
type Stackelem = Integer
@@ -41,13 +45,36 @@ fromLeft (Left l) = l
ordI :: (Integral a) => Char -> a
ordI = fromIntegral . ord
-safeGetChar :: IO (Maybe Char)
-safeGetChar =
+pad :: a -> Int -> [a] -> [a]
+pad c n s
+ | length s >= n = s
+ | otherwise = c : pad c (n-1) s
+
+getBytes :: Stackelem -> [Int]
+getBytes = reverse . getBytes'
+
+getBytes' :: Stackelem -> [Int]
+getBytes' 0 = []
+getBytes' n = fromIntegral m : getBytes' q
+ where (q,m) = divMod n 256
+
+hex :: (Integral a, Show a) => a -> String
+hex n = showHex n ""
+
+pairs :: [a] -> [(a,a)]
+pairs [] = []
+pairs (a:b:cs) = (a,b) : pairs cs
+
+safeHGetChar :: Handle -> IO (Maybe Char)
+safeHGetChar h =
catch
- (liftM Just getChar)
+ (liftM Just $ hGetChar h)
((\ex -> if isEOFError ex then return Nothing else ioError ex)
:: IOError -> IO (Maybe Char))
+safeGetChar :: IO (Maybe Char)
+safeGetChar = safeHGetChar stdin
+
parenpairs :: Char -> Char -> String -> Either String [(Int,Int)]
parenpairs open close s = go 0 [] s -- index, stack, string
@@ -104,41 +131,45 @@ getfuncname' (_:xs) =
then Left "No closing '>' in function name"
else Right name
where
- maybeidx = List.findIndex (== '>') xs
+ maybeidx = findIndex (== '>') xs
name = take (fromJust maybeidx) xs
-- returns the resulting stack
-- rip: Rip InterPreter (recursive acronym)
-rip :: String -> IO [Stackelem]
-rip s = rip' s Map.empty []
-
--- code function map stack resulting stack
-rip' :: String -> Map.Map String String -> [Stackelem] -> IO [Stackelem]
-rip' [] _ st = return st
-rip' code@(x:xs) fns st = do
+rip :: String -> IO ([Stackelem],Map.Map Stackelem Handle)
+rip s = rip' s Map.empty Map.empty []
+
+-- code function map filedesc table stack resulting stack
+rip' :: String -- code
+ -> Map.Map String String -- function map
+ -> Map.Map Stackelem Handle -- filedecs table
+ -> [Stackelem] -- stack
+ -> IO ([Stackelem],Map.Map Stackelem Handle) -- resulting stack and filedesc table
+rip' [] _ conns st = return (st,conns)
+rip' code@(x:xs) fns conns st = do
if c_debugmode then print st else return ()
case x of
n | '0' <= n && n <= '9' ->
- rip' xs fns (fromIntegral (ord n - ord '0') : st)
+ rip' xs fns conns (fromIntegral (ord n - ord '0') : st)
'P' ->
- rip' xs fns (tail st)
+ rip' xs fns conns (tail st)
'S' ->
- rip' xs fns (b:a:cs)
+ rip' xs fns conns (b:a:cs)
where (a:b:cs) = st
'D' ->
- rip' xs fns (head st : st)
+ rip' xs fns conns (head st : st)
'i' ->
- rip' xs fns (head st + 1 : tail st)
+ rip' xs fns conns (head st + 1 : tail st)
'd' ->
- rip' xs fns (head st - 1 : tail st)
+ rip' xs fns conns (head st - 1 : tail st)
'r' ->
- rip' xs fns res
+ rip' xs fns conns res
where
n = fromIntegral $ head st
newst = tail st
@@ -146,7 +177,7 @@ rip' code@(x:xs) fns st = do
res = tail begin ++ head begin : rest
'R' ->
- rip' xs fns res
+ rip' xs fns conns res
where
n = fromIntegral $ head st
newst = tail st
@@ -154,46 +185,46 @@ rip' code@(x:xs) fns st = do
res = last begin : init begin ++ rest --SLOW!
'l' ->
- rip' xs fns (fromIntegral (length st) : st)
+ rip' xs fns conns (fromIntegral (length st) : st)
'a' ->
- rip' xs fns (a + b : cs)
+ rip' xs fns conns (a + b : cs)
where (b:a:cs) = st
's' ->
- rip' xs fns (a - b : cs)
+ rip' xs fns conns (a - b : cs)
where (b:a:cs) = st
'm' ->
- rip' xs fns (a * b : cs)
+ rip' xs fns conns (a * b : cs)
where (b:a:cs) = st
'q' ->
- rip' xs fns (a `div` b : cs)
+ rip' xs fns conns (a `div` b : cs)
where (b:a:cs) = st
'M' ->
- rip' xs fns (a `mod` b : cs)
+ rip' xs fns conns (a `mod` b : cs)
where (b:a:cs) = st
'p' ->
- rip' xs fns (a ^ b : cs)
+ rip' xs fns conns (a ^ b : cs)
where (b:a:cs) = st
'G' ->
- rip' xs fns (booltoint (a > b) : cs)
+ rip' xs fns conns (booltoint (a > b) : cs)
where (b:a:cs) = st
'L' ->
- rip' xs fns (booltoint (a < b) : cs)
+ rip' xs fns conns (booltoint (a < b) : cs)
where (b:a:cs) = st
'E' ->
- rip' xs fns (booltoint (a == b) : cs)
+ rip' xs fns conns (booltoint (a == b) : cs)
where (b:a:cs) = st
'n' ->
- rip' xs fns (booltoint (head st == 0) : tail st)
+ rip' xs fns conns (booltoint (head st == 0) : tail st)
'I' ->
let maybecb = getcodeblock xs
@@ -203,9 +234,9 @@ rip' code@(x:xs) fns st = do
Right (inblock,afterblock) ->
if head st /= 0
then do
- newstack <- rip' inblock fns (tail st)
- rip' afterblock fns newstack
- else rip' afterblock fns (tail st)
+ (newstack,newconns) <- rip' inblock fns conns (tail st)
+ rip' afterblock fns newconns newstack
+ else rip' afterblock fns conns (tail st)
'W' ->
let maybecb = getcodeblock xs
@@ -214,16 +245,16 @@ rip' code@(x:xs) fns st = do
Right (inblock,afterblock) ->
let
- doloop st = do
- newstack <- rip' inblock fns st
+ doloop st cn = do
+ (newstack,newconns) <- rip' inblock fns cn st
if head newstack /= 0
- then doloop $ tail newstack
- else return $ tail newstack
+ then doloop (tail newstack) newconns
+ else return (tail newstack,newconns)
in if head st /= 0
then do
- newstack <- doloop (tail st)
- rip' afterblock fns newstack
- else rip' afterblock fns (tail st)
+ (newstack,newconns) <- doloop (tail st) conns
+ rip' afterblock fns newconns newstack
+ else rip' afterblock fns conns (tail st)
'o' -> do
let n = fromIntegral (head st)
@@ -232,16 +263,46 @@ rip' code@(x:xs) fns st = do
(\ex -> riperror $ "Invalid character value " ++ (show n))
(\c -> do
putChar c
- rip' xs fns (tail st))
+ rip' xs fns conns (tail st))
res
'O' -> do
putStr $ show (head st)
- rip' xs fns (tail st)
+ rip' xs fns conns (tail st)
'g' -> do
n <- liftM (maybe (-1) ord) safeGetChar
- rip' xs fns (fromIntegral n : st)
+ rip' xs fns conns (fromIntegral n : st)
+
+ 'C' -> do
+ let (portint:hostnameint:newst) = st
+ hostname =
+ if hostnameint < 2^32
+ then intercalate "." $ map show $ getBytes hostnameint
+ else intercalate ":" $ map (\(a,b) -> pad '0' 2 (hex a) ++ pad '0' 2 (hex b)) $ pairs $ pad 0 16 $ getBytes hostnameint
+ addrinfo <- liftM head $ getAddrInfo (Just $ defaultHints {addrSocketType = Stream}) (Just hostname) (Just $ show portint)
+ sock <- socket (addrFamily addrinfo) Stream defaultProtocol
+ connect sock (addrAddress addrinfo)
+ h <- socketToHandle sock ReadWriteMode
+ let ident = fromIntegral $ succ $ Map.size conns
+ rip' xs fns (Map.insert ident h conns) $ ident : newst
+
+ 'c' -> do
+ let (ident:newst) = st
+ hClose $ conns ! ident
+ let newconns = Map.delete ident conns
+ rip' xs fns newconns newst
+
+ 'w' -> do
+ let (c:newst@(ident:_)) = st
+ hPutChar (conns ! ident) $ chr $ fromIntegral c
+ rip' xs fns conns newst
+
+ 't' -> do
+ let (ident:_) = st
+ c <- liftM (maybe (-1) ordI) $ safeHGetChar $ conns ! ident
+ --c <- liftM ordI $ hGetChar $ conns ! ident
+ rip' xs fns conns $ c : st
'<' ->
case (getfuncname code) of
@@ -250,8 +311,8 @@ rip' code@(x:xs) fns st = do
Nothing -> riperror $ "Function '" ++ name ++ "' not found"
Just s -> let newcode = drop (length name + 1) xs
in do
- newstack <- rip' s fns st
- rip' newcode fns newstack
+ (newstack,newconns) <- rip' s fns conns st
+ rip' newcode fns newconns newstack
'F' -> case (getfuncname xs) of
Left s -> riperror s
@@ -260,22 +321,22 @@ rip' code@(x:xs) fns st = do
Nothing -> case (getcodeblock $ drop (length name + 2) xs) of
Left s -> riperror s
Right (inblock,afterblock) ->
- rip' afterblock (Map.insert name inblock fns) st
+ rip' afterblock (Map.insert name inblock fns) conns st
'#' -> case (getfuncname xs) of
Left s -> riperror s
Right name -> do
contents <- readFile name
- rip' (contents ++ drop (length name + 2) xs) fns st
+ rip' (contents ++ drop (length name + 2) xs) fns conns st
- '\'' -> rip' (tail xs) fns $ ordI (head xs) : st
+ '\'' -> rip' (tail xs) fns conns $ ordI (head xs) : st
'$' -> do
- (putStrLn . List.intercalate " " . List.map show . reverse) st
- rip' xs fns st
+ (putStrLn . intercalate " " . map show . reverse) st
+ rip' xs fns conns st
c | isSpace c ->
- rip' xs fns st
+ rip' xs fns conns st
_ -> riperror $ "Unknown command '" ++ [x,'\'']