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
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
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