express-your-self
Python, with no statements!
Inside expr.py you'll find some utility functions and classes that let you write programs without any statements (barring a single import at the top of the file...).
I've written a (sort-of working) TCP server and an HTTP server.
Here's an example of the code you might write. This starts a mutli-threaded TCP server that simply echos whatever you send it. Try it out using netcat. (warning: it's a little broken)
from expr import * # `do` lets use sequence "statements" do([ # "walrus operator" gives us variables (python 3.8+) socket := require('socket'), threading := require('threading'), spawn := lambda target, args: do([ handler_thread := threading.Thread(target=target, args=args), setattr(handler_thread, 'daemon', True), handler_thread.start() ]), ends_with_newline := lambda bytes_: \ len(bytes_) > 0 and bytes_[len(bytes_) - 1] == ord('\n'), handle_client := lambda current_connection, client_addr: do([ print(f"client connected at {client_addr}"), # loop_while calls the provided lambda over and over, until the final expression is falsy loop_while(lambda: do([ recvd_bytes := current_connection.recv(1024), current_connection.send(recvd_bytes), not ends_with_newline(recvd_bytes), ])), ]), listen := lambda host, port: do([ connection := socket.socket(socket.AF_INET, socket.SOCK_STREAM), connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1), connection.bind((host, port)), # Listen for clients (max 10 clients in waiting) connection.listen(10), print(f"server listening on {host}:{port}"), loop(lambda: do([ client_connection := connection.accept(), spawn(target=handle_client, args=client_connection), ])) ]), listen("localhost", 3000) ])
The code in http.py and http_server.py is much more interesting. Cool things not included in this snippet:
tis a way to get "data classes". You give it a name and a list of properties, as follows:Pair := t('Pair', ['one', 'two'])Boxis to get around the fact that we don't have mutable bindings. Instead of the binding being mutable, just stick it in a container!klass, for when a data class isn't enough. Used to defineBox:
Box = klass('Box', { '__init__': lambda self, value: setattr(self, 'value', value), 'get': lambda self: self.value, 'set': lambda self, setter: setattr(self, 'value', setter(self.value)), })
improvements
- Exceptions! There's no way to catch exceptions at the moment. It would be easy to write a helper function using
try/catchstatements, but that's cheating.