Skip to content

Commit 0b91aff

Browse files
committed
Initial revision (work in progress)
1 parent cff3c62 commit 0b91aff

File tree

5 files changed

+521
-0
lines changed

5 files changed

+521
-0
lines changed

pypuppetdbquery/__init__.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# This file is part of pypuppetdbquery.
4+
# Copyright © 2016 Chris Boot <[email protected]>
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
19+
from .evaluator import Evaluator
20+
from .parser import Parser
21+
22+
23+
def parse(s, parser_opts=None, evaluator_opts=None):
24+
parser = Parser(**(parser_opts or {}))
25+
evaluator = Evaluator(**(evaluator_opts or {}))
26+
27+
ast = parser.parse(s)
28+
return evaluator.evaluate(ast)

pypuppetdbquery/ast.py

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# This file is part of pypuppetdbquery.
4+
# Copyright © 2016 Chris Boot <[email protected]>
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
19+
20+
class Node(object):
21+
pass
22+
23+
24+
class Literal(Node):
25+
def __init__(self, value):
26+
self.value = value
27+
28+
29+
class Date(Literal):
30+
pass
31+
32+
33+
class Query(Node):
34+
def __init__(self, expression):
35+
self.expression = expression
36+
37+
38+
class Expression(Node):
39+
pass
40+
41+
42+
class UnaryExpression(Node):
43+
def __init__(self, expression):
44+
self.expression = expression
45+
46+
47+
class BinaryExpression(Node):
48+
def __init__(self, left, right):
49+
self.left = left
50+
self.right = right
51+
52+
53+
class AndExpression(BinaryExpression):
54+
pass
55+
56+
57+
class OrExpression(BinaryExpression):
58+
pass
59+
60+
61+
class NotExpression(UnaryExpression):
62+
pass
63+
64+
65+
class ParenthesizedExpression(UnaryExpression):
66+
pass
67+
68+
69+
class BlockExpression(UnaryExpression):
70+
pass
71+
72+
73+
class Comparison(Expression):
74+
def __init__(self, operator, left, right):
75+
self.operator = operator
76+
self.left = left
77+
self.right = right
78+
79+
80+
class Identifier(Node):
81+
def __init__(self, name):
82+
self.name = name
83+
84+
85+
class RegexpIdentifier(Identifier):
86+
pass
87+
88+
89+
class IdentifierPath(Node):
90+
def __init__(self, component):
91+
self.components = [component]
92+
93+
94+
class Subquery(Node):
95+
def __init__(self, endpoint, expression):
96+
self.endpoint = endpoint
97+
self.expression = expression
98+
99+
100+
class Resource(Expression):
101+
def __init__(self, res_type, title, exported, parameters=None):
102+
self.res_type = res_type
103+
self.title = title
104+
self.exported = exported
105+
self.parameters = parameters
106+
107+
108+
class RegexpNodeMatch(Expression):
109+
def __init__(self, value):
110+
self.value = value

pypuppetdbquery/evaluator.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# This file is part of pypuppetdbquery.
4+
# Copyright © 2016 Chris Boot <[email protected]>
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
19+
# from . import ast
20+
21+
22+
class EvaluationException(Exception):
23+
def __init__(self, message):
24+
super(EvaluationException, self).__init__(message)
25+
26+
27+
class Evaluator(object):
28+
def __init__(self):
29+
pass
30+
31+
def evaluate(self, ast):
32+
pass

