blc2 - Python library and frontend for running theatrical lighting and SFX. Written for the English 2041F fall 2019 theatre production of "The Cenci".

git clone https://benconnors.ca/git-repos/blc2

Log | Files | Refs

parsers.py (4548B) - raw


      1 from blc2.constants import INFTY
      2 
      3 def parse_interval(s):
      4     if not s:
      5         return None, s
      6     dash = False
      7     init_s = s
      8     buff = ""
      9     r = [-1, -1]
     10     i = 0
     11     while s:
     12         if not dash and s[0] == '-':
     13             if buff:
     14                 r[0] = int(buff)
     15                 buff = ""
     16             dash = True
     17         elif s[0] in "0123456789":
     18             buff += s[0]
     19         else:
     20             break
     21         s = s[1:]
     22         i += 1
     23 
     24     if buff:
     25         r[1 if dash else 0] = int(buff)
     26     elif not buff and not dash:
     27         return None, s, None
     28     
     29     if not dash:
     30         r[1] = r[0]
     31 
     32     return tuple(r), s, init_s[:i]
     33 
     34 def parse_range(s):
     35     if not s:
     36         return None, s, None
     37 
     38     rs = []
     39     disp = []
     40     tc = False
     41     while s:
     42         r, s, d = parse_interval(s)
     43         if r is None:
     44             break
     45         tc = False
     46         rs.append(r)
     47         disp.append(d)
     48         if s and s[0] == ',':
     49             s = s[1:]
     50             tc = True
     51         else:
     52             break
     53 
     54     if not rs:
     55         return None, s, None
     56     return tuple(rs), s, ", ".join(disp) + (", " if tc else "")
     57 
     58 def parse_channelrange(s):
     59     if not s:
     60         return None, s, None
     61 
     62     f, s, d1 = parse_range(s)
     63     if f is None:
     64         return None, s, None
     65     elif not s or s[0] != ';':
     66         return (f, ((-1,-1),)), s, d1
     67 
     68 
     69     s = s[1:]
     70     c, s, d2 = parse_range(s)
     71     if c is None:
     72         return (f, ((-1, -1),)), s, d1 + "; "
     73 
     74     return (f, c), s, d1+"; "+d2
     75 
     76 def parse_value(s):
     77     if not s:
     78         return None, s, None
     79     
     80     buff = ""
     81     while s:
     82         if s[0] in "0123456789" and int(buff+s[0]) < 256:
     83             buff += s[0]
     84             s = s[1:]
     85         else:
     86             break
     87 
     88     return (None if not buff else int(buff)), s, buff
     89 
     90 def parse_num(s):
     91     if not s:
     92         return None, s, None
     93     
     94     buff = ""
     95     while s:
     96         if s[0] in "0123456789":
     97             buff += s[0]
     98             s = s[1:]
     99         else:
    100             break
    101 
    102     return (None if not buff else int(buff)), s, buff
    103 
    104 def parse_numlist(s):
    105     if not s:
    106         return None, s, None
    107 
    108     rs = []
    109     disp = []
    110     tc = False
    111     while s:
    112         r, s, d = parse_num(s)
    113         if r is None:
    114             break
    115         tc = False
    116         rs.append(r)
    117         disp.append(d)
    118         if s and s[0] == ',':
    119             s = s[1:]
    120             tc = True
    121         else:
    122             break
    123 
    124     if not rs:
    125         return None, s, None
    126     return tuple(rs), s, ", ".join(disp) + (", " if tc else "")
    127 
    128 _POSTFIXES = "mcisahkegtp"
    129 
    130 def parse_time(s):
    131     if not s:
    132         return None, s, None
    133 
    134     v, s, d = parse_num(s)
    135     if v is None:
    136         if s[0].lower() == 'i':
    137             return INFTY, s[1:], "infinity"
    138         return None, s, None
    139 
    140     if not s:
    141         return v, s, d
    142 
    143     try:
    144         idx = _POSTFIXES.index(s[0].lower())
    145     except ValueError:
    146         return v, s, d
    147 
    148     v *= 10**idx
    149     return v, s[1:], d+s[0].lower()
    150 
    151 _ALL_LETTERS = "abcdefghijklmnopqrstuvwxyz"
    152 def parse_any_letter(s):
    153     if not s:
    154         return None, s
    155 
    156     l = s[0].lower()
    157     
    158     if l not in _ALL_LETTERS:
    159         return None, s, None
    160     
    161     return _ALL_LETTERS.index(l), s[1:], l
    162 
    163 def make_parse_letter(letter, display):
    164     def inner(s):
    165         if not s or s[0] != letter:
    166             return None, s, None
    167         return True, s[1:], display
    168 
    169     return inner
    170 
    171 def parse_null(s):
    172     return True, s, ""
    173 
    174 def parse_string(s):
    175     if not s:
    176         return None, s, None
    177 
    178     buff = ""
    179     while s:
    180         if s[0] != ' ':
    181             buff += s[0]
    182             s = s[1:]
    183         else:
    184             if not buff:
    185                 return None, s, None
    186             break
    187 
    188     return buff, s, buff
    189 
    190 def parse_quotedstring(s):
    191     if not s:
    192         return None, s, None
    193 
    194     if s[0] != "'":
    195         return None, s, None 
    196     s = s[1:]
    197 
    198     buff = ""
    199     bs = False
    200     while s:
    201         if s[0] == '\\':
    202             buff += s[0]
    203             bs = not bs
    204         elif s[0] == "'":
    205             if bs:
    206                 buff += s[0]
    207                 bs = False
    208             else:
    209                 s = s[1:]
    210                 break
    211         else:
    212             buff += s[0]
    213             bs = False
    214         s = s[1:]
    215     else:
    216         return buff, s, "'"+buff
    217     return buff, s, "'"+buff+"'"
    218 
    219 PARSE_MAP = {
    220     "$channel_range": parse_channelrange,
    221     "$value": parse_value,
    222     "$null": parse_null,
    223     "$string": parse_string,
    224     "$num": parse_num,
    225     "$quoted_string": parse_quotedstring,
    226     "$letter": parse_any_letter,
    227     "$time": parse_time,
    228     "$numlist": parse_numlist,
    229 }