92 lines
2.3 KiB
Python
92 lines
2.3 KiB
Python
from tango.value import TangoIdent, TangoExpr
|
|
|
|
PAREN_OPEN = '('
|
|
PAREN_CLOSE = ')'
|
|
DOUBLE_QUOTE = '"'
|
|
WHITESPACE = ' \t\n\r'
|
|
|
|
|
|
class StringReader:
|
|
def __init__(self, s):
|
|
self._src = s
|
|
self._len = len(s)
|
|
self._cur = -1
|
|
|
|
def next(self):
|
|
if self._len == self._cur + 1:
|
|
return None
|
|
else:
|
|
self._cur += 1
|
|
return self._src[self._cur]
|
|
|
|
|
|
class TangoParser:
|
|
def __init__(self, src):
|
|
self._cur = None
|
|
self._src = src
|
|
self._next()
|
|
|
|
def parse(self):
|
|
while self._cur is not None:
|
|
self._skip_whitespace()
|
|
if self._cur is PAREN_OPEN:
|
|
return self._parse_expr()
|
|
elif self._cur is DOUBLE_QUOTE:
|
|
return self._parse_str()
|
|
elif self._cur.isalpha():
|
|
return self._parse_ident()
|
|
elif self._cur.isnumeric():
|
|
return self._parse_int()
|
|
else:
|
|
self._raise_invalid_char()
|
|
|
|
def _parse_expr(self):
|
|
expr = TangoExpr()
|
|
self._next()
|
|
while self._cur is not None:
|
|
self._skip_whitespace()
|
|
if self._cur is PAREN_CLOSE:
|
|
self._next()
|
|
return expr
|
|
else:
|
|
expr.append(self.parse())
|
|
|
|
self._raise_unexpected_end()
|
|
|
|
def _parse_ident(self):
|
|
ident = self._read_until(WHITESPACE + PAREN_CLOSE)
|
|
return TangoIdent(ident)
|
|
|
|
def _parse_str(self):
|
|
self._next()
|
|
s = self._read_until(DOUBLE_QUOTE)
|
|
self._next()
|
|
return s
|
|
|
|
def _parse_int(self):
|
|
s = self._read_until(WHITESPACE + PAREN_CLOSE)
|
|
return int(s)
|
|
|
|
def _read_until(self, delims):
|
|
s = ''
|
|
|
|
while self._cur is not None and self._cur not in delims:
|
|
s += self._cur
|
|
self._next()
|
|
|
|
return s
|
|
|
|
def _next(self):
|
|
self._cur = self._src.next()
|
|
return self._cur
|
|
|
|
def _raise_unexpected_end(self):
|
|
raise ValueError('Unexpected end of stream')
|
|
|
|
def _raise_invalid_char(self):
|
|
raise ValueError('Invalid chr: ' + self._cur)
|
|
|
|
def _skip_whitespace(self):
|
|
if self._cur in WHITESPACE:
|
|
while self._next() in WHITESPACE:
|
|
continue |