from blc2.constants import INFTY def parse_interval(s): if not s: return None, s dash = False init_s = s buff = "" r = [-1, -1] i = 0 while s: if not dash and s[0] == '-': if buff: r[0] = int(buff) buff = "" dash = True elif s[0] in "0123456789": buff += s[0] else: break s = s[1:] i += 1 if buff: r[1 if dash else 0] = int(buff) elif not buff and not dash: return None, s, None if not dash: r[1] = r[0] return tuple(r), s, init_s[:i] def parse_range(s): if not s: return None, s, None rs = [] disp = [] tc = False while s: r, s, d = parse_interval(s) if r is None: break tc = False rs.append(r) disp.append(d) if s and s[0] == ',': s = s[1:] tc = True else: break if not rs: return None, s, None return tuple(rs), s, ", ".join(disp) + (", " if tc else "") def parse_channelrange(s): if not s: return None, s, None f, s, d1 = parse_range(s) if f is None: return None, s, None elif not s or s[0] != ';': return (f, ((-1,-1),)), s, d1 s = s[1:] c, s, d2 = parse_range(s) if c is None: return (f, ((-1, -1),)), s, d1 + "; " return (f, c), s, d1+"; "+d2 def parse_value(s): if not s: return None, s, None buff = "" while s: if s[0] in "0123456789" and int(buff+s[0]) < 256: buff += s[0] s = s[1:] else: break return (None if not buff else int(buff)), s, buff def parse_num(s): if not s: return None, s, None buff = "" while s: if s[0] in "0123456789": buff += s[0] s = s[1:] else: break return (None if not buff else int(buff)), s, buff def parse_numlist(s): if not s: return None, s, None rs = [] disp = [] tc = False while s: r, s, d = parse_num(s) if r is None: break tc = False rs.append(r) disp.append(d) if s and s[0] == ',': s = s[1:] tc = True else: break if not rs: return None, s, None return tuple(rs), s, ", ".join(disp) + (", " if tc else "") _POSTFIXES = "mcisahkegtp" def parse_time(s): if not s: return None, s, None v, s, d = parse_num(s) if v is None: if s[0].lower() == 'i': return INFTY, s[1:], "infinity" return None, s, None if not s: return v, s, d try: idx = _POSTFIXES.index(s[0].lower()) except ValueError: return v, s, d v *= 10**idx return v, s[1:], d+s[0].lower() _ALL_LETTERS = "abcdefghijklmnopqrstuvwxyz" def parse_any_letter(s): if not s: return None, s l = s[0].lower() if l not in _ALL_LETTERS: return None, s, None return _ALL_LETTERS.index(l), s[1:], l def make_parse_letter(letter, display): def inner(s): if not s or s[0] != letter: return None, s, None return True, s[1:], display return inner def parse_null(s): return True, s, "" def parse_string(s): if not s: return None, s, None buff = "" while s: if s[0] != ' ': buff += s[0] s = s[1:] else: if not buff: return None, s, None break return buff, s, buff def parse_quotedstring(s): if not s: return None, s, None if s[0] != "'": return None, s, None s = s[1:] buff = "" bs = False while s: if s[0] == '\\': buff += s[0] bs = not bs elif s[0] == "'": if bs: buff += s[0] bs = False else: s = s[1:] break else: buff += s[0] bs = False s = s[1:] else: return buff, s, "'"+buff return buff, s, "'"+buff+"'" PARSE_MAP = { "$channel_range": parse_channelrange, "$value": parse_value, "$null": parse_null, "$string": parse_string, "$num": parse_num, "$quoted_string": parse_quotedstring, "$letter": parse_any_letter, "$time": parse_time, "$numlist": parse_numlist, }