class CodeVisitor(pc_util.Visitor):
def __init__(self, name, root):
self.__root = root
+ self.__attrs = {}
self.__header = object()
self.__footer = object()
self.__code = collections.defaultdict(lambda: pc_util.Code())
def __getitem__(self, node):
return self.__code[node]
+ def __setitem__(self, node, code):
+ self.__code[node] = code
+
def transient(self, node,
value="UINT64_C(0)",
bits="(uint8_t)OPPC_XLEN"):
self.traverse(root=call)
return call
- def ternary(self, node):
+ def fixup_ternary(self, node):
self[node].clear()
test = self.call(name="oppc_bool", node=node, code=[
self[node.test],
self[node].emit(stmt=stmt, level=level)
self[node].emit(stmt=")")
+ def fixup_attr(self, node, assign=False):
+ root = node
+ code = tuple(self[root])
+ attribute_or_subscript = (
+ pc_ast.Attribute,
+ pc_ast.SubscriptExpr,
+ pc_ast.RangeSubscriptExpr,
+ )
+ while isinstance(node.subject, attribute_or_subscript):
+ node = node.subject
+
+ def wrap(code):
+ def wrap(item):
+ (level, stmt) = item
+ if not (not stmt or
+ stmt.startswith("/*") or
+ stmt.endswith((",", "(", "{", "*/"))):
+ stmt = (stmt + ",")
+ return (level, stmt)
+
+ return tuple(map(wrap, code))
+
+ code = pc_util.Code()
+ for (level, stmt) in wrap(self[node.subject]):
+ code.emit(stmt=stmt, level=level)
+ for (level, stmt) in wrap(self[root]):
+ code.emit(stmt=stmt, level=level)
+
+ # discard the last comma
+ (level, stmt) = code[-1]
+ code[-1] = (level, stmt[:-1])
+
+ if not assign:
+ call = self.call(name="oppc_attr", node=root, code=[
+ code,
+ ])
+ code = self[call]
+ self[root] = code
+
@contextlib.contextmanager
def pseudocode(self, node):
for (level, stmt) in self.__pseudocode[node]:
self.__regfetch[str(node.rvalue)].append(node.rvalue)
if isinstance(node.rvalue, pc_ast.IfExpr):
- self.ternary(node=node.rvalue)
+ self.fixup_ternary(node=node.rvalue)
+ if isinstance(node.lvalue, pc_ast.Attribute):
+ self.fixup_attr(node=node.lvalue, assign=True)
+ if isinstance(node.rvalue, pc_ast.Attribute):
+ self.fixup_attr(node=node.rvalue)
if isinstance(node.lvalue, pc_ast.SubscriptExpr):
call = self.call(name="oppc_subscript_assign", node=node, stmt=True, code=[
self[node.lvalue.end],
self[node.rvalue],
])
+ elif isinstance(node.lvalue, pc_ast.Attribute):
+ call = self.call(name="oppc_attr_assign", stmt=True, node=node, code=[
+ self[node.lvalue],
+ self[node.rvalue],
+ ])
else:
call = self.call(name="oppc_assign", stmt=True, node=node, code=[
self[node.lvalue],
pc_ast.LtU, pc_ast.GtU,
)
if isinstance(node.left, pc_ast.IfExpr):
- self.ternary(node=node.left)
+ self.fixup_ternary(node=node.left)
if isinstance(node.right, pc_ast.IfExpr):
- self.ternary(node=node.right)
+ self.fixup_ternary(node=node.right)
+ if isinstance(node.left, pc_ast.Attribute):
+ self.fixup_attr(node=node.left)
+ if isinstance(node.right, pc_ast.Attribute):
+ self.fixup_attr(node=node.right)
if isinstance(node.op, comparison):
call = self.call(name=str(self[node.op]), node=node, code=[
def UnaryExpr(self, node):
yield node
if isinstance(node.value, pc_ast.IfExpr):
- self.ternary(node=node.value)
+ self.fixup_ternary(node=node.value)
call = self.call(name=str(self[node.op]), node=node, code=[
self[node.value],
])
for (level, stmt) in self[call]:
self[node].emit(stmt=stmt, level=level)
+ @pc_util.Hook(pc_ast.Attribute.Name)
+ def AttributeName(self, node):
+ yield node
+
+ @pc_util.Hook(pc_ast.Attribute)
+ def Attribute(self, node):
+ yield node
+ attr = str(self.__pseudocode[node])
+ symbol = f"OPPC_ATTR_{attr.replace('.', '_')}"
+ self[node].emit(f"/* {attr} */")
+ self[node].emit(stmt=symbol)
+ self.__attrs[node] = symbol
+
@pc_util.Hook(pc_ast.Symbol)
def Symbol(self, node):
yield node