AbstractRegex parseClosure(StringStream stream) {
        switch (stream.peek()) {
            case '^':
                stream.poll();
                return new HatRegex();
            case '$':
                stream.poll();
                return new DollarRegex();
        }
        AbstractRegex term = parseTerm(stream);
        if (term == null) {
            return null;
        }
        switch (stream.peek()) {
            case '*':
                stream.poll();
                return new ClosureRegex(term, 0);
            case '+':
                stream.poll();
                return new ClosureRegex(term, 1);
            case '?':
                stream.poll();
                return new ClosureRegex(term, 0, 1);
            case '{':
                stream.poll();
                int start = parseNumber(stream);
                int end = start;
                if (stream.peek() == ',') {
                    stream.poll();
                    end = parseNumber(stream);
                    verify(start <= end, stream.getPos(), "Invalid repeat range");
                }
                verify(stream.poll() == '}', stream.getPos(), "Missing '}'");
                return new ClosureRegex(term, start, end);
            default:
                return term;
        }
    }