Atlas 0.7.0
Networking protocol for the Worldforge system.
bach.py
1#Bach parser and generator
2
3#Copyright 2001 by Aloril
4#Copyright 2002 by AIR-IX SUUNNITTELU/Ahiplan Oy
5
6#This library is free software; you can redistribute it and/or
7#modify it under the terms of the GNU Lesser General Public
8#License as published by the Free Software Foundation; either
9#version 2.1 of the License, or (at your option) any later version.
10
11#This library 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 GNU
14#Lesser General Public License for more details.
15
16#You should have received a copy of the GNU Lesser General Public
17#License along with this library; if not, write to the Free Software
18#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20
21import string
22import atlas
23from atlas.typemap import *
24
25from atlas.gen_bach import *
26import encoder, decoder
27
28class BachException(Exception): pass
29
31 begin_string = "[\n"
32 middle_string = ",\n"
33 end_string = "\n]\n"
34 empty_end_string = "[]\n"
35
36 def encode1stream(self, object):
37 return "\t" + encode(object, "\t")
38
39 def encode1(self, object):
40 return gen_bach(object)
41
42
43
44def get_encoder(stream_flag=None):
45 return Encoder(stream_flag)
46
47
48
49
50class Context:
51 def __init__(self, value, excepted_value=""):
52 self.value = value
53 self.excepted_value = excepted_value # "map_name", "map_value", "list_value"
54 self.name = None
55 def __repr__(self):
56 return "Context(%s, %s, %s)" % (repr(self.value), self.excepted_value, self.name)
57
59 def __init__(self, stream_flag=None):
60 """uses tree that start from root_obj, current route to leave
61 is kept in obj_stack"""
62 #Root object is never removed or visible for parser users,
63 #incoming objects are added to its value
64 #resulting complete atlas 'messages' are added here
65 self.stack = []
66 self.mode = self.skip_white_space
67 self.lineno = 1
68 self.setup(stream_flag=None)
69
70 def eos(self):
71 """end of stream"""
72 return not self.data and not self.stack
73
74 def feed(self, msg):
75 #import pdb; pdb.set_trace()
76 for ch in msg:
77 #print ch
78 if ch=="\n":
79 self.lineno = self.lineno + 1
80 self.mode(ch)
81
82 def context(self):
83 return self.stack[-1]
84
85 def add_value(self):
86 value = self.stack.pop().value
87 c = self.context()
88 obj = c.value
89 if c.excepted_value == "map_name":
90 if not isinstance(obj, atlas.Object):
91 raise BachException("attribute name outside mapping (%s)!" % \
92 (value))
93 c.name = value
94 c.excepted_value = "map_value"
95 elif c.excepted_value == "map_value":
96 if not isinstance(obj, atlas.Object):
97 raise BachException("attribute value outside mapping (%s:%s)!" % \
98 (c.name, value))
99 if not isinstance(c.name, str):
100 c.name = str(c.name)
101 setattr(obj, c.name, value)
102 c.excepted_value = "map_name"
103 elif c.excepted_value == "list_value":
104 if not isinstance(obj, list):
105 raise BachException("object not inside list (%s)!" % value)
106 obj.append(value)
107 else:
108 raise BachException("unknown container (%s)!" % value)
109 self.mode = self.skip_white_space
110
111 def push(self, value, mode = None, ch=None, excepted_value=""):
112 self.stack.append(Context(value, excepted_value))
113 if mode: self.mode = mode
114 else: self.mode = self.skip_white_space
115 if ch: self.mode(ch)
116
117 def pop(self):
118 if self.stream_flag:
119 if len(self.stack)>1:
120 self.add_value()
121 if len(self.stack)==1:
122 obj=self.stack[0].value.pop(0)
123 self.msgList.append(obj)
124 else:
125 self.stack.pop() #stream is closed now really...
126 else:
127 if len(self.stack)==1:
128 obj=self.stack.pop().value
129 self.msgList.append(obj)
130 else:
131 self.add_value()
132
133 def get_next_mode(self, ch):
134 if ch=="{":
135 self.push(atlas.Object(), excepted_value="map_name")
136 elif ch=="[":
137 self.push([], excepted_value="list_value")
138 elif ch in "}]":
139 self.pop()
140 elif ch in int_characters:
141 self.push("", self.int, ch)
142 elif ch=='"':
143 self.push("", self.string)
144 elif ch in plain_name_characters:
145 self.push("", self.name, ch)
146 elif ch in ",:" + string.whitespace:
147 self.mode = self.skip_white_space
148 elif ch=="#":
149 self.mode = self.add_comment
150 else:
151 raise BachException("illegal character (%s (%s) at line %i)!" % (ch, ord(ch), self.lineno))
152
153 def add_comment(self, ch):
154 #CHEAT: should add comment field
155 if ch=="\n":
156 self.mode = self.skip_white_space
157 return
158
159 def skip_white_space(self, ch):
160 if ch in string.whitespace:
161 return
162 self.get_next_mode(ch)
163
164 def int(self, ch):
165 c = self.context()
166 if ch in int_characters:
167 c.value = c.value + ch
168 elif ch in float_characters:
169 self.mode = self.float
170 self.mode(ch)
171 else:
172 try:
173 c.value = int(c.value)
174 except ValueError:
175 c.value = int(c.value)
176 self.add_value()
177 self.get_next_mode(ch)
178
179 def float(self, ch):
180 c = self.context()
181 if ch in float_characters:
182 c.value = c.value + ch
183 else:
184 c.value = float(c.value)
185 self.add_value()
186 self.get_next_mode(ch)
187
188 def quote(self, ch):
189 c = self.context()
190 c.value = c.value + ch
191 self.mode = self.string
192
193 def string(self, ch):
194 c = self.context()
195 if ch=="\\":
196 self.mode = self.quote
197 elif ch!='"':
198 c.value = c.value + ch
199 else:
200 self.add_value()
201
202 def name(self, ch):
203 c = self.context()
204 if ch in plain_name_characters:
205 c.value = c.value + ch
206 elif ch in ":" + string.whitespace:
207 self.add_value()
208 else:
209 raise BachException("illegal character (%s)!" % ch)
210
211def get_decoder(stream_flag=None):
212 bach_msg_parser=BachParser(stream_flag)
213 return bach_msg_parser
def float(self, ch)
Definition: bach.py:179
def __init__(self, stream_flag=None)
Definition: bach.py:59
def quote(self, ch)
Definition: bach.py:188
def push(self, value, mode=None, ch=None, excepted_value="")
Definition: bach.py:111
def name(self, ch)
Definition: bach.py:202
def int(self, ch)
Definition: bach.py:164
def skip_white_space(self, ch)
Definition: bach.py:159
def get_next_mode(self, ch)
Definition: bach.py:133
def add_comment(self, ch)
Definition: bach.py:153
def string(self, ch)
Definition: bach.py:193
def setup(self, stream_flag=None)
Definition: decoder.py:23