hissp.reader module#

The Lissp language reader and associated helper functions.

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.GENSYM_BYTES = 5#

The number of bytes gensym $# hashes have.

The default 5 bytes (40 bits) should be more than sufficient space to eliminate collisions with typical usage, but for unusual applications, hash length can be increased, up to a maximum of 32 bytes. (16 would have more space than a uuid.uuid4.)

Each hash character encodes 5 bits (base32 encoding), so 40-bit hashes typically take 8 characters.

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. (Not recommended.)

exception hissp.reader.SoftSyntaxError[source]#

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 = '<?>')[source]#

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][source]#

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

class hissp.reader.Comment(token)[source]#

Bases: object

Parsed object for a comment token (line comment block).

The reader normally discards these, but reader macros can use them.


Gets the comment text inside the comment token.

Strips any leading indent, the ; character(s), and up to one following space for each line in the comment block.

class hissp.reader.Kwarg(k, v)[source]#

Bases: object

Contains a read-time keyword argument for reader macros.

Normally made with kwarg tags, but can be constructed directly.

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

Bases: object

The parser for the Lissp language.

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


Reset hasher, position, nesting depth, and gensym stacks.

property ns: Dict[str, Any]#

The wrapped Compiler’s ns.

compile(code: str) str[source]#

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

reads(code: str) Iterable[source]#

Read Hissp forms from code string.

parse(tokens: Lexer) Iterator[source]#

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)[source]#

Apply a reader macro to a form.

The built-in reader macros are handled here. They are



` (backtick)

template quote (starts a template)




inject (evaluate at read time and use resulting object)

Plus the three built-in template helper macros, which are only valid inside a template.




splice unquote



The built-in macros are reserved by the reader and cannot be reassigned.


Process form as template.

qualify(symbol: str, invocation=False) str[source]#

Qualify symbol based on current context.

gensym(form: str)[source]#

Generate a symbol unique to the current template. Re-munges any $’s as a gensym hash, or adds it as a prefix if there aren’t any. Gensym hashes are deterministic for reproducible builds. Inputs are the code string being read, the current __name__ (defaults to “__main__” if not found) and a count of templates read so far.

static escape(atom)[source]#

Process the backslashes in a token.

static atom(v)[source]#

Preprocesses atoms. Handles escapes and munging.

hissp.reader.is_hissp_string(form) bool[source]#

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[source]#

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) bool | None[source]#

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, a prefix auto-gensym, already qualified, method syntax, or a module handle; and must be a valid identifier or attribute identifier.

hissp.reader.transpile(package: str | None, *modules: str)[source]#

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)[source]#

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

hissp.reader.transpile_file(path: Path | str, package: str | None = None)[source]#

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 handle templates and macros correctly.

After the .py file is written, __file__ will be set to it, if it doesn’t exist already.