예제 #1
0
def parse_query(expr_str):
    def parse_terminal(pstate):
        next_tag = pstate.next_tag()
        if next_tag is _tag:
            return make_tag_query(pstate.next_str_and_advance())
        elif next_tag is _negtag:
            return NotQuery(make_tag_query(pstate.next_str_and_advance()[1:]))
        elif next_tag is _fulltext:
            return FulltextQuery(pstate.next_str_and_advance()[1:-1])
        elif next_tag is _dated:
            pstate.advance()
            return DatedQuery()
        elif next_tag in _STATELESS_TERMINALS:
            pstate.advance()
            return _STATELESS_TERMINALS[next_tag]
        elif next_tag in [_id]:
            result = IdQuery(int(pstate.next_match_obj().group(1)))
            pstate.advance()
            return result
        elif next_tag in [_before, _after]:
            from parsedatetime.parsedatetime import Calendar
            cal = Calendar()
            timetup = cal.parse(pstate.next_match_obj().group(1))
            pstate.advance()
            import time
            return DateQuery(next_tag == _before, time.mktime(timetup[0]))
        else:
            pstate.expected("terminal")

    def inner_parse(pstate, min_precedence=0):
        pstate.expect_not_end()

        if pstate.is_next(_not):
            pstate.advance()
            left_query = make_not_query(inner_parse(pstate, _PREC_NOT))
        elif pstate.is_next(_openpar):
            pstate.advance()
            left_query = inner_parse(pstate)
            pstate.expect(_closepar)
            pstate.advance()
        else:
            left_query = parse_terminal(pstate)

        did_something = True
        while did_something:
            did_something = False
            if pstate.is_at_end():
                return left_query

            next_tag = pstate.next_tag()

            if next_tag is _and and _PREC_AND > min_precedence:
                pstate.advance()
                left_query = make_and_query(
                    [left_query, inner_parse(pstate, _PREC_AND)])
                did_something = True
            elif next_tag is _or and _PREC_OR > min_precedence:
                pstate.advance()
                left_query = make_or_query(
                    [left_query, inner_parse(pstate, _PREC_OR)])
                did_something = True
            elif (next_tag in _TERMINALS + [_not, _openpar]
                  and _PREC_AND > min_precedence):
                left_query = make_and_query(
                    [left_query, inner_parse(pstate, _PREC_AND)])
                did_something = True

        return left_query

    from pytools.lex import LexIterator, lex
    pstate = LexIterator(
        [(tag, s, idx, matchobj)
         for (tag, s, idx,
              matchobj) in lex(_LEX_TABLE, expr_str, match_objects=True)
         if tag is not _whitespace], expr_str)

    if pstate.is_at_end():
        return TagQuery(u"home")

    result = inner_parse(pstate)
    if not pstate.is_at_end():
        pstate.raise_parse_error("leftover input after completed parse")

    return result
