"""Base classes for Emacs Lisp abstract syntax trees."""
from typing import Union, Tuple, Iterable
from .util import escape_emacs_string
[docs]class Expr:
"""Base for classes which represent Elisp expressions."""
def __str__(self):
"""Render the expression as elisp code."""
raise NotImplementedError()
[docs] def quote(self) -> 'Expr':
"""Return a quoted form of this expression."""
return Quote(self)
@property
def q(self):
"""Shortcut for ``self.quote()``."""
return self.quote()
def __repr__(self):
return '<el %s>' % self
def _repr_quoted(self) -> str:
"""Get representation within a quoted expression."""
return str(self)
[docs]class Literal(Expr):
"""Basic self-evaluating expressions like strings, numbers, etc.
Attributes
----------
pyvalue
The Python value of the literal.
"""
PY_TYPES = (str, int, float)
pyvalue: Union[PY_TYPES]
[docs] def __init__(self, pyvalue: Union[PY_TYPES]):
if not isinstance(pyvalue, self.PY_TYPES):
raise TypeError('Instances of %s not allowed as Elisp literals' % type(pyvalue))
self.pyvalue = pyvalue
def __eq__(self, other):
return isinstance(other, Literal) \
and type(other.pyvalue) is type(self.pyvalue) \
and other.pyvalue == self.pyvalue
def __str__(self):
if isinstance(self.pyvalue, str):
return escape_emacs_string(self.pyvalue, quotes=True)
else:
return str(self.pyvalue)
[docs]class Symbol(Expr):
"""An Elisp symbol."""
name: str
[docs] def __init__(self, name: str):
assert isinstance(name, str) and name
self.name = name
def __eq__(self, other):
return isinstance(other, Symbol) and other.name == self.name
@property
def isconst(self) -> bool:
return self.name.startswith(':') or self.name in ('nil', 't')
def __call__(self, *args, **kwargs) -> 'List':
"""Produce a function call expression from this symbol.
See :func:`emacs.elisp.ast.funccall`.
"""
from .exprs import funccall
return funccall(self, *args, **kwargs)
def __str__(self):
return self.name
[docs]class Cons(Expr):
"""A cons cell."""
car: Expr
cdr: Expr
[docs] def __init__(self, car: Expr, cdr: Expr):
self.car = car
self.cdr = cdr
def __eq__(self, other):
return isinstance(other, Cons) \
and other.car == self.car \
and other.cdr == self.cdr
def __str__(self):
return '(cons %s %s)' % (self.car, self.cdr)
def _repr_quoted(self) -> str:
return '(%s . %s)' % (self.car._repr_quoted(), self.cdr._repr_quoted())
[docs]class List(Expr):
"""An Elisp list expression.
Attributes
----------
items
Items in the list.
"""
items: Tuple[Expr, ...]
[docs] def __init__(self, items: Iterable[Expr]):
self.items = tuple(items)
def __eq__(self, other):
return isinstance(other, List) and other.items == self.items
def __str__(self):
return '(%s)' % ' '.join(map(str, self.items))
def _repr_quoted(self) -> str:
return '(%s)' % ' '.join(item._repr_quoted() for item in self.items)
[docs]class Quote(Expr):
"""A quoted Elisp expression.
Attributes
----------
expr
The quoted Elisp expression.
"""
[docs] def __init__(self, expr: Expr):
self.expr = expr
def __eq__(self, other):
return isinstance(other, Quote) and other.expr == self.expr
def __str__(self):
return "'" + self.expr._repr_quoted()
[docs]class Raw(Expr):
"""Just raw Elisp code to be pasted in at this point.
Attributes
----------
src
Raw Elisp source code.
"""
src: str
[docs] def __init__(self, src: str):
self.src = src
def __eq__(self, other):
return isinstance(other, Raw) and other.src == self.src
def __str__(self):
return self.src