hissp.reader module

The Lissp language reader and associated helper functions.

Compiles Lissp files to Python files when run as the main module.

The reader is organized as a lexer and parser. The parser is extensible with Lissp reader macros. The lexer is not extensible, and doesn’t do much more than pull tokens from a relatively simple regex and track its position for error messages.

hissp.reader.ENTUPLE = ('lambda', (':', ':*', ' _'), ' _')

Used by the template macro to make tuples.

To avoid creating a dependency on Hissp, by default, templates spell out the entuple implementation every time, but you can override this by setting some other value here.

hissp.reader.DROP = <object object>

The sentinel value returned by the discard macro _#, which the reader skips over when parsing. Reader macros can have read-time side effects with no Hissp output by returning this.

exception hissp.reader.SoftSyntaxError

Bases: SyntaxError

A syntax error that could be corrected with more lines of input.

When the REPL encounters this when attempting to evaluate a form, it will ask for more lines, rather than aborting with an error.

class hissp.reader.Lexer(code: str, file: str = '<?>')

Bases: Iterator

The tokenizer for the Lissp language.

Most of the actual tokenizing is done by the regex. The Lexer adds some position tracking to that to help with error messages.

position(pos: int) Tuple[str, int, int, str]

Compute the filename, lineno, offset and text for a SyntaxError, using the current character offset in code.

class hissp.reader.Comment(content)

Bases: tuple


Alias for field number 0

class hissp.reader.Extra(iterable=(), /)

Bases: tuple

Designates Extra read-time arguments for reader macros.

hissp.reader.gensym_counter(_count=[74], _lock=<unlocked _thread.lock object>)

Call to increment the gensym counter, and return the new count. Used by the gensym reader macro $# to ensure symbols are unique.

class hissp.reader.Lissp(qualname='__main__', ns=None, evaluate=False, filename='<?>')

Bases: object

The parser for the Lissp language.

Wraps around a Hissp compiler instance. Parses Lissp tokens into Hissp syntax trees.


Reset position, nesting depth, and gensym stack.

property ns

The wrapped Compiler’s ns.

compile(code: str) str

Read Lissp code and pass it on to the Hissp compiler.

reads(code: str) Iterable

Read Hissp forms from code string.

parse(tokens: hissp.reader.Lexer) Iterator

Build Hissp forms from a Lexer.


Get the filename, lineno, offset and text for a SyntaxError, from the Lexer given to parse.


Start a new gensym context for the current template.


Start a new unquote context for the current template.

parse_macro(tag: str, form, extras)

Apply a reader macro to a form.


Process form as template.

qualify(symbol: str, invocation=False) str

Qualify symbol based on current context.

gensym(form: str)

Generate a symbol unique to the current template. Re-munges any $’s as a gensym counter, or adds it as a prefix if there aren’t any.

static escape(atom)

Process the backslashes in a token.

static atom(v)

Preprocesses atoms. Handles escapes and munging.

hissp.reader.is_hissp_string(form) bool

Determines if form would directly represent a string in Hissp.

Allows “readerless mode”-style strings: (‘quote’, ‘foo’,) and any string literal in a Hissp-level str: ‘“foo”’ (including the “(‘foo’)” form produced by the Lissp reader).

Macros often produce strings in one of these forms, via ' or repr on a string object.

hissp.reader.is_lissp_string(form) bool

Determines if form could have been read from a Lissp string literal.

It’s not enough to check if the form has a string type. Several token types such as control words, symbols, and Python injections, read in as strings. Macros may need to distinguish these cases.

hissp.reader.is_string_literal(form) Optional[bool]

Determines if ast.literal_eval on form produces a string.

False if it produces something else or None if it raises Exception.


Determines if symbol can be qualified with a module.

Can’t be quote, __import__, any Python reserved word, an auto-gensym, already qualified, method syntax, or a module handle; and must be a valid identifier or attribute identifier.

hissp.reader.transpile(package: Optional[str], *modules: str)

Transpiles the named Python modules from Lissp.

A .lissp file of the same name must be present in the module’s location. The Python modules are overwritten. Missing modules are created. If the package is “” or None, transpile writes non- packaged modules to the current working directory instead.

hissp.reader.transpile_packaged(resource: str, package: str)

Locates & transpiles a packaged .lissp resource file to .py.

hissp.reader.transpile_file(path: Union[pathlib.Path, str], package: Optional[str] = None)

Transpiles a single .lissp file to .py in the same location.

Code in .lissp files is executed upon compilation. This is necessary because macro definitions can alter the compilation of subsequent top-level forms. A packaged Lissp file must know its package at compile time to resolve imports correctly.