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
18 import collections
19 import os
20 import re
21 
22 from atlas import *
23 from atlas.typemap import get_atlas_type
24 
25 class DefParser:
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 
189 def 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 
197 if __name__=="__main__":
198  filelist=["root","entity","operation","type"]
199  defs=read_all_defs([file+".def" for file in filelist])
def syntax_error(self, msg, obj)
Definition: parse_def.py:120
def read_file(self, filename)
Definition: parse_def.py:110
def parse_lines(self, lines, depth, parent_obj)
Definition: parse_def.py:31
def check_type_object(self, obj)
Definition: parse_def.py:162