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..78a5ffb 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 @@ -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,18 @@ 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('<') + 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 self._unsupported_syntax(type_hint) if isinstance(type_hint, typed_ast3.Attribute): if isinstance(type_hint.value, typed_ast3.Name): @@ -108,12 +121,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 +142,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) @@ -138,14 +162,33 @@ 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) - 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: @@ -168,12 +211,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() @@ -208,7 +255,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 +268,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,21 +307,50 @@ 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) 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): + 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)) - class Cpp14HeaderUnparserBackend(Cpp14UnparserBackend): def _FunctionDef(self, t):