1 # This file is part of python-rwhoisd
3 # Copyright (C) 2003, David E. Blacka
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 # This module uses PLY (Python Lex-Yacc). See
21 # http://www.dabeaz.com/ply/ for more info.
23 # This module is actually the grammar definition. The lexer finds
24 # variables and functions starting with 't_', as well as a list called
25 # 'tokens'. The parser (i.e., yacc) finds things starting with 'p_'.
27 # queryparser.db must be set to a DB class instance.
30 # Define the Lexer for the RWhois query language
50 # for now, quoted values must have the wildcards inside the quotes.
51 # I kind of wonder if anyone would ever notice this.
52 t_QUOTEDVALUE = r'["\']\*?[^"*\n]+\*{0,2}["\']'
55 r'^\*?[^\s"\'=*]+\*{0,2}'
57 if db.is_objectclass(t.value):
59 elif db.is_attribute(t.value):
66 r'\*?[^\s"\'=!*]+\*{0,2}'
77 if db.is_attribute(t.value):
86 # print "Illegal character '%r'" % t.value[0]
94 # Define the parser for the query language
96 # 'value' productions are simple strings
97 # 'querystr' productions are tuples (either 1 or 3 values)
98 # 'query' productions are Query objects
99 # 'total' productions are Query objects
101 def p_total_class_query(t):
102 'total : CLASS query'
107 def p_total_query(t):
113 def p_query_oper_querystr(t):
114 '''query : query AND querystr
115 | query OR querystr'''
119 t[0].cur_clause = [ t[3] ]
120 t[0].clauses.append(t[0].cur_clause)
122 t[0].cur_clause.append(t[3])
124 def p_query_querystr(t):
128 t[0].cur_clause = [ t[1] ]
129 t[0].clauses.append(t[0].cur_clause)
131 def p_querystr_attr_value(t):
132 '''querystr : ATTR EQ value
135 t[0] = (t[1], t[2], t[3])
137 def p_querystr_attr_attr(t):
138 '''querystr : ATTR EQ ATTR
141 t[0] = (t[1], t[2], t[3])
143 def p_querystr_value(t):
147 t[0] = (None, '=', t[1])
156 def p_quotedvalue(t):
157 'value : QUOTEDVALUE'
159 t[0] = t[1].strip('"')
163 raise yacc.YaccError, "Syntax error at %r" % t.value
168 """A representation of a parsed RWhois query."""
172 self.cur_clause = None
173 self.objectclass = None
174 self.prepared = False
179 for i in range(len(self.clauses)):
181 res += "clause %d:\n" % i
183 res += " " + repr(item) + "\n"
187 return "<Query:\n" + str(self) + ">"
190 """Prepare the query for use. For now, this means propagating
191 an objectclass restriction to all query clauses."""
193 if self.prepared: return
195 for c in self.clauses:
196 c.append(("class-name", "=", self.objectclass))
199 """Return the query clauses. This is a list of AND clauses,
200 which are, in turn, lists of query terms. Query terms are 3
201 element tuples: (attr, op, value)."""
205 def set_class(self, objectclass):
206 """Set the query-wide objectclass restriction."""
208 # note: we don't allow the code to set this more than once,
209 # because we would have to code the removal of the previous
210 # class restriction from the query clauses, and it just isn't
211 # worth it. Queries are built, used and thrown away.
212 assert not self.prepared
213 self.objectclass = objectclass
221 """Return a parser instances. Parser objects should not be shared
227 """Parse a query, raising a RwhoisError in case of parse failure.
228 Returns a Query object."""
230 # before using any parser objects, the database backend must be
231 # set (and it shared by all parsers).
234 return p.parse(query)
235 except (lex.LexError, yacc.YaccError), e:
236 raise Rwhois.RwhoisError, (350, "Invalid Query Syntax: " + e.message)