1 | #! /usr/bin/env python
|
---|
2 | """Generate C code from an ASDL description."""
|
---|
3 |
|
---|
4 | # TO DO
|
---|
5 | # handle fields that have a type but no name
|
---|
6 |
|
---|
7 | import os, sys, traceback
|
---|
8 |
|
---|
9 | import asdl
|
---|
10 |
|
---|
11 | TABSIZE = 8
|
---|
12 | MAX_COL = 80
|
---|
13 |
|
---|
14 | def get_c_type(name):
|
---|
15 | """Return a string for the C name of the type.
|
---|
16 |
|
---|
17 | This function special cases the default types provided by asdl:
|
---|
18 | identifier, string, int, bool.
|
---|
19 | """
|
---|
20 | # XXX ack! need to figure out where Id is useful and where string
|
---|
21 | if isinstance(name, asdl.Id):
|
---|
22 | name = name.value
|
---|
23 | if name in asdl.builtin_types:
|
---|
24 | return name
|
---|
25 | else:
|
---|
26 | return "%s_ty" % name
|
---|
27 |
|
---|
28 | def reflow_lines(s, depth):
|
---|
29 | """Reflow the line s indented depth tabs.
|
---|
30 |
|
---|
31 | Return a sequence of lines where no line extends beyond MAX_COL
|
---|
32 | when properly indented. The first line is properly indented based
|
---|
33 | exclusively on depth * TABSIZE. All following lines -- these are
|
---|
34 | the reflowed lines generated by this function -- start at the same
|
---|
35 | column as the first character beyond the opening { in the first
|
---|
36 | line.
|
---|
37 | """
|
---|
38 | size = MAX_COL - depth * TABSIZE
|
---|
39 | if len(s) < size:
|
---|
40 | return [s]
|
---|
41 |
|
---|
42 | lines = []
|
---|
43 | cur = s
|
---|
44 | padding = ""
|
---|
45 | while len(cur) > size:
|
---|
46 | i = cur.rfind(' ', 0, size)
|
---|
47 | # XXX this should be fixed for real
|
---|
48 | if i == -1 and 'GeneratorExp' in cur:
|
---|
49 | i = size + 3
|
---|
50 | assert i != -1, "Impossible line %d to reflow: %s" % (size, `s`)
|
---|
51 | lines.append(padding + cur[:i])
|
---|
52 | if len(lines) == 1:
|
---|
53 | # find new size based on brace
|
---|
54 | j = cur.find('{', 0, i)
|
---|
55 | if j >= 0:
|
---|
56 | j += 2 # account for the brace and the space after it
|
---|
57 | size -= j
|
---|
58 | padding = " " * j
|
---|
59 | else:
|
---|
60 | j = cur.find('(', 0, i)
|
---|
61 | if j >= 0:
|
---|
62 | j += 1 # account for the paren (no space after it)
|
---|
63 | size -= j
|
---|
64 | padding = " " * j
|
---|
65 | cur = cur[i+1:]
|
---|
66 | else:
|
---|
67 | lines.append(padding + cur)
|
---|
68 | return lines
|
---|
69 |
|
---|
70 | def is_simple(sum):
|
---|
71 | """Return True if a sum is a simple.
|
---|
72 |
|
---|
73 | A sum is simple if its types have no fields, e.g.
|
---|
74 | unaryop = Invert | Not | UAdd | USub
|
---|
75 | """
|
---|
76 |
|
---|
77 | for t in sum.types:
|
---|
78 | if t.fields:
|
---|
79 | return False
|
---|
80 | return True
|
---|
81 |
|
---|
82 | class EmitVisitor(asdl.VisitorBase):
|
---|
83 | """Visit that emits lines"""
|
---|
84 |
|
---|
85 | def __init__(self, file):
|
---|
86 | self.file = file
|
---|
87 | super(EmitVisitor, self).__init__()
|
---|
88 |
|
---|
89 | def emit(self, s, depth, reflow=1):
|
---|
90 | # XXX reflow long lines?
|
---|
91 | if reflow:
|
---|
92 | lines = reflow_lines(s, depth)
|
---|
93 | else:
|
---|
94 | lines = [s]
|
---|
95 | for line in lines:
|
---|
96 | line = (" " * TABSIZE * depth) + line + "\n"
|
---|
97 | self.file.write(line)
|
---|
98 |
|
---|
99 | class TypeDefVisitor(EmitVisitor):
|
---|
100 | def visitModule(self, mod):
|
---|
101 | for dfn in mod.dfns:
|
---|
102 | self.visit(dfn)
|
---|
103 |
|
---|
104 | def visitType(self, type, depth=0):
|
---|
105 | self.visit(type.value, type.name, depth)
|
---|
106 |
|
---|
107 | def visitSum(self, sum, name, depth):
|
---|
108 | if is_simple(sum):
|
---|
109 | self.simple_sum(sum, name, depth)
|
---|
110 | else:
|
---|
111 | self.sum_with_constructors(sum, name, depth)
|
---|
112 |
|
---|
113 | def simple_sum(self, sum, name, depth):
|
---|
114 | enum = []
|
---|
115 | for i in range(len(sum.types)):
|
---|
116 | type = sum.types[i]
|
---|
117 | enum.append("%s=%d" % (type.name, i + 1))
|
---|
118 | enums = ", ".join(enum)
|
---|
119 | ctype = get_c_type(name)
|
---|
120 | s = "typedef enum _%s { %s } %s;" % (name, enums, ctype)
|
---|
121 | self.emit(s, depth)
|
---|
122 | self.emit("", depth)
|
---|
123 |
|
---|
124 | def sum_with_constructors(self, sum, name, depth):
|
---|
125 | ctype = get_c_type(name)
|
---|
126 | s = "typedef struct _%(name)s *%(ctype)s;" % locals()
|
---|
127 | self.emit(s, depth)
|
---|
128 | self.emit("", depth)
|
---|
129 |
|
---|
130 | def visitProduct(self, product, name, depth):
|
---|
131 | ctype = get_c_type(name)
|
---|
132 | s = "typedef struct _%(name)s *%(ctype)s;" % locals()
|
---|
133 | self.emit(s, depth)
|
---|
134 | self.emit("", depth)
|
---|
135 |
|
---|
136 | class StructVisitor(EmitVisitor):
|
---|
137 | """Visitor to generate typdefs for AST."""
|
---|
138 |
|
---|
139 | def visitModule(self, mod):
|
---|
140 | for dfn in mod.dfns:
|
---|
141 | self.visit(dfn)
|
---|
142 |
|
---|
143 | def visitType(self, type, depth=0):
|
---|
144 | self.visit(type.value, type.name, depth)
|
---|
145 |
|
---|
146 | def visitSum(self, sum, name, depth):
|
---|
147 | if not is_simple(sum):
|
---|
148 | self.sum_with_constructors(sum, name, depth)
|
---|
149 |
|
---|
150 | def sum_with_constructors(self, sum, name, depth):
|
---|
151 | def emit(s, depth=depth):
|
---|
152 | self.emit(s % sys._getframe(1).f_locals, depth)
|
---|
153 | enum = []
|
---|
154 | for i in range(len(sum.types)):
|
---|
155 | type = sum.types[i]
|
---|
156 | enum.append("%s_kind=%d" % (type.name, i + 1))
|
---|
157 |
|
---|
158 | emit("enum _%(name)s_kind {" + ", ".join(enum) + "};")
|
---|
159 |
|
---|
160 | emit("struct _%(name)s {")
|
---|
161 | emit("enum _%(name)s_kind kind;", depth + 1)
|
---|
162 | emit("union {", depth + 1)
|
---|
163 | for t in sum.types:
|
---|
164 | self.visit(t, depth + 2)
|
---|
165 | emit("} v;", depth + 1)
|
---|
166 | for field in sum.attributes:
|
---|
167 | # rudimentary attribute handling
|
---|
168 | type = str(field.type)
|
---|
169 | assert type in asdl.builtin_types, type
|
---|
170 | emit("%s %s;" % (type, field.name), depth + 1);
|
---|
171 | emit("};")
|
---|
172 | emit("")
|
---|
173 |
|
---|
174 | def visitConstructor(self, cons, depth):
|
---|
175 | if cons.fields:
|
---|
176 | self.emit("struct {", depth)
|
---|
177 | for f in cons.fields:
|
---|
178 | self.visit(f, depth + 1)
|
---|
179 | self.emit("} %s;" % cons.name, depth)
|
---|
180 | self.emit("", depth)
|
---|
181 | else:
|
---|
182 | # XXX not sure what I want here, nothing is probably fine
|
---|
183 | pass
|
---|
184 |
|
---|
185 | def visitField(self, field, depth):
|
---|
186 | # XXX need to lookup field.type, because it might be something
|
---|
187 | # like a builtin...
|
---|
188 | ctype = get_c_type(field.type)
|
---|
189 | name = field.name
|
---|
190 | if field.seq:
|
---|
191 | if field.type.value in ('cmpop',):
|
---|
192 | self.emit("asdl_int_seq *%(name)s;" % locals(), depth)
|
---|
193 | else:
|
---|
194 | self.emit("asdl_seq *%(name)s;" % locals(), depth)
|
---|
195 | else:
|
---|
196 | self.emit("%(ctype)s %(name)s;" % locals(), depth)
|
---|
197 |
|
---|
198 | def visitProduct(self, product, name, depth):
|
---|
199 | self.emit("struct _%(name)s {" % locals(), depth)
|
---|
200 | for f in product.fields:
|
---|
201 | self.visit(f, depth + 1)
|
---|
202 | self.emit("};", depth)
|
---|
203 | self.emit("", depth)
|
---|
204 |
|
---|
205 | class PrototypeVisitor(EmitVisitor):
|
---|
206 | """Generate function prototypes for the .h file"""
|
---|
207 |
|
---|
208 | def visitModule(self, mod):
|
---|
209 | for dfn in mod.dfns:
|
---|
210 | self.visit(dfn)
|
---|
211 |
|
---|
212 | def visitType(self, type):
|
---|
213 | self.visit(type.value, type.name)
|
---|
214 |
|
---|
215 | def visitSum(self, sum, name):
|
---|
216 | if is_simple(sum):
|
---|
217 | pass # XXX
|
---|
218 | else:
|
---|
219 | for t in sum.types:
|
---|
220 | self.visit(t, name, sum.attributes)
|
---|
221 |
|
---|
222 | def get_args(self, fields):
|
---|
223 | """Return list of C argument into, one for each field.
|
---|
224 |
|
---|
225 | Argument info is 3-tuple of a C type, variable name, and flag
|
---|
226 | that is true if type can be NULL.
|
---|
227 | """
|
---|
228 | args = []
|
---|
229 | unnamed = {}
|
---|
230 | for f in fields:
|
---|
231 | if f.name is None:
|
---|
232 | name = f.type
|
---|
233 | c = unnamed[name] = unnamed.get(name, 0) + 1
|
---|
234 | if c > 1:
|
---|
235 | name = "name%d" % (c - 1)
|
---|
236 | else:
|
---|
237 | name = f.name
|
---|
238 | # XXX should extend get_c_type() to handle this
|
---|
239 | if f.seq:
|
---|
240 | if f.type.value in ('cmpop',):
|
---|
241 | ctype = "asdl_int_seq *"
|
---|
242 | else:
|
---|
243 | ctype = "asdl_seq *"
|
---|
244 | else:
|
---|
245 | ctype = get_c_type(f.type)
|
---|
246 | args.append((ctype, name, f.opt or f.seq))
|
---|
247 | return args
|
---|
248 |
|
---|
249 | def visitConstructor(self, cons, type, attrs):
|
---|
250 | args = self.get_args(cons.fields)
|
---|
251 | attrs = self.get_args(attrs)
|
---|
252 | ctype = get_c_type(type)
|
---|
253 | self.emit_function(cons.name, ctype, args, attrs)
|
---|
254 |
|
---|
255 | def emit_function(self, name, ctype, args, attrs, union=1):
|
---|
256 | args = args + attrs
|
---|
257 | if args:
|
---|
258 | argstr = ", ".join(["%s %s" % (atype, aname)
|
---|
259 | for atype, aname, opt in args])
|
---|
260 | argstr += ", PyArena *arena"
|
---|
261 | else:
|
---|
262 | argstr = "PyArena *arena"
|
---|
263 | self.emit("%s %s(%s);" % (ctype, name, argstr), 0)
|
---|
264 |
|
---|
265 | def visitProduct(self, prod, name):
|
---|
266 | self.emit_function(name, get_c_type(name),
|
---|
267 | self.get_args(prod.fields), [], union=0)
|
---|
268 |
|
---|
269 | class FunctionVisitor(PrototypeVisitor):
|
---|
270 | """Visitor to generate constructor functions for AST."""
|
---|
271 |
|
---|
272 | def emit_function(self, name, ctype, args, attrs, union=1):
|
---|
273 | def emit(s, depth=0, reflow=1):
|
---|
274 | self.emit(s, depth, reflow)
|
---|
275 | argstr = ", ".join(["%s %s" % (atype, aname)
|
---|
276 | for atype, aname, opt in args + attrs])
|
---|
277 | if argstr:
|
---|
278 | argstr += ", PyArena *arena"
|
---|
279 | else:
|
---|
280 | argstr = "PyArena *arena"
|
---|
281 | self.emit("%s" % ctype, 0)
|
---|
282 | emit("%s(%s)" % (name, argstr))
|
---|
283 | emit("{")
|
---|
284 | emit("%s p;" % ctype, 1)
|
---|
285 | for argtype, argname, opt in args:
|
---|
286 | # XXX hack alert: false is allowed for a bool
|
---|
287 | if not opt and not (argtype == "bool" or argtype == "int"):
|
---|
288 | emit("if (!%s) {" % argname, 1)
|
---|
289 | emit("PyErr_SetString(PyExc_ValueError,", 2)
|
---|
290 | msg = "field %s is required for %s" % (argname, name)
|
---|
291 | emit(' "%s");' % msg,
|
---|
292 | 2, reflow=0)
|
---|
293 | emit('return NULL;', 2)
|
---|
294 | emit('}', 1)
|
---|
295 |
|
---|
296 | emit("p = (%s)PyArena_Malloc(arena, sizeof(*p));" % ctype, 1);
|
---|
297 | emit("if (!p) {", 1)
|
---|
298 | emit("PyErr_NoMemory();", 2)
|
---|
299 | emit("return NULL;", 2)
|
---|
300 | emit("}", 1)
|
---|
301 | if union:
|
---|
302 | self.emit_body_union(name, args, attrs)
|
---|
303 | else:
|
---|
304 | self.emit_body_struct(name, args, attrs)
|
---|
305 | emit("return p;", 1)
|
---|
306 | emit("}")
|
---|
307 | emit("")
|
---|
308 |
|
---|
309 | def emit_body_union(self, name, args, attrs):
|
---|
310 | def emit(s, depth=0, reflow=1):
|
---|
311 | self.emit(s, depth, reflow)
|
---|
312 | emit("p->kind = %s_kind;" % name, 1)
|
---|
313 | for argtype, argname, opt in args:
|
---|
314 | emit("p->v.%s.%s = %s;" % (name, argname, argname), 1)
|
---|
315 | for argtype, argname, opt in attrs:
|
---|
316 | emit("p->%s = %s;" % (argname, argname), 1)
|
---|
317 |
|
---|
318 | def emit_body_struct(self, name, args, attrs):
|
---|
319 | def emit(s, depth=0, reflow=1):
|
---|
320 | self.emit(s, depth, reflow)
|
---|
321 | for argtype, argname, opt in args:
|
---|
322 | emit("p->%s = %s;" % (argname, argname), 1)
|
---|
323 | assert not attrs
|
---|
324 |
|
---|
325 | class PickleVisitor(EmitVisitor):
|
---|
326 |
|
---|
327 | def visitModule(self, mod):
|
---|
328 | for dfn in mod.dfns:
|
---|
329 | self.visit(dfn)
|
---|
330 |
|
---|
331 | def visitType(self, type):
|
---|
332 | self.visit(type.value, type.name)
|
---|
333 |
|
---|
334 | def visitSum(self, sum, name):
|
---|
335 | pass
|
---|
336 |
|
---|
337 | def visitProduct(self, sum, name):
|
---|
338 | pass
|
---|
339 |
|
---|
340 | def visitConstructor(self, cons, name):
|
---|
341 | pass
|
---|
342 |
|
---|
343 | def visitField(self, sum):
|
---|
344 | pass
|
---|
345 |
|
---|
346 | class MarshalPrototypeVisitor(PickleVisitor):
|
---|
347 |
|
---|
348 | def prototype(self, sum, name):
|
---|
349 | ctype = get_c_type(name)
|
---|
350 | self.emit("static int marshal_write_%s(PyObject **, int *, %s);"
|
---|
351 | % (name, ctype), 0)
|
---|
352 |
|
---|
353 | visitProduct = visitSum = prototype
|
---|
354 |
|
---|
355 | class PyTypesDeclareVisitor(PickleVisitor):
|
---|
356 |
|
---|
357 | def visitProduct(self, prod, name):
|
---|
358 | self.emit("static PyTypeObject *%s_type;" % name, 0)
|
---|
359 | self.emit("static PyObject* ast2obj_%s(void*);" % name, 0)
|
---|
360 | if prod.fields:
|
---|
361 | self.emit("static char *%s_fields[]={" % name,0)
|
---|
362 | for f in prod.fields:
|
---|
363 | self.emit('"%s",' % f.name, 1)
|
---|
364 | self.emit("};", 0)
|
---|
365 |
|
---|
366 | def visitSum(self, sum, name):
|
---|
367 | self.emit("static PyTypeObject *%s_type;" % name, 0)
|
---|
368 | if sum.attributes:
|
---|
369 | self.emit("static char *%s_attributes[] = {" % name, 0)
|
---|
370 | for a in sum.attributes:
|
---|
371 | self.emit('"%s",' % a.name, 1)
|
---|
372 | self.emit("};", 0)
|
---|
373 | ptype = "void*"
|
---|
374 | if is_simple(sum):
|
---|
375 | ptype = get_c_type(name)
|
---|
376 | tnames = []
|
---|
377 | for t in sum.types:
|
---|
378 | tnames.append(str(t.name)+"_singleton")
|
---|
379 | tnames = ", *".join(tnames)
|
---|
380 | self.emit("static PyObject *%s;" % tnames, 0)
|
---|
381 | self.emit("static PyObject* ast2obj_%s(%s);" % (name, ptype), 0)
|
---|
382 | for t in sum.types:
|
---|
383 | self.visitConstructor(t, name)
|
---|
384 |
|
---|
385 | def visitConstructor(self, cons, name):
|
---|
386 | self.emit("static PyTypeObject *%s_type;" % cons.name, 0)
|
---|
387 | if cons.fields:
|
---|
388 | self.emit("static char *%s_fields[]={" % cons.name, 0)
|
---|
389 | for t in cons.fields:
|
---|
390 | self.emit('"%s",' % t.name, 1)
|
---|
391 | self.emit("};",0)
|
---|
392 |
|
---|
393 | class PyTypesVisitor(PickleVisitor):
|
---|
394 |
|
---|
395 | def visitModule(self, mod):
|
---|
396 | self.emit("""
|
---|
397 | static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int num_fields)
|
---|
398 | {
|
---|
399 | PyObject *fnames, *result;
|
---|
400 | int i;
|
---|
401 | if (num_fields) {
|
---|
402 | fnames = PyTuple_New(num_fields);
|
---|
403 | if (!fnames) return NULL;
|
---|
404 | } else {
|
---|
405 | fnames = Py_None;
|
---|
406 | Py_INCREF(Py_None);
|
---|
407 | }
|
---|
408 | for(i=0; i < num_fields; i++) {
|
---|
409 | PyObject *field = PyString_FromString(fields[i]);
|
---|
410 | if (!field) {
|
---|
411 | Py_DECREF(fnames);
|
---|
412 | return NULL;
|
---|
413 | }
|
---|
414 | PyTuple_SET_ITEM(fnames, i, field);
|
---|
415 | }
|
---|
416 | result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}",
|
---|
417 | type, base, "_fields", fnames, "__module__", "_ast");
|
---|
418 | Py_DECREF(fnames);
|
---|
419 | return (PyTypeObject*)result;
|
---|
420 | }
|
---|
421 |
|
---|
422 | static int add_attributes(PyTypeObject* type, char**attrs, int num_fields)
|
---|
423 | {
|
---|
424 | int i, result;
|
---|
425 | PyObject *s, *l = PyList_New(num_fields);
|
---|
426 | if (!l) return 0;
|
---|
427 | for(i = 0; i < num_fields; i++) {
|
---|
428 | s = PyString_FromString(attrs[i]);
|
---|
429 | if (!s) {
|
---|
430 | Py_DECREF(l);
|
---|
431 | return 0;
|
---|
432 | }
|
---|
433 | PyList_SET_ITEM(l, i, s);
|
---|
434 | }
|
---|
435 | result = PyObject_SetAttrString((PyObject*)type, "_attributes", l) >= 0;
|
---|
436 | Py_DECREF(l);
|
---|
437 | return result;
|
---|
438 | }
|
---|
439 |
|
---|
440 | static PyObject* ast2obj_list(asdl_seq *seq, PyObject* (*func)(void*))
|
---|
441 | {
|
---|
442 | int i, n = asdl_seq_LEN(seq);
|
---|
443 | PyObject *result = PyList_New(n);
|
---|
444 | PyObject *value;
|
---|
445 | if (!result)
|
---|
446 | return NULL;
|
---|
447 | for (i = 0; i < n; i++) {
|
---|
448 | value = func(asdl_seq_GET(seq, i));
|
---|
449 | if (!value) {
|
---|
450 | Py_DECREF(result);
|
---|
451 | return NULL;
|
---|
452 | }
|
---|
453 | PyList_SET_ITEM(result, i, value);
|
---|
454 | }
|
---|
455 | return result;
|
---|
456 | }
|
---|
457 |
|
---|
458 | static PyObject* ast2obj_object(void *o)
|
---|
459 | {
|
---|
460 | if (!o)
|
---|
461 | o = Py_None;
|
---|
462 | Py_INCREF((PyObject*)o);
|
---|
463 | return (PyObject*)o;
|
---|
464 | }
|
---|
465 | #define ast2obj_identifier ast2obj_object
|
---|
466 | #define ast2obj_string ast2obj_object
|
---|
467 | static PyObject* ast2obj_bool(bool b)
|
---|
468 | {
|
---|
469 | return PyBool_FromLong(b);
|
---|
470 | }
|
---|
471 |
|
---|
472 | static PyObject* ast2obj_int(bool b)
|
---|
473 | {
|
---|
474 | return PyInt_FromLong(b);
|
---|
475 | }
|
---|
476 | """, 0, reflow=False)
|
---|
477 |
|
---|
478 | self.emit("static int init_types(void)",0)
|
---|
479 | self.emit("{", 0)
|
---|
480 | self.emit("static int initialized;", 1)
|
---|
481 | self.emit("if (initialized) return 1;", 1)
|
---|
482 | self.emit('AST_type = make_type("AST", &PyBaseObject_Type, NULL, 0);', 1)
|
---|
483 | for dfn in mod.dfns:
|
---|
484 | self.visit(dfn)
|
---|
485 | self.emit("initialized = 1;", 1)
|
---|
486 | self.emit("return 1;", 1);
|
---|
487 | self.emit("}", 0)
|
---|
488 |
|
---|
489 | def visitProduct(self, prod, name):
|
---|
490 | if prod.fields:
|
---|
491 | fields = name.value+"_fields"
|
---|
492 | else:
|
---|
493 | fields = "NULL"
|
---|
494 | self.emit('%s_type = make_type("%s", AST_type, %s, %d);' %
|
---|
495 | (name, name, fields, len(prod.fields)), 1)
|
---|
496 | self.emit("if (!%s_type) return 0;" % name, 1)
|
---|
497 |
|
---|
498 | def visitSum(self, sum, name):
|
---|
499 | self.emit('%s_type = make_type("%s", AST_type, NULL, 0);' % (name, name), 1)
|
---|
500 | self.emit("if (!%s_type) return 0;" % name, 1)
|
---|
501 | if sum.attributes:
|
---|
502 | self.emit("if (!add_attributes(%s_type, %s_attributes, %d)) return 0;" %
|
---|
503 | (name, name, len(sum.attributes)), 1)
|
---|
504 | else:
|
---|
505 | self.emit("if (!add_attributes(%s_type, NULL, 0)) return 0;" % name, 1)
|
---|
506 | simple = is_simple(sum)
|
---|
507 | for t in sum.types:
|
---|
508 | self.visitConstructor(t, name, simple)
|
---|
509 |
|
---|
510 | def visitConstructor(self, cons, name, simple):
|
---|
511 | if cons.fields:
|
---|
512 | fields = cons.name.value+"_fields"
|
---|
513 | else:
|
---|
514 | fields = "NULL"
|
---|
515 | self.emit('%s_type = make_type("%s", %s_type, %s, %d);' %
|
---|
516 | (cons.name, cons.name, name, fields, len(cons.fields)), 1)
|
---|
517 | self.emit("if (!%s_type) return 0;" % cons.name, 1)
|
---|
518 | if simple:
|
---|
519 | self.emit("%s_singleton = PyType_GenericNew(%s_type, NULL, NULL);" %
|
---|
520 | (cons.name, cons.name), 1)
|
---|
521 | self.emit("if (!%s_singleton) return 0;" % cons.name, 1)
|
---|
522 |
|
---|
523 | class ASTModuleVisitor(PickleVisitor):
|
---|
524 |
|
---|
525 | def visitModule(self, mod):
|
---|
526 | self.emit("PyMODINIT_FUNC", 0)
|
---|
527 | self.emit("init_ast(void)", 0)
|
---|
528 | self.emit("{", 0)
|
---|
529 | self.emit("PyObject *m, *d;", 1)
|
---|
530 | self.emit("if (!init_types()) return;", 1)
|
---|
531 | self.emit('m = Py_InitModule3("_ast", NULL, NULL);', 1)
|
---|
532 | self.emit("if (!m) return;", 1)
|
---|
533 | self.emit("d = PyModule_GetDict(m);", 1)
|
---|
534 | self.emit('if (PyDict_SetItemString(d, "AST", (PyObject*)AST_type) < 0) return;', 1)
|
---|
535 | self.emit('if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)', 1)
|
---|
536 | self.emit("return;", 2)
|
---|
537 | # Value of version: "$Revision: 45390 $"
|
---|
538 | self.emit('if (PyModule_AddStringConstant(m, "__version__", "%s") < 0)' % mod.version.value[12:-3], 1)
|
---|
539 | self.emit("return;", 2)
|
---|
540 | for dfn in mod.dfns:
|
---|
541 | self.visit(dfn)
|
---|
542 | self.emit("}", 0)
|
---|
543 |
|
---|
544 | def visitProduct(self, prod, name):
|
---|
545 | self.addObj(name)
|
---|
546 |
|
---|
547 | def visitSum(self, sum, name):
|
---|
548 | self.addObj(name)
|
---|
549 | for t in sum.types:
|
---|
550 | self.visitConstructor(t, name)
|
---|
551 |
|
---|
552 | def visitConstructor(self, cons, name):
|
---|
553 | self.addObj(cons.name)
|
---|
554 |
|
---|
555 | def addObj(self, name):
|
---|
556 | self.emit('if (PyDict_SetItemString(d, "%s", (PyObject*)%s_type) < 0) return;' % (name, name), 1)
|
---|
557 |
|
---|
558 | _SPECIALIZED_SEQUENCES = ('stmt', 'expr')
|
---|
559 |
|
---|
560 | def find_sequence(fields, doing_specialization):
|
---|
561 | """Return True if any field uses a sequence."""
|
---|
562 | for f in fields:
|
---|
563 | if f.seq:
|
---|
564 | if not doing_specialization:
|
---|
565 | return True
|
---|
566 | if str(f.type) not in _SPECIALIZED_SEQUENCES:
|
---|
567 | return True
|
---|
568 | return False
|
---|
569 |
|
---|
570 | def has_sequence(types, doing_specialization):
|
---|
571 | for t in types:
|
---|
572 | if find_sequence(t.fields, doing_specialization):
|
---|
573 | return True
|
---|
574 | return False
|
---|
575 |
|
---|
576 |
|
---|
577 | class StaticVisitor(PickleVisitor):
|
---|
578 | CODE = '''Very simple, always emit this static code. Overide CODE'''
|
---|
579 |
|
---|
580 | def visit(self, object):
|
---|
581 | self.emit(self.CODE, 0, reflow=False)
|
---|
582 |
|
---|
583 | class ObjVisitor(PickleVisitor):
|
---|
584 |
|
---|
585 | def func_begin(self, name):
|
---|
586 | ctype = get_c_type(name)
|
---|
587 | self.emit("PyObject*", 0)
|
---|
588 | self.emit("ast2obj_%s(void* _o)" % (name), 0)
|
---|
589 | self.emit("{", 0)
|
---|
590 | self.emit("%s o = (%s)_o;" % (ctype, ctype), 1)
|
---|
591 | self.emit("PyObject *result = NULL, *value = NULL;", 1)
|
---|
592 | self.emit('if (!o) {', 1)
|
---|
593 | self.emit("Py_INCREF(Py_None);", 2)
|
---|
594 | self.emit('return Py_None;', 2)
|
---|
595 | self.emit("}", 1)
|
---|
596 | self.emit('', 0)
|
---|
597 |
|
---|
598 | def func_end(self):
|
---|
599 | self.emit("return result;", 1)
|
---|
600 | self.emit("failed:", 0)
|
---|
601 | self.emit("Py_XDECREF(value);", 1)
|
---|
602 | self.emit("Py_XDECREF(result);", 1)
|
---|
603 | self.emit("return NULL;", 1)
|
---|
604 | self.emit("}", 0)
|
---|
605 | self.emit("", 0)
|
---|
606 |
|
---|
607 | def visitSum(self, sum, name):
|
---|
608 | if is_simple(sum):
|
---|
609 | self.simpleSum(sum, name)
|
---|
610 | return
|
---|
611 | self.func_begin(name)
|
---|
612 | self.emit("switch (o->kind) {", 1)
|
---|
613 | for i in range(len(sum.types)):
|
---|
614 | t = sum.types[i]
|
---|
615 | self.visitConstructor(t, i + 1, name)
|
---|
616 | self.emit("}", 1)
|
---|
617 | for a in sum.attributes:
|
---|
618 | self.emit("value = ast2obj_%s(o->%s);" % (a.type, a.name), 1)
|
---|
619 | self.emit("if (!value) goto failed;", 1)
|
---|
620 | self.emit('if (PyObject_SetAttrString(result, "%s", value) < 0)' % a.name, 1)
|
---|
621 | self.emit('goto failed;', 2)
|
---|
622 | self.emit('Py_DECREF(value);', 1)
|
---|
623 | self.func_end()
|
---|
624 |
|
---|
625 | def simpleSum(self, sum, name):
|
---|
626 | self.emit("PyObject* ast2obj_%s(%s_ty o)" % (name, name), 0)
|
---|
627 | self.emit("{", 0)
|
---|
628 | self.emit("switch(o) {", 1)
|
---|
629 | for t in sum.types:
|
---|
630 | self.emit("case %s:" % t.name, 2)
|
---|
631 | self.emit("Py_INCREF(%s_singleton);" % t.name, 3)
|
---|
632 | self.emit("return %s_singleton;" % t.name, 3)
|
---|
633 | self.emit("}", 1)
|
---|
634 | self.emit("return NULL; /* cannot happen */", 1)
|
---|
635 | self.emit("}", 0)
|
---|
636 |
|
---|
637 | def visitProduct(self, prod, name):
|
---|
638 | self.func_begin(name)
|
---|
639 | self.emit("result = PyType_GenericNew(%s_type, NULL, NULL);" % name, 1);
|
---|
640 | self.emit("if (!result) return NULL;", 1)
|
---|
641 | for field in prod.fields:
|
---|
642 | self.visitField(field, name, 1, True)
|
---|
643 | self.func_end()
|
---|
644 |
|
---|
645 | def visitConstructor(self, cons, enum, name):
|
---|
646 | self.emit("case %s_kind:" % cons.name, 1)
|
---|
647 | self.emit("result = PyType_GenericNew(%s_type, NULL, NULL);" % cons.name, 2);
|
---|
648 | self.emit("if (!result) goto failed;", 2)
|
---|
649 | for f in cons.fields:
|
---|
650 | self.visitField(f, cons.name, 2, False)
|
---|
651 | self.emit("break;", 2)
|
---|
652 |
|
---|
653 | def visitField(self, field, name, depth, product):
|
---|
654 | def emit(s, d):
|
---|
655 | self.emit(s, depth + d)
|
---|
656 | if product:
|
---|
657 | value = "o->%s" % field.name
|
---|
658 | else:
|
---|
659 | value = "o->v.%s.%s" % (name, field.name)
|
---|
660 | self.set(field, value, depth)
|
---|
661 | emit("if (!value) goto failed;", 0)
|
---|
662 | emit('if (PyObject_SetAttrString(result, "%s", value) == -1)' % field.name, 0)
|
---|
663 | emit("goto failed;", 1)
|
---|
664 | emit("Py_DECREF(value);", 0)
|
---|
665 |
|
---|
666 | def emitSeq(self, field, value, depth, emit):
|
---|
667 | emit("seq = %s;" % value, 0)
|
---|
668 | emit("n = asdl_seq_LEN(seq);", 0)
|
---|
669 | emit("value = PyList_New(n);", 0)
|
---|
670 | emit("if (!value) goto failed;", 0)
|
---|
671 | emit("for (i = 0; i < n; i++) {", 0)
|
---|
672 | self.set("value", field, "asdl_seq_GET(seq, i)", depth + 1)
|
---|
673 | emit("if (!value1) goto failed;", 1)
|
---|
674 | emit("PyList_SET_ITEM(value, i, value1);", 1)
|
---|
675 | emit("value1 = NULL;", 1)
|
---|
676 | emit("}", 0)
|
---|
677 |
|
---|
678 | def set(self, field, value, depth):
|
---|
679 | if field.seq:
|
---|
680 | # XXX should really check for is_simple, but that requires a symbol table
|
---|
681 | if field.type.value == "cmpop":
|
---|
682 | # While the sequence elements are stored as void*,
|
---|
683 | # ast2obj_cmpop expects an enum
|
---|
684 | self.emit("{", depth)
|
---|
685 | self.emit("int i, n = asdl_seq_LEN(%s);" % value, depth+1)
|
---|
686 | self.emit("value = PyList_New(n);", depth+1)
|
---|
687 | self.emit("if (!value) goto failed;", depth+1)
|
---|
688 | self.emit("for(i = 0; i < n; i++)", depth+1)
|
---|
689 | # This cannot fail, so no need for error handling
|
---|
690 | self.emit("PyList_SET_ITEM(value, i, ast2obj_cmpop((cmpop_ty)asdl_seq_GET(%s, i)));" % value,
|
---|
691 | depth+2, reflow=False)
|
---|
692 | self.emit("}", depth)
|
---|
693 | else:
|
---|
694 | self.emit("value = ast2obj_list(%s, ast2obj_%s);" % (value, field.type), depth)
|
---|
695 | else:
|
---|
696 | ctype = get_c_type(field.type)
|
---|
697 | self.emit("value = ast2obj_%s(%s);" % (field.type, value), depth, reflow=False)
|
---|
698 |
|
---|
699 |
|
---|
700 | class PartingShots(StaticVisitor):
|
---|
701 |
|
---|
702 | CODE = """
|
---|
703 | PyObject* PyAST_mod2obj(mod_ty t)
|
---|
704 | {
|
---|
705 | init_types();
|
---|
706 | return ast2obj_mod(t);
|
---|
707 | }
|
---|
708 | """
|
---|
709 |
|
---|
710 | class ChainOfVisitors:
|
---|
711 | def __init__(self, *visitors):
|
---|
712 | self.visitors = visitors
|
---|
713 |
|
---|
714 | def visit(self, object):
|
---|
715 | for v in self.visitors:
|
---|
716 | v.visit(object)
|
---|
717 | v.emit("", 0)
|
---|
718 |
|
---|
719 | def main(srcfile):
|
---|
720 | argv0 = sys.argv[0]
|
---|
721 | components = argv0.split(os.sep)
|
---|
722 | argv0 = os.sep.join(components[-2:])
|
---|
723 | auto_gen_msg = '/* File automatically generated by %s */\n' % argv0
|
---|
724 | mod = asdl.parse(srcfile)
|
---|
725 | if not asdl.check(mod):
|
---|
726 | sys.exit(1)
|
---|
727 | if INC_DIR:
|
---|
728 | p = "%s/%s-ast.h" % (INC_DIR, mod.name)
|
---|
729 | f = open(p, "wb")
|
---|
730 | print >> f, auto_gen_msg
|
---|
731 | print >> f, '#include "asdl.h"\n'
|
---|
732 | c = ChainOfVisitors(TypeDefVisitor(f),
|
---|
733 | StructVisitor(f),
|
---|
734 | PrototypeVisitor(f),
|
---|
735 | )
|
---|
736 | c.visit(mod)
|
---|
737 | print >>f, "PyObject* PyAST_mod2obj(mod_ty t);"
|
---|
738 | f.close()
|
---|
739 |
|
---|
740 | if SRC_DIR:
|
---|
741 | p = os.path.join(SRC_DIR, str(mod.name) + "-ast.c")
|
---|
742 | f = open(p, "wb")
|
---|
743 | print >> f, auto_gen_msg
|
---|
744 | print >> f, '#include "Python.h"'
|
---|
745 | print >> f, '#include "%s-ast.h"' % mod.name
|
---|
746 | print >> f
|
---|
747 | print >>f, "static PyTypeObject* AST_type;"
|
---|
748 | v = ChainOfVisitors(
|
---|
749 | PyTypesDeclareVisitor(f),
|
---|
750 | PyTypesVisitor(f),
|
---|
751 | FunctionVisitor(f),
|
---|
752 | ObjVisitor(f),
|
---|
753 | ASTModuleVisitor(f),
|
---|
754 | PartingShots(f),
|
---|
755 | )
|
---|
756 | v.visit(mod)
|
---|
757 | f.close()
|
---|
758 |
|
---|
759 | if __name__ == "__main__":
|
---|
760 | import sys
|
---|
761 | import getopt
|
---|
762 |
|
---|
763 | INC_DIR = ''
|
---|
764 | SRC_DIR = ''
|
---|
765 | opts, args = getopt.getopt(sys.argv[1:], "h:c:")
|
---|
766 | if len(opts) != 1:
|
---|
767 | print "Must specify exactly one output file"
|
---|
768 | sys.exit(1)
|
---|
769 | for o, v in opts:
|
---|
770 | if o == '-h':
|
---|
771 | INC_DIR = v
|
---|
772 | if o == '-c':
|
---|
773 | SRC_DIR = v
|
---|
774 | if len(args) != 1:
|
---|
775 | print "Must specify single input file"
|
---|
776 | sys.exit(1)
|
---|
777 | main(args[0])
|
---|