diff options
author | alexv-smirnov <alex@ydb.tech> | 2023-06-13 11:05:01 +0300 |
---|---|---|
committer | alexv-smirnov <alex@ydb.tech> | 2023-06-13 11:05:01 +0300 |
commit | bf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0 (patch) | |
tree | 1d1df72c0541a59a81439842f46d95396d3e7189 /contrib/tools/cython/Cython/CodeWriter.py | |
parent | 8bfdfa9a9bd19bddbc58d888e180fbd1218681be (diff) | |
download | ydb-bf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0.tar.gz |
add ymake export to ydb
Diffstat (limited to 'contrib/tools/cython/Cython/CodeWriter.py')
-rw-r--r-- | contrib/tools/cython/Cython/CodeWriter.py | 816 |
1 files changed, 816 insertions, 0 deletions
diff --git a/contrib/tools/cython/Cython/CodeWriter.py b/contrib/tools/cython/Cython/CodeWriter.py new file mode 100644 index 0000000000..2e4646a654 --- /dev/null +++ b/contrib/tools/cython/Cython/CodeWriter.py @@ -0,0 +1,816 @@ +""" +Serializes a Cython code tree to Cython code. This is primarily useful for +debugging and testing purposes. + +The output is in a strict format, no whitespace or comments from the input +is preserved (and it could not be as it is not present in the code tree). +""" + +from __future__ import absolute_import, print_function + +from .Compiler.Visitor import TreeVisitor +from .Compiler.ExprNodes import * + + +class LinesResult(object): + def __init__(self): + self.lines = [] + self.s = u"" + + def put(self, s): + self.s += s + + def newline(self): + self.lines.append(self.s) + self.s = u"" + + def putline(self, s): + self.put(s) + self.newline() + +class DeclarationWriter(TreeVisitor): + + indent_string = u" " + + def __init__(self, result=None): + super(DeclarationWriter, self).__init__() + if result is None: + result = LinesResult() + self.result = result + self.numindents = 0 + self.tempnames = {} + self.tempblockindex = 0 + + def write(self, tree): + self.visit(tree) + return self.result + + def indent(self): + self.numindents += 1 + + def dedent(self): + self.numindents -= 1 + + def startline(self, s=u""): + self.result.put(self.indent_string * self.numindents + s) + + def put(self, s): + self.result.put(s) + + def putline(self, s): + self.result.putline(self.indent_string * self.numindents + s) + + def endline(self, s=u""): + self.result.putline(s) + + def line(self, s): + self.startline(s) + self.endline() + + def comma_separated_list(self, items, output_rhs=False): + if len(items) > 0: + for item in items[:-1]: + self.visit(item) + if output_rhs and item.default is not None: + self.put(u" = ") + self.visit(item.default) + self.put(u", ") + self.visit(items[-1]) + + def visit_Node(self, node): + raise AssertionError("Node not handled by serializer: %r" % node) + + def visit_ModuleNode(self, node): + self.visitchildren(node) + + def visit_StatListNode(self, node): + self.visitchildren(node) + + def visit_CDefExternNode(self, node): + if node.include_file is None: + file = u'*' + else: + file = u'"%s"' % node.include_file + self.putline(u"cdef extern from %s:" % file) + self.indent() + self.visit(node.body) + self.dedent() + + def visit_CPtrDeclaratorNode(self, node): + self.put('*') + self.visit(node.base) + + def visit_CReferenceDeclaratorNode(self, node): + self.put('&') + self.visit(node.base) + + def visit_CArrayDeclaratorNode(self, node): + self.visit(node.base) + self.put(u'[') + if node.dimension is not None: + self.visit(node.dimension) + self.put(u']') + + def visit_CArrayDeclaratorNode(self, node): + self.visit(node.base) + self.put(u'[') + if node.dimension is not None: + self.visit(node.dimension) + self.put(u']') + + def visit_CFuncDeclaratorNode(self, node): + # TODO: except, gil, etc. + self.visit(node.base) + self.put(u'(') + self.comma_separated_list(node.args) + self.endline(u')') + + def visit_CNameDeclaratorNode(self, node): + self.put(node.name) + + def visit_CSimpleBaseTypeNode(self, node): + # See Parsing.p_sign_and_longness + if node.is_basic_c_type: + self.put(("unsigned ", "", "signed ")[node.signed]) + if node.longness < 0: + self.put("short " * -node.longness) + elif node.longness > 0: + self.put("long " * node.longness) + self.put(node.name) + + def visit_CComplexBaseTypeNode(self, node): + self.put(u'(') + self.visit(node.base_type) + self.visit(node.declarator) + self.put(u')') + + def visit_CNestedBaseTypeNode(self, node): + self.visit(node.base_type) + self.put(u'.') + self.put(node.name) + + def visit_TemplatedTypeNode(self, node): + self.visit(node.base_type_node) + self.put(u'[') + self.comma_separated_list(node.positional_args + node.keyword_args.key_value_pairs) + self.put(u']') + + def visit_CVarDefNode(self, node): + self.startline(u"cdef ") + self.visit(node.base_type) + self.put(u" ") + self.comma_separated_list(node.declarators, output_rhs=True) + self.endline() + + def visit_container_node(self, node, decl, extras, attributes): + # TODO: visibility + self.startline(decl) + if node.name: + self.put(u' ') + self.put(node.name) + if node.cname is not None: + self.put(u' "%s"' % node.cname) + if extras: + self.put(extras) + self.endline(':') + self.indent() + if not attributes: + self.putline('pass') + else: + for attribute in attributes: + self.visit(attribute) + self.dedent() + + def visit_CStructOrUnionDefNode(self, node): + if node.typedef_flag: + decl = u'ctypedef ' + else: + decl = u'cdef ' + if node.visibility == 'public': + decl += u'public ' + if node.packed: + decl += u'packed ' + decl += node.kind + self.visit_container_node(node, decl, None, node.attributes) + + def visit_CppClassNode(self, node): + extras = "" + if node.templates: + extras = u"[%s]" % ", ".join(node.templates) + if node.base_classes: + extras += "(%s)" % ", ".join(node.base_classes) + self.visit_container_node(node, u"cdef cppclass", extras, node.attributes) + + def visit_CEnumDefNode(self, node): + self.visit_container_node(node, u"cdef enum", None, node.items) + + def visit_CEnumDefItemNode(self, node): + self.startline(node.name) + if node.cname: + self.put(u' "%s"' % node.cname) + if node.value: + self.put(u" = ") + self.visit(node.value) + self.endline() + + def visit_CClassDefNode(self, node): + assert not node.module_name + if node.decorators: + for decorator in node.decorators: + self.visit(decorator) + self.startline(u"cdef class ") + self.put(node.class_name) + if node.base_class_name: + self.put(u"(") + if node.base_class_module: + self.put(node.base_class_module) + self.put(u".") + self.put(node.base_class_name) + self.put(u")") + self.endline(u":") + self.indent() + self.visit(node.body) + self.dedent() + + def visit_CTypeDefNode(self, node): + self.startline(u"ctypedef ") + self.visit(node.base_type) + self.put(u" ") + self.visit(node.declarator) + self.endline() + + def visit_FuncDefNode(self, node): + self.startline(u"def %s(" % node.name) + self.comma_separated_list(node.args) + self.endline(u"):") + self.indent() + self.visit(node.body) + self.dedent() + + def visit_CArgDeclNode(self, node): + if node.base_type.name is not None: + self.visit(node.base_type) + self.put(u" ") + self.visit(node.declarator) + if node.default is not None: + self.put(u" = ") + self.visit(node.default) + + def visit_CImportStatNode(self, node): + self.startline(u"cimport ") + self.put(node.module_name) + if node.as_name: + self.put(u" as ") + self.put(node.as_name) + self.endline() + + def visit_FromCImportStatNode(self, node): + self.startline(u"from ") + self.put(node.module_name) + self.put(u" cimport ") + first = True + for pos, name, as_name, kind in node.imported_names: + assert kind is None + if first: + first = False + else: + self.put(u", ") + self.put(name) + if as_name: + self.put(u" as ") + self.put(as_name) + self.endline() + + def visit_NameNode(self, node): + self.put(node.name) + + def visit_IntNode(self, node): + self.put(node.value) + + def visit_NoneNode(self, node): + self.put(u"None") + + def visit_NotNode(self, node): + self.put(u"(not ") + self.visit(node.operand) + self.put(u")") + + def visit_DecoratorNode(self, node): + self.startline("@") + self.visit(node.decorator) + self.endline() + + def visit_BinopNode(self, node): + self.visit(node.operand1) + self.put(u" %s " % node.operator) + self.visit(node.operand2) + + def visit_AttributeNode(self, node): + self.visit(node.obj) + self.put(u".%s" % node.attribute) + + def visit_BoolNode(self, node): + self.put(str(node.value)) + + # FIXME: represent string nodes correctly + def visit_StringNode(self, node): + value = node.value + if value.encoding is not None: + value = value.encode(value.encoding) + self.put(repr(value)) + + def visit_PassStatNode(self, node): + self.startline(u"pass") + self.endline() + +class CodeWriter(DeclarationWriter): + + def visit_SingleAssignmentNode(self, node): + self.startline() + self.visit(node.lhs) + self.put(u" = ") + self.visit(node.rhs) + self.endline() + + def visit_CascadedAssignmentNode(self, node): + self.startline() + for lhs in node.lhs_list: + self.visit(lhs) + self.put(u" = ") + self.visit(node.rhs) + self.endline() + + def visit_PrintStatNode(self, node): + self.startline(u"print ") + self.comma_separated_list(node.arg_tuple.args) + if not node.append_newline: + self.put(u",") + self.endline() + + def visit_ForInStatNode(self, node): + self.startline(u"for ") + self.visit(node.target) + self.put(u" in ") + self.visit(node.iterator.sequence) + self.endline(u":") + self.indent() + self.visit(node.body) + self.dedent() + if node.else_clause is not None: + self.line(u"else:") + self.indent() + self.visit(node.else_clause) + self.dedent() + + def visit_IfStatNode(self, node): + # The IfClauseNode is handled directly without a separate match + # for clariy. + self.startline(u"if ") + self.visit(node.if_clauses[0].condition) + self.endline(":") + self.indent() + self.visit(node.if_clauses[0].body) + self.dedent() + for clause in node.if_clauses[1:]: + self.startline("elif ") + self.visit(clause.condition) + self.endline(":") + self.indent() + self.visit(clause.body) + self.dedent() + if node.else_clause is not None: + self.line("else:") + self.indent() + self.visit(node.else_clause) + self.dedent() + + def visit_SequenceNode(self, node): + self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm... + + def visit_SimpleCallNode(self, node): + self.visit(node.function) + self.put(u"(") + self.comma_separated_list(node.args) + self.put(")") + + def visit_GeneralCallNode(self, node): + self.visit(node.function) + self.put(u"(") + posarg = node.positional_args + if isinstance(posarg, AsTupleNode): + self.visit(posarg.arg) + else: + self.comma_separated_list(posarg.args) # TupleNode.args + if node.keyword_args: + if isinstance(node.keyword_args, DictNode): + for i, (name, value) in enumerate(node.keyword_args.key_value_pairs): + if i > 0: + self.put(', ') + self.visit(name) + self.put('=') + self.visit(value) + else: + raise Exception("Not implemented yet") + self.put(u")") + + def visit_ExprStatNode(self, node): + self.startline() + self.visit(node.expr) + self.endline() + + def visit_InPlaceAssignmentNode(self, node): + self.startline() + self.visit(node.lhs) + self.put(u" %s= " % node.operator) + self.visit(node.rhs) + self.endline() + + def visit_WithStatNode(self, node): + self.startline() + self.put(u"with ") + self.visit(node.manager) + if node.target is not None: + self.put(u" as ") + self.visit(node.target) + self.endline(u":") + self.indent() + self.visit(node.body) + self.dedent() + + def visit_TryFinallyStatNode(self, node): + self.line(u"try:") + self.indent() + self.visit(node.body) + self.dedent() + self.line(u"finally:") + self.indent() + self.visit(node.finally_clause) + self.dedent() + + def visit_TryExceptStatNode(self, node): + self.line(u"try:") + self.indent() + self.visit(node.body) + self.dedent() + for x in node.except_clauses: + self.visit(x) + if node.else_clause is not None: + self.visit(node.else_clause) + + def visit_ExceptClauseNode(self, node): + self.startline(u"except") + if node.pattern is not None: + self.put(u" ") + self.visit(node.pattern) + if node.target is not None: + self.put(u", ") + self.visit(node.target) + self.endline(":") + self.indent() + self.visit(node.body) + self.dedent() + + def visit_ReturnStatNode(self, node): + self.startline("return ") + self.visit(node.value) + self.endline() + + def visit_ReraiseStatNode(self, node): + self.line("raise") + + def visit_ImportNode(self, node): + self.put(u"(import %s)" % node.module_name.value) + + def visit_TempsBlockNode(self, node): + """ + Temporaries are output like $1_1', where the first number is + an index of the TempsBlockNode and the second number is an index + of the temporary which that block allocates. + """ + idx = 0 + for handle in node.temps: + self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx) + idx += 1 + self.tempblockindex += 1 + self.visit(node.body) + + def visit_TempRefNode(self, node): + self.put(self.tempnames[node.handle]) + + +class PxdWriter(DeclarationWriter): + def __call__(self, node): + print(u'\n'.join(self.write(node).lines)) + return node + + def visit_CFuncDefNode(self, node): + if 'inline' in node.modifiers: + return + if node.overridable: + self.startline(u'cpdef ') + else: + self.startline(u'cdef ') + if node.visibility != 'private': + self.put(node.visibility) + self.put(u' ') + if node.api: + self.put(u'api ') + self.visit(node.declarator) + + def visit_StatNode(self, node): + pass + + +class ExpressionWriter(TreeVisitor): + + def __init__(self, result=None): + super(ExpressionWriter, self).__init__() + if result is None: + result = u"" + self.result = result + self.precedence = [0] + + def write(self, tree): + self.visit(tree) + return self.result + + def put(self, s): + self.result += s + + def remove(self, s): + if self.result.endswith(s): + self.result = self.result[:-len(s)] + + def comma_separated_list(self, items): + if len(items) > 0: + for item in items[:-1]: + self.visit(item) + self.put(u", ") + self.visit(items[-1]) + + def visit_Node(self, node): + raise AssertionError("Node not handled by serializer: %r" % node) + + def visit_NameNode(self, node): + self.put(node.name) + + def visit_NoneNode(self, node): + self.put(u"None") + + def visit_EllipsisNode(self, node): + self.put(u"...") + + def visit_BoolNode(self, node): + self.put(str(node.value)) + + def visit_ConstNode(self, node): + self.put(str(node.value)) + + def visit_ImagNode(self, node): + self.put(node.value) + self.put(u"j") + + def emit_string(self, node, prefix=u""): + repr_val = repr(node.value) + if repr_val[0] in 'ub': + repr_val = repr_val[1:] + self.put(u"%s%s" % (prefix, repr_val)) + + def visit_BytesNode(self, node): + self.emit_string(node, u"b") + + def visit_StringNode(self, node): + self.emit_string(node) + + def visit_UnicodeNode(self, node): + self.emit_string(node, u"u") + + def emit_sequence(self, node, parens=(u"", u"")): + open_paren, close_paren = parens + items = node.subexpr_nodes() + self.put(open_paren) + self.comma_separated_list(items) + self.put(close_paren) + + def visit_ListNode(self, node): + self.emit_sequence(node, u"[]") + + def visit_TupleNode(self, node): + self.emit_sequence(node, u"()") + + def visit_SetNode(self, node): + if len(node.subexpr_nodes()) > 0: + self.emit_sequence(node, u"{}") + else: + self.put(u"set()") + + def visit_DictNode(self, node): + self.emit_sequence(node, u"{}") + + def visit_DictItemNode(self, node): + self.visit(node.key) + self.put(u": ") + self.visit(node.value) + + unop_precedence = { + 'not': 3, '!': 3, + '+': 11, '-': 11, '~': 11, + } + binop_precedence = { + 'or': 1, + 'and': 2, + # unary: 'not': 3, '!': 3, + 'in': 4, 'not_in': 4, 'is': 4, 'is_not': 4, '<': 4, '<=': 4, '>': 4, '>=': 4, '!=': 4, '==': 4, + '|': 5, + '^': 6, + '&': 7, + '<<': 8, '>>': 8, + '+': 9, '-': 9, + '*': 10, '@': 10, '/': 10, '//': 10, '%': 10, + # unary: '+': 11, '-': 11, '~': 11 + '**': 12, + } + + def operator_enter(self, new_prec): + old_prec = self.precedence[-1] + if old_prec > new_prec: + self.put(u"(") + self.precedence.append(new_prec) + + def operator_exit(self): + old_prec, new_prec = self.precedence[-2:] + if old_prec > new_prec: + self.put(u")") + self.precedence.pop() + + def visit_NotNode(self, node): + op = 'not' + prec = self.unop_precedence[op] + self.operator_enter(prec) + self.put(u"not ") + self.visit(node.operand) + self.operator_exit() + + def visit_UnopNode(self, node): + op = node.operator + prec = self.unop_precedence[op] + self.operator_enter(prec) + self.put(u"%s" % node.operator) + self.visit(node.operand) + self.operator_exit() + + def visit_BinopNode(self, node): + op = node.operator + prec = self.binop_precedence.get(op, 0) + self.operator_enter(prec) + self.visit(node.operand1) + self.put(u" %s " % op.replace('_', ' ')) + self.visit(node.operand2) + self.operator_exit() + + def visit_BoolBinopNode(self, node): + self.visit_BinopNode(node) + + def visit_PrimaryCmpNode(self, node): + self.visit_BinopNode(node) + + def visit_IndexNode(self, node): + self.visit(node.base) + self.put(u"[") + if isinstance(node.index, TupleNode): + self.emit_sequence(node.index) + else: + self.visit(node.index) + self.put(u"]") + + def visit_SliceIndexNode(self, node): + self.visit(node.base) + self.put(u"[") + if node.start: + self.visit(node.start) + self.put(u":") + if node.stop: + self.visit(node.stop) + if node.slice: + self.put(u":") + self.visit(node.slice) + self.put(u"]") + + def visit_SliceNode(self, node): + if not node.start.is_none: + self.visit(node.start) + self.put(u":") + if not node.stop.is_none: + self.visit(node.stop) + if not node.step.is_none: + self.put(u":") + self.visit(node.step) + + def visit_CondExprNode(self, node): + self.visit(node.true_val) + self.put(u" if ") + self.visit(node.test) + self.put(u" else ") + self.visit(node.false_val) + + def visit_AttributeNode(self, node): + self.visit(node.obj) + self.put(u".%s" % node.attribute) + + def visit_SimpleCallNode(self, node): + self.visit(node.function) + self.put(u"(") + self.comma_separated_list(node.args) + self.put(")") + + def emit_pos_args(self, node): + if node is None: + return + if isinstance(node, AddNode): + self.emit_pos_args(node.operand1) + self.emit_pos_args(node.operand2) + elif isinstance(node, TupleNode): + for expr in node.subexpr_nodes(): + self.visit(expr) + self.put(u", ") + elif isinstance(node, AsTupleNode): + self.put("*") + self.visit(node.arg) + self.put(u", ") + else: + self.visit(node) + self.put(u", ") + + def emit_kwd_args(self, node): + if node is None: + return + if isinstance(node, MergedDictNode): + for expr in node.subexpr_nodes(): + self.emit_kwd_args(expr) + elif isinstance(node, DictNode): + for expr in node.subexpr_nodes(): + self.put(u"%s=" % expr.key.value) + self.visit(expr.value) + self.put(u", ") + else: + self.put(u"**") + self.visit(node) + self.put(u", ") + + def visit_GeneralCallNode(self, node): + self.visit(node.function) + self.put(u"(") + self.emit_pos_args(node.positional_args) + self.emit_kwd_args(node.keyword_args) + self.remove(u", ") + self.put(")") + + def emit_comprehension(self, body, target, + sequence, condition, + parens=(u"", u"")): + open_paren, close_paren = parens + self.put(open_paren) + self.visit(body) + self.put(u" for ") + self.visit(target) + self.put(u" in ") + self.visit(sequence) + if condition: + self.put(u" if ") + self.visit(condition) + self.put(close_paren) + + def visit_ComprehensionAppendNode(self, node): + self.visit(node.expr) + + def visit_DictComprehensionAppendNode(self, node): + self.visit(node.key_expr) + self.put(u": ") + self.visit(node.value_expr) + + def visit_ComprehensionNode(self, node): + tpmap = {'list': u"[]", 'dict': u"{}", 'set': u"{}"} + parens = tpmap[node.type.py_type_name()] + body = node.loop.body + target = node.loop.target + sequence = node.loop.iterator.sequence + condition = None + if hasattr(body, 'if_clauses'): + # type(body) is Nodes.IfStatNode + condition = body.if_clauses[0].condition + body = body.if_clauses[0].body + self.emit_comprehension(body, target, sequence, condition, parens) + + def visit_GeneratorExpressionNode(self, node): + body = node.loop.body + target = node.loop.target + sequence = node.loop.iterator.sequence + condition = None + if hasattr(body, 'if_clauses'): + # type(body) is Nodes.IfStatNode + condition = body.if_clauses[0].condition + body = body.if_clauses[0].body.expr.arg + elif hasattr(body, 'expr'): + # type(body) is Nodes.ExprStatNode + body = body.expr.arg + self.emit_comprehension(body, target, sequence, condition, u"()") |