Symbol table problem

I’m trying to write some thing to match AST up with symbol table, but I encounter this problem.

import symtable

script = """
[[i for i in range(10)], [j for j in range(10)]]
"""

symt = symtable.symtable(script, "test.py", "exec")
print(symt.get_children()) 
# [<Function SymbolTable for listcomp in test.py>, <Function SymbolTable for listcomp in test.py>]

I got 2 symbol tables from symt.get_children(). But I don’t know which one matchs the first list comprehension and which one match the second.
get_lineno() may work in some other cases, but in this case, these two namespace are in one line.

I’ve tried a hacky way to get the col_offset of the symtable.
Then I can use the col_offset and the line number to find the ast node.
This works well. But is there any non-hacking way to solve this problem?

import ctypes
import symtable

Py_ssize_t = ctypes.c_int64 if ctypes.sizeof(ctypes.c_void_p) == 8 else ctypes.c_int32


class PyObject(ctypes.Structure):
    _fields_ = [
        ("ob_refcnt", Py_ssize_t),
        ("ob_type", ctypes.c_void_p),  # a pointer to type obj
    ]


class SymbolTableEntry(ctypes.Structure):
    _fields_ = [
        ("ob_base", PyObject),
        ("ste_id", ctypes.py_object),
        ("ste_symbols", ctypes.py_object),
        ("ste_name", ctypes.py_object),
        ("ste_varnames", ctypes.py_object),
        ("ste_children", ctypes.py_object),
        ("ste_directives", ctypes.py_object),
        ("ste_type", ctypes.c_int),  # enumerate type
        ("ste_nested", ctypes.c_int),
        ("ste_free", ctypes.c_uint, 1),
        ("ste_child_free", ctypes.c_uint, 1),
        ("ste_generator", ctypes.c_uint, 1),
        ("ste_coroutine", ctypes.c_uint, 1),
        ("ste_comprehension", ctypes.c_int),  # enumerate type
        ("ste_varargs", ctypes.c_uint, 1),
        ("ste_varkeywords", ctypes.c_uint, 1),
        ("ste_returns_value", ctypes.c_uint, 1),
        ("ste_needs_class_closure", ctypes.c_uint, 1),
        ("ste_comp_iter_target", ctypes.c_uint, 1),
        ("ste_comp_iter_expr", ctypes.c_int),
        ("ste_lineno", ctypes.c_int),
        ("ste_col_offset", ctypes.c_int),
        ("ste_end_lineno", ctypes.c_int),
        ("ste_end_col_offset", ctypes.c_int),
        ("ste_opt_lineno", ctypes.c_int),
        ("ste_opt_col_offset", ctypes.c_int),
        ("ste_table", ctypes.c_void_p),  # a pointer to the symbol table struct
    ]


def get_symtable_col_offset(symt: symtable.symtable):
    p_ste = ctypes.cast(
        ctypes.c_void_p(id(symt._table)),
        ctypes.POINTER(SymbolTableEntry),
    )
    return p_ste.contents.ste_col_offset


script = """
[[i for i in range(10)],[j for j in range(10)]]
"""

symt = symtable.symtable(script, "test.py", "exec")
symt = symt.get_children()[1]
print(get_symtable_col_offset(symt))  # 24