Compile the DSL to python lambdas instead of using an IR interpreter

This commit is contained in:
Juhani Haverinen 2016-08-25 23:05:46 +03:00
parent f7d712437e
commit 258a578cb7
3 changed files with 32 additions and 32 deletions

View File

@ -1,7 +1,7 @@
import datetime import datetime
import sys import sys
import os.path import os.path
from . import check_date from . import dsl
from . import daterange from . import daterange
from . import generate_timetable from . import generate_timetable
from . import parse_coursefile from . import parse_coursefile
@ -37,7 +37,7 @@ def main():
courses = [] courses = []
for name, info, parsed_filter in courses_parsed: for name, info, parsed_filter in courses_parsed:
date_filter = check_date.compile(parsed_filter) date_filter = dsl.compile(parsed_filter)
courses.append((name, info, date_filter)) courses.append((name, info, date_filter))
timetable = generate_timetable.generate_timetable(dates, courses) timetable = generate_timetable.generate_timetable(dates, courses)

View File

@ -7,7 +7,7 @@ class Filters(enum.Enum):
class Conjunctions(enum.Enum): class Conjunctions(enum.Enum):
all, any, none, implies = range(4) all, any, none, implies = range(4)
def compile(parsed): def to_ir(parsed):
assert(len(parsed) >= 1) assert(len(parsed) >= 1)
function, *parameters = parsed function, *parameters = parsed
@ -26,7 +26,7 @@ def compile(parsed):
elif function == 'week': elif function == 'week':
if len(parameters) > 1: if len(parameters) > 1:
return (Conjunctions.any,) + tuple([compile(('week', week)) for week in parameters]) return (Conjunctions.any,) + tuple([to_ir(('week', week)) for week in parameters])
else: else:
assert(len(parameters) == 1) assert(len(parameters) == 1)
week_data, = parameters week_data, = parameters
@ -37,7 +37,7 @@ def compile(parsed):
elif function == 'weekday': elif function == 'weekday':
if len(parameters) > 1: if len(parameters) > 1:
return (Conjunctions.any,) + tuple([compile(('weekday', weekday)) for weekday in parameters]) return (Conjunctions.any,) + tuple([to_ir(('weekday', weekday)) for weekday in parameters])
else: else:
assert(len(parameters) == 1) assert(len(parameters) == 1)
weekday, = parameters weekday, = parameters
@ -45,50 +45,51 @@ def compile(parsed):
return (Filters.is_weekday, weekday) return (Filters.is_weekday, weekday)
elif function == 'and': elif function == 'and':
return (Conjunctions.all,) + tuple([compile(parameter) for parameter in parameters]) return (Conjunctions.all,) + tuple([to_ir(parameter) for parameter in parameters])
elif function == 'or': elif function == 'or':
return (Conjunctions.any,) + tuple([compile(parameter) for parameter in parameters]) return (Conjunctions.any,) + tuple([to_ir(parameter) for parameter in parameters])
elif function == 'not': elif function == 'not':
return (Conjunctions.none,) + tuple([compile(parameter) for parameter in parameters]) return (Conjunctions.none,) + tuple([to_ir(parameter) for parameter in parameters])
elif function == 'if': elif function == 'if':
assert(len(parameters) == 2) assert(len(parameters) == 2)
condition, then = parameters condition, then = parameters
return (Conjunctions.implies, compile(condition), compile(then)) return (Conjunctions.implies, to_ir(condition), to_ir(then))
def check_day_match(day, date_filter): def to_lambda(date_filter):
assert(len(date_filter) >= 1) assert(len(date_filter) >= 1)
function, *parameters = date_filter function, *parameters = date_filter
assert(function in Filters or function in Conjunctions) assert(function in Filters or function in Conjunctions)
if function == Conjunctions.implies:
assert(len(parameters) == 2)
elif function in [Filters.in_date_range, Filters.is_weekday]:
assert(len(parameters) == 1)
else:
assert(function in [Conjunctions.all, Conjunctions.any, Conjunctions.none])
if function == Conjunctions.all: if function == Conjunctions.all:
return all(map(lambda parameter: check_day_match(day, parameter), parameters)) compiled = [to_lambda(parameter) for parameter in parameters]
return lambda day: all(map(lambda f: f(day), compiled))
elif function == Conjunctions.any: elif function == Conjunctions.any:
return any(map(lambda parameter: check_day_match(day, parameter), parameters)) compiled = [to_lambda(parameter) for parameter in parameters]
return lambda day: any(map(lambda f: f(day), compiled))
elif function == Conjunctions.implies: elif function == Conjunctions.implies:
left, right = parameters assert(len(parameters) == 2)
left_truth = check_day_match(day, left) left, right = to_lambda(parameters[0], parameters[1])
right_truth = check_day_match(day, right) return lambda day: right(day) if left(day) else True
return left_truth and right_truth or not left_truth
elif function == Conjunctions.none: elif function == Conjunctions.none:
return not any(map(lambda parameter: check_day_match(day, parameter), parameters)) compiled = [to_lambda(parameter) for parameter in parameters]
return lambda day: not any(map(lambda f: f(day), compiled))
elif function == Filters.in_date_range: elif function == Filters.in_date_range:
assert(len(parameters) == 1)
date_range, = parameters date_range, = parameters
return day in date_range return lambda day: day in date_range
elif function == Filters.is_weekday: elif function == Filters.is_weekday:
assert(len(parameters) == 1)
weekday, = parameters weekday, = parameters
return day.isoweekday() == weekday return lambda day: day.isoweekday() == weekday
def compile(parsed):
ir = to_ir(parsed)
return to_lambda(ir)

View File

@ -1,5 +1,4 @@
import datetime import datetime
from . import check_date
def generate_timetable(day_range, courses): def generate_timetable(day_range, courses):
start_date, end_date = day_range.range() start_date, end_date = day_range.range()
@ -7,7 +6,7 @@ def generate_timetable(day_range, courses):
appointments = [] appointments = []
while True: while True:
for name, info, date_filter in courses: for name, info, date_filter in courses:
if check_date.check_day_match(date, date_filter): if date_filter(date):
appointments.append((date, name, info)) appointments.append((date, name, info))
if date == end_date: if date == end_date: