Skip to content

Latest commit

 

History

History
182 lines (120 loc) · 5.91 KB

File metadata and controls

182 lines (120 loc) · 5.91 KB

purescript-python

Motivation

This is the successor to my works of Idris-Python.

Idris didn't provide me metadata such as source code positions hence debugging(especially FFI) is horrible, but PureScript's IR output is pretty nice.

Besides, Idris FFI, though designed smart, but to be honest not that "industrially" practical, while PureScript's Haskell-like foreign import mechanism is extremely straightforward and flexible.

Then I found PureScript, and now I think I love it.

Status

The code generation itself is finished, but still needs testing.

Currently I'm working on the support of some FFI libraries, for example, Prelude. Without Prelude we cannot even print anything or proceed testing.

The first binary release(v0.1) will be available after

  • passing the testcases provided by PureScript GitHub repository, and
  • implementing an extensible and customizable Python FFI providing mechanism.

Python Package Generation Specification

Generating PySExpr

After slightly modifying a JavaScript-like IR produced by the builtin compiler, PureScript gets compiled to PySExpr and shall work since Python 3.5.

The reason why we generate the IR PySExpr instead of Python source code, is for getting better cross-Python-version compatibility, Python-version-specific optimizations, source code positioning for using existing Python debuggers in PureScript, and expression-first expressiveness. You could check out this reddit post for more details.

Directory Tree of Generated Package

Given a PureScript module, not losing the generality, we abbreviate it as A.B.

After processing this module via the command

# `output` is the directory produced by the PureScript build tool `spago`.
pspy-blueprint --out-python aaa/bbb/output_top_dir --corefn-entry A.B --out-ffi-dep ffi-requires.txt

Command pspy-blueprint generates following directory tree(all __init__.py will be added later, but not in Haskell side):

- aaa/bbb/output_top_dir
    - A
        - B
            - pure.py
            - pure.src.py

    - ffi
- ffi-requires.txt # lines of paths from which FFI files are required

pure.src.py Generated for Each Module

This Python module creates Python code/bytecode object.

In CPython, every Python file will be compiled to a Python code object, which will finally be executed in CPython virtual machine.

In pure.src.py, we just create the code object, but don't execute it, for achieving the further flexibility of caching and composition of our compilation.

pure.py Generated for Each Module

This is, actually the loader for corresponding pure.src.py.

This module implements the concrete code caching system which avoids the redundant Python source code to bytecode compilation, and finally greatly reduce the module loading time.

Hence, a PureScript module A.B compiled by PureScript-Python will be able to imported by the statement import output_top_dir.A.B.pure.

The code of pure.py, corresponding to a PureScript module, is fixed to be

from purescripto import LoadPureScript
__py__ = globals()
__ps__ = LoadPureScript(__file__, __name__)
__all__ = list(__ps__)
__py__.update(__ps__)

which relies on the Python package purescripto.

The Python package purescripto provides a common RTS and supplements all required functionalities for being a full featured PureScript backend.