OSDN Git Service

scons: add llvm 3.9 support.
[android-x86/external-mesa.git] / scons / source_list.py
1 """Source List Parser
2
3 The syntax of a source list file is a very small subset of GNU Make.  These
4 features are supported
5
6  operators: =, +=, :=
7  line continuation
8  non-nested variable expansion
9  comment
10
11 The goal is to allow Makefile's and SConscript's to share source listing.
12 """
13
14 class SourceListParser(object):
15     def __init__(self):
16         self.symbol_table = {}
17         self._reset()
18
19     def _reset(self, filename=None):
20         self.filename = filename
21
22         self.line_no = 1
23         self.line_cont = ''
24
25     def _error(self, msg):
26         raise RuntimeError('%s:%d: %s' % (self.filename, self.line_no, msg))
27
28     def _next_dereference(self, val, cur):
29         """Locate the next $(...) in value."""
30         deref_pos = val.find('$', cur)
31         if deref_pos < 0:
32             return (-1, -1)
33         elif val[deref_pos + 1] != '(':
34             self._error('non-variable dereference')
35
36         deref_end = val.find(')', deref_pos + 2)
37         if deref_end < 0:
38             self._error('unterminated variable dereference')
39
40         return (deref_pos, deref_end + 1)
41
42     def _expand_value(self, val):
43         """Perform variable expansion."""
44         expanded = ''
45         cur = 0
46         while True:
47             deref_pos, deref_end = self._next_dereference(val, cur)
48             if deref_pos < 0:
49                 expanded += val[cur:]
50                 break
51
52             sym = val[(deref_pos + 2):(deref_end - 1)]
53             expanded += val[cur:deref_pos] + self.symbol_table[sym]
54             cur = deref_end
55
56         return expanded
57
58     def _parse_definition(self, line):
59         """Parse a variable definition line."""
60         op_pos = line.find('=')
61         op_end = op_pos + 1
62         if op_pos < 0:
63             self._error('not a variable definition')
64
65         if op_pos > 0:
66             if line[op_pos - 1] in [':', '+', '?']:
67                 op_pos -= 1
68         else:
69             self._error('only =, :=, and += are supported')
70
71         # set op, sym, and val
72         op = line[op_pos:op_end]
73         sym = line[:op_pos].strip()
74         val = self._expand_value(line[op_end:].lstrip())
75
76         if op in ('=', ':='):
77             self.symbol_table[sym] = val
78         elif op == '+=':
79             self.symbol_table[sym] += ' ' + val
80         elif op == '?=':
81             if sym not in self.symbol_table:
82                 self.symbol_table[sym] = val
83
84     def _parse_line(self, line):
85         """Parse a source list line."""
86         # more lines to come
87         if line and line[-1] == '\\':
88             # spaces around "\\\n" are replaced by a single space
89             if self.line_cont:
90                 self.line_cont += line[:-1].strip() + ' '
91             else:
92                 self.line_cont = line[:-1].rstrip() + ' '
93             return 0
94
95         # combine with previous lines
96         if self.line_cont:
97             line = self.line_cont + line.lstrip()
98             self.line_cont = ''
99
100         if line:
101             begins_with_tab = (line[0] == '\t')
102
103             line = line.lstrip()
104             if line[0] != '#':
105                 if begins_with_tab:
106                     self._error('recipe line not supported')
107                 else:
108                     self._parse_definition(line)
109
110         return 1
111
112     def parse(self, filename):
113         """Parse a source list file."""
114         if self.filename != filename:
115             fp = open(filename)
116             lines = fp.read().splitlines()
117             fp.close()
118
119             try:
120                 self._reset(filename)
121                 for line in lines:
122                     self.line_no += self._parse_line(line)
123             except:
124                 self._reset()
125                 raise
126
127         return self.symbol_table
128
129     def add_symbol(self, name, value):
130         self.symbol_table[name] = value