Skip to content

Commit

Permalink
Scope code cleanup.
Browse files Browse the repository at this point in the history
Track if identifier is a candidate for mangling and is part of an
expression. This allows to simplify some code in scope and name
mangling visitors.
  • Loading branch information
rspivak committed Jun 16, 2011
1 parent 9319217 commit 08607e1
Show file tree
Hide file tree
Showing 4 changed files with 357 additions and 371 deletions.
26 changes: 18 additions & 8 deletions src/slimit/ast.py
Expand Up @@ -153,6 +153,7 @@ class VarStatement(Node):
class VarDecl(Node):
def __init__(self, identifier, initializer=None):
self.identifier = identifier
self.identifier._mangle_candidate = True
self.initializer = initializer

def children(self):
Expand Down Expand Up @@ -329,23 +330,32 @@ def __init__(self, value):
def children(self):
return []

class FuncDecl(Node):

class FuncBase(Node):
def __init__(self, identifier, parameters, elements):
self.identifier = identifier
self.parameters = parameters if parameters is not None else []
self.elements = elements if elements is not None else []
self._init_ids()

def _init_ids(self):
# function declaration/expression name and parameters are identifiers
# and therefore are subject to name mangling. we need to mark them.
if self.identifier is not None:
self.identifier._mangle_candidate = True
for param in self.parameters:
param._mangle_candidate = True

def children(self):
return [self.identifier] + self.parameters + self.elements

class FuncExpr(Node):
def __init__(self, identifier, parameters, elements):
self.identifier = identifier
self.parameters = parameters if parameters is not None else []
self.elements = elements if elements is not None else []
class FuncDecl(FuncBase):
pass

# The only difference is that function expression might not have an identifier
class FuncExpr(FuncBase):
pass

def children(self):
return [self.identifier] + self.parameters + self.elements

class Comma(Node):
def __init__(self, left, right):
Expand Down
30 changes: 18 additions & 12 deletions src/slimit/parser.py
Expand Up @@ -191,20 +191,26 @@ def p_primary_expr(self, p):
"""
p[0] = p[1]

def p_primary_expr_no_brace(self, p):
"""primary_expr_no_brace : THIS
| identifier
| literal
def p_primary_expr_no_brace_1(self, p):
"""primary_expr_no_brace : identifier"""
p[1]._mangle_candidate = True
p[1]._in_expression = True
p[0] = p[1]

def p_primary_expr_no_brace_2(self, p):
"""primary_expr_no_brace : THIS"""
p[0] = ast.This()

def p_primary_expr_no_brace_3(self, p):
"""primary_expr_no_brace : literal
| array_literal
| LPAREN expr RPAREN
"""
if p[1] == 'this':
p[0] = ast.This()
elif len(p) == 2:
p[0] = p[1]
else:
p[2]._parens = True
p[0] = p[2]
p[0] = p[1]

def p_primary_expr_no_brace_4(self, p):
"""primary_expr_no_brace : LPAREN expr RPAREN"""
p[2]._parens = True
p[0] = p[2]

def p_array_literal_1(self, p):
"""array_literal : LBRACKET elision_opt RBRACKET"""
Expand Down
76 changes: 23 additions & 53 deletions src/slimit/visitors/scopevisitor.py
Expand Up @@ -51,15 +51,6 @@ def __init__(self, sym_table):
self.sym_table = sym_table
self.current_scope = sym_table.globals

def visit_Assign(self, node):
# property_assignment
# skip identifier
if node.op == ':' and isinstance(node.left, ast.Identifier):
self.visit(node.right)
else:
self.visit(node.left)
self.visit(node.right)

def visit_VarDecl(self, node):
ident = node.identifier
symbol = VarSymbol(name=ident.value)
Expand Down Expand Up @@ -107,26 +98,20 @@ def visit_FuncDecl(self, node):
class RefVisitor(Visitor):
"""Fill 'ref' attribute in scopes."""

def visit_VarDecl(self, node):
# we skip Identifier node because it's not part of an expression
self.visit(node.initializer)

def visit_FuncDecl(self, node):
# we skip all Identifier nodes because they are not part of expressions
for element in node.elements:
self.visit(element)
# alias
visit_FuncExpr = visit_FuncDecl

def visit_DotAccessor(self, node):
# we skip identifier
self.visit(node.node)

def visit_Identifier(self, node):
if getattr(node, 'scope', None) is not None:
if self._is_id_in_expr(node):
self._fill_scope_refs(node.value, node.scope)

def _fill_scope_refs(self, name, scope):
@staticmethod
def _is_id_in_expr(node):
"""Return True if Identifier node is part of an expression."""
return (
getattr(node, 'scope', None) is not None and
getattr(node, '_in_expression', False)
)

@staticmethod
def _fill_scope_refs(name, scope):
"""Put referenced name in 'ref' dictionary of a scope.
Walks up the scope tree and adds the name to 'ref' of every scope
Expand Down Expand Up @@ -172,37 +157,22 @@ class NameManglerVisitor(Visitor):
mangled names.
"""

def visit_VarDecl(self, node):
self.visit(node.identifier)
self.visit(node.initializer)

def visit_FuncDecl(self, node):
if node.identifier is not None:
self.visit(node.identifier)
@staticmethod
def _is_mangle_candidate(id_node):
"""Return True if Identifier node is a candidate for mangling.
for param in node.parameters:
self.visit(param)

for element in node.elements:
self.visit(element)

visit_FuncExpr = visit_FuncDecl

def visit_Assign(self, node):
# property_assignment
# skip identifier
if node.op == ':' and isinstance(node.left, ast.Identifier):
self.visit(node.right)
else:
self.visit(node.left)
self.visit(node.right)

def visit_DotAccessor(self, node):
self.visit(node.node)
There are 5 cases when Identifier is a mangling candidate:
1. Function declaration identifier
2. Function expression identifier
3. Function declaration/expression parameter
4. Variable declaration identifier
5. Identifier is a part of an expression (primary_expr_no_brace rule)
"""
return getattr(id_node, '_mangle_candidate', False)

def visit_Identifier(self, node):
"""Mangle names."""
if getattr(node, 'scope', None) is None:
if not self._is_mangle_candidate(node):
return
name = node.value
symbol = node.scope.resolve(node.value)
Expand Down
596 changes: 298 additions & 298 deletions src/slimit/yacctab.py

Large diffs are not rendered by default.

0 comments on commit 08607e1

Please sign in to comment.