The Avail Programming Language

Asynchronous Numbers Station

/* Mystify the client at the other end of the specified client socket by sending * some cryptic numbers. */ Method "Mystify_" is [ client : client socket | rng ::= a Mersenne Twister; sem ::= a semaphore named "done" with 0 out of 1 permits; Guard [ killer : exception; /* Allow fast reuse of the local address. */ client's address reusability := true; /* Send the size of the stream of mysterious numbers. */ howMany ::= 5 × rng's next [1..51]; Ignore: a fiber writing <howMany> to client, on success doing [Signal sem;], on failure doing [e : exception | killer := e; Signal sem;]; Await sem; If killer is assigned then [Raise killer]; /* Send some mysterious numbers. */ weirdNumbers ::= map 1 to howMany through [i : byte | rng's next byte]; Ignore: a fiber writing weirdNumbers to client, on success doing [Signal sem;], on failure doing [e : exception | killer := e; Signal sem;]; Await sem; If killer is assigned then [Raise killer]; ] ensure [Close client;]; ] : ⊤; /* At the present time, the spaces are required in the specification of an IP * address. This limitation will be removed once Avail has a backtracking * lexical scanner. * * Incidentally, port 0 represents a wildcard port; the system will choose a * suitable one. */ serverAddress ::= 127 . 0 . 0 . 1 : 0; /* Run the numbers station. The server stops automatically after mystifying * three clients. */ Method "Start Lincolnshire Poacher" is [ sem ::= a semaphore named "not accepting" with 0 out of 1 permits; server ::= a server socket named "Lincolnshire Poacher"; Guard [ server's address reusability := true; Bind server to serverAddress; Repeat [ killer : exception; Ignore: a fiber waiting until server accepts a new connection, on success doing [client : client socket | Signal sem; Mystify client;] on failure doing [e : exception | killer := e; Signal sem;]; Await sem; If killer is assigned then [Raise killer]; ] 3 times; ] ensure [Close server;] ] : ⊤; /* Connect to the server, receive the mysterious numbers, and regurgitate them * to standard output as hyphen-separated quintets. */ Method "Be mystified" is [ sem ::= a semaphore named "done" with 0 out of 1 permits; client ::= a client socket named "amateur spy"; Guard [ client's address reusability := true; Bind client to 127 . 0 . 0 . 1 : 0; Ignore: a fiber connecting client to serverAddress, on success doing [Signal sem;], on failure doing [e : exception | killer := e; Signal sem;]; Await sem; If killer is assigned then [Raise killer]; expected : byte; Ignore: a fiber reading 1 byte from client, on success doing [ justRead : <byte…|>, endOfStream : boolean | expected := justRead[1]; Signal sem; ] on failure doing [e : exception | killer := e; Signal sem;]; Await sem; If killer is assigned then [Raise killer]; Assert: expected is assigned; weirdNumbers : <byte…|> := <>; Until [ Ignore: a fiber reading (expected - |weirdNumbers|) bytes from client, on success doing [ justRead : <byte…|>, endOfStream : boolean | weirdNumbers := weirdNumbers ++ justRead; Signal sem; ] on failure doing [e : exception | killer := e; Signal sem;]; Await sem; killer is assigned ∨ [expected = |weirdNumbers|] ]; If killer is assigned then [Raise killer]; /* Report the mysterious numbers. */ quintets ::= map 1 to |weirdNumbers| - 1 by 5 through [i : byte | weirdNumbers[i..i + 4]]; For each of quintets do [ q : <byte…|5> | Print: format "“①”-“②”-“③”-“④”-“⑤”\n" with unchecked q; ]; ] ensure [Close client;]; ] : ⊤; /* Run it! */ Start Lincolnshire Poacher; Repeat [Be mystified;] 3 times;
Return to Avail Newsletters, Edition #3