Lispy Modules

Lispy: A simple Lisp interpreter in Python.

This package provides a complete Lisp interpreter with support for: - Basic Scheme primitives - Macros (define-macro) - Tail call optimization (via Python’s stack, limited) - REPL - File loading

Usage:
>>> import lispy
>>> lispy.repl()

Type definitions for Lispy.

This module defines the types used in the interpreter, such as Symbol, Exp, and Atom.

class lispy.types.Promise(proc: Any)[source]

Bases: object

A Scheme Promise (delayed evaluation).

class lispy.types.Symbol[source]

Bases: str

A Scheme Symbol.

This class inherits from str and is used to represent Scheme symbols in the Python environment.

lispy.types.get_symbol(s: str, symbol_table: Dict[str, Symbol] = {'#<eof-object>': '#<eof-object>', '=': '=', '__or_temp__': '__or_temp__', 'and': 'and', 'append': 'append', 'args': 'args', 'begin': 'begin', 'car': 'car', 'cdr': 'cdr', 'cons': 'cons', 'define': 'define', 'define-macro': 'define-macro', 'delay': 'delay', 'do': 'do', 'dynamic-let': 'dynamic-let', 'if': 'if', 'lambda': 'lambda', 'length': 'length', 'let': 'let', 'make-promise': 'make-promise', 'null?': 'null?', 'or': 'or', 'quasiquote': 'quasiquote', 'quote': 'quote', 'set!': 'set!', 'try': 'try', 'unquote': 'unquote', 'unquote-splicing': 'unquote-splicing'}) Symbol[source]

Find or create a unique Symbol entry for the string s in the symbol table.

Parameters:
  • s (str) – The string representation of the symbol.

  • symbol_table (Dict[str, Symbol], optional) – The symbol table to use. Defaults to the module-level symbol table.

Returns:

The unique Symbol instance corresponding to s.

Return type:

Symbol

Constants used throughout the Lispy interpreter.

Exception classes for Lispy.

exception lispy.errors.ArgumentError[source]

Bases: LispyError, TypeError

Raised when function arguments don’t match parameters.

exception lispy.errors.Continuation(retval=None)[source]

Bases: BaseException

Used for call/cc control flow. Inherits from BaseException so it’s not caught by standard ‘try’ blocks which catch Exception.

exception lispy.errors.LispyError[source]

Bases: Exception

Base class for all Lispy exceptions.

exception lispy.errors.ParseError[source]

Bases: LispyError

Raised when the parser encounters an error (e.g. unexpected EOF, unexpected parenthesis).

exception lispy.errors.SchemeSyntaxError[source]

Bases: LispyError

Raised when a macro or special form has invalid syntax (e.g. wrong number of arguments to ‘if’).

exception lispy.errors.SymbolNotFoundError[source]

Bases: LispyError, LookupError

Raised when a symbol is not found in the environment.

exception lispy.errors.TypeMismatchError[source]

Bases: LispyError, TypeError

Raised when a type check fails.

exception lispy.errors.UserError[source]

Bases: LispyError

Raised by the user via the ‘raise’ primitive.

Error messages and constants for Lispy.

Parser module.

This module handles the tokenization and parsing of Scheme source code into Abstract Syntax Trees (ASTs).

class lispy.parser.InPort(file: TextIO)[source]

Bases: object

An input port. Retains a line of chars.

file

The file object to read from.

Type:

TextIO

line

The current line buffer.

Type:

str

next_token() str | None[source]

Return the next token, reading new text into line buffer if needed.

Returns:

The next token string, or EOF_OBJECT if end of file.

Return type:

Optional[str]

tokenizer = '\\s*(,@|[(\'`,)]|"(?:[\\\\].|[^\\\\"])*"|;.*|[^\\s()\'`,";]*)(.*)'
lispy.parser.atom(token: str) str | int | float[source]

Convert a token into an Atom.

Numbers become numbers; #t and #f are booleans; “…” string; otherwise Symbol.

Parameters:

token (str) – The token string to convert.

Returns:

The corresponding atomic value (int, float, complex, str, bool, or Symbol).

Return type:

Atom

lispy.parser.read(inport: InPort) str | int | float | List[Any][source]

Read a Scheme expression from an input port.

Parameters:

inport (InPort) – The input port to read from.

Returns:

