Atlas 0.7.0
Networking protocol for the Worldforge system.
parse_def.py
1#parse def format
2
3#Copyright 2000 by Aloril
4
5#This library is free software; you can redistribute it and/or
6#modify it under the terms of the GNU Lesser General Public
7#License as published by the Free Software Foundation; either
8#version 2.1 of the License, or (at your option) any later version.
9
10#This library is distributed in the hope that it will be useful,
11#but WITHOUT ANY WARRANTY; without even the implied warranty of
12#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13#Lesser General Public License for more details.
14
15#You should have received a copy of the GNU Lesser General Public
16#License along with this library; if not, write to the Free Software
17#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18import collections
19import os
20import re
21
22from atlas import *
23from atlas.typemap import get_atlas_type
24
26 """reads 'atlas def' files into atlas Objects"""
27 def __init__(self):
28 self.id_dict = {}
29 self.objects = []
30 self.lineno = 0
31 def parse_lines(self, lines, depth, parent_obj):
32 last_obj=None
33 while self.lineno < len(lines):
34 line = lines[self.lineno]
35 space_count=len(re.match("( *)",line).group(1))
36 #empty or comment line
37 if line[0] in '#\n' or \
38 space_count==len(line)-1: #Only spaces in line
39 self.lineno = self.lineno + 1
40 continue
41 if space_count>depth: #sub object
42 if last_obj==None:
43 raise SyntaxError("Unexpected indentation",
44 (self.filename, self.lineno, space_count, line))
45 self.parse_lines(lines, space_count, last_obj)
46 last_obj = None
47 continue
48 if space_count<depth: #all objects in this level done
49 return
50 #split into parts using ':' but not inside string
51 parts=[]
52 rest=line[space_count:-1]
53 while 1:
54 match=re.match("""([^"':]*):(.*)""",rest) #' (for xemacs highlight)
55 if match:
56 parts.append(match.group(1))
57 rest=match.group(2)
58 else:
59 parts.append(rest)
60 break
61 if len(parts)==3: #hmm.. probably name undefined
62 name,type,value=parts
63 elif len(parts)==2: #name and value defined, type undefined
64 name,value=parts
65 if len(value)==0:
66 type="list" #guessing
67 else:
68 type=""
69 else:
70 raise SyntaxError("Unexpected element numbers (things delimited with ':')",
71 (self.filename, self.lineno, space_count, line))
72 if type=="list": #new list subobject
73 if len(value):
74 try:
75 value=eval(value)
76 except:
77 print("Error at:",(self.filename, self.lineno, line))
78 raise
79 else:
80 value = []
81 last_obj = value
82 elif type=="map": #new mapping subobject
83 value = last_obj = Object()
84 last_obj.specification_file = Object(attribute_order = [],
85 filename = os.path.basename(self.filename),
86 lineno = self.lineno+1)
87 else:
88 #hack: reading several lines if """ string
89 if value[:3]=='"""' and not value[-3:]=='"""':
90 value=value+"\n"
91 while 1:
92 self.lineno=self.lineno+1
93 line = lines[self.lineno]
94 value = value + line
95 if not line or line.find('"""')>=0:
96 break
97 try:
98 value=eval(value)
99 except:
100 print("Error at:",(self.filename, self.lineno, line))
101 raise
102 last_obj=None
103 if name:
104 setattr(parent_obj, name, value)
105 parent_obj.specification_file.attribute_order.append(name)
106 else:
107 parent_obj.append(value)
108 self.lineno=self.lineno+1
109
110 def read_file(self, filename):
111 """read one file"""
112 self.filename=filename
113 self.lineno=0
114 fp=open(filename)
115 lines = fp.readlines()
116 lines.append("\n") #to avoid checking for end
117 self.parse_lines(lines, 0, self.objects)
118 fp.close()
119
120 def syntax_error(self, msg, obj):
121 info = obj.specification_file
122 raise SyntaxError("%s at %s:%s" % (msg, info.filename, info.lineno))
123
124 def check_fill(self):
125 """fill missing attributes and check for attribute definitions"""
126 self.fill_id_dict()
127 self.fill_children()
128 find_parents_children_objects(self.id_dict)
129 self.check_type()
130
131 def fill_id_dict(self):
132 """fill id_dict with all objects"""
133 for obj in self.objects:
134 try:
135 id = obj.id
136 if id in self.id_dict:
137 self.syntax_error(
138 'Object with "'+id+'"-id already exists', obj)
139 self.id_dict[id]=obj
140 except AttributeError:
141 self.syntax_error(
142 "Id attribute is not specified for object", obj)
143
144 def fill_children(self):
145 for obj in self.objects:
146 attr_order = obj.specification_file.attribute_order
147 try:
148 parent_loc = attr_order.index("parent")
149 attr_order.insert(parent_loc+1, "children")
150 except ValueError:
151 self.syntax_error("Parent attribute missing in %s" % obj.id, obj)
152 obj.children=[]
153 for obj in self.objects:
154 pid = obj.parent
155 if pid is not None and pid != "":
156 try:
157 parent_obj = self.id_dict[pid]
158 parent_obj.children.append(obj.id)
159 except KeyError:
160 self.syntax_error('Parent "%s" is missing in %s' % (pid, obj.id), obj)
161
162 def check_type_object(self, obj):
163 """recursively check types for all objects"""
164 if isinstance(obj, list):
165 for sub_obj in obj:
166 self.check_type_object(sub_obj)
167 elif isinstance(obj, dict):
168 for name, value in list(obj.items()):
169 if name != "parent":
170 if value:
171 try:
172 type_obj = self.id_dict[name]
173 except KeyError:
174 if "id" in obj:
175 self.syntax_error('Name "'+name+'" is not specified for type %s' % obj.id, obj)
176 else:
177 self.syntax_error('Name "'+name+'" is not specified', obj)
178 should_be_type = get_atlas_type(value)
179 if not type_obj.has_parent(should_be_type):
180 self.syntax_error(
181 'Type doesn\'t match or is not found: "'+name+'"',obj)
182 self.check_type_object(value)
183 def check_type(self):
184 self.check_type_object(self.objects)
185
186
187
188
189def read_all_defs(filelist):
190 parser=DefParser()
191 for file in filelist:
192 parser.read_file(file)
193 parser.check_fill()
194 #for item in parser.id_dict.items(): print item
195 return parser
196
197if __name__=="__main__":
198 filelist=["root","entity","operation","type"]
199 defs=read_all_defs([file+".def" for file in filelist])
def read_file(self, filename)
Definition: parse_def.py:110
def check_type_object(self, obj)
Definition: parse_def.py:162
def syntax_error(self, msg, obj)
Definition: parse_def.py:120
def parse_lines(self, lines, depth, parent_obj)
Definition: parse_def.py:31