pypuppetdbquery/lexer.py

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# This file is part of pypuppetdbquery.
4+
# Copyright © 2016 Chris Boot <[email protected]>
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
19+
import ply.lex as lex
20+
21+
22+
class LexException(Exception):
23+
def __init__(self, message, position):
24+
super(LexException, self).__init__(message)
25+
self.position = position
26+
27+
28+
class Lexer(object):
29+
"""
30+
Lexer for the PuppetDB query language.
31+
"""
32+
def __init__(self, **kwargs):
33+
super(Lexer, self).__init__()
34+
self.lexer = lex.lex(object=self, **kwargs)
35+
36+
def input(self, s):
37+
self.lexer.input(s)
38+
39+
def token(self):
40+
return self.lexer.token()
41+
42+
def __iter__(self):
43+
return self
44+
45+
def next(self):
46+
t = self.token()
47+
if t is None:
48+
raise StopIteration()
49+
return t
50+
51+
__next__ = next
52+
53+
# List of token names.
54+
tokens = (
55+
'LPAREN',
56+
'RPAREN',
57+
'LBRACK',
58+
'RBRACK',
59+
'LBRACE',
60+
'RBRACE',
61+
'EQUALS',
62+
'NOTEQUALS',
63+
'MATCH',
64+
'NOTMATCH',
65+
'LESSTHANEQ',
66+
'LESSTHAN',
67+
'GREATERTHANEQ',
68+
'GREATERTHAN',
69+
'ASTERISK',
70+
'HASH',
71+
'DOT',
72+
'NOT',
73+
'AND',
74+
'OR',
75+
'BOOLEAN',
76+
'NUMBER',
77+
'STRING',
78+
'EXPORTED',
79+
'AT',
80+
)
81+
82+
# Regular expression rules for simple tokens
83+
t_LPAREN = r'\('
84+
t_RPAREN = r'\)'
85+
t_LBRACK = r'\['
86+
t_RBRACK = r'\]'
87+
t_LBRACE = r'{'
88+
t_RBRACE = r'}'
89+
t_EQUALS = r'='
90+
t_NOTEQUALS = r'!='
91+
t_MATCH = r'~'
92+
t_NOTMATCH = r'!~'
93+
t_LESSTHANEQ = r'<='
94+
t_LESSTHAN = r'<'
95+
t_GREATERTHANEQ = r'>='
96+
t_GREATERTHAN = r'>'
97+
t_ASTERISK = r'\*'
98+
t_HASH = r'[#]'
99+
t_DOT = r'\.'
100+
t_NOT = r'not'
101+
t_AND = r'and'
102+
t_OR = r'or'
103+
t_EXPORTED = r'@@'
104+
t_AT = r'@'
105+
106+
# Boolean values
107+
def t_BOOLEAN(self, t):
108+
r'true|false'
109+
t.value = (t.value == 'true')
110+
return t
111+
112+
# Numeric values
113+
def t_NUMBER(self, t):
114+
r'-?\d+'
115+
t.value = int(t.value)
116+
return t
117+
118+
# The next three functions handle string parsing, because there are three
119+
# slightly different syntaxes for strings (which are handled the same way
120+
# in the parser).
121+
def t_STRING_bareword(self, t):
122+
r'[-\w_:]+'
123+
t.type = 'STRING'
124+
# This is a bareword string, it has no quotes around it so the value is
125+
# unchanged.
126+
return t
127+
128+
def t_STRING_double_quoted(self, t):
129+
r'"(\\.|[^\\"])*"'
130+
t.type = 'STRING'
131+
# This is a double-quoted string. The regex handles most of what we
132+
# need but we must strip off the quote characters around the string.
133+
t.value = t.value[1:-1]
134+
return t
135+
136+
def t_STRING_single_quoted(self, t):
137+
r"'(\\.|[^\\'])*'"
138+
t.type = 'STRING'
139+
# This is a single-quoted string. The regex handles most of what we
140+
# need but we must strip off the quote characters around the string.
141+
t.value = t.value[1:-1]
142+
return t
143+
144+
# A string containing ignored characters
145+
t_ignore = " \t\n\r\f\v" # all whitespace
146+
147+
# Error handling rule
148+
def t_error(self, t):
149+
msg = "Illegal character '{}'".format(t.value[0])
150+
raise LexException(msg, t.lexpos)

0 commit comments

Comments
 (0)