diff options
author | Roger Gonzalez <rogergonzalez21@gmail.com> | 2020-04-08 10:38:14 -0300 |
---|---|---|
committer | Roger Gonzalez <rogergonzalez21@gmail.com> | 2020-04-08 10:38:14 -0300 |
commit | 5f0f2f90361a4c0a76478b288998595fc3ddebd2 (patch) | |
tree | fba8d30e376187e1b0b441314497bb1a70989f08 /.emacs.d.back/.python-environments/default/lib/python3.7/site-packages/sexpdata.py | |
parent | 47e1414d1be0069b158d0d0718988d72b0fb5d0d (diff) |
Added my old emacs config
Diffstat (limited to '.emacs.d.back/.python-environments/default/lib/python3.7/site-packages/sexpdata.py')
-rw-r--r-- | .emacs.d.back/.python-environments/default/lib/python3.7/site-packages/sexpdata.py | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/.emacs.d.back/.python-environments/default/lib/python3.7/site-packages/sexpdata.py b/.emacs.d.back/.python-environments/default/lib/python3.7/site-packages/sexpdata.py new file mode 100644 index 00000000..74f10b06 --- /dev/null +++ b/.emacs.d.back/.python-environments/default/lib/python3.7/site-packages/sexpdata.py @@ -0,0 +1,675 @@ +# [[[cog import cog; cog.outl('"""\n%s\n"""' % file('README.rst').read()) ]]] +""" +S-expression parser for Python +============================== + +`sexpdata` is a simple S-expression parser/serializer. It has +simple `load` and `dump` functions like `pickle`, `json` or `PyYAML` +module. + +>>> from sexpdata import loads, dumps +>>> loads('("a" "b")') +['a', 'b'] +>>> print(dumps(['a', 'b'])) +("a" "b") + + +You can install `sexpdata` from PyPI_:: + + pip install sexpdata + + +Links: + +* `Documentation (at Read the Docs) <http://sexpdata.readthedocs.org/>`_ +* `Repository (at GitHub) <https://github.com/tkf/sexpdata>`_ +* `Issue tracker (at GitHub) <https://github.com/tkf/sexpdata/issues>`_ +* `PyPI <http://pypi.python.org/pypi/sexpdata>`_ +* `Travis CI <https://travis-ci.org/#!/tkf/sexpdata>`_ + + +License +------- + +`sexpdata` is licensed under the terms of the BSD 2-Clause License. +See the source code for more information. + +""" +# [[[end]]] + +# Copyright (c) 2012 Takafumi Arakaki +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: + +# Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. + +# Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +__version__ = '0.0.3' +__author__ = 'Takafumi Arakaki' +__license__ = 'BSD License' +__all__ = [ + # API functions: + 'load', 'loads', 'dump', 'dumps', + # Utility functions: + 'car', 'cdr', + # S-expression classes: + 'Symbol', 'String', 'Quoted', +] + +import re +from string import whitespace +import functools + +BRACKETS = {'(': ')', '[': ']'} + + +### Python 3 compatibility + +try: + unicode + PY3 = False +except NameError: + basestring = unicode = str # Python 3 + PY3 = True + + +def uformat(s, *args, **kwds): + """Alias of ``unicode(s).format(...)``.""" + return tounicode(s).format(*args, **kwds) + + +### Utility + +def tounicode(string): + """ + Decode `string` if it is not unicode. Do nothing in Python 3. + """ + if not isinstance(string, unicode): + string = unicode(string, 'utf-8') + return string + + +def return_as(converter): + """ + Decorator to convert result of a function. + + It is just a function composition. The following two codes are + equivalent. + + Using `@return_as`:: + + @return_as(converter) + def generator(args): + ... + + result = generator(args) + + Manually do the same:: + + def generator(args): + ... + + result = converter(generator(args)) + + Example: + + >>> @return_as(list) + ... def f(): + ... for i in range(3): + ... yield i + ... + >>> f() # this gives a list, not an iterator + [0, 1, 2] + + """ + def wrapper(generator): + @functools.wraps(generator) + def func(*args, **kwds): + return converter(generator(*args, **kwds)) + return func + return wrapper + + +### Interface + +def load(filelike, **kwds): + """ + Load object from S-expression stored in `filelike`. + + :arg filelike: A text stream object. + + See :func:`loads` for valid keyword arguments. + + >>> import io + >>> fp = io.StringIO() + >>> sexp = [Symbol('a'), Symbol('b')] # let's dump and load this object + >>> dump(sexp, fp) + >>> _ = fp.seek(0) + >>> load(fp) == sexp + True + + """ + return loads(filelike.read(), **kwds) + + +def loads(string, **kwds): + """ + Load object from S-expression `string`. + + :arg string: String containing an S-expression. + :type nil: str or None + :keyword nil: A symbol interpreted as an empty list. + Default is ``'nil'``. + :type true: str or None + :keyword true: A symbol interpreted as True. + Default is ``'t'``. + :type false: str or None + :keyword false: A symbol interpreted as False. + Default is ``None``. + :type line_comment: str + :keyword line_comment: Beginning of line comment. + Default is ``';'``. + + >>> loads("(a b)") + [Symbol('a'), Symbol('b')] + >>> loads("a") + Symbol('a') + >>> loads("(a 'b)") + [Symbol('a'), Quoted(Symbol('b'))] + >>> loads("(a '(b))") + [Symbol('a'), Quoted([Symbol('b')])] + >>> loads(''' + ... ;; This is a line comment. + ... ("a" "b") ; this is also a comment. + ... ''') + ['a', 'b'] + >>> loads(''' + ... # This is a line comment. + ... ("a" "b") # this is also a comment. + ... ''', line_comment='#') + ['a', 'b'] + + ``nil`` is converted to an empty list by default. You can use + keyword argument `nil` to change what symbol must be interpreted + as nil: + + >>> loads("nil") + [] + >>> loads("null", nil='null') + [] + >>> loads("nil", nil=None) + Symbol('nil') + + ``t`` is converted to True by default. You can use keyword + argument `true` to change what symbol must be converted to True.: + + >>> loads("t") + True + >>> loads("#t", true='#t') + True + >>> loads("t", true=None) + Symbol('t') + + No symbol is converted to False by default. You can use keyword + argument `false` to convert a symbol to False. + + >>> loads("#f") + Symbol('#f') + >>> loads("#f", false='#f') + False + >>> loads("nil", false='nil', nil=None) + False + + """ + obj = parse(string, **kwds) + assert len(obj) == 1 # FIXME: raise an appropriate error + return obj[0] + + +def dump(obj, filelike, **kwds): + """ + Write `obj` as an S-expression into given stream `filelike`. + + :arg obj: A Python object. + :arg filelike: A text stream object. + + See :func:`dumps` for valid keyword arguments. + + >>> import io + >>> fp = io.StringIO() + >>> dump([Symbol('a'), Symbol('b')], fp) + >>> print(fp.getvalue()) + (a b) + + """ + filelike.write(unicode(dumps(obj))) + + +def dumps(obj, **kwds): + """ + Convert python object into an S-expression. + + :arg obj: A Python object. + :type str_as: ``'symbol'`` or ``'string'`` + :keyword str_as: How string should be interpreted. + Default is ``'string'``. + :type tuple_as: ``'list'`` or ``'array'`` + :keyword tuple_as: How tuple should be interpreted. + Default is ``'list'``. + :type true_as: str + :keyword true_as: How True should be interpreted. + Default is ``'t'`` + :type false_as: str + :keyword false_as: How False should be interpreted. + Default is ``'()'`` + :type none_as: str + :keyword none_as: How None should be interpreted. + Default is ``'()'`` + + Basic usage: + + >>> print(dumps(['a', 'b'])) + ("a" "b") + >>> print(dumps(['a', 'b'], str_as='symbol')) + (a b) + >>> print(dumps(dict(a=1, b=2))) + (:a 1 :b 2) + >>> print(dumps([None, True, False, ()])) + (() t () ()) + >>> print(dumps([None, True, False, ()], + ... none_as='null', true_as='#t', false_as='#f')) + (null #t #f ()) + >>> print(dumps(('a', 'b'))) + ("a" "b") + >>> print(dumps(('a', 'b'), tuple_as='array')) + ["a" "b"] + + More verbose usage: + + >>> print(dumps([Symbol('a'), Symbol('b')])) + (a b) + >>> print(dumps(Symbol('a'))) + a + >>> print(dumps([Symbol('a'), Quoted(Symbol('b'))])) + (a 'b) + >>> print(dumps([Symbol('a'), Quoted([Symbol('b')])])) + (a '(b)) + + """ + return tosexp(obj, **kwds) + + +def car(obj): + """ + Alias of ``obj[0]``. + + >>> car(loads('(a . b)')) + Symbol('a') + >>> car(loads('(a b)')) + Symbol('a') + + """ + return obj[0] + + +def cdr(obj): + """ + `cdr`-like function. + + >>> cdr(loads('(a . b)')) + Symbol('b') + >>> cdr(loads('(a b)')) + [Symbol('b')] + >>> cdr(loads('(a . (b))')) + [Symbol('b')] + >>> cdr(loads('(a)')) + [] + >>> cdr(loads('(a . nil)')) + [] + + """ + # This is very lazy implementation. Probably the best way to do + # it is to define `Cons` S-expression class. + if len(obj) > 2: + dot = obj[1] + if isinstance(dot, Symbol) and dot.value() == '.': + return obj[2] + return obj[1:] + + +### Core + +def tosexp(obj, str_as='string', tuple_as='list', + true_as='t', false_as='()', none_as='()'): + """ + Convert an object to an S-expression (`dumps` is just calling this). + + See this table for comparison of lispy languages, to support them + as much as possible: + `Lisp: Common Lisp, Scheme/Racket, Clojure, Emacs Lisp - Hyperpolyglot + <http://hyperpolyglot.org/lisp>`_ + + """ + _tosexp = lambda x: tosexp( + x, str_as=str_as, tuple_as=tuple_as, + true_as=true_as, false_as=false_as, none_as=none_as) + if isinstance(obj, list): + return Bracket(obj, '(').tosexp(_tosexp) + elif isinstance(obj, tuple): + if tuple_as == 'list': + return Bracket(obj, '(').tosexp(_tosexp) + elif tuple_as == 'array': + return Bracket(obj, '[').tosexp(_tosexp) + else: + raise ValueError(uformat("tuple_as={0!r} is not valid", tuple_as)) + elif obj is True: # must do this before ``isinstance(obj, int)`` + return true_as + elif obj is False: + return false_as + elif obj is None: + return none_as + elif isinstance(obj, (int, float)): + return str(obj) + elif isinstance(obj, basestring): + if str_as == 'symbol': + return obj + elif str_as == 'string': + return String(obj).tosexp() + else: + raise ValueError(uformat("str_as={0!r} is not valid", str_as)) + elif isinstance(obj, dict): + return _tosexp(dict_to_plist(obj)) + elif isinstance(obj, SExpBase): + return obj.tosexp(_tosexp) + else: + raise TypeError(uformat( + "Object of type '{0}' cannot be converted by `tosexp`. " + "It's value is '{1!r}'", type(obj), obj)) + + +@return_as(list) +def dict_to_plist(obj): + for key in obj: + yield Symbol(uformat(":{0}", key)) + yield obj[key] + + +class SExpBase(object): + + def __init__(self, val): + self._val = val + + def __repr__(self): + return uformat("{0}({1!r})", self.__class__.__name__, self._val) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self._val == other._val + else: + return False + + def value(self): + return self._val + + def tosexp(self, tosexp=tosexp): + """ + Decode this object into an S-expression string. + + :arg tosexp: A function to be used when converting sub S-expression. + + """ + raise NotImplementedError + + @classmethod + def quote(cls, string): + for (s, q) in cls._lisp_quoted_specials: + string = string.replace(s, q) + return tounicode(string) + + @classmethod + def unquote(cls, string): + return cls._lisp_quoted_to_raw.get(string, string) + + +class Symbol(SExpBase): + + _lisp_quoted_specials = [ + ('\\', '\\\\'), # must come first to avoid doubly quoting "\" + ("'", r"\'"), ("`", r"\`"), ('"', r'\"'), + ('(', r'\('), (')', r'\)'), ('[', r'\['), (']', r'\]'), + (' ', r'\ '), ('.', r'\.'), (',', r'\,'), ('?', r'\?'), + (';', r'\;'), ('#', r'\#'), + ] + + _lisp_quoted_to_raw = dict((q, r) for (r, q) in _lisp_quoted_specials) + + def tosexp(self, tosexp=None): + return self.quote(self._val) + + +class String(SExpBase): + + _lisp_quoted_specials = [ # from Pymacs + ('\\', '\\\\'), # must come first to avoid doubly quoting "\" + ('"', '\\"'), ('\b', '\\b'), ('\f', '\\f'), + ('\n', '\\n'), ('\r', '\\r'), ('\t', '\\t')] + + _lisp_quoted_to_raw = dict((q, r) for (r, q) in _lisp_quoted_specials) + + def tosexp(self, tosexp=None): + return uformat('"{0}"', self.quote(self._val)) + + +class Quoted(SExpBase): + + def tosexp(self, tosexp=tosexp): + return uformat("'{0}", tosexp(self._val)) + + +class Bracket(SExpBase): + + def __init__(self, val, bra): + assert bra in BRACKETS # FIXME: raise an appropriate error + super(Bracket, self).__init__(val) + self._bra = bra + + def __repr__(self): + return uformat("{0}({1!r}, {2!r})", + self.__class__.__name__, self._val, self._bra) + + def tosexp(self, tosexp=tosexp): + bra = self._bra + ket = BRACKETS[self._bra] + c = ' '.join(tosexp(v) for v in self._val) + return uformat("{0}{1}{2}", bra, c, ket) + + +def bracket(val, bra): + if bra == '(': + return val + else: + return Bracket(val, bra) + + +class ExpectClosingBracket(Exception): + + def __init__(self, got, expect): + super(ExpectClosingBracket, self).__init__(uformat( + "Not enough closing brackets. " + "Expected {0!r} to be the last letter in the sexp. " + "Got: {1!r}", expect, got)) + + +class ExpectNothing(Exception): + + def __init__(self, got): + super(ExpectNothing, self).__init__(uformat( + "Too many closing brackets. " + "Expected no character left in the sexp. " + "Got: {0!r}", got)) + + +class Parser(object): + + closing_brackets = set(BRACKETS.values()) + atom_end = \ + set(BRACKETS) | set(closing_brackets) | set('"\'') | set(whitespace) + atom_end_or_escape_re = re.compile("|".join(map(re.escape, + atom_end | set('\\')))) + quote_or_escape_re = re.compile(r'"|\\') + + def __init__(self, string, string_to=None, nil='nil', true='t', false=None, + line_comment=';'): + self.string = string + self.nil = nil + self.true = true + self.false = false + self.string_to = (lambda x: x) if string_to is None else string_to + self.line_comment = line_comment + + def parse_str(self, i): + string = self.string + chars = [] + append = chars.append + search = self.quote_or_escape_re.search + + assert string[i] == '"' # never fail + while True: + i += 1 + match = search(string, i) + end = match.start() + append(string[i:end]) + c = match.group() + if c == '"': + i = end + 1 + break + elif c == '\\': + i = end + 1 + append(String.unquote(c + string[i])) + else: + raise ExpectClosingBracket('"', None) + return (i, ''.join(chars)) + + def parse_atom(self, i): + string = self.string + chars = [] + append = chars.append + search = self.atom_end_or_escape_re.search + atom_end = self.atom_end + + while True: + match = search(string, i) + if not match: + append(string[i:]) + i = len(string) + break + end = match.start() + append(string[i:end]) + c = match.group() + if c in atom_end: + i = end # this is different from str + break + elif c == '\\': + i = end + 1 + append(Symbol.unquote(c + string[i])) + i += 1 + else: + raise ExpectClosingBracket('"', None) + return (i, self.atom(''.join(chars))) + + def atom(self, token): + if token == self.nil: + return [] + if token == self.true: + return True + if token == self.false: + return False + try: + return int(token) + except ValueError: + try: + return float(token) + except ValueError: + return Symbol(token) + + def parse_sexp(self, i): + string = self.string + len_string = len(self.string) + sexp = [] + append = sexp.append + while i < len_string: + c = string[i] + if c == '"': + (i, subsexp) = self.parse_str(i) + append(self.string_to(subsexp)) + elif c in whitespace: + i += 1 + continue + elif c in BRACKETS: + close = BRACKETS[c] + (i, subsexp) = self.parse_sexp(i + 1) + append(bracket(subsexp, c)) + try: + nc = string[i] + except IndexError: + nc = None + if nc != close: + raise ExpectClosingBracket(nc, close) + i += 1 + elif c in self.closing_brackets: + break + elif c == "'": + (i, subsexp) = self.parse_sexp(i + 1) + append(Quoted(subsexp[0])) + sexp.extend(subsexp[1:]) + elif c == self.line_comment: + i = string.find('\n', i) + 1 + if i <= 0: + i = len_string + break + else: + (i, subsexp) = self.parse_atom(i) + append(subsexp) + return (i, sexp) + + def parse(self): + (i, sexp) = self.parse_sexp(0) + if i < len(self.string): + raise ExpectNothing(self.string[i:]) + return sexp + + +def parse(string, **kwds): + """ + Parse s-expression. + + >>> parse("(a b)") + [[Symbol('a'), Symbol('b')]] + >>> parse("a") + [Symbol('a')] + >>> parse("(a 'b)") + [[Symbol('a'), Quoted(Symbol('b'))]] + >>> parse("(a '(b))") + [[Symbol('a'), Quoted([Symbol('b')])]] + + """ + return Parser(string, **kwds).parse() |