diff --git a/parse.py b/parse.py new file mode 100644 index 0000000..dc90208 --- /dev/null +++ b/parse.py @@ -0,0 +1,198 @@ +import sys + +class Element(object): + def __init__(self): + self.outputs = [] + + def display(self, indent): + print ("\t" * indent) + self.get_description() + for output in self.outputs: + output.display(indent + 1) + +class Bin(Element): + def __init__(self, name): + Element.__init__(self) + self.name = name + + def get_description(self): + return "[Bin] %s" % self.name + +class Rule(Element): + def __init__(self, input_): + Element.__init__(self) + self.input_ = input_ + + def process(self, message): + self.forward(message) + + def forward(self, message): + for output in self.outputs: + output.process(message) + +class Filter(Rule): + def __init__(self, input_, rule): + Rule.__init__(self, input_) + # TODO: Filter parsing loop goes here + self.rule = rule + + def get_description(self): + return "[Filter] %s" % self.rule + +class BinReference(Rule): + def __init__(self, input_, name): + Rule.__init__(self, input_) + self.bin_name = name + + def get(self): + try: + return bins[self.bin_name] + except KeyError, e: + new_bin = Bin(self.bin_name) + bins[self.bin_name] = new_bin + return new_bin + + def get_description(self): + return "[BinRef] %s" % self.bin_name + +class NodeReference(Rule): + def __init__(self, input_, name): + Rule.__init__(self, input_) + self.node_name = name + + def get_description(self): + return "[NodeRef] %s" % self.node_name + +class MethodReference(Rule): + def __init__(self, input_, name): + Rule.__init__(self, input_) + self.method_name = name + + def get_description(self): + return "[MethodRef] %s" % self.method_name + +class DistributorReference(Rule): + def __init__(self, input_, name, args): + Rule.__init__(self, input_) + self.distributor_name = name + self.args = args + + def get_description(self): + return "[DistRef] %s" % self.distributor_name + +def create_rule(buff, input_): + buff = buff.strip() + if buff[0] == "*": + # Node reference + new_obj = NodeReference(input_, buff[1:]) + elif buff[0] == "@": + # Method call + new_obj = MethodReference(input_, buff[1:]) + elif buff[0] == "#": + # Bin reference + new_obj = BinReference(input_, buff[1:]) + elif buff[0] == ":": + # Distributor + if "(" in buff and buff[-1:] == ")": + name, arglist = buff[1:-1].split("(", 1) + args = [x.strip() for x in arglist.split(",")] + else: + name = buff[1:] + args = [] + new_obj = DistributorReference(input_, name, args) + else: + # Filter + new_obj = Filter(input_, buff) + + input_.outputs.append(new_obj) + return new_obj + +f = open(sys.argv[1]) +rulebook = f.read() +f.close() +rulebook_length = len(rulebook) + +# Main parsing loop +idx = 0 +tab_count = 0 +current_level = 0 +current_rule = {} +target_rule = None +statement_cache = None +new_line = True +multiple_statements = False +buff = "" +bins = {} + +while idx < rulebook_length: + char = rulebook[idx] + + if char == "\t": + if buff == "": + new_line = True + tab_count += 1 + else: + buff += char + else: + if new_line == True: + if tab_count > current_level + 1: + raise Exception("Incorrect indentation") + else: + try: + target_rule = current_rule[tab_count - 1] + except KeyError, e: + pass# FIXME: raise Exception("Incorrect indentation (bug?)") + + if rulebook[idx:idx+2] == "=>": + # Skip over this, it's optional at the start of a line + idx += 2 + continue + + new_line = False + + if char == "\r": + pass #ignore + elif char == "\n": + # Process + if buff.strip() == "": + # Skip empty lines, we don't care about them + idx += 1 + tab_count = 0 + continue + + current_level = tab_count + tab_count = 0 + + if current_level == 0: + bin_name = buff.strip() + new_bin = Bin(bin_name) + current_rule[current_level] = new_bin + bins[bin_name] = new_bin + else: + if multiple_statements == True: + new_rule = create_rule(buff, statement_cache) + else: + new_rule = create_rule(buff, current_rule[current_level - 1]) + + current_rule[current_level] = new_rule + + buff = "" + new_line = True + multiple_statements = False + elif char == "=" and rulebook[idx + 1] == ">": + # Next rule, same line! + if multiple_statements == True: + statement_cache = create_rule(buff, statement_cache) + else: + multiple_statements = True + statement_cache = create_rule(buff, current_rule[tab_count - 1]) + + buff = "" + idx += 1 # We read one extra character ahead + else: + buff += char + + idx += 1 + # TODO: detect infinite loops via bins! + +for bin_name, bin_ in bins.iteritems(): + bin_.display(0)