def closure(self, rules):
closure = set()<EOL>todo = set(rules)<EOL>while todo:<EOL><INDENT>rule = todo.pop()<EOL>closure.add(rule)<EOL>if rule.at_end:<EOL><INDENT>continue<EOL><DEDENT>symbol = rule.rhs[rule.pos]<EOL>for production in self.nonterminals[symbol]:<EOL><INDENT>for first in self.first(rule.rest):<EOL><INDENT>if EPSILON in production.rhs:<EOL><INDENT>new_rule = DottedRule(production, <NUM_LIT:1>, first)<EOL><DEDENT>else:<EOL><INDENT>new_rule = DottedRule(production, <NUM_LIT:0>, first)<EOL><DEDENT>if new_rule not in closure:<EOL><INDENT>todo.add(new_rule)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>return frozenset(closure)<EOL>
Fills out the entire closure based on some initial dotted rules.

        Args:
            rules - an iterable of DottedRules

        Returns: frozenset of DottedRules