Skip to content

Commit 940b430

Browse files
committed
compile: symtable: test and fix flags
1 parent 44e6f63 commit 940b430

File tree

7 files changed

+415
-171
lines changed

7 files changed

+415
-171
lines changed

compile/make_symtable_test.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@
88
import subprocess
99
import dis
1010
from symtable import symtable
11-
12-
# FIXME test errors too
11+
try:
12+
# run ./build.sh in the readsymtab directory to create this module
13+
from readsymtab import readsymtab
14+
use_readsymtab = True
15+
except ImportError:
16+
import ctypes
17+
use_readsymtab = False
18+
print("Using compiler dependent code to read bitfields - compile readsymtab module to be sure!")
1319

1420
inp = [
1521
('''1''', "eval"),
@@ -103,12 +109,36 @@ def dump_symtable(st):
103109
out += 'Lineno:%s,\n' % st.get_lineno() # Return the number of the first line in the block this table represents.
104110
out += 'Unoptimized:%s,\n' % dump_flags(st._table.optimized, OPT_FLAGS) # Return False if the locals in this table can be optimized.
105111
out += 'Nested:%s,\n' % dump_bool(st.is_nested()) # Return True if the block is a nested class or function.
112+
113+
if use_readsymtab:
114+
# Use readsymtab modules to read the bitfields which aren't normally exported
115+
free, child_free, generator, varargs, varkeywords, returns_value, needs_class_closure = readsymtab(st._table)
116+
out += 'Free:%s,\n' % dump_bool(free)
117+
out += 'ChildFree:%s,\n' % dump_bool(child_free)
118+
out += 'Generator:%s,\n' % dump_bool(generator)
119+
out += 'Varargs:%s,\n' % dump_bool(varargs)
120+
out += 'Varkeywords:%s,\n' % dump_bool(varkeywords)
121+
out += 'ReturnsValue:%s,\n' % dump_bool(returns_value)
122+
out += 'NeedsClassClosure:%s,\n' % dump_bool(needs_class_closure)
123+
else:
124+
# Use ctypes to read the bitfields which aren't normally exported
125+
# FIXME compiler dependent!
126+
base_addr = id(st._table) + ctypes.sizeof(ctypes.c_long)*8+ ctypes.sizeof(ctypes.c_int)*3
127+
flags = int.from_bytes(ctypes.c_int.from_address(base_addr), sys.byteorder)
128+
out += 'Free:%s,\n' % dump_bool(flags & (1 << 0))
129+
out += 'ChildFree:%s,\n' % dump_bool(flags & (1 << 1))
130+
out += 'Generator:%s,\n' % dump_bool(flags & (1 << 2))
131+
out += 'Varargs:%s,\n' % dump_bool(flags & (1 << 3))
132+
out += 'Varkeywords:%s,\n' % dump_bool(flags & (1 << 4))
133+
out += 'ReturnsValue:%s,\n' % dump_bool(flags & (1 << 5))
134+
out += 'NeedsClassClosure:%s,\n' % dump_bool(flags & (1 << 6))
135+
106136
#out += 'Exec:%s,\n' % dump_bool(st.has_exec()) # Return True if the block uses exec.
107137
#out += 'ImportStar:%s,\n' % dump_bool(st.has_import_star()) # Return True if the block uses a starred from-import.
108138
out += 'Varnames:%s,\n' % dump_strings(st._table.varnames)
109139
out += 'Symbols: Symbols{\n'
110140
children = dict()
111-
for name in st.get_identifiers():
141+
for name in sorted(st.get_identifiers()):
112142
s = st.lookup(name)
113143
out += '"%s":%s,\n' % (name, dump_symbol(s))
114144
ns = s.get_namespaces()
@@ -120,7 +150,7 @@ def dump_symtable(st):
120150
raise AssertionError("More than one namespace")
121151
out += '},\n'
122152
out += 'Children:map[string]*SymTable{\n'
123-
for name, symtable in children.items():
153+
for name, symtable in sorted(children.items()):
124154
out += '"%s":%s,\n' % (name, dump_symtable(symtable))
125155
out += '},\n'
126156
out += "}"

compile/readsymtab_module/build.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/sh
2+
set -e
3+
rm -rf build
4+
PYTHON=/opt/python3.4/bin/python3.4
5+
INCLUDE=/opt/python3.4/include/python3.4m
6+
$PYTHON setup.py build_ext --inplace
7+
cp -av *.so *.dll ..
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include <Python.h>
2+
#include "Python-ast.h"
3+
#include "code.h"
4+
#include "symtable.h"
5+
#include "structmember.h"
6+
7+
static PyObject*
8+
readsymtab(PyObject* self, PyObject* args)
9+
{
10+
PyObject* obj;
11+
12+
if (!PyArg_ParseTuple(args, "O", &obj))
13+
return NULL;
14+
15+
if (Py_TYPE(obj) != &PySTEntry_Type) {
16+
fprintf(stderr, "Ooops wrong type\n");
17+
}
18+
19+
PySTEntryObject *st = (PySTEntryObject *)obj;
20+
21+
return Py_BuildValue("(iiiiiii)",
22+
st->ste_free,
23+
st->ste_child_free,
24+
st->ste_generator,
25+
st->ste_varargs,
26+
st->ste_varkeywords,
27+
st->ste_returns_value,
28+
st->ste_needs_class_closure);
29+
}
30+
31+
static PyMethodDef readsymtabmethods[] =
32+
{
33+
{"readsymtab", readsymtab, METH_VARARGS, "Read the symbol table."},
34+
{NULL, NULL, 0, NULL}
35+
};
36+
37+
static struct PyModuleDef readsymtabmodule = {
38+
PyModuleDef_HEAD_INIT,
39+
"readsymtab",
40+
"Read the symbol table.",
41+
-1,
42+
readsymtabmethods,
43+
NULL,
44+
NULL,
45+
NULL,
46+
NULL
47+
};
48+
49+
50+
PyMODINIT_FUNC
51+
PyInit_readsymtab(void)
52+
{
53+
return PyModule_Create(&readsymtabmodule);
54+
}

compile/readsymtab_module/setup.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from distutils.core import setup, Extension
2+
3+
readsymtab = Extension('readsymtab', sources = ['readsymtab.c'])
4+
5+
setup (name = 'readsymtab',
6+
version = '1.0',
7+
description = 'Read the symbol table',
8+
ext_modules = [readsymtab]
9+
)

compile/symtable.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ type SymTable struct {
9999
Generator bool // true if namespace is a generator
100100
Varargs bool // true if block has varargs
101101
Varkeywords bool // true if block has varkeywords
102-
Returns_value bool // true if namespace uses return with an argument
102+
ReturnsValue bool // true if namespace uses return with an argument
103103
NeedsClassClosure bool // for class scopes, true if a closure over __class__ should be created
104-
col_offset int // offset of first line of block
105-
opt_lineno int // lineno of last exec or import *
106-
opt_col_offset int // offset of last exec or import *
107-
tmpname int // counter for listcomp temp vars
104+
// col_offset int // offset of first line of block
105+
// opt_lineno int // lineno of last exec or import *
106+
// opt_col_offset int // offset of last exec or import *
107+
// tmpname int // counter for listcomp temp vars
108108

109109
Symbols Symbols
110110
Global *SymTable // symbol table entry for module
@@ -282,6 +282,11 @@ func (st *SymTable) Parse(Ast ast.Ast) {
282282
}
283283
st.Unoptimized |= optImportStar
284284
}
285+
286+
case *ast.Return:
287+
if node.Value != nil {
288+
st.ReturnsValue = true
289+
}
285290
}
286291
return true
287292
})

0 commit comments

Comments
 (0)