I recently thought about how I can merge lisp programming language and python, and tried to write a lisp syntax like compiler in python. Some thing that can convert the following lisp code:



( repeat 2 ( write-ln ( + 10 20 )))

to this tree:



word: "repeat" int: 2 word: "write-ln" symbol: + int: 10 int: 20

And then write an executor for executing tree.

But I figured out that I don't need to write a lisp syntax parser. Instead I can use python builtins types directly.

for example:



( 'repeat' , ( 'print' , ( 'add' , 10 , 20 )))

And then the result of my thoughts was that I wrote this simple python builtins types compiler . ( pbtc for shorthand)



#!/usr/bin/python3 # filename: main.py import itertools import sys def add ( * args ): result = args [ 0 ] if len ( args ) != 0 else None for arg in args [ 1 :]: result += arg return result def sub ( * args ): result = args [ 0 ] if len ( args ) != 0 else None for arg in args [ 1 :]: result -= arg return result def mul ( * args ): result = args [ 0 ] if len ( args ) != 0 else None for arg in args [ 1 :]: result *= arg return result def div ( * args ): result = args [ 0 ] if len ( args ) != 0 else None for arg in args [ 1 :]: result /= arg return result def true_div ( * args ): result = args [ 0 ] if len ( args ) != 0 else None for arg in args [ 1 :]: result //= arg return result def join ( sep , args ): return sep . join ( args ) tuple_compilers = { 'add' : add , 'sub' : sub , 'mul' : mul , 'div' : div , 'tdiv' : true_div , 'print' : lambda * args : print ( * args ), 'join' : join , 'repeat' : itertools . repeat , } def compile_tuple ( tree , memory , compile ): if len ( tree ) == 0 : raise ValueError ( 'invalid tuple length: {}' . format ( len ( tree ))) if not isinstance ( tree [ 0 ], str ): raise ValueError ( 'invalid tuple instruction: {}' . format ( tree [ 0 ])) if tree [ 0 ] not in tuple_compilers : raise ValueError ( 'unknown tuple instruction: {}' . format ( tree [ 0 ])) args = [] for node in tree [ 1 :]: args . append ( compile ( node , memory )) return tuple_compilers [ tree [ 0 ]]( * args ) compilers = { tuple : compile_tuple , ( list , dict , str , int , float , bytes ): lambda tree , memory , compile : tree , } def compile_tree ( tree , compilers , memory = None ): self = lambda tree , memory : compile_tree ( tree , compilers , memory ) for _type , compile in compilers . items (): if isinstance ( tree , _type ): return compile ( tree , memory , self ) raise TypeError ( type ( tree ). __name__ ) with open ( sys . argv [ 1 ]) as infile : globals_dict = {} exec ( 'grammar = ' + infile . read ()) compile_tree ( grammar , compilers )

it's not safe, it's slow, but works.

testing:



# filename: lispy ( 'print' , ( 'join' , ' ' , ( 'repeat' , ( 'join' , ' ' , [ 'hi' , 'bye' ]), 10 )) )

$./main.py lispy :



hi bye hi bye hi bye hi bye hi bye hi bye hi bye hi bye hi bye hi bye

It's fun...

Maybe later, I wrote a more complete version of this and publish it somewhere, as open source.