The parsed Scheme expression (Atom or List).

Return type:

Exp

Raises:

ParseError – If the syntax is invalid (e.g., unexpected EOF or parenthesis).

lispy.parser.readchar(inport: InPort) str[source]

Read the next character from an input port.

Parameters:

inport (InPort) – The input port to read from.

Returns:

The next character, or EOF_OBJECT.

Return type:

str

lispy.parser.to_string(x: Any) str[source]
lispy.parser.to_string(x: bool) str
lispy.parser.to_string(x: Symbol) str
lispy.parser.to_string(x: str) str
lispy.parser.to_string(x: list) str
lispy.parser.to_string(x: complex) str

Convert a Python object back into a Lisp-readable string.

Parameters:

x (Any) – The expression to convert.

Returns:

The string representation of the expression.

Return type:

str

Environment module.

This module defines the Env class, which represents the execution environment (scope) for variables.

class lispy.env.Env(parms: List[Symbol] | Symbol = (), args: List[str | int | float | List[Any]] = (), outer: Env | None = None)[source]

Bases: dict

An environment: a dict of {‘var’:val} pairs, with an outer Env.

This class represents a scope in the Scheme interpreter. It inherits from dict to store variable bindings and maintains a reference to the outer (enclosing) environment for lexical scoping.

find(var: Symbol) Env[source]

Find the innermost Env where var appears.

Parameters:

var (Symbol) – The variable name to look up.

Returns:

The environment containing the variable.

Return type:

Env

Raises:

SymbolNotFoundError – If the variable is not found in this or any outer environment.

Evaluator module for Lispy.

This module contains the core evaluation logic, including the eval function and handlers for special forms. It implements Tail Call Optimization (TCO) using the TailCall class.

class lispy.evaluator.Procedure(parms: List[Symbol], exp: str | int | float | List[Any], env: Env)[source]

Bases: object

A user-defined Scheme procedure.

parms

The parameter names.

Type:

List[Symbol]

exp

The body of the procedure.

Type:

Exp

env

The environment in which the procedure was defined (closure).

Type:

Env

check_types(args: List[Any]) None[source]

Check argument types against annotations.

class lispy.evaluator.TailCall(x: str | int | float | List[Any], env: Env)[source]

Bases: object

Represents a tail call to be executed by the evaluator loop.

lispy.evaluator.eval(x: str | int | float | List[Any], env: Env | None = None) Any[source]

Evaluate an expression in an environment.

This is the core evaluation loop. It handles variable lookups, constant literals, special forms (quote, if, set!, define, lambda, begin), and procedure calls. It implements Tail Call Optimization (TCO) by using a loop for tail calls.

Parameters:
  • x (Exp) – The expression to evaluate.

  • env (Optional[Env]) – The environment to evaluate in. Defaults to global_env.

Returns:

The result of the evaluation.

Return type:

Any

lispy.evaluator.eval_begin(x: str | int | float | List[Any], env: Env) Any[source]

Evaluate a begin expression.

Parameters:
  • x (Exp) – The expression (begin exp…).

  • env (Env) – The environment.

Returns:

The result of the last expression, wrapped in TailCall.

Return type:

Any

lispy.evaluator.eval_define(x: str | int | float | List[Any], env: Env) Any[source]

Evaluate a define expression.

Parameters:
  • x (Exp) – The expression (define var exp).

  • env (Env) – The environment.

Returns:

None.

Return type:

Any

lispy.evaluator.eval_dynamic_let(x: str | int | float | List[Any], env: Env) Any[source]

Evaluate a dynamic-let expression.

Parameters:
  • x (Exp) – The expression (dynamic-let ((var val)…) body…).

  • env (Env) – The environment.

Returns:

The result of the body evaluation.

Return type:

Any

lispy.evaluator.eval_if(x: str | int | float | List[Any], env: Env) Any[source]

Evaluate an if expression.

Parameters:
  • x (Exp) – The expression (if test conseq alt).

  • env (Env) – The environment.

Returns:

The result of the consequent or alternative, wrapped in TailCall.

Return type:

Any

lispy.evaluator.eval_lambda(x: str | int | float | List[Any], env: Env) Any[source]

Evaluate a lambda expression.

Parameters:
  • x (Exp) – The expression (lambda vars body).

  • env (Env) – The environment.

Returns:

The created procedure.

