148 lines
2.9 KiB
Python
148 lines
2.9 KiB
Python
from . import timerange
|
|
|
|
def strip_comments(text):
|
|
lines = []
|
|
for line in text.split('\n'):
|
|
comment_start = line.find('#')
|
|
if comment_start != -1:
|
|
lines.append(line[:comment_start])
|
|
else:
|
|
lines.append(line)
|
|
return '\n'.join(lines)
|
|
|
|
def parse_timerange(text):
|
|
ends = [i.split(':') for i in text.split('-')]
|
|
assert(len(ends) == 2)
|
|
start, end = ((int(i[0]), 0) if len(i) == 1 else tuple(map(int, i)) for i in ends)
|
|
assert(len(start) == 2 and len(end) == 2)
|
|
return timerange.between(start, end)
|
|
|
|
def parse_filter(text):
|
|
weekdays = {'mon': 1, 'tue': 2, 'wed': 3, 'thu': 4, 'fri': 5, 'sat': 6, 'sun': 7}
|
|
functions = ['date', 'week', 'weekday', 'and', 'or', 'not', 'if']
|
|
def eof():
|
|
nonlocal index, length
|
|
return index >= length
|
|
|
|
def skip_whitespace():
|
|
nonlocal index, length
|
|
while not eof() and text[index].isspace():
|
|
index += 1
|
|
|
|
def match(matches):
|
|
nonlocal index, length
|
|
assert(not eof())
|
|
assert(text[index] in matches)
|
|
index += 1
|
|
|
|
def read_atom():
|
|
nonlocal index, length
|
|
start = index
|
|
|
|
while not eof() and not text[index].isspace() and text[index] != ')':
|
|
index += 1
|
|
|
|
return text[start:index]
|
|
|
|
def subexpression():
|
|
nonlocal index, length
|
|
if not eof() and text[index] == '(':
|
|
match('(')
|
|
skip_whitespace()
|
|
|
|
elements = []
|
|
|
|
function = read_atom()
|
|
skip_whitespace()
|
|
assert(not eof())
|
|
|
|
assert(function in functions)
|
|
elements.append(function)
|
|
|
|
while not eof() and text[index] != ')':
|
|
elements.append(subexpression())
|
|
skip_whitespace()
|
|
|
|
match(')')
|
|
|
|
return elements
|
|
|
|
else:
|
|
atom = read_atom()
|
|
assert(len(atom) >= 1)
|
|
|
|
if atom in weekdays:
|
|
return weekdays[atom]
|
|
else:
|
|
split = atom.split('-')
|
|
assert(all(map(lambda x: x.isnumeric(), split)))
|
|
assert(len(split) == 2 or len(split) == 3)
|
|
return tuple(map(int, split))
|
|
|
|
index = 0
|
|
length = len(text)
|
|
|
|
skip_whitespace()
|
|
expression = subexpression()
|
|
skip_whitespace()
|
|
assert(eof())
|
|
|
|
return expression
|
|
|
|
def parse(text):
|
|
def eof():
|
|
nonlocal index, length
|
|
return index >= length
|
|
|
|
def skip_whitespace():
|
|
nonlocal index, length
|
|
while not eof() and text[index].isspace():
|
|
index += 1
|
|
|
|
def match(matches):
|
|
nonlocal index, length
|
|
assert(not eof())
|
|
assert(text[index] in matches)
|
|
index += 1
|
|
|
|
def read_field():
|
|
nonlocal index, length
|
|
skip_whitespace()
|
|
|
|
start = index
|
|
while not eof() and text[index] not in [';', '\n']:
|
|
if text[index] == '\\':
|
|
index += 1
|
|
index += 1
|
|
|
|
return text[start:index].strip()
|
|
|
|
text = strip_comments(text)
|
|
index = 0
|
|
length = len(text)
|
|
|
|
courses = []
|
|
while True:
|
|
skip_whitespace()
|
|
if eof():
|
|
break
|
|
|
|
name = read_field()
|
|
match(';')
|
|
|
|
time_range = parse_timerange(read_field())
|
|
match(';')
|
|
|
|
info = read_field()
|
|
match(';')
|
|
|
|
date_filter = parse_filter(read_field())
|
|
if not eof():
|
|
match('\n')
|
|
|
|
courses.append((name, time_range, info, date_filter))
|
|
|
|
assert(eof())
|
|
|
|
return courses
|