cmake_parser.py
Go to the documentation of this file.
1 import re
2 import sys
3 from cmake import CMake, Command, Section, SectionStyle, CommandGroup
4 
5 ALL_CAPS = re.compile('^[A-Z_]+$')
6 ALL_WHITESPACE = ['whitespace', 'newline']
7 NOT_REAL = ALL_WHITESPACE + ['comment']
8 
9 
10 def word_cb(scanner, token):
11  if ALL_CAPS.match(token):
12  return ('caps', token)
13  else:
14  return ('word', token)
15 
16 
17 scanner = re.Scanner([
18  (r'#.*\n', lambda scanner, token: ("comment", token)),
19  (r'"[^"]*"', lambda scanner, token: ("string", token)),
20  (r"\(", lambda scanner, token: ("left paren", token)),
21  (r"\)", lambda scanner, token: ("right paren", token)),
22  (r'[^ \t\r\n()#"]+', word_cb),
23  (r'\n', lambda scanner, token: ("newline", token)),
24  (r"[ \t]+", lambda scanner, token: ("whitespace", token)),
25 ])
26 
27 
28 def match_command_groups(contents, base_depth=0):
29  revised_contents = []
30 
31  current = []
32  group = None
33  depth = base_depth
34 
35  for content in contents:
36  if group is None:
37  if content.__class__ == Command and content.command_name in ['if', 'foreach']:
38  group = content
39  depth = base_depth + 1
40  else:
41  revised_contents.append(content)
42  else:
43  if content.__class__ == Command:
44  if content.command_name == group.command_name:
45  depth += 1
46  elif content.command_name == 'end' + group.command_name:
47  depth -= 1
48  if depth == base_depth:
49  recursive_contents = match_command_groups(current, base_depth + 1)
50  sub = CMake(initial_contents=recursive_contents, depth=base_depth + 1)
51  cg = CommandGroup(group, sub, content)
52  revised_contents.append(cg)
53  group = None
54  current = []
55  continue
56  current.append(content)
57 
58  # Only will happen if the tags don't match. Shouldn't happen, but resolve leftovers
59  if len(current) > 0:
60  revised_contents += current
61 
62  return revised_contents
63 
64 
65 class CMakeParseError(Exception):
66  def __init__(self, msg):
67  Exception.__init__(self, msg)
68 
69 
71  def __init__(self, s, debug=False):
72  self.tokens, remainder = scanner.scan(s)
73  if remainder != '':
74  msg = 'Unrecognized tokens: %s' % (remainder)
75  raise ValueError(msg)
76 
77  if debug:
78  for typ, token in self.tokens:
79  print('[%s]%s' % (typ, repr(token)))
80 
81  self.contents = []
82  while len(self.tokens) > 0:
83  typ = self.get_type()
84  if typ == 'comment':
85  self.contents.append(self.match(typ))
86  elif typ == 'newline' or typ == 'whitespace':
87  s = self.match(typ)
88  self.contents.append(s)
89  elif typ in ['word', 'caps']:
90  cmd = self.parse_command()
91  self.contents.append(cmd)
92  else:
93  raise Exception('token ' + typ)
94 
95  # Match Command Groups
97 
98  if debug:
99  for chunk in self.contents:
100  print('[%s]' % chunk)
101 
102  def parse_command(self):
103  command_name = self.match()
104  original = command_name
105  cmd = Command(command_name)
106  while self.get_type() == 'whitespace':
107  s = self.match('whitespace')
108  cmd.pre_paren += s
109  original += s
110  original += self.match('left paren')
111  paren_depth = 1
112 
113  while len(self.tokens) > 0:
114  typ = self.next_real_type()
115  if typ in ['word', 'caps', 'string']:
116  section, s = self.parse_section()
117  cmd.sections.append(section)
118  original += s
119  else:
120  typ, tok_contents = self.tokens.pop(0)
121  original += tok_contents
122  if typ == 'right paren':
123  paren_depth -= 1
124  if paren_depth == 0:
125  cmd.original = original
126  return cmd
127  elif typ == 'left paren':
128  paren_depth += 1
129  else:
130  cmd.sections.append(tok_contents)
131  raise CMakeParseError('File ended while processing command "%s"' % (command_name))
132 
133  def parse_section(self):
134  original = ''
135  style = SectionStyle()
136  tokens = []
137  cat = ''
138  while self.get_type() in NOT_REAL:
139  s = self.match()
140  original += s
141  style.prename += s
142 
143  if self.get_type() == 'caps':
144  cat = self.match('caps')
145  original += cat
146  style.name_val_sep = ''
147  while self.get_type() in ALL_WHITESPACE:
148  s = self.match()
149  original += s
150  style.name_val_sep += s
151  if len(style.name_val_sep) == 0:
152  style.name_val_sep = ' '
153 
154  delims = set()
155  current = ''
156  while self.next_real_type() not in ['left paren', 'right paren', 'caps']:
157  typ = self.get_type()
158  if typ in ALL_WHITESPACE:
159  token = self.match()
160  original += token
161  current += token
162  else:
163  if len(current) > 0:
164  delims.add(current)
165  current = ''
166  token = self.match()
167  original += token
168  tokens.append(token)
169  if len(current) > 0:
170  delims.add(current)
171  if len(delims) > 0:
172  if len(delims) == 1:
173  style.val_sep = list(delims)[0]
174  else:
175  # TODO: Smarter multi delim parsing
176  # print(delims)
177  style.val_sep = list(delims)[0]
178 
179  # print(cat, tokens, style)
180  return Section(cat, tokens, style), original
181 
182  def match(self, typ=None):
183  if typ is None or self.get_type() == typ:
184  typ, tok = self.tokens.pop(0)
185  # print('[%s]%s'%(typ, repr(tok)))
186  return tok
187  else:
188  sys.stderr.write('Token Dump:\n')
189  for a in self.tokens:
190  sys.stderr.write(str(a) + '\n')
191  raise CMakeParseError('Expected type "%s" but got "%s"' % (typ, self.get_type()))
192 
193  def get_type(self):
194  if len(self.tokens) > 0:
195  return self.tokens[0][0]
196  else:
197  return None
198 
199  def next_real_type(self):
200  for x, y in self.tokens:
201  if x not in NOT_REAL:
202  return x
203 
204 
206  parser = AwesomeParser(s)
207  return parser.contents
208 
209 
211  parser = AwesomeParser(s)
212  assert len(parser.contents) == 1
213  return parser.contents[0]
214 
215 
216 def parse_file(filename):
217  with open(filename) as f:
218  s = f.read()
219  return CMake(file_path=filename, initial_contents=parse_commands(s))
def word_cb(scanner, token)
Definition: cmake_parser.py:10
def match_command_groups(contents, base_depth=0)
Definition: cmake_parser.py:28


ros_introspection
Author(s):
autogenerated on Wed Jun 19 2019 19:56:52