packages feed

pi-calculus 0.0.4 → 0.0.5

raw patch · 16 files changed

+182/−173 lines, 16 filesdep +AESdep +RSAdep +binary

Dependencies added: AES, RSA, binary, byteable, cryptohash

Files

Channel.hs view
@@ -35,26 +35,6 @@     chan <- Ch.newChan     return $ Channel (Ch.writeChan chan) (Ch.readChan chan) []     -{-newInternalChan :: String -> String -> Integer -> IO Channel-newInternalChan hostName hostPort cp = do-    currentHost <- getHostName-    let ex = makeExtra ["host","clientPort"] [currentHost ++ ":" ++ hostPort,show cp]-    return $ Channel s r True ex-    where-       r   = N.withSocketsDo $ do-            sock <- N.listenOn $ N.PortNumber $ fromIntegral cp-            (inHandle,_,_) <- N.accept sock-            msg <- unlines <$> emptyHandle inHandle-            putStrLn $ "got: " ++ msg-            N.sClose sock-            return msg-       s v = N.withSocketsDo $ do-            _ <- forkIO $ do-                outHandle <- waitForConnect hostName $ N.PortNumber $ port hostPort-                putStrLn $ "sending: " ++ v-                hPutStr outHandle v-            return ()-}- newChanServer :: Integer -> IO Channel newChanServer cp = N.withSocketsDo $ do     hanVar <- newEmptyMVar@@ -72,9 +52,8 @@     _ <- forkIO $ do         serverHandle <- waitForConnect hostName $ N.PortNumber $ fromIntegral hostPort         putMVar hanVar serverHandle+    let ex = makeExtra [hostSig, portSig] [hostName,  show hostPort]     return $ Channel (send' hanVar) (receive' hanVar) ex-    where-       ex = makeExtra [hostSig, portSig] [hostName,  show hostPort]  waitForConnect :: N.HostName -> N.PortID -> IO Handle waitForConnect h p = N.connectTo h p `catchIOError`
Parser.hs view
@@ -200,11 +200,11 @@ parseType :: Parser Type parseType =  try (str HttpRequest)          <|> try (str HttpResponse)-         <|> try (str Header)-         <|> parseListType+         -- <|> try (str Header)+         -- <|> parseListType          where          str t = string (show t) >> return t-         parseListType = string "List" >> many1 space >> fmap List parseType +         --parseListType = string "List" >> many1 space >> fmap List parseType            bracketed :: Parser a -> Parser a@@ -222,6 +222,4 @@ readProcesses = readOrThrow parseProcesses "multiple-processes"  readTerm :: String -> ThrowsError Term -readTerm str = case parse parseTerm "term" str of-                Left  err -> throwError $ Parser err-                Right val -> return val +readTerm = readOrThrow parseTerm "term"
PatternMatching.hs view
@@ -1,4 +1,4 @@-module PatternMatching (match, matchTest) where            +module PatternMatching (match) where                          import Control.Arrow (second)  import Control.Monad (liftM,liftM2)@@ -7,18 +7,19 @@ import Parser (readTerm) import Network.HTTP.Base  -match :: Term -> Term -> ThrowsError [(String,Value)]+match :: Term -> Term -> ThrowsError [(Name,Value)] match a b = liftM (map (second Term)) $ match' a b -match' :: Term -> Term -> ThrowsError [(String,Term)]+match' :: Term -> Term -> ThrowsError [(Name,Term)] match' (TVar name _) term = case name of                                 '_':_ -> return []                                 _     -> return [(name,term)] match' (TPair (m1, m2)) (TPair (t1,t2)) = liftM2 (++) (match' m1 t1)  (match' m2 t2) match' (TList (m:ms)) (TList (t:ts)) = do                 bind <- match' m t-                rest <- case ms of-                    [v] -> match' v $ TList ts+                rest   <- case (ms,ts) of+                    ([v],[t']) -> match' v t'+                    ([v], _ ) -> match' v $ TList ts                     _   -> match' (TList ms) (TList ts)                 return $ bind ++ rest match' l@(TList _) (TData d) = match' l $ dataToList d
PiCalculus.hs view
@@ -7,7 +7,6 @@ import Control.Monad.Trans (liftIO) import Control.Monad.Trans.Except (catchE, runExceptT, throwE) import Data.IORef (newIORef, readIORef,writeIORef)-import Data.Maybe (isJust) import Network.HTTP.Base (Request(..),Response(..), parseResponseHead, parseRequestHead) import System.Environment (getArgs, getProgName) import System.IO (hFlush, stderr, stdin, stdout)@@ -25,32 +24,16 @@ nullEnv :: IO Env nullEnv = newIORef Map.empty -isBound :: Env -> String -> IO Bool-isBound envRef var = liftM (isJust . Map.lookup var) $ readIORef envRef- getVar :: Env -> String -> IOThrowsError Value  getVar envRef var = do env <- liftIO $ readIORef envRef                        maybe (throwE $ UnboundVar "Getting an unbound variable" var)                              return                              (Map.lookup var env)--setVar :: Env -> String -> Value -> IOThrowsError Value-setVar _ "_" _ = return $ Term $ TVar "_" Nothing -- to allow wildcard matching-setVar envRef var val = do env <- liftIO $ readIORef envRef-                           maybe (throwE $ UnboundVar "Setting an unbound variable" var)-                                 (return $ liftIO $ writeIORef envRef $ Map.insert var val env)-                                 (Map.lookup var env)-                           return val                            -defineVar :: Env -> String -> Value -> IOThrowsError Value-defineVar envRef var val = do-    alreadyDefined <- liftIO $ isBound envRef var-    if alreadyDefined-        then setVar envRef var val >> return val-        else liftIO $ do-            env      <- readIORef envRef-            writeIORef envRef $ Map.insert var val env-            return val+defineVar :: Env -> String -> Value -> IOThrowsError ()+defineVar envRef var val = liftIO $ do+         env      <- readIORef envRef+         writeIORef envRef $ Map.insert var val env  bindVars :: Env -> [(String , Value)] -> IO Env bindVars envRef bindings = do@@ -85,7 +68,7 @@         pilude <- getDataFileName "pilude.pi"         case args of             []  -> runRepl coreBindings-            [x] -> liftM (("&load("++pilude++");")++) (readFile x) >>= runProcess coreBindings +            [x] -> readFile x >>= runProcess coreBindings              _   -> do                     putStrLn           "Use:"                     putStrLn $ name ++ " -- Enter the REPL"@@ -103,10 +86,11 @@  evalTerm :: Env -> Term -> IOThrowsError Value evalTerm env (TVar name _) = getVar env name-evalTerm _   (TNum num) = return $ Term $ TNum num-evalTerm _   (TStr str) = return $ Term $ TStr str-evalTerm _   (TBool b ) = return $ Term $ TBool b-evalTerm _   (TData d ) = return $ Term $ TData d+evalTerm _   t@(TNum  _ ) = return $ Term t+evalTerm _   t@(TStr  _ ) = return $ Term t+evalTerm _   t@(TBool _ ) = return $ Term t+evalTerm _   t@(TBS   _ ) = return $ Term t+evalTerm _   t@(TData _ ) = return $ Term t evalTerm env   (TList ls) = do     vs <- mapM (evalTerm env) ls     ts <- extractTerms vs@@ -163,7 +147,7 @@ assignFreePort :: Env -> IOThrowsError Integer assignFreePort env = do             Term (TNum port) <- getVar env counterRef-            _ <- setVar env counterRef $ Term $ TNum $ port + 1+            defineVar env counterRef $ Term $ TNum $ port + 1             if port == 2 ^ (16 :: Integer)                 then error "HOW MANY CHANNELS DO YOU WANT?!"                  else return port@@ -240,7 +224,7 @@ eval env (p1 `Seq` p2) = do                 eval env p1                 eval env p2-eval env (New var@(TVar name _)) = void $ defineVar env name $ Term var+eval env (New var@(TVar name _)) = defineVar env name $ Term var eval env (If b p1 p2) = do                 cond <- evalCond env b                 eval env (if cond then p1 else p2)@@ -250,14 +234,11 @@                 eval newEnv p eval env (Let (TVar name _) (Term t2) Nothing) = do                 val <- evalTerm env t2-                _ <- defineVar env name val-                return ()+                defineVar env name val eval env (Let (TVar name _) proc@(Proc _) (Just p)) = do                 newEnv <- liftIO $ bindVars env [(name,proc)]                 eval newEnv p-eval env (Let (TVar name _) proc@(Proc _) Nothing) = do-                _ <- defineVar env name proc-                return ()+eval env (Let (TVar name _) proc@(Proc _) Nothing) = defineVar env name proc eval env (Let (TFun name args) t2 (Just p)) =              defineLocalFun env name args t2 p eval env (Let (TFun name args) t2 Nothing)  = @@ -293,7 +274,7 @@ eval _ _ = throwE $ Default "undefined action"  defineGlobalFun :: Env -> String -> [Term] -> Value -> IOThrowsError ()-defineGlobalFun env name args term = void $ defineVar env name $ makeFun args term env+defineGlobalFun env name args term = defineVar env name $ makeFun args term env  defineLocalFun :: Env -> String -> [Term] -> Value -> PiProcess -> IOThrowsError () defineLocalFun env name args term p = do
Primitives.hs view
@@ -2,6 +2,9 @@  import Control.Applicative ((<$>)) import Control.Monad.Error (throwError)+import qualified Crypto.Hash as Crypto+import Data.Byteable (toBytes)+import qualified Data.ByteString.Char8 as C8 import Network.HTTP.Base (Request(..), Response(..), RequestMethod(..), mkRequest) import Network.HTTP.Cookie (Cookie, cookiesToHeader) import Network.HTTP.Headers (HasHeaders(..), Header, HeaderName(..), hdrName, hdrValue, findHeader, parseHeader, replaceHeader, setHeaders)@@ -9,41 +12,43 @@  import TypDefs -primitives :: [(String      , TermFun)]-primitives = [ ("fst"       , first)-             , ("snd"       , secnd)-             , ("hash"      , unaryId "hash")-             , ("pk"        , unaryId "pk")-             , ("httpReq"   , httpReq)-             , ("httpResp"  , httpResp)-             , ("getmsg"    , getmsg)-             , ("pair"      , binaryId "pair")-             , ("sdec"      , sdec)-             , ("senc"      , binaryId "senc")-             , ("adec"      , adec)-             , ("aenc"      , binaryId "aenc")-             , ("sign"      , binaryId "sign")-             , ("checksign" , checksign)-             , ("mac"       , binaryId "mac")-             , ("headers"   , listId)-             , ("header"    , header)-             , ("cookies"   , listId)-             , ("httpGet"   , constId "httpGet")-             , ("httpHead"  , constId "httpHead")-             , ("httpPost"  , constId "httpPost")-             , ("getHeaders", getHeadersFromData)-             , ("setHeader" , setHeader)-             , ("getHeader" , getHeader)-             , ("getCookie" , getCookie)-             , ("setCookie" , setCookie)-             , ("uri"       , makeUri)-             , ("rspCode"   , responseCode)-             , ("add"       , add)-             , ("cons"      , cons)-             , ("head"      , head')-             , ("tail"      , tail')+primitives :: [(Name          , TermFun)]+primitives = [ ("fst"         , first)+             , ("snd"         , secnd)+             , ("hash"        , hash)+             , ("pk"          , unaryId "pk")+             , ("httpReq"     , httpReq)+             , ("httpResp"    , httpResp)+             , ("getmsg"      , getmsg)+             , ("sdec"        , sdec)+             , ("senc"        , binaryId "senc")+             , ("adec"        , adec)+             , ("aenc"        , binaryId "aenc")+             , ("sign"        , binaryId "sign")+             , ("checksign"   , checksign)+             , ("mac"         , mac)+             , ("headers"     , listId)+             , ("header"      , header)+             , ("cookies"     , listId)+             , ("httpGet"     , constId "httpGet")+             , ("httpHead"    , constId "httpHead")+             , ("httpPost"    , constId "httpPost")+             , ("getHeaders"  , getHeadersFromData)+             , ("insertHeader", insertHeader)+             , ("getHeader"   , getHeader)+             , ("getCookie"   , getCookie)+             , ("setCookie"   , setCookie)+             , ("uri"         , makeUri)+             , ("rspCode"     , responseCode)+             , ("add"         , add)+             , ("cons"        , cons)+             , ("head"        , head')+             , ("tail"        , tail')+             , ("append"      , append)              ] ++ constId :: String -> TermFun constId name [] = return $ TFun name [] constId name e  = throwError $ NumArgs name 0 (map Term e)@@ -87,6 +92,7 @@ checksign [TFun "pk" [k1], TFun "sign" [k2,_] ] = return $ TBool (k1 == k2) checksign e = throwError $ TypeMismatch "(pk(var),sign(var,var))" $ map Term e + httpReq :: TermFun httpReq [TStr url, TList hs , reqMethod] = do     uri <- case parseURI http' of @@ -149,14 +155,14 @@             _       -> throwError $ Default $ headr ++ " not in " ++ show d getHeader e = throwError $ TypeMismatch "httpData" $ map Term e -setHeader :: TermFun-setHeader [h@(TStr _), TData d] = do +insertHeader :: TermFun+insertHeader [h@(TStr _), TData d] = do                        headr <- makeHeader h                       let name = hdrName headr                       let val  = hdrValue headr                       return $ TData $ replaceHeader name val d -setHeader [h@(TStr _), TList hs] = return $ TList $ h : hs  -setHeader e = throwError $ TypeMismatch "(header,httpData|headers)" $ map Term e+insertHeader [h@(TStr _), TList hs] = return $ TList $ h : hs  +insertHeader e = throwError $ TypeMismatch "(header,httpData|headers)" $ map Term e  getCookie :: TermFun getCookie [TData d] = @@ -166,7 +172,7 @@ getCookie e = throwError $ TypeMismatch "httpData" $ map Term e      setCookie :: TermFun-setCookie [TData d, c] = do+setCookie [c, TData d] = do     cookie <- makeCookie c     let cookieHeader = cookiesToHeader [cookie]     let n = hdrName cookieHeader@@ -204,3 +210,17 @@ tail' [TList []] = throwError $ Default "tail of empty list"  tail' [TList x] = return $ TList $ tail x tail' e = throwError $ TypeMismatch "list" $ map Term e++hash :: TermFun+hash [TBS msg]  = return $ TBS $ toBytes (Crypto.hash msg :: Crypto.Digest Crypto.MD5)+hash [TStr msg] = let mBS = C8.pack msg in return $ TBS $ toBytes (Crypto.hash mBS :: Crypto.Digest Crypto.MD5)+hash e = throwError $ TypeMismatch "bytestring" $ map Term e+        +mac :: TermFun+mac [TBS key,TBS msg]  = return $ TBS $ toBytes $ Crypto.hmacGetDigest $ Crypto.hmacAlg Crypto.MD5 key msg+mac [TBS key,TStr msg] = let mBS = C8.pack msg in return $ TBS $ toBytes $ Crypto.hmacGetDigest $ Crypto.hmacAlg Crypto.MD5 key mBS+mac e = throwError $ TypeMismatch "(bytestring,bytestring)" $ map Term e++append :: TermFun+append [TList x, TList y] = return $ TList $ x ++ y +append e = throwError $ TypeMismatch "(list,list)" $ map Term e
TypDefs.hs view
@@ -17,6 +17,7 @@  import Control.Monad.Trans.Except(ExceptT(..)) import Data.Char (toLower)+import Data.ByteString (ByteString) import Data.IORef (IORef) import Data.List (intercalate) import Data.Map (Map)@@ -43,6 +44,7 @@           | TBool Bool           | TPair (Term, Term)           | TList [Term]+          | TBS ByteString           | TData HttpData           | TFun Name [Term]             deriving (Eq)@@ -50,22 +52,13 @@ data HttpData = Resp (Response String)               | Req  (Request String) -instance Eq HttpData where (==) = eqHttpData-instance Show HttpData where show = showHttpData- instance HasHeaders HttpData where     getHeaders (Resp r) = getHeaders r     getHeaders (Req r)  = getHeaders r     setHeaders (Resp r) = Resp . setHeaders r     setHeaders (Req r)  = Req . setHeaders r -showHttpData :: HttpData -> String-showHttpData (Resp r) = show r-showHttpData (Req r)  = show r  -eqHttpData :: HttpData -> HttpData -> Bool-eqHttpData _ _ = False- type TermFun = [Term] -> ThrowsError Term  type Name      = String@@ -93,27 +86,9 @@  data Type = HttpRequest           | HttpResponse-          | Header-          | List Type           deriving (Eq, Read, Show) -instance Show PiError where show = showError--showError :: PiError -> String-showError (UnboundVar message var)      = message ++ ": " ++ var-showError (NotFunction message fun)     = message ++ ": " ++ fun-showError (NotChannel chan)             = "Not a channel: " ++ chan -showError (NotProcess proc)             = "Not a Process: " ++ proc-showError (NotTerm name var)            = "Expecting " ++ name ++ " to be a Term, found: " ++ show var-showError (NumArgs name expected found) = "Expected " ++ show name ++ show expected ++ " args; found values "-                                          ++ unwordsList found-showError (TypeMismatch expected found) = "Invalid type: expected " ++ expected ++ ", found "-                                          ++ show found-showError (Parser parseErr)             = "Parse error at " ++ show parseErr-showError (PatternMatch t1 t2)          = "Pattern match failure: cannot match " ++ show t1 ++ " and \n" ++ show t2-showError (Default msg)                 = msg--type Env = IORef (Map String Value)+type Env = IORef (Map Name Value)  data Channel = Channel {                send         :: String -> IO ()@@ -125,22 +100,12 @@                | Connect                  deriving (Eq, Show, Read) -showValue :: Value -> String-showValue (Proc p)  = show p-showValue (Term t)  = show t-showValue (Chan c)  = show $ convert c-    where -        convert ch = TFun "<chan>" (map TStr ex) -            where ex = extra ch-showValue (PrimitiveFunc _)  = "<primitive>" -showValue (Func {})          = "<user function>"  --eqvVal :: Value -> Value -> Bool-eqvVal (Proc p1)  (Proc p2) = p1 == p2-eqvVal (Term t1)  (Term t2) = t1 == t2-eqvVal _ _ = False--instance Eq Value where (==) = eqvVal+instance Show PiProcess where show = showPi+instance Show Term      where show = showTerm+instance Show Value     where show = showValue+instance Show Condition where show = showCond+instance Show PiError where show = showError+instance Show HttpData where show = showHttpData  showPi :: PiProcess -> String showPi Null = "0"@@ -166,15 +131,51 @@ showTerm (TList ls) = "list(" ++ intercalate "," (map show ls) ++ ")" showTerm (TPair (a,b)) = "pair("++ show a ++ ","++ show b ++ ")" showTerm (TData d) = show d+showTerm (TBS bs)  = show bs showTerm (TFun n ts) = n ++ "(" ++ intercalate "," (map show ts) ++ ")" +showValue :: Value -> String+showValue (Proc p)  = show p+showValue (Term t)  = show t+showValue (Chan c)  = show $ convert c+    where +        convert ch = TFun "<chan>" (map TStr ex) +            where ex = extra ch+showValue (PrimitiveFunc _)  = "<primitive>" +showValue (Func {})          = "<user function>"  + showCond :: Condition -> String showCond (t1 `Equals` t2) = show t1 ++ " == " ++ show t2 -instance Show PiProcess where show = showPi-instance Show Term      where show = showTerm-instance Show Condition where show = showCond-instance Show Value     where show = showValue+showError :: PiError -> String+showError (UnboundVar message var)      = message ++ ": " ++ var+showError (NotFunction message fun)     = message ++ ": " ++ fun+showError (NotChannel chan)             = "Not a channel: " ++ chan +showError (NotProcess proc)             = "Not a Process: " ++ proc+showError (NotTerm name var)            = "Expecting " ++ name ++ " to be a Term, found: " ++ show var+showError (NumArgs name expected found) = "Expected " ++ show name ++ show expected ++ " args; found values "+                                          ++ unwordsList found+showError (TypeMismatch expected found) = "Invalid type: expected " ++ expected ++ ", found "+                                          ++ show found+showError (Parser parseErr)             = "Parse error at " ++ show parseErr+showError (PatternMatch t1 t2)          = "Pattern match failure: cannot match " ++ show t1 ++ " and \n" ++ show t2+showError (Default msg)                 = msg++showHttpData :: HttpData -> String+showHttpData (Resp r) = show r+showHttpData (Req r)  = show r ++instance Eq Value where (==) = eqvVal+instance Eq HttpData where (==) = eqHttpData++eqHttpData :: HttpData -> HttpData -> Bool+eqHttpData _ _ = False++eqvVal :: Value -> Value -> Bool+eqvVal (Proc p1)  (Proc p2) = p1 == p2+eqvVal (Term t1)  (Term t2) = t1 == t2+eqvVal _ _ = False+  unwordsList :: [Value] -> String unwordsList = unwords . map show
+ changes.md view
@@ -0,0 +1,10 @@+Version 0.0.5:+--------------++Changelog!++- Fixed an issue with pattern matching on lists. Lists of the same length pattern match exactly: i.e.+let list(a,b,c) = list(1,2,3) => a = 1 , b = 2, c = 3 . ++- Added the primitive append(list(a..),list(b..)) => list(a..,b..)+
pi-calculus.cabal view
@@ -2,9 +2,9 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                pi-calculus-version:             0.0.4-synopsis:            Applied pi-calculus compiler-description:         Phi - A compiler for the applied pi-calculus. Very rough around the edges.+version:             0.0.5+synopsis:            Applied pi-calculus interpreter+description:         Phi -  an interpreter for the applied pi-calculus. Very rough around the edges. license:             GPL-3 license-file:        LICENSE author:              Will de Renzy-Martin@@ -15,8 +15,9 @@ build-type:          Simple cabal-version:       >=1.8 data-files:          testing/*.pi, pilude.pi+extra-source-files:  changes.md  executable phi   main-is:           PiCalculus.hs   other-modules:     Channel, Parser, PatternMatching, Primitives, TypDefs, Paths_pi_calculus-  build-depends:       base >=4.5 && <=4.8, mtl ==2.2.*, parsec ==3.1.*, containers ==0.5.*, transformers ==0.4.*, network ==2.5.*, HTTP >=2.15, bytestring >= 0.10, io-streams ==1.1.*+  build-depends:       base >=4.5 && <=4.8, mtl ==2.2.*, parsec ==3.1.*, containers ==0.5.*, transformers ==0.4.*, network ==2.5.*, HTTP >=2.15, bytestring >=0.10, io-streams ==1.1.*, cryptohash ==0.11.*, byteable ==0.1.*, binary ==0.7.2.*, AES ==0.2.*, RSA ==1.2.2.*
pilude.pi view
@@ -2,4 +2,9 @@ let print(msg) = out(stdout,msg) let error(msg) = out(stderr,msg) let dbgOut(c, msg) = out(c,msg);out(stdout,msg)-let forever(process) = &process;&forever(process)+let fetch_out(c) = in(stdin,msg);out(c,msg)+let in_print(c)  = in(c,msg);out(stdout,msg)+let forever(p) = &p;&forever(p)+let getLocation(data) = getHeader("location",data)+let in_and_out(c) = &in_print(c);&fetch_out(c)+let out_and_in(c) = &fetch_out(c);&in_print(c) 
testing/client.pi view
@@ -1,6 +1,6 @@-out(stdout,"Enter host:"); in(stdin,host);-out(stdout,"Enter port:"); in(stdin,port);-let ch = chan(host,port) in-    let sch = {} in-        out(stdout,sch);out(ch,sch);in(sch,msg);out(stdout,msg)-+&load("pilude.pi");+out(stdout,"Enter Host"); in(stdin,host);+out(stdout,"Enter Port"); in(stdin,port);+    let ch = chan(host,port) in+        let proc = out_and_in(ch) in+            &forever(proc)
testing/follow.pi view
@@ -1,5 +1,5 @@ let follow(ch,r) = (out(ch,r);in(ch,resp:HttpResponse);-    let list(c,_,h,_) = resp in+    let list(c,_,h,b) = resp in         if c = 302              then let req = httpReq(getHeader("location",resp),headers(),httpGet()) in &follow(ch,req) -            else out(stdout,h)) +            else &print(b)) 
+ testing/get.pi view
@@ -0,0 +1,6 @@+&load("pilude.pi");+&load("follow.pi");+&print("Host:");in(stdin,site);+&print("Resource:");in(stdin,res);+let siteChan = httpChan(site) in+    let req = httpReq(uri(site,res),headers(),httpGet()) in &follow(siteChan,req)
− testing/index.pi
@@ -1,4 +0,0 @@-&load("follow.pi");-out(stdout,"Host:");in(stdin,site);-let siteChan = httpChan(site) in-let req = httpReq(uri(site,"index.html"),headers(),httpGet()) in &follow(siteChan,req)
+ testing/p_chan_client.pi view
@@ -0,0 +1,6 @@+out(stdout,"Enter host:"); in(stdin,host);+out(stdout,"Enter port:"); in(stdin,port);+let ch = chan(host,port) in+    let sch = {} in+        out(ch,sch);in(sch,msg);out(stdout,msg)+
+ testing/p_chan_server.pi view
@@ -0,0 +1,3 @@+out(stdout,"Enter port:"); in(stdin,port);+let ch = {port} in +    in(ch,sch);in(stdin,msg);out(sch,msg)
testing/server.pi view
@@ -1,3 +1,5 @@-out(stdout,"Enter port:"); in(stdin,port);-let ch = {port} in -    in(ch,sch);out(stdout,sch);in(stdin,msg);out(sch,msg)+&load("pilude.pi");+out(stdout,"Enter Port");+in(stdin,port);+    let ch = {port} in+        &in_and_out(ch)