Return type:

Procedure

lispy.evaluator.eval_quote(x: str | int | float | List[Any], env: Env) Any[source]

Evaluate a quote expression.

Parameters:
  • x (Exp) – The expression (quote exp).

  • env (Env) – The environment (unused).

Returns:

The quoted expression.

Return type:

Any

lispy.evaluator.eval_set(x: str | int | float | List[Any], env: Env) Any[source]

Evaluate a set! expression.

Parameters:
  • x (Exp) – The expression (set! var exp).

  • env (Env) – The environment.

Returns:

None.

Return type:

Any

lispy.evaluator.eval_try(x: str | int | float | List[Any], env: Env) Any[source]

Evaluate a try expression.

Parameters:
  • x (Exp) – The expression (try exp handler).

  • env (Env) – The environment.

Returns:

The result of the expression or the handler.

Return type:

Any

Macro expansion module.

This module handles the expansion of macros and special forms before evaluation. It includes the expand function and handlers for various special forms.

lispy.macros.delay(exp: str | int | float | List[Any]) str | int | float | List[Any][source]

Expand a delay expression.

(delay exp) -> (make-promise (lambda () exp))

Parameters:

exp (Exp) – The expression to delay.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.do_macro(*args: str | int | float | List[Any]) str | int | float | List[Any][source]

Expand a do expression.

(do ((var init [step]) …) (test expr …) command …)

Parameters:

*args (Exp) – The arguments to the do macro.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.expand(x: str | int | float | List[Any], toplevel: bool = False) str | int | float | List[Any][source]

Walk tree of x, making optimizations/fixes, and signaling SchemeSyntaxError.

This function handles macro expansion and syntax checking for special forms.

Parameters:
  • x (Exp) – The expression to expand.

  • toplevel (bool) – Whether this is a top-level expression (relevant for define-macro).

Returns:

The expanded expression.

Return type:

Exp

Raises:

SchemeSyntaxError – If the syntax is invalid.

lispy.macros.expand_begin(x: str | int | float | List[Any], toplevel: bool) str | int | float | List[Any][source]

Expand a begin expression.

Parameters:
  • x (Exp) – The expression.

  • toplevel (bool) – Whether it’s at the top level.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.expand_define(x: str | int | float | List[Any], toplevel: bool) str | int | float | List[Any][source]

Expand a define expression.

Parameters:
  • x (Exp) – The expression.

  • toplevel (bool) – Whether it’s at the top level.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.expand_dynamic_let(x: str | int | float | List[Any], toplevel: bool) str | int | float | List[Any][source]

Expand a dynamic-let expression.

Parameters:
  • x (Exp) – The expression.

  • toplevel (bool) – Whether it’s at the top level.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.expand_if(x: str | int | float | List[Any], toplevel: bool) str | int | float | List[Any][source]

Expand an if expression.

Parameters:
  • x (Exp) – The expression.

  • toplevel (bool) – Whether it’s at the top level.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.expand_lambda(x: str | int | float | List[Any], toplevel: bool) str | int | float | List[Any][source]

Expand a lambda expression.

Parameters:
  • x (Exp) – The expression.

  • toplevel (bool) – Whether it’s at the top level.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.expand_quasiquote(x: str | int | float | List[Any]) str | int | float | List[Any][source]

Expand quasiquote expressions.

