From 18473c9cdb258d0b7902528cff351c2faf33e90e Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Sun, 29 Sep 2019 22:34:27 -0500 Subject: [PATCH] Fix code gen to respect declarator precedence (Closes gh-21) --- cgen/__init__.py | 38 +++++++++++++++++++++++++++++++++++++- test/test_cgen.py | 20 +++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/cgen/__init__.py b/cgen/__init__.py index 7d9a8b1..9d98e57 100644 --- a/cgen/__init__.py +++ b/cgen/__init__.py @@ -272,7 +272,7 @@ def get_decl_pair(self): class MaybeUnused(NestedDeclarator): def get_decl_pair(self): sub_tp, sub_decl = self.subdecl.get_decl_pair() - return sub_tp, ("%s __attribute__ ((unused))" % sub_decl) + return sub_tp, ("(%s __attribute__ ((unused)))" % sub_decl) mapper_method = "map_maybe_unused" @@ -296,6 +296,16 @@ def __init__(self, subdecl): def get_decl_pair(self): sub_tp, sub_decl = self.subdecl.get_decl_pair() + + if not isinstance(self.subdecl, (Pointer, POD, Value)): + # declarator might "change direction" + # (e.g. include an array declarator) + # + # Note that * binds less strongly than [], so these + # parentheses might not be necessary. Nonetheless, + # we insert them for clarity. + sub_decl = "(%s)" % sub_decl + return sub_tp, ("*%s" % sub_decl) def struct_maker_code(self, data): @@ -313,6 +323,16 @@ def alignment_requirement(self): class RestrictPointer(Pointer): def get_decl_pair(self): sub_tp, sub_decl = self.subdecl.get_decl_pair() + + if not isinstance(self.subdecl, (Pointer, POD, Value)): + # declarator might "change direction" + # (e.g. include an array declarator) + # + # Note that * binds less strongly than [], so these + # parentheses might not be necessary. Nonetheless, + # we insert them for clarity. + sub_decl = "(%s)" % sub_decl + return sub_tp, ("*__restrict__ %s" % sub_decl) mapper_method = "map_restrict_pointer" @@ -321,6 +341,16 @@ def get_decl_pair(self): class Reference(Pointer): def get_decl_pair(self): sub_tp, sub_decl = self.subdecl.get_decl_pair() + + if not isinstance(self.subdecl, (Pointer, POD, Value)): + # declarator might "change direction" + # (e.g. include an array declarator) + # + # Note that * binds less strongly than [], so these + # parentheses might not be necessary. Nonetheless, + # we insert them for clarity. + sub_decl = "(%s)" % sub_decl + return sub_tp, ("&%s" % sub_decl) mapper_method = "map_reference" @@ -337,6 +367,12 @@ def get_decl_pair(self): count_str = "" else: count_str = str(self.count) + + if not isinstance(self.subdecl, (POD, Value, ArrayOf)): + # declarator might "change direction" + # (e.g. include a pointer declarator) + sub_decl = "(%s)" % sub_decl + return sub_tp, ("%s[%s]" % (sub_decl, count_str)) def struct_maker_code(self, name): diff --git a/test/test_cgen.py b/test/test_cgen.py index b1de365..cbb3d9f 100644 --- a/test/test_cgen.py +++ b/test/test_cgen.py @@ -1,7 +1,9 @@ +import sys + from cgen import ( POD, Struct, FunctionBody, FunctionDeclaration, For, If, Assign, Value, Block, ArrayOf, Comment, - Template) + Template, Pointer) import numpy as np @@ -46,3 +48,19 @@ def test_cgen(): print(s) print(f_body) print(t_decl) + + +def test_ptr_to_array(): + t1 = Pointer(ArrayOf(Pointer(POD(np.float32, "xxx")), 2)) + assert str(t1) == "float *((*xxx)[2]);" + + t2 = Pointer(Pointer(ArrayOf(POD(np.float32, "yyy"), 2))) + assert str(t2) == "float **(yyy[2]);" + + +if __name__ == "__main__": + if len(sys.argv) > 1: + exec(sys.argv[1]) + else: + from pytest import main + main([__file__])