예제 #2
0
def parse_query(course, expr_str):
    from django.db.models import Q

    def parse_terminal(pstate):
        next_tag = pstate.next_tag()
        if next_tag is _id:
            result = Q(user__id=int(pstate.next_match_obj().group(1)))
            pstate.advance()
            return result

        elif next_tag is _email:
            result = Q(user__email__iexact=pstate.next_match_obj().group(1))
            pstate.advance()
            return result

        elif next_tag is _email_contains:
            result = Q(user__email__icontains=pstate.next_match_obj().group(1))
            pstate.advance()
            return result

        elif next_tag is _user:
            result = Q(user__username__exact=pstate.next_match_obj().group(1))
            pstate.advance()
            return result

        elif next_tag is _user_contains:
            result = Q(
                user__username__contains=pstate.next_match_obj().group(1))
            pstate.advance()
            return result

        elif next_tag is _institutional_id:
            result = Q(user__institutional_id__iexact=pstate.next_match_obj().
                       group(1))
            pstate.advance()
            return result

        elif next_tag is _institutional_id_contains:
            result = Q(user__institutional_id__icontains=pstate.next_match_obj(
            ).group(1))
            pstate.advance()
            return result

        elif next_tag is _tagged:
            ptag, created = ParticipationTag.objects.get_or_create(
                course=course, name=pstate.next_match_obj().group(1))

            result = Q(tags__pk=ptag.pk)

            pstate.advance()
            return result

        elif next_tag is _role:
            result = Q(role=pstate.next_match_obj().group(1))

            pstate.advance()
            return result

        elif next_tag is _status:
            result = Q(status=pstate.next_match_obj().group(1))

            pstate.advance()
            return result

        elif next_tag is _has_started:
            flow_id = pstate.next_match_obj().group(1)
            result = (Q(flow_sessions__flow_id=flow_id)
                      & Q(flow_sessions__course=course))
            pstate.advance()
            return result

        elif next_tag is _has_submitted:
            flow_id = pstate.next_match_obj().group(1)
            result = (Q(flow_sessions__flow_id=flow_id)
                      & Q(flow_sessions__course=course)
                      & Q(flow_sessions__in_progress=False))
            pstate.advance()
            return result

        else:
            pstate.expected("terminal")

    def inner_parse(pstate, min_precedence=0):
        pstate.expect_not_end()

        if pstate.is_next(_not):
            pstate.advance()
            left_query = ~inner_parse(pstate, _PREC_NOT)
        elif pstate.is_next(_openpar):
            pstate.advance()
            left_query = inner_parse(pstate)
            pstate.expect(_closepar)
            pstate.advance()
        else:
            left_query = parse_terminal(pstate)

        did_something = True
        while did_something:
            did_something = False
            if pstate.is_at_end():
                return left_query

            next_tag = pstate.next_tag()

            if next_tag is _and and _PREC_AND > min_precedence:
                pstate.advance()
                left_query = left_query & inner_parse(pstate, _PREC_AND)
                did_something = True
            elif next_tag is _or and _PREC_OR > min_precedence:
                pstate.advance()
                left_query = left_query | inner_parse(pstate, _PREC_OR)
                did_something = True
            elif (next_tag in _TERMINALS + [_not, _openpar]
                  and _PREC_AND > min_precedence):
                left_query = left_query & inner_parse(pstate, _PREC_AND)
                did_something = True

        return left_query

    from pytools.lex import LexIterator, lex
    pstate = LexIterator(
        [(tag, s, idx, matchobj)
         for (tag, s, idx,
              matchobj) in lex(_LEX_TABLE, expr_str, match_objects=True)
         if tag is not _whitespace], expr_str)

    if pstate.is_at_end():
        pstate.raise_parse_error("unexpected end of input")

    result = inner_parse(pstate)
    if not pstate.is_at_end():
        pstate.raise_parse_error("leftover input after completed parse")

    return result
예제 #3
0
def parse_match(expr):
    """Syntax examples::

    * ``id:yoink and writes:a_temp``
    * ``id:yoink and (not writes:a_temp or tag:input)``
    """
    if not expr:
        return All()

    def parse_terminal(pstate):
        next_tag = pstate.next_tag()
        if next_tag is _id:
            result = Id(pstate.next_match_obj().group(1))
            pstate.advance()
            return result
        elif next_tag is _tag:
            result = Tagged(pstate.next_match_obj().group(1))
            pstate.advance()
            return result
        elif next_tag is _writes:
            result = Writes(pstate.next_match_obj().group(1))
            pstate.advance()
            return result
        elif next_tag is _reads:
            result = Reads(pstate.next_match_obj().group(1))
            pstate.advance()
            return result
        elif next_tag is _iname:
            result = Iname(pstate.next_match_obj().group(1))
            pstate.advance()
            return result
        else:
            pstate.expected("terminal")

    def inner_parse(pstate, min_precedence=0):
        pstate.expect_not_end()

        if pstate.is_next(_not):
            pstate.advance()
            left_query = Not(inner_parse(pstate, _PREC_NOT))
        elif pstate.is_next(_openpar):
            pstate.advance()
            left_query = inner_parse(pstate)
            pstate.expect(_closepar)
            pstate.advance()
        else:
            left_query = parse_terminal(pstate)

        did_something = True
        while did_something:
            did_something = False
            if pstate.is_at_end():
                return left_query

            next_tag = pstate.next_tag()

            if next_tag is _and and _PREC_AND > min_precedence:
                pstate.advance()
                left_query = And((left_query, inner_parse(pstate, _PREC_AND)))
                did_something = True
            elif next_tag is _or and _PREC_OR > min_precedence:
                pstate.advance()
                left_query = Or((left_query, inner_parse(pstate, _PREC_OR)))
                did_something = True

        return left_query

    if isinstance(expr, MatchExpressionBase):
        return expr

    from pytools.lex import LexIterator, lex, InvalidTokenError
    try:
        pstate = LexIterator(
            [(tag, s, idx, matchobj)
             for (tag, s, idx,
                  matchobj) in lex(_LEX_TABLE, expr, match_objects=True)
             if tag is not _whitespace], expr)
    except InvalidTokenError as e:
        from loopy.diagnostic import LoopyError
        raise LoopyError(
            "invalid match expression: '{match_expr}' ({err_type}: {err_str})".
            format(match_expr=expr, err_type=type(e).__name__, err_str=str(e)))

    if pstate.is_at_end():
        pstate.raise_parse_error("unexpected end of input")

    result = inner_parse(pstate)
    if not pstate.is_at_end():
        pstate.raise_parse_error("leftover input after completed parse")

    return result