Skip to content

symbol_table

Symbol Table module for ASTx.

The SymbolTable class offered here allows the definition of scopes, so the variable or function would be available in specifics scopes.

Scope

Scope(scope_node_class: Type[ScopeNodeBase] = ScopeNode)

Organize the ASTx objects according to the scope.

Source code in src/astx/symbol_table.py
55
56
57
58
59
60
61
62
63
64
65
66
67
def __init__(
    self,
    scope_node_class: Type[ScopeNodeBase] = ScopeNode,
) -> None:
    """Initialize the scope."""
    self.nodes: dict[int, ScopeNodeBase] = {}
    self.current = None
    self.previous = None
    self.scope_node_class = scope_node_class

    self.add("root")

    self.scope_node_class.default_parent = self.current

add

add(name: str, parent: Optional[ScopeNodeBase] = None, change_current: bool = True) -> ScopeNodeBase

Add a new node in the scope.

Source code in src/astx/symbol_table.py
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def add(
    self,
    name: str,
    parent: Optional[ScopeNodeBase] = None,
    change_current: bool = True,
) -> ScopeNodeBase:
    """Add a new node in the scope."""
    node = self.scope_node_class(name, parent)

    # The use of id(node) as keys in the nodes dictionary is generally
    # fine, but be aware that this approach may lead to potential issues
    # if the id() of a node is reused after its destruction. It's #
    # unlikely to happen in the current code, but it's something to be
    # aware of.
    self.nodes[id(node)] = node

    if len(self.nodes) == 1 or change_current:
        self.previous = self.current
        self.current = self.nodes[id(node)]

    return node

destroy

destroy(node: ScopeNodeBase) -> None

Destroy the current scope.

Source code in src/astx/symbol_table.py
101
102
103
104
105
def destroy(self, node: ScopeNodeBase) -> None:
    """Destroy the current scope."""
    del self.nodes[id(node)]
    self.current = self.previous
    self.previous = None

get_first

get_first() -> ScopeNodeBase

Get the first node in the scope.

Source code in src/astx/symbol_table.py
91
92
93
94
def get_first(self) -> ScopeNodeBase:
    """Get the first node in the scope."""
    node_id = next(iter(self.nodes.keys()))
    return self.nodes[node_id]

get_last

get_last() -> ScopeNodeBase

Get the latest node in the scope.

Source code in src/astx/symbol_table.py
96
97
98
99
def get_last(self) -> ScopeNodeBase:
    """Get the latest node in the scope."""
    node_id = list(self.nodes.keys())[-1]
    return self.nodes[node_id]

set_default_parent

set_default_parent(node: ScopeNodeBase) -> None

Set default parent for the current scope.

Source code in src/astx/symbol_table.py
107
108
109
def set_default_parent(self, node: ScopeNodeBase) -> None:
    """Set default parent for the current scope."""
    self.scope_node_class.default_parent = node

ScopeNode

ScopeNode(name: str, parent: Optional[ScopeNodeBase] = None)

Bases: ScopeNodeBase

Scope node organize the scope in different levels in the stack.

Source code in src/astx/symbol_table.py
28
29
30
31
32
33
34
35
36
def __init__(
    self, name: str, parent: Optional[ScopeNodeBase] = None
) -> None:
    """Initialize ScopeNodeBase."""
    self.parent: Optional[ScopeNodeBase] = (
        parent or ScopeNodeBase.default_parent
    )
    self.name: str = name
    self.named_expr: dict[str, NamedExpr] = {}

ScopeNodeBase

ScopeNodeBase(name: str, parent: Optional[ScopeNodeBase] = None)

ScopeNodeBase is the base used for the nodes (levels) in the scope.

Source code in src/astx/symbol_table.py
28
29
30
31
32
33
34
35
36
def __init__(
    self, name: str, parent: Optional[ScopeNodeBase] = None
) -> None:
    """Initialize ScopeNodeBase."""
    self.parent: Optional[ScopeNodeBase] = (
        parent or ScopeNodeBase.default_parent
    )
    self.name: str = name
    self.named_expr: dict[str, NamedExpr] = {}

SymbolTable

SymbolTable()

Symbol Table for ASTx.

Source code in src/astx/symbol_table.py
118
119
def __init__(self) -> None:
    self.scopes = Scope()

define

define(expr: NamedExpr) -> None

Define a new named expression inside the scoped stack.

Source code in src/astx/symbol_table.py
121
122
123
124
125
def define(self, expr: NamedExpr) -> None:
    """Define a new named expression inside the scoped stack."""
    if not self.scopes.current:
        raise Exception("SymbolTable: No scope active.")
    self.scopes.current.named_expr[expr.name] = expr

lookup

lookup(name: str) -> NamedExpr

Get a named expression from the scope stack.

Source code in src/astx/symbol_table.py
139
140
141
142
143
144
145
146
def lookup(self, name: str) -> NamedExpr:
    """Get a named expression from the scope stack."""
    scope = self.scopes.current
    while scope is not None:
        if name in scope.named_expr:
            return scope.named_expr[name]
        scope = scope.parent
    raise NameError(f"Name '{name}' is not defined")

update

update(expr: NamedExpr) -> None

Update the expression on the SymbolTable.

It is useful mainly for updating the comment of the expression.

Source code in src/astx/symbol_table.py
127
128
129
130
131
132
133
134
135
136
137
def update(self, expr: NamedExpr) -> None:
    """
    Update the expression on the SymbolTable.

    It is useful mainly for updating the comment of the expression.
    """
    if not self.scopes.current:
        raise Exception("SymbolTable: No scope active.")
    if expr.name not in self.scopes.current.named_expr:
        raise Exception("This name doesn't exist in the SymbolTable.")
    self.scopes.current.named_expr[expr.name] = expr