Expands `` x => ‘x`, `` ,x => x`, and `` (,@x y) => (append x y)`.

Parameters:

x (Exp) – The quasiquoted expression.

Returns:

The expanded expression using cons, append, and quote.

Return type:

Exp

lispy.macros.expand_quasiquote_macro(x: str | int | float | List[Any], toplevel: bool) str | int | float | List[Any][source]

Expand a quasiquote expression.

Parameters:
  • x (Exp) – The expression.

  • toplevel (bool) – Whether it’s at the top level.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.expand_quote(x: str | int | float | List[Any], toplevel: bool) str | int | float | List[Any][source]

Expand a quote expression.

Parameters:
  • x (Exp) – The expression.

  • toplevel (bool) – Whether it’s at the top level.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.expand_set(x: str | int | float | List[Any], toplevel: bool) str | int | float | List[Any][source]

Expand a set! expression.

Parameters:
  • x (Exp) – The expression.

  • toplevel (bool) – Whether it’s at the top level.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.expand_try(x: str | int | float | List[Any], toplevel: bool) str | int | float | List[Any][source]

Expand a try expression.

Parameters:
  • x (Exp) – The expression.

  • toplevel (bool) – Whether it’s at the top level.

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.is_pair(x: str | int | float | List[Any]) bool[source]

Check if x is a pair (non-empty list).

Parameters:

x (Exp) – The expression to check.

Returns:

True if x is a pair, False otherwise.

Return type:

bool

lispy.macros.let(*args: str | int | float | List[Any]) str | int | float | List[Any][source]

Expand a let expression into a lambda application.

(let ((v1 e1) …) body…) => ((lambda (v1 …) body…) e1 …)

Parameters:

*args (Exp) – The arguments to the let macro (bindings and body).

Returns:

The expanded expression.

Return type:

Exp

lispy.macros.require(x: str | int | float | List[Any], predicate: bool, msg: str = 'Incorrect number of arguments') None[source]

Signal a syntax error if predicate is false.

Parameters:
  • x (Exp) – The expression causing the error.

  • predicate (bool) – The condition that must be true.

  • msg (str) – The error message. Defaults to “wrong length”.

Raises:

SchemeSyntaxError – If predicate is False.

Standard library primitives.

This module defines the standard Scheme procedures available in the global environment, such as arithmetic operations, list manipulation, and I/O.

lispy.primitives.add_globals(env: Env) Env[source]

Add some Scheme standard procedures to the environment.

Parameters:

env (Env) – The environment to populate.

Returns:

The updated environment.

Return type:

Env

lispy.primitives.callcc(proc: Callable) Any[source]

Call proc with current continuation; escape only.

Parameters:

proc (Callable) – The procedure to call.

Returns:

The result of the procedure or the continuation value.

Return type:

Any

Raises:

Continuation – Used to implement the continuation jump.

lispy.primitives.cons(x: Any, y: List[Any]) List[Any][source]

Construct a new list with x as the first element and y as the rest.

Parameters:
  • x (Any) – The first element.

  • y (ListType) – The rest of the list.

Returns:

The new list.

Return type:

ListType

lispy.primitives.curry(proc: Any) Any[source]

Return a curried version of the procedure.

Parameters:

proc (Any) – The procedure to curry.

Returns:

A new procedure that accepts arguments incrementally.

Return type:

Any

lispy.primitives.force(obj: Any) Any[source]

Force the evaluation of a promise.

Parameters:

obj (Any) – The object to force.

Returns:

The result of the promise evaluation, or the object itself if not a promise.

Return type:

Any

lispy.primitives.is_pair(x: str | int | float | List[Any]) bool[source]

Check if x is a pair (non-empty list).

Parameters:

x (Exp) – The expression to check.

Returns:

True if x is a pair, False otherwise.

Return type:

bool

lispy.primitives.make_promise(proc: Callable) Promise[source]

Create a new Promise.

Parameters:

proc (Callable) – The thunk (procedure with no arguments) to delay.

Returns:

The created promise.

Return type:

Promise

lispy.primitives.raise_error(x: Any) None[source]

Raise an exception.

Parameters:

x (Any) – The exception object or message to raise.

Raises:

Exception – The provided exception or a new Exception with the message.

Read-Eval-Print Loop (REPL) module.

This module implements the interactive shell and file loading functionality.

lispy.repl.load(filename: str) None[source]

Eval every expression from a file.

Parameters:

filename (str) – The path to the file to load.

lispy.repl.parse(inport: str | InPort) str | int | float | List[Any][source]

Parse a program: read and expand/error-check it.

Parameters:

inport (Union[str, InPort]) – The input string or port to read from.

Returns:

The parsed and expanded expression.

Return type:

Exp

lispy.repl.repl(prompt: str = 'lispy> ', inport: ~lispy.parser.InPort | None = None, out: ~typing.TextIO | None = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>, stop_on_error: bool = False) None[source]

A prompt-read-eval-print loop.

Parameters:
  • prompt (str, optional) – The prompt string. Defaults to ‘lispy> ‘.

  • inport (Optional[InPort], optional) – The input port. Defaults to None (stdin).

  • out (Optional[TextIO], optional) – The output stream. Defaults to sys.stdout.

  • stop_on_error (bool, optional) – Whether to exit on error. Defaults to False.