diff --git a/degrees.py b/degrees.py index 956cb4c..0ca8e93 100644 --- a/degrees.py +++ b/degrees.py @@ -1,5 +1,5 @@ from lark import Lark, Transformer, v_args - +import json @@ -13,57 +13,57 @@ consist of groups of courses that must be taken. The groups have rules associate -grammar = """ - start: program - program: course_declaration* - - course_declaration: "course" CNAME INT "prerequisites" (CNAME ","?)* "degree" CNAME "{" degree_rule* "}" - - degree_rule: "take" ("all" | "at" INT "from") ("the" "following") "courses" course_list - - course_list: (CNAME ","?)* - - %import common.CNAME - %import common.INT - %import common.WS - %ignore WS -""" class Course: - def __init__(self, name, units, prerequisites, degree): + def __init__(self, name, units, prerequisites=[]): self.name = name self.units = units self.prerequisites = prerequisites - self.degree = degree + def __repr__(self): + return f"{self.name} ({self.units} units)" class DegreeRule: - def __init__(self, verb, n, course_list): - self.verb = verb - self.n = n + def __init__(self, rule_type, course_list): + self.rule_type = rule_type + if 'n' in rule_type.__dict__: self.n = rule_type.n self.course_list = course_list + def __repr__(self): + return f"DegreeRule({self.rule_type}, {self.course_list})" class Degree: def __init__(self, name, degree_rules): self.name = name self.degree_rules = degree_rules + def __repr__(self): + return f"Degree({self.name}, {self.degree_rules})" + +class RuleType(): + def __init__(self,what,n=0): + self.what = what + self.n = n + def __repr__(self): + return "" #f"RuleType({self.what}, {self.n})" class Rule: pass class TakeAll(Rule): - def __init__(self, courses): - self.courses = courses + def __repr__(self): + return f"Take all:" class TakeN(Rule): - def __init__(self, courses, n): - self.courses = courses + def __init__(self, n): self.n = n + def __repr__(self): + return f"Take {self.n} courses:" class TakeNUnits(Rule): - def __init__(self, courses, n): - self.courses = courses + def __init__(self, n): self.n = n + def __repr__(self): + return f"Take {self.n} units:" + @v_args(inline=True) class DSLTransformer(Transformer): @@ -71,38 +71,44 @@ class DSLTransformer(Transformer): self.courses = {} self.degrees = {} - def course_declaration(self, name, units, prerequisites, degree): - return Course(name, int(units), prerequisites.children, degree) + def course_declaration(self, name, units): + #return Course(name, int(units), prerequisites.children) + self.courses[name.value] = Course(name.value, int(units)) - def degree(self, name, required_courses): - self.degrees[name] = Degree(name, required_courses) + '''def program(self, name, rules): + self.degrees[name.value] = Degree(name.value, rules) + return self.degrees[name.value]''' - def take_all(self, courses): - return TakeAll(courses) - - def take_n(self, courses, n): - return TakeN(courses, n) - - def take_n_units(self, courses, n): - return TakeNUnits(courses, n) - - def degree_rule(self, items): - verb = items[0] + def rule_type(self, items): + what = items[0] n = None - course_list = items[-1] - if len(items) == 4: - n = int(items[2]) - return DegreeRule(verb, n, course_list.children) + if len(items) == 2: + n = int(items[1]) + return RuleType(what, n) + + def take_all(self): + return TakeAll() - def course_list(self, items): - return items[:-1] + def take_n_courses(self, n): + return TakeN(n) - def program(self, items): - courses = [item for item in items if isinstance(item, Course)] - degrees = [item for item in items if isinstance(item, Degree)] - return courses, degrees + def take_n_units(self, n): + return TakeNUnits(n) + + def degree_rule(self, rule_type, course_list): + return DegreeRule(rule_type, course_list) + def course_list(self, *courses): + return [c.value for c in courses] + + def program(self, *items): + #print(items) + name = items[0].value + rules = items[1:] + self.degrees[name] = Degree(name, rules) + return self.degrees[name] +""" dsl = DSLTransformer() dsl.course('CS101', 3) dsl.course('CS102', 3, prerequisites=['CS101']) @@ -115,11 +121,65 @@ dsl.degree('CS', [ print(dsl.courses) print(dsl.degrees) +""" + + + +grammar = """ + start: _spec+ + + _spec: program | course_declaration + + program: "program" PROGRAMNAME degree_rule* + + degree_rule: "take" rule_type course_list + + rule_type: "all from" -> take_all + | "at least" INT "units from" -> take_n_units + | "at least" INT "courses from" -> take_n_courses + + course_declaration: "course" COURSECODE INT "units" ["prerequisites" (COURSECODE ","?)*] + + course_list: (COURSECODE ","?)* + + COURSECODE: ("A".."Z")+ INT+ ["A".."Z"]* + PROGRAMNAME: ("A".."Z" | "a".."z")+ + %import common.INT + %import common.WS + %ignore WS +""" + + + +dsl = """ +course CSIS1 2 units +course CSIS2 4 units +course ACCT120 3 units +course ACCT20 4 units +course BUS1 3 units +course ENGL250 3 units +course ACCT105 3 units +course ACCT121 3 units +course BOT100 3 units +course BOT105B 3 units + +program BusinessAccountingOption + take all from CSIS1, CSIS2 + take at least 6 units from ACCT120, ACCT20 + take at least 3 courses from BUS1, ENGL250, ACCT120, BOT100, ACCT121, BOT105B +""" + +parser = Lark(grammar) +print(parser.parse(dsl).pretty()) + +print("\n\n\n") + + parser = Lark(grammar) transformer = DSLTransformer() @@ -127,24 +187,19 @@ def parse_dsl(dsl): tree = parser.parse(dsl) return transformer.transform(tree) -dsl = """ -course CS101 3 prerequisites none degree CS { - take all the following courses { - CS102, CS103 - } - take at least 6 from { - MATH101, MATH102, MATH103 - } -} + +result = parse_dsl(dsl) + +print(transformer.courses) +print() +print(transformer.degrees) +print() +[print(c) for c in transformer.courses] +print() +[print(d) for d in transformer.degrees] + """ -courses, degrees = parse_dsl(dsl) -print(courses) -print(degrees) - - - - def compute_degree_progress(student_courses, degree): total_units_completed = 0 @@ -162,3 +217,4 @@ def compute_degree_progress(student_courses, degree): progress_percent = total_units_completed / total_required_units * 100 if total_required_units > 0 else 0 return progress_percent +""" \ No newline at end of file