Source code for hdlConvertorAst.to.common

from enum import Enum

from hdlConvertorAst.hdlAst import HdlModuleDec, HdlOp
from hdlConvertorAst.hdlAst._expr import HdlOpType, HdlValueId, HdlValueInt
from hdlConvertorAst.py_ver_compatibility import is_str
from hdlConvertorAst.to.hdlUtils import AutoIndentingStream, iter_with_last
from hdlConvertorAst.to.hdl_ast_visitor import HdlAstVisitor


# https://www.geeksforgeeks.org/operator-precedence-and-associativity-in-c/
# http://www.euroelectronica.ro/7-operators/
# https://gist.github.com/kputnam/5625856
# https://github.com/kaitai-io/kaitai_struct/issues/69
[docs]class ASSOCIATIVITY(Enum): L_TO_R = "L_TO_R" R_TO_L = "R_TO_L" NONE = "NONE"
ASSIGN_OPERATORS_SYMBOLS_C = { HdlOpType.ASSIGN: ' = ', HdlOpType.PLUS_ASSIGN: ' += ', HdlOpType.MINUS_ASSIGN: ' -= ', HdlOpType.MUL_ASSIGN: ' *= ', HdlOpType.DIV_ASSIGN: ' /= ', HdlOpType.MOD_ASSIGN: ' %= ', HdlOpType.AND_ASSIGN: ' &= ', HdlOpType.OR_ASSIGN: ' |= ', HdlOpType.XOR_ASSIGN: ' ^= ', HdlOpType.SHIFT_LEFT_ASSIGN: ' <<= ', HdlOpType.SHIFT_RIGHT_ASSIGN: ' >>= ', }
[docs]class ToHdlCommon(HdlAstVisitor): INDENT_STEP = " " ALL_UNARY_OPS = { getattr(HdlOpType, name) for name in dir(HdlOpType) if name.endswith("_UNARY") } GENERIC_UNARY_OPS = { HdlOpType.PLUS_UNARY: "+", HdlOpType.MINUS_UNARY: "-", } GENERIC_UNARY_OPS_POSTFIX = {} GENERIC_BIN_OPS = { HdlOpType.ADD: " + ", HdlOpType.SUB: " - ", HdlOpType.MUL: " * ", HdlOpType.LT: " < ", HdlOpType.LE: " <= ", HdlOpType.GT: " > ", HdlOpType.GE: " >= ", HdlOpType.DOT: ".", }
[docs] def __init__(self, out_stream): super(ToHdlCommon, self).__init__() self.out = AutoIndentingStream(out_stream, self.INDENT_STEP)
[docs] def visit_doc(self, obj, line_comment_prefix): """ Format doc as line comments :type line_comment_prefix: str """ doc = obj.doc if doc is not None: doc = doc.split("\n") w = self.out.write for last, d in iter_with_last(doc): if last and d == "": break w(line_comment_prefix) w(d.replace('\r', '')) w("\n")
[docs] def _precedence_of_expr(self, o): """ :type o: iHdlExpr """ # not id or value if not isinstance(o, HdlOp): return (-1, ASSOCIATIVITY.NONE, None) return self.OP_PRECEDENCE[o.fn] + (o.fn,)
[docs] def visit_HdlOp(self, op): """ :type op: HdlOp """ o = op.fn w = self.out.write argc = len(op.ops) if argc == 1: op_str = self.GENERIC_UNARY_OPS.get(o, None) if op_str is not None: w(op_str) self._visit_operand(op.ops[0], 0, op, False, False) return op_str = self.GENERIC_UNARY_OPS_POSTFIX.get(o, None) if op_str is not None: self._visit_operand(op.ops[0], 0, op, False, False) w(op_str) return if argc == 2: op_str = self.GENERIC_BIN_OPS.get(o, None) if op_str is not None: return self._visit_bin_op(op, op_str) if o == HdlOpType.INDEX: return self._visit_operator_index(op) elif o == HdlOpType.CALL or o == HdlOpType.PARAMETRIZATION: return self.visit_operator_call(op) else: raise NotImplementedError( "Do not know how to convert %s argc:%d" % (o, argc))
[docs] def visit_iHdlExpr(self, o): """ :type o: iHdlExpr """ w = self.out.write if isinstance(o, HdlValueId): w(o.val) return elif is_str(o): w('"%s"' % o.replace("\n", "\\\n")) return elif isinstance(o, HdlValueInt): self.visit_HdlValueInt(o) return elif isinstance(o, HdlOp): self.visit_HdlOp(o) return elif isinstance(o, float): w("%e" % o) else: raise NotImplementedError( "Do not know how to convert %r" % (o))
[docs] def _visit_operand_parentheses_extra_check( self, op_my, precedence_my, asoc_my, op_parent, precedence_parent, asoc_parent, left, right): if op_my in self.ALL_UNARY_OPS and op_parent in self.ALL_UNARY_OPS: return True return False
[docs] def _visit_operand(self, operand, i, parent, expr_requires_parenthesis, cancel_parenthesis): """ :type operand: iHdlExpr :type i: int :type parent: HdlOp :type expr_requires_parenthesis: bool :type cancel_parenthesis: bool """ use_parenthesis = False if not cancel_parenthesis: # resolve if the parenthesis are required precedence_my, asoc_my, op_my = self._precedence_of_expr(operand) if precedence_my >= 0: # if this is an expression if expr_requires_parenthesis or asoc_my is ASSOCIATIVITY.NONE: use_parenthesis = True else: precedence_parent, asoc_parent = self.OP_PRECEDENCE[parent.fn] right = None left = None argc = len(parent.ops) assert argc, parent if argc == 1: if asoc_parent == ASSOCIATIVITY.L_TO_R: # post fix left = parent.ops[0] else: assert asoc_parent == ASSOCIATIVITY.R_TO_L, asoc_parent right = parent.ops[0] else: if i == 0: right = parent.ops[1] else: left = parent.ops[i - 1] if argc > i + 2: right = parent.ops[i + 1] if self._visit_operand_parentheses_extra_check( op_my, precedence_my, asoc_my, parent.fn, precedence_parent, asoc_parent, left, right): use_parenthesis = True else: if left is not None: # "operand" is on right side of parent operator # same precedence -> parenthesis on right (this) if it is expression # a + (b + c) # a + b + c = (a + b) + c # right with lower precedence -> parenthesis for right not required # a + b * c = a + (b * c) # right with higher precedence -> parenthesis for right # a * (b + c) if precedence_my > precedence_parent: use_parenthesis = True elif precedence_my == precedence_parent: use_parenthesis = argc != 1 or asoc_parent != ASSOCIATIVITY.L_TO_R if not use_parenthesis and right is not None: # "operand" is on left side of parent operator # if op_my == parent.fn: # right_prec, _, right_op = self._precedence_of_expr(right) # if right_op == op_my: # # right and left with same precedence -> parenthesis on both sides # # (a + b) + (c + d) # use_parenthesis = True if precedence_my > precedence_parent: # left with higher precedence -> parenthesis for left # (a + b) * c # a + b + c + d = (a + b) + c + d # = ((a + b) + c) + d use_parenthesis = True w = self.out.write if use_parenthesis: w("(") self.visit_iHdlExpr(operand) if use_parenthesis: w(")")
[docs] def _visit_bin_op(self, operator, op_str, expr_requires_parenthesis=False, cancel_parenthesis=False): """ :type operator: HdlOp :type op_str: str """ op0, op1 = operator.ops self._visit_operand(op0, 0, operator, expr_requires_parenthesis, cancel_parenthesis) self.out.write(op_str) self._visit_operand(op1, 1, operator, expr_requires_parenthesis, cancel_parenthesis)
[docs] def _visit_operator_index(self, operator): """ :type operator: HdlOp """ op0, op1 = operator.ops self._visit_operand(op0, 0, operator, False, False) w = self.out.write w("[") self._visit_operand(op1, 1, operator, False, True) w("]")
[docs] def visit_operator_call(self, o): """ :type operator: HdlOp """ self._visit_operand(o.ops[0], 0, o, False, False) w = self.out.write w("(") for is_last, (o_i, _o) in iter_with_last(enumerate(o.ops[1:])): self._visit_operand(_o, o_i, o, False, True) if not is_last: w(", ") w(")")
[docs] def visit_HdlFunctionDef(self, o): """ :type o: HdlFunctionDef """ raise TypeError("does not support HdlFunctionDef", self, o)
[docs] def visit_HdlStmProcess(self, o): """ :type proc: HdlStmProcess """ raise TypeError("does not support HdlStmProcess", self, o)
[docs] def visit_HdlStmBlock(self, o): """ :type o: HdlStmBlock """ raise TypeError("does not support HdlStmBlock", self, o)
[docs] def visit_HdlStmIf(self, o): """ :type o: HdlStmIf """ raise TypeError("does not support HdlStmIf", self, o)
[docs] def visit_HdlStmCase(self, o): """ :type o: HdlStmCase """ raise TypeError("does not support HdlStmCase", self, o)
[docs] def visit_HdlStmWait(self, o): """ :type o: HdlStmWait """ raise TypeError("does not support HdlStmWait", self, o)
[docs] def visit_HdlStmFor(self, o): """ :type o: HdlStmFor """ raise TypeError("does not support HdlStmFor", self, o)
[docs] def visit_HdlStmForIn(self, o): """ :type o: HdlStmForIn """ raise TypeError("does not support HdlStmForIn", self, o)
[docs] def visit_HdlStmWhile(self, o): """ :type o: HdlStmWhile """ raise TypeError("does not support HdlStmWhile", self, o)
[docs] def visit_HdlStmAssign(self, o): """ :type o: HdlStmAssign """ raise TypeError("does not support HdlStmAssign", self, o)
[docs] def visit_HdlStmRepeat(self, o): """ :type o: HdlStmRepeat """ raise TypeError("does not support HdlStmRepeat", self, o)
[docs] def visit_HdlStmReturn(self, o): """ :type o: HdlStmReturn """ raise TypeError("does not support HdlStmReturn", self, o)
[docs] def visit_HdlStmContinue(self, o): """ :type o: HdlStmContinue """ raise TypeError("does not support HdlStmContinue", self, o)
[docs] def visit_HdlStmBreak(self, o): """ :type o: HdlStmBreak """ raise TypeError("does not support HdlStmBreak", self, o)