~ubuntu-branches/ubuntu/utopic/exabgp/utopic

« back to all changes in this revision

Viewing changes to lib/exabgp/configuration/json.py

  • Committer: Package Import Robot
  • Author(s): Henry-Nicolas Tourneur
  • Date: 2014-03-08 19:07:00 UTC
  • mfrom: (1.1.8)
  • Revision ID: package-import@ubuntu.com-20140308190700-xjbibpg1g6001c9x
Tags: 3.3.1-1
* New upstream release
* Bump python minimal required version (2.7)
* Closes: #726066 Debian packaging improvements proposed by Vincent Bernat
* Closes: #703774 not existent rundir (/var/run/exabgp) after reboot

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# encoding: utf-8
 
2
"""
 
3
json.py
 
4
 
 
5
Created by Thomas Mangin on 2013-07-01.
 
6
Copyright (c) 2009-2012 Exa Networks. All rights reserved.
 
7
"""
 
8
 
 
9
from decimal import Decimal
 
10
 
 
11
from exabgp.util import coroutine
 
12
 
 
13
class JSONError(Exception):
 
14
        pass
 
15
 
 
16
class UnexpectedData(JSONError):
 
17
        def __init__(self, line, position, token):
 
18
                super(UnexpectedData, self).__init__('Unexpected data at line %d position %d : "%s"' % (line,position,token))
 
19
 
 
20
@coroutine.join
 
21
def unescape(s):
 
22
        start = 0
 
23
        while start < len(s):
 
24
                pos = s.find('\\', start)
 
25
                if pos == -1:
 
26
                        yield s[start:]
 
27
                        break
 
28
                yield s[start:pos]
 
29
                pos += 1
 
30
                esc = s[pos]
 
31
                if esc == 'b':
 
32
                        yield '\b'
 
33
                elif esc == 'f':
 
34
                        yield '\f'
 
35
                elif esc == 'n':
 
36
                        yield '\n'
 
37
                elif esc == 'r':
 
38
                        yield '\r'
 
39
                elif esc == 't':
 
40
                        yield '\t'
 
41
                elif esc == 'u':
 
42
                        yield chr(int(s[pos + 1:pos + 5], 16))
 
43
                        pos += 4
 
44
                else:
 
45
                        yield esc
 
46
                start = pos + 1
 
47
 
 
48
@coroutine.each
 
49
def tokens (stream):
 
50
        spaces = [' ', '\t', '\r', '\n']
 
51
        strings = ['"', "'"]
 
52
        syntax = [',','[',']','{','}']
 
53
        nb_lines = 0
 
54
        for line in stream:
 
55
                nb_lines += 1
 
56
                nb_chars = 0
 
57
                quoted = ''
 
58
                word = ''
 
59
                for char in line:
 
60
                        if char in spaces:
 
61
                                if quoted:
 
62
                                        word += char
 
63
                                elif word:
 
64
                                        yield nb_lines,nb_chars,word
 
65
                                        nb_chars += len(word)
 
66
                                        word = ''
 
67
                                nb_chars += 1
 
68
 
 
69
                        elif char in strings:
 
70
                                word += char
 
71
                                if quoted == char:
 
72
                                        quoted = ''
 
73
                                        yield nb_lines,nb_chars,word
 
74
                                        nb_chars += len(word) + 1
 
75
                                        word = ''
 
76
                                else:
 
77
                                        quoted = char
 
78
                                        nb_chars += 1
 
79
 
 
80
                        elif char in syntax:
 
81
                                if quoted:
 
82
                                        word += char
 
83
                                else:
 
84
                                        if word:
 
85
                                                yield nb_lines,nb_chars,word
 
86
                                                nb_chars += len(word)
 
87
                                                word = ''
 
88
                                        yield nb_lines,nb_chars,char
 
89
                                nb_chars += 1
 
90
 
 
91
                        else:
 
92
                                word += char
 
93
                                nb_chars += 1
 
94
 
 
95
def parser (tokeniser,container):
 
96
        # Yes, you can add attributes to function ...
 
97
        tokeniser.path = []
 
98
 
 
99
        def content(next):
 
100
                try:
 
101
                        while True:
 
102
                                line,position,token = next()
 
103
 
 
104
                                if token == '{':
 
105
                                        klass = container(next.path)
 
106
                                        d = klass()
 
107
                                        for key,value in iterate_dict(next):
 
108
                                                d[key] = value
 
109
                                        return d
 
110
                                elif token == '[':
 
111
                                        l = []
 
112
                                        for element in iterate_list(next):
 
113
                                                l.append(element)
 
114
                                        return l
 
115
                                elif token[0] == '"':
 
116
                                        return unescape(token[1:-1])
 
117
                                elif token == 'true':
 
118
                                        return True
 
119
                                elif token == 'false':
 
120
                                        return False
 
121
                                elif token == 'null':
 
122
                                        return None
 
123
                                elif token == ']':  # required for parsing arrays
 
124
                                        return ']'
 
125
                                else:
 
126
                                        # can raise ValueError
 
127
                                        return Decimal(token) if '.' in token else int(token)
 
128
                except ValueError:
 
129
                        raise UnexpectedData(line,position,token)
 
130
                except StopIteration:
 
131
                        return ''
 
132
 
 
133
        def iterate_dict(next):
 
134
                line,position,key = next()
 
135
                if key != '}':
 
136
                        while True:
 
137
                                if key[0] != '"':
 
138
                                        raise UnexpectedData(line,position,key)
 
139
 
 
140
                                line,position,colon = next()
 
141
                                if colon != ':':
 
142
                                        raise UnexpectedData(line,position,colon)
 
143
 
 
144
                                next.path.append(key)
 
145
                                yield key[1:-1],content(next)
 
146
                                next.path.pop()
 
147
 
 
148
                                line,position,separator = next()
 
149
                                if separator == '}':
 
150
                                        break
 
151
                                if separator != ',':
 
152
                                        raise UnexpectedData(line,position,separator)
 
153
                                line,position,key = next()
 
154
 
 
155
        def iterate_list(next):
 
156
                value = content(next)
 
157
                if value != ']':
 
158
                        while True:
 
159
                                yield value
 
160
 
 
161
                                line,position,separator = next()
 
162
                                if separator == ']':
 
163
                                        break
 
164
                                if separator != ',':
 
165
                                        raise UnexpectedData(line,position,separator)
 
166
 
 
167
                                value = content(next)
 
168
 
 
169
        return content(tokeniser)
 
170
 
 
171
 
 
172
def load (stream,container=lambda _:dict):
 
173
        return parser(tokens(stream),container)
 
174
 
 
175
__all__ = [load,JSONError,UnexpectedData]