Snippets support.

Parse, print.
This commit is contained in:
Simon Forman 2022-03-01 19:13:44 -08:00
parent 142d6e53b0
commit 87fe1d0b3c
3 changed files with 20 additions and 8 deletions

View File

@ -38,6 +38,11 @@ around square brackets.
''' '''
from re import Scanner from re import Scanner
from .utils.stack import list_to_stack from .utils.stack import list_to_stack
from .utils.snippets import (
pat as SNIPPETS,
from_string,
Snippet,
)
BRACKETS = r'\[|\]' BRACKETS = r'\[|\]'
@ -46,6 +51,7 @@ WORDS = r'[^[\]\s]+'
token_scanner = Scanner([ token_scanner = Scanner([
(SNIPPETS, lambda _, token: from_string(token)),
(BRACKETS, lambda _, token: token), (BRACKETS, lambda _, token: token),
(BLANKS, None), (BLANKS, None),
(WORDS, lambda _, token: token), (WORDS, lambda _, token: token),
@ -111,6 +117,8 @@ def _parse(tokens):
frame.append(True) frame.append(True)
elif tok == 'false': elif tok == 'false':
frame.append(False) frame.append(False)
elif isinstance(tok, Snippet):
frame.append(tok)
else: else:
try: try:
thing = int(tok) thing = int(tok)

View File

@ -2,7 +2,7 @@ from collections import namedtuple
from re import compile as RE from re import compile as RE
Snippet = namedtuple('Snippet', 'sha offset length') Snippet = namedtuple('Snippet', 'sha offset length')
fmt = '{%s %i %i}' _fmt = '{%s %i %i}'
pat = ( pat = (
'{' '{'
'\s*' '\s*'
@ -14,21 +14,20 @@ pat = (
'\s*' '\s*'
'}' '}'
) )
PAT = RE(pat) _PAT = RE(pat)
def to_string(snip): def to_string(snip):
return fmt % _ts(*snip) return _fmt % _ts(*snip)
def _ts(sha, offset, length): def _ts(sha, offset, length):
return sha.decode('ascii'), offset, length return sha.decode('ascii'), offset, length
def from_string(text): def from_string(text):
m = PAT.match(text) m = _PAT.match(text)
if not m: if not m:
raise ValueError raise ValueError
return _fs(**m.groupdict()) return _fs(**m.groupdict())
def _fs(sha, offset, length): def _fs(sha, offset, length):
return Snippet(sha.encode('ascii'), int(offset), int(length)) return Snippet(sha.encode('ascii'), int(offset), int(length))

View File

@ -71,6 +71,7 @@ printed left-to-right. These functions are written to support :doc:`../pretty`.
''' '''
from .errors import NotAListError from .errors import NotAListError
from .snippets import Snippet, to_string as snip_to_string
def list_to_stack(el, stack=()): def list_to_stack(el, stack=()):
@ -133,20 +134,24 @@ _JOY_BOOL_LITS = 'false', 'true'
def _joy_repr(thing): def _joy_repr(thing):
if isinstance(thing, bool): if isinstance(thing, bool): return _JOY_BOOL_LITS[thing]
return _JOY_BOOL_LITS[thing] if isinstance(thing, Snippet): return snip_to_string(thing)
return repr(thing) return repr(thing)
def _to_string(stack, f): def _to_string(stack, f):
if not isinstance(stack, tuple): return _joy_repr(stack) if not isinstance(stack, tuple): return _joy_repr(stack)
if not stack: return '' # shortcut if not stack: return '' # shortcut
if isinstance(stack, Snippet): return snip_to_string(stack)
return ' '.join(map(_s, f(stack))) return ' '.join(map(_s, f(stack)))
_s = lambda s: ( _s = lambda s: (
'[%s]' % expression_to_string(s) '[%s]' % expression_to_string(s)
if isinstance(s, tuple) if isinstance(s, tuple)
and not isinstance(s, Snippet)
# Is it worth making a non-tuple class for Snippet?
# Doing this check on each tuple seems a bit much.
else _joy_repr(s) else _joy_repr(s)
) )