From b7fc2c7887257bcd9236295c7b6526be20d44f97 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Thu, 6 Dec 2018 16:12:53 +0100 Subject: [PATCH 1/4] Added some hacky code to CppUnparser to make more unparing possible. --- transpyle/cpp/__init__.py | 3 ++ transpyle/cpp/unparser.py | 73 ++++++++++++++++++++++++++++++--------- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/transpyle/cpp/__init__.py b/transpyle/cpp/__init__.py index 36ade7e..2cbcc1a 100644 --- a/transpyle/cpp/__init__.py +++ b/transpyle/cpp/__init__.py @@ -6,6 +6,9 @@ from .unparser import Cpp14Unparser from .compiler import CppSwigCompiler +# Annotation to mark a class as a struct. (Python -> Cpp) +def struct(f): + return f class CppBinder(Binder): diff --git a/transpyle/cpp/unparser.py b/transpyle/cpp/unparser.py index 3262d0b..74b2a44 100644 --- a/transpyle/cpp/unparser.py +++ b/transpyle/cpp/unparser.py @@ -85,6 +85,7 @@ def leave(self): super().leave() self.fill('}') + # Misusing ast.Index to signify reference types. Should probably fork typed-ast or something. The ast generalizer does something string based. def dispatch_type(self, type_hint): _LOG.debug('dispatching type hint %s', type_hint) if isinstance(type_hint, typed_ast3.Subscript): @@ -97,6 +98,15 @@ def dispatch_type(self, type_hint): sli = type_hint.slice self.write('>') return + elif isinstance(type_hint.value, typed_ast3.Name): + unparsed = horast.unparse(type_hint.value).strip() + self.write(unparsed) + self.write('<') + self.write(horast.unparse(type_hint.slice).strip()) + self.write('>') + if isinstance(type_hint.slice, typed_ast3.Index): + self.write('&') + return self._unsupported_syntax(type_hint) if isinstance(type_hint, typed_ast3.Attribute): if isinstance(type_hint.value, typed_ast3.Name): @@ -108,12 +118,19 @@ def dispatch_type(self, type_hint): assert type_hint.value is None self.write('void') return + self.dispatch(type_hint) + if isinstance(type_hint, typed_ast3.Index): + if isinstance(type_hint.value, typed_ast3.Name): + self.write('&') def _Expr(self, tree): super()._Expr(tree) self.write(';') + def _Pass(self, tree): + self.fill('/* pass */') + def _Import(self, t): self.fill('/* Python import') # raise NotImplementedError('not supported yet') @@ -122,7 +139,11 @@ def _Import(self, t): # #include "boost/multi_array.hpp" def _ImportFrom(self, t): - raise NotImplementedError('not supported yet') + self.fill('/* Python import') + # raise NotImplementedError('not supported yet') + super()._ImportFrom(t) + self.fill('*/') + # #include "boost/multi_array.hpp" def _Assign(self, t): super()._Assign(t) @@ -142,10 +163,26 @@ def _AnnAssign(self, t): if t.value: self.write(' = ') self.dispatch(t.value) - self.write(';') + self.write(';') def _ClassDef(self, t): - raise NotImplementedError('not supported yet') + if len(t.decorator_list) > 1: + self._unsupported_syntax(t, ' with decorators') + self.write('\n') + self.fill() + is_struct = False + if len(t.decorator_list) == 1: + is_struct = t.decorator_list[0].id=='struct' + if is_struct: + self.write('struct') + else: + self.write('class') + + self.write(' {}'.format(t.name)) + self.enter() + self.dispatch(t.body) + self.leave() + def _FunctionDef(self, t): if t.decorator_list: @@ -208,7 +245,7 @@ def _If(self, t): self.dispatch(t.orelse) self.leave() - raise NotImplementedError('not supported yet') + #raise NotImplementedError('not supported yet') def _While(self, t): raise NotImplementedError('not supported yet') @@ -221,17 +258,20 @@ def _AsyncWith(self, t): def _Attribute(self, t): if isinstance(t.value, typed_ast3.Name): - unparsed = { - ('a', 'shape'): '???', - ('b', 'shape'): '???', - ('c', 'shape'): '???', - ('np', 'single'): 'int32_t', - ('np', 'double'): 'int64_t', - ('np', 'zeros'): 'boost::multi_array', - ('st', 'ndarray'): 'boost::multi_array' - }[t.value.id, t.attr] - self.write(unparsed) - return + try: + unparsed = { + ('a', 'shape'): '???', + ('b', 'shape'): '???', + ('c', 'shape'): '???', + ('np', 'single'): 'int32_t', + ('np', 'double'): 'int64_t', + ('np', 'zeros'): 'boost::multi_array', + ('st', 'ndarray'): 'boost::multi_array' + }[t.value.id, t.attr] + self.write(unparsed) + return + except Exception: + pass self.dispatch(t.value) self.write('.') self.write(t.attr) @@ -257,7 +297,7 @@ def _Subscript(self, t): def _arg(self, t): if t.annotation is None: self._unsupported_syntax(t, ' without annotation') - self.dispatch(t.annotation) + self.dispatch_type(t.annotation) self.write(' ') self.write(t.arg) @@ -271,7 +311,6 @@ def _Comment(self, node): def _unsupported_syntax(self, tree, comment: str = ''): raise SyntaxError('unparsing {}{} to C++ is not supported'.format(type(tree), comment)) - class Cpp14HeaderUnparserBackend(Cpp14UnparserBackend): def _FunctionDef(self, t): From 298182a214276ddf268f330af08e9e5472e0b979 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Sun, 24 Feb 2019 21:32:36 +0100 Subject: [PATCH 2/4] Unparser changes. Added more options to for mode unparsing. Added support for NameConstants. Added support for Byte strings (and also chars as single byte strings). --- transpyle/cpp/unparser.py | 42 ++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/transpyle/cpp/unparser.py b/transpyle/cpp/unparser.py index 74b2a44..5a30386 100644 --- a/transpyle/cpp/unparser.py +++ b/transpyle/cpp/unparser.py @@ -65,7 +65,7 @@ def for_header_to_tuple(target, target_type, iter_) -> t.Tuple[ init = typed_ast3.Assign(targets=[target], value=begin, type_comment=None) else: init = typed_ast3.AnnAssign(target=target, annotation=target_type, value=begin, simple=True) - condition = typed_ast3.Compare(left=target, ops=[typed_ast3.Lt()], comparators=[end]) + condition = typed_ast3.Expr(typed_ast3.Compare(left=target, ops=[typed_ast3.Lt()], comparators=[end])) increment = typed_ast3.AugAssign(target=target, op=typed_ast3.Add(), value=step) return init, condition, increment @@ -205,12 +205,16 @@ def _AsyncFunctionDef(self, t): def _For(self, t): self.fill('for (') - init, cond, increment = for_header_to_tuple(t.target, t.resolved_type_comment, t.iter) - self.dispatch(init) - self.write(', ') - self.dispatch(cond) - self.write(', ') - self.dispatch(increment) + init, cond, increment = for_header_to_tuple(t.target, t.type_comment, t.iter) + #self.dispatch(init) + #self.dispatch(cond) + #self.dispatch(increment) + unparser = Cpp14Unparser() + self.write(unparser.unparse(init).strip('\n\r;)(')) + self.write('; ') + self.write(unparser.unparse(cond).strip('\n\r;)(')) + self.write('; ') + self.write(unparser.unparse(increment).strip('\n\r;)(')) # self.dispatch(t.iter) self.write(')') self.enter() @@ -308,6 +312,30 @@ def _Comment(self, node): self.fill('//') self.write(node.value.s) + def _NameConstant(self, node): + if node.value == 'False': + self.write("false") + elif node.value == 'True': + self.write("true") + elif node.value == 'None': + self.write("null") + else: + self.write(node.value) + + def _Str(self, node): + self.write('"') + self.write(node.s.replace('"', '\\"').replace("\0", "\\0").replace("\n", "\\n").replace("\t", "\\t").replace("\r", "\\r")) + self.write('"') + + def _Bytes(self, node): + # Char + if len(node.s) == 1: + self.write("'") + self.write(node.s.replace("'", "\\'").replace("\0", "\\0").replace("\n", "\\n").replace("\t", "\\t").replace("\r", "\\r")) + self.write("'") + else: + self._Str(node) + def _unsupported_syntax(self, tree, comment: str = ''): raise SyntaxError('unparsing {}{} to C++ is not supported'.format(type(tree), comment)) From fa739c066098e57eeace2960ada5d5ac6b9a5b12 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Tue, 7 May 2019 14:32:29 +0200 Subject: [PATCH 3/4] Added pragma support. --- transpyle/cpp/unparser.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/transpyle/cpp/unparser.py b/transpyle/cpp/unparser.py index 5a30386..b63cb32 100644 --- a/transpyle/cpp/unparser.py +++ b/transpyle/cpp/unparser.py @@ -306,10 +306,16 @@ def _arg(self, t): self.write(t.arg) def _Comment(self, node): - if node.eol: - self.write(' //') + if node.value.s.startswith("pragma"): + if node.eol: + self.write('\n#') + else: + self.fill('#') else: - self.fill('//') + if node.eol: + self.write(' //') + else: + self.fill('//') self.write(node.value.s) def _NameConstant(self, node): From d8efae626360113c0b38ea3561dfbe5b830d661c Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Tue, 21 May 2019 15:00:12 +0200 Subject: [PATCH 4/4] Fixed some slided type output support. --- transpyle/cpp/unparser.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/transpyle/cpp/unparser.py b/transpyle/cpp/unparser.py index b63cb32..78a5ffb 100644 --- a/transpyle/cpp/unparser.py +++ b/transpyle/cpp/unparser.py @@ -102,8 +102,11 @@ def dispatch_type(self, type_hint): unparsed = horast.unparse(type_hint.value).strip() self.write(unparsed) self.write('<') - self.write(horast.unparse(type_hint.slice).strip()) - self.write('>') + if isinstance(type_hint.slice, typed_ast3.Subscript): + self.dispatch_type(type_hint.slice) + else: + self.write(horast.unparse(type_hint.slice).strip()) + self.write(' >') if isinstance(type_hint.slice, typed_ast3.Index): self.write('&') return @@ -159,7 +162,10 @@ def _AnnAssign(self, t): self._unsupported_syntax(t, ' which is not simple') self.dispatch_type(t.annotation) self.write(' ') - self.dispatch(t.target) + try: + self.dispatch(t.target) + except AttributeError as e: + print(e) if t.value: self.write(' = ') self.dispatch(t.value)