first draft degree parser
This commit is contained in:
parent
27d05f0712
commit
484cc4235f
192
degrees.py
192
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 course_list(self, items):
|
||||
return items[:-1]
|
||||
def take_all(self):
|
||||
return TakeAll()
|
||||
|
||||
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_courses(self, n):
|
||||
return TakeN(n)
|
||||
|
||||
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
|
||||
|
||||
"""
|
||||
Loading…
Reference in New Issue