Skip to content

lepisma/pigeon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pigeon

A toy S-EXP (a particular flavor) to python transpiler in the spirit of sxc. The plan is to exploit the macro system of common lisp to emit plain python source (not vm bytecode). Most of the useful stuff will go as regular lisp macros.

For a practical python-lisp, see hy.

Building

lake build
./bin/pigeon <input-file> <output-path>

Quickstart

(pgfmt
 (import (numpy :as np))

 (defun random (size)
   (np.random.rand size size))

 (defun some-key (a :key-arg 10)
   (+ 1 1))

 (setf a "hello")
 (print a))
import numpy as np

def random(size):
    return np.random.rand(size, size)

def some_key(a, key_arg=10):
    return (1 + 1)

a = "hello"

print(a)

Features

Types

(pgfmt
 t                              ;; True
 f                              ;; False
 none                           ;; None
 (setf some-array #(1 2 3 5))   ;; lisp type vectors go as numpy array

 (setf some-list [12 2 3])      ;; hy style lists go as python lists

 (setf some-dict (dict "a" "world" "b" "hello"))

 (setf some-tuple (tuple 1 2)))
True

False

None

some_array = np.array([1, 2, 3, 5])

some_list = [12, 2, 3]

some_dict = {"a": "world", "b": "hello"}

some_tuple = (1, 2)

Inline constants

Lambdas

(pgfmt
 (fn "lol kek")
 (fn-xy (+ x y))
 (fn-abc (+ a b (/ 2 c))))
(lambda : "lol kek")

(lambda x, y: (x + y))

(lambda a, b, c: (a + b + (2 / c)))

Conditionals and loops

(pgfmt
 (cond ((this-thing) (then-that))
       ((another-thing) (another-that))
       (t fallback)))
if this_thing():
    then_that()
elif another_thing():
    another_that()
else:
    fallback
(pgfmt @[(+ x x) :for x :in (range 10) :if (evenp x)])
[(x + x) for x in range(10) if evenp(x)]

Contexts

(pgfmt
 (with (open "this-thing")
       (do-something))

 (with (some-fn) :as k
       (something-else k)))
with open("this-thing"):
    do_something()

with some_fn() as k:
    something_else(k)

Macros

Pigeon uses usual lisp macros loaded from a .pgl files using require. Macro expansion works on the pigeon code before converting to python.

(pgfmt
 (require ./samples/macros))
# loaded extension from ./SAMPLES/MACROS

Imports

(pgfmt
 (import numpy)
 (import (kek :as lol) :from lel)
 (import (this :as that) (who :as whom)))
import numpy

from lel import kek as lol

import this as that
import who as whom

IDs

To use case sensitive python ids, use #i reader macro:

(pgfmt
 (setf #iTHisIsSick 343)
 (import #iLastFm))
THisIsSick = 343

import LastFm

Python snippets

(pgfmt
 (setf some-list @<[a for a in range(10)]>)

 (defun a-fun (arg)
   (compute arg)
   @<
   def something_in_python(a, b):
       return a + b
   >
   (something-in-python 1 arg)))
some_list = [a for a in range(10)]

def a_fun(arg):
    compute(arg)
    def something_in_python(a, b):
        return a + b
    
    return something_in_python(1, arg)

Quasiquotes

Arrows

Some stupid stuff