lukkari/lukkari/parse_coursefile.py

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