Skip to content

christianscott/express-your-self

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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:

  • t is a way to get "data classes". You give it a name and a list of properties, as follows: Pair := t('Pair', ['one', 'two'])
  • Box is 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 define Box:
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/catch statements, but that's cheating.

About

๐Ÿ•บ Writing Python without any statements*

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages