2 # queryparser.db must be set to a DB class instance.
5 # Define the Lexer for the RWhois query language
25 # for now, quoted values must have the wildcards inside the quotes.
26 # I kind of wonder if anyone would ever notice this.
27 t_QUOTEDVALUE = r'["\']\*?[^"*\n]+\*{0,2}["\']'
30 r'^\*?[^\s"\'=*]+\*{0,2}'
32 if db.is_objectclass(t.value):
39 r'\*?[^\s"\'=!*]+\*{0,2}'
41 if t.value.upper() == 'AND':
43 t.value = t.value.upper()
45 if t.value.upper() == 'OR':
47 t.value = t.value.upper()
49 if db.is_attribute(t.value):
58 # print "Illegal character '%r'" % t.value[0]
66 # Define the parser for the query language
68 # 'value' productions are simple strings
69 # 'querystr' productions are tuples (either 1 or 3 values)
70 # 'query' productions are Query objects
71 # 'total' productions are Query objects
73 def p_total_class_query(t):
85 def p_query_oper_querystr(t):
86 '''query : query AND querystr
87 | query OR querystr'''
91 t[0].cur_clause = [ t[3] ]
92 t[0].clauses.append(t[0].cur_clause)
94 t[0].cur_clause.append(t[3])
96 def p_query_querystr(t):
100 t[0].cur_clause = [ t[1] ]
101 t[0].clauses.append(t[0].cur_clause)
103 def p_querystr_attr_value(t):
104 '''querystr : ATTR EQ value
107 t[0] = (t[1], t[2], t[3])
109 def p_querystr_attr(t):
112 t[0] = (None, '=', t[1])
114 def p_querystr_value(t):
117 t[0] = (None, '=', t[1])
127 def p_quotedvalue(t):
128 'value : QUOTEDVALUE'
130 t[0] = t[1].strip('"')
134 # print "Syntax error at '%s:%s'" % (t.type, t.value)
135 raise yacc.YaccError, "Syntax error at %r" % t.value
140 """A representation of a parsed RWhois query."""
144 self.cur_clause = None
145 self.objectclass = None
146 self.prepared = False
151 for i in range(len(self.clauses)):
153 res += "clause %d:\n" % i
155 res += " " + repr(item) + "\n"
159 return "<Query:\n" + str(self) + ">"
162 """Prepare the query for use. For now, this means propagating
163 an objectclass restriction to all query clauses."""
165 if self.prepared: return
167 for c in self.clauses:
168 c.append(("class-name", "=", self.objectclass))
171 """Return the query clauses. This is a list of AND clauses,
172 which are, in turn, lists of query terms. Query terms are 3
173 element tuples: (attr, op, value)."""
177 def set_class(self, objectclass):
178 """Set the query-wide objectclass restriction."""
180 # note: we don't allow the code to set this more than once,
181 # because we would have to code the removal of the previous
182 # class restriction from the query clauses, and it just isn't
183 # worth it. Queries are built, used and thrown away.
184 assert not self.prepared
185 self.objectclass = objectclass
193 """Return a parser instances. Parser objects should not be shared
199 """Parse a query, raising a RwhoisError in case of parse failure.
200 Returns a Query object."""
202 # before using any parser objects, the database backend must be
203 # set (and it shared by all parsers).
206 return p.parse(query)
207 except (lex.LexError, yacc.YaccError):
208 raise Rwhois.RwhoisError, (350, "")
210 if __name__ == "__main__":
216 print "loading schema:", sys.argv[1]
217 mydb.init_schema(sys.argv[1])
218 for data_file in sys.argv[2:]:
219 print "loading data file:", data_file
220 mydb.load_data(data_file)
226 for line in sys.stdin.readlines():
227 line = line.rstrip('\n')
229 if not line: continue
230 print 'inputting:', `line`
234 except (lex.LexError, yacc.YaccError), x:
235 print "parse error occurred:", x