hissp.compiler module¶
The Hissp data-structure language compiler and associated helper functions.
-
hissp.compiler.
NS
= <ContextVar name='NS' default=()>¶ Sometimes macros need the current namespace when expanding, instead of its defining namespace. Rather than pass in an implicit argument to all macros, it’s available here.
readerless
uses this automatically.
-
exception
hissp.compiler.
CompileError
¶ Bases:
SyntaxError
Catch-all exception for compilation failures.
-
exception
hissp.compiler.
PostCompileWarning
¶ Bases:
Warning
Form compiled to Python, but execution of it failed.
-
class
hissp.compiler.
Compiler
(qualname='__main__', ns=None, evaluate=True)¶ Bases:
object
The Hissp recursive-descent compiler.
Translates the Hissp data-structure language into a functional subset of Python.
-
static
new_ns
(name, doc=None, package=None)¶
-
compile
(forms: Iterable) → str¶ Compile multiple forms, and execute them them if evaluate mode enabled.
-
form
(form) → str¶ Compile Hissp form to the equivalent Python code as a string.
tuple
andstr
have special evaluation rules, otherwise it’s anatom
that represents itself.
-
special
(form: Tuple) → str¶ Try to compile as special form, else
invocation
.
-
function
(form: Tuple) → str¶ Compile the anonymous function special form.
- (lambda (<parameters>)
<body>)
The parameters tuple is divided into (<single> : <paired>)
Parameter types are the same as Python’s. For example,
>>> readerless( ... ('lambda', ('a',':/','b', ... ':', 'e',1, 'f',2, ... ':*','args', 'h',4, 'i',':?', 'j',1, ... ':**','kwargs',), ... 42,), ... ) '(lambda a,/,b,e=(1),f=(2),*args,h=(4),i,j=(1),**kwargs:(42))'
The special control words :* and :** designate the remainder of the positional and keyword parameters, respectively. Note this body has an implicit PROGN:
>>> print(readerless( ... ('lambda', (':',':*','args',':**','kwargs',), ... ('print','args',), ... ('print','kwargs',),), ... )) (lambda *args,**kwargs:( print( args), print( kwargs))[-1])
You can omit the right of a pair with
:?
(except the final**kwargs
). Also note that the body can be empty.>>> readerless( ... ('lambda', (':','a',1, ':/',':?', ':*',':?', 'b',':?', 'c',2,),), ... ) '(lambda a=(1),/,*,b,c=(2):())'
The ‘:’ may be omitted if there are no paired parameters.
>>> readerless(('lambda', ('a','b','c',':',),),) '(lambda a,b,c:())' >>> readerless(('lambda', ('a','b','c',),),) '(lambda a,b,c:())' >>> readerless(('lambda', (':',),),) '(lambda :())' >>> readerless(('lambda', (),),) '(lambda :())'
:
is required if there are any paired parameters, even if there are no single parameters:>>> readerless(('lambda', (':',':**','kwargs',),),) '(lambda **kwargs:())'
-
call
(form: Iterable) → str¶ Compile call form.
Any tuple that is not quoted,
()
, or aspecial
form ormacro
is a runtime call.Like Python, it has three parts. (<callable> <args> : <kwargs>) For example:
>>> print(readerless( ... ('print',1,2,3, ... ':','sep',('quote',":",), 'end',('quote',"\n\n",),) ... )) print( (1), (2), (3), sep=':', end='\n\n')
Either <args> or <kwargs> may be empty:
>>> readerless(('foo',':',),) 'foo()' >>> print(readerless(('foo','bar',':',),)) foo( bar) >>> print(readerless(('foo',':','bar','baz',),)) foo( bar=baz)
The : is optional if the <kwargs> part is empty:
>>> readerless(('foo',),) 'foo()' >>> print(readerless(('foo','bar',),),) foo( bar)
The <kwargs> part has implicit pairs; there must be an even number.
Use the control words
:*
and:**
for iterable and mapping unpacking:>>> print(readerless( ... ('print',':',':*',[1,2], 'a',3, ':*',[4], ':**',{'sep':':','end':'\n\n'},), ... )) print( *[1, 2], a=(3), *[4], **{'sep': ':', 'end': '\n\n'})
Unlike other control words, these can be repeated, but (as in Python) a ‘*’ is not allowed to follow ‘**’.
Method calls are similar to function calls. (.<method name> <object> <args> : <kwargs>) Like Clojure, a method on the first object is assumed if the function name starts with a dot:
>>> readerless(('.conjugate', 1j,),) '(1j).conjugate()' >>> eval(_) -1j >>> readerless(('.decode', b'\xfffoo', ':', 'errors',('quote','ignore',),),) "b'\\xfffoo'.decode(\n errors='ignore')" >>> eval(_) 'foo'
-
str
(code: str) → str¶ Compile code strings. Expands qualified identifiers and module literals into imports. Otherwise, injects as raw Python directly into the output.
-
qualified_identifier
(code)¶ Compile qualified identifier into import and attribute.
-
module_identifier
(code)¶ Compile module identifier to import.
-
atom
(form) → hissp.compiler.Compiler.str¶ Compile forms that evaluate to themselves.
Emits a literal if possible, otherwise falls back to
pickle
:>>> readerless(-4.2j) '((-0-4.2j))' >>> print(readerless(float('nan'))) __import__('pickle').loads( # nan b'Fnan\n.' ) >>> readerless([{'foo':2},(),1j,2.0,{3}]) "[{'foo': 2}, (), 1j, 2.0, {3}]" >>> spam = [] >>> spam.append(spam) >>> print(readerless(spam)) __import__('pickle').loads( # [[...]] b'(lp0\ng0\na.' )
-
pickle
(form) → hissp.compiler.Compiler.str¶ Compile to
pickle.loads
. The final fallback foratom
.
-
eval
(form: hissp.compiler.Compiler.str) → Tuple[hissp.compiler.Compiler.str, …]¶ Execute compiled form, but only if evaluate mode is enabled.
-
static