From e11f2fe54562a09d6bcde523f14bbd5e4a7d85c8 Mon Sep 17 00:00:00 2001 From: Oliver Lee Date: Tue, 20 Oct 2015 19:12:42 +0200 Subject: [PATCH] Add whitespace to generated code to allow line breaks Some generated expressions, particularly those that contain only '*' and '/' operands, have no whitespace. In this case, the textwrap module may break the line in the middle of a symbol or mathematical expression if the line is long, resulting in code that cannot compile. This commit adds whitespace before and after the '*', '/' operands so that textwrap will have more options for inserting line breaks. The textwrap option 'break_long_words' is also set to True, allowing long lines in the event that no whitespace is present. This commit resolves https://github.com/pydy/pydy/issues/263. --- pydy/codegen/tests/test_c_code.py | 102 +++++++++++++++--------------- pydy/utils.py | 9 ++- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/pydy/codegen/tests/test_c_code.py b/pydy/codegen/tests/test_c_code.py index 5b65a3f2..215cc64b 100644 --- a/pydy/codegen/tests/test_c_code.py +++ b/pydy/codegen/tests/test_c_code.py @@ -191,11 +191,11 @@ def test_generate_code_blocks(self): double pydy_5 = input_3[3]; double pydy_6 = input_3[4]; double pydy_7 = input_3[5]; - double pydy_8 = input_0[6]*input_0[15]; - double pydy_9 = input_0[6]*input_0[16]; - double pydy_10 = input_0[6]*input_0[17]; - double pydy_11 = input_0[6]*input_0[18]; - double pydy_12 = input_0[6]*input_0[14] + pydy_10 + pydy_11 + pydy_4 + + double pydy_8 = input_0[6] * input_0[15]; + double pydy_9 = input_0[6] * input_0[16]; + double pydy_10 = input_0[6] * input_0[17]; + double pydy_11 = input_0[6] * input_0[18]; + double pydy_12 = input_0[6] * input_0[14] + pydy_10 + pydy_11 + pydy_4 + pydy_5 + pydy_6 + pydy_7 + pydy_8 + pydy_9 + input_3[1];\ """ @@ -239,17 +239,17 @@ def test_generate_code_blocks(self): output_0[34] = input_0[18]; output_0[35] = input_0[18]; - output_1[0] = -input_0[0]*input_2[0] + input_0[6]*input_0[13] - - input_0[7]*input_1[0] + pydy_12 + input_3[0]; - output_1[1] = -input_0[1]*input_2[1] - input_0[8]*input_1[1] + pydy_12; - output_1[2] = -input_0[2]*input_2[2] - input_0[9]*input_1[2] + pydy_10 + - pydy_11 + pydy_4 + pydy_5 + pydy_6 + pydy_7 + pydy_8 + pydy_9; - output_1[3] = -input_0[3]*input_2[3] - input_0[10]*input_1[3] + pydy_10 + - pydy_11 + pydy_5 + pydy_6 + pydy_7 + pydy_9; - output_1[4] = -input_0[4]*input_2[4] - input_0[11]*input_1[4] + pydy_10 + - pydy_11 + pydy_6 + pydy_7; - output_1[5] = -input_0[5]*input_2[5] - input_0[12]*input_1[5] + pydy_11 + - pydy_7;\ + output_1[0] = -input_0[0] * input_2[0] + input_0[6] * input_0[13] - + input_0[7] * input_1[0] + pydy_12 + input_3[0]; + output_1[1] = -input_0[1] * input_2[1] - input_0[8] * input_1[1] + pydy_12; + output_1[2] = -input_0[2] * input_2[2] - input_0[9] * input_1[2] + pydy_10 + + pydy_11 + pydy_4 + pydy_5 + pydy_6 + pydy_7 + pydy_8 + pydy_9; + output_1[3] = -input_0[3] * input_2[3] - input_0[10] * input_1[3] + pydy_10 + + pydy_11 + pydy_5 + pydy_6 + pydy_7 + pydy_9; + output_1[4] = -input_0[4] * input_2[4] - input_0[11] * input_1[4] + pydy_10 + + pydy_11 + pydy_6 + pydy_7; + output_1[5] = -input_0[5] * input_2[5] - input_0[12] * input_1[5] + pydy_11 + + pydy_7;\ """ self.generator._generate_cse() @@ -332,25 +332,27 @@ def test_generate_code_blocks_without_cse(self): output_0[34] = input_0[18]; output_0[35] = input_0[18]; - output_1[0] = -input_0[0]*input_2[0] + input_0[6]*input_0[13] + - input_0[6]*input_0[14] + input_0[6]*input_0[15] + input_0[6]*input_0[16] + - input_0[6]*input_0[17] + input_0[6]*input_0[18] - input_0[7]*input_1[0] + - input_3[0] + input_3[1] + input_3[2] + input_3[3] + input_3[4] + + output_1[0] = -input_0[0] * input_2[0] + input_0[6] * input_0[13] + + input_0[6] * input_0[14] + input_0[6] * input_0[15] + input_0[6] * + input_0[16] + input_0[6] * input_0[17] + input_0[6] * input_0[18] - + input_0[7] * input_1[0] + input_3[0] + input_3[1] + input_3[2] + input_3[3] + + input_3[4] + input_3[5]; + output_1[1] = -input_0[1] * input_2[1] + input_0[6] * input_0[14] + + input_0[6] * input_0[15] + input_0[6] * input_0[16] + input_0[6] * + input_0[17] + input_0[6] * input_0[18] - input_0[8] * input_1[1] + + input_3[1] + input_3[2] + input_3[3] + input_3[4] + input_3[5]; + output_1[2] = -input_0[2] * input_2[2] + input_0[6] * input_0[15] + + input_0[6] * input_0[16] + input_0[6] * input_0[17] + input_0[6] * + input_0[18] - input_0[9] * input_1[2] + input_3[2] + input_3[3] + + input_3[4] + input_3[5]; + output_1[3] = -input_0[3] * input_2[3] + input_0[6] * input_0[16] + + input_0[6] * input_0[17] + input_0[6] * input_0[18] - input_0[10] * + input_1[3] + input_3[3] + input_3[4] + input_3[5]; + output_1[4] = -input_0[4] * input_2[4] + input_0[6] * input_0[17] + + input_0[6] * input_0[18] - input_0[11] * input_1[4] + input_3[4] + input_3[5]; - output_1[1] = -input_0[1]*input_2[1] + input_0[6]*input_0[14] + - input_0[6]*input_0[15] + input_0[6]*input_0[16] + input_0[6]*input_0[17] + - input_0[6]*input_0[18] - input_0[8]*input_1[1] + input_3[1] + input_3[2] + - input_3[3] + input_3[4] + input_3[5]; - output_1[2] = -input_0[2]*input_2[2] + input_0[6]*input_0[15] + - input_0[6]*input_0[16] + input_0[6]*input_0[17] + input_0[6]*input_0[18] - - input_0[9]*input_1[2] + input_3[2] + input_3[3] + input_3[4] + input_3[5]; - output_1[3] = -input_0[3]*input_2[3] + input_0[6]*input_0[16] + - input_0[6]*input_0[17] + input_0[6]*input_0[18] - input_0[10]*input_1[3] + - input_3[3] + input_3[4] + input_3[5]; - output_1[4] = -input_0[4]*input_2[4] + input_0[6]*input_0[17] + - input_0[6]*input_0[18] - input_0[11]*input_1[4] + input_3[4] + input_3[5]; - output_1[5] = -input_0[5]*input_2[5] + input_0[6]*input_0[18] - - input_0[12]*input_1[5] + input_3[5];\ + output_1[5] = -input_0[5] * input_2[5] + input_0[6] * input_0[18] - + input_0[12] * input_1[5] + input_3[5];\ """ self.generator._ignore_cse() @@ -403,11 +405,11 @@ def test_doprint(self): double pydy_5 = input_3[3]; double pydy_6 = input_3[4]; double pydy_7 = input_3[5]; - double pydy_8 = input_0[6]*input_0[15]; - double pydy_9 = input_0[6]*input_0[16]; - double pydy_10 = input_0[6]*input_0[17]; - double pydy_11 = input_0[6]*input_0[18]; - double pydy_12 = input_0[6]*input_0[14] + pydy_10 + pydy_11 + pydy_4 + + double pydy_8 = input_0[6] * input_0[15]; + double pydy_9 = input_0[6] * input_0[16]; + double pydy_10 = input_0[6] * input_0[17]; + double pydy_11 = input_0[6] * input_0[18]; + double pydy_12 = input_0[6] * input_0[14] + pydy_10 + pydy_11 + pydy_4 + pydy_5 + pydy_6 + pydy_7 + pydy_8 + pydy_9 + input_3[1]; output_0[0] = input_0[13] + pydy_3; @@ -447,17 +449,17 @@ def test_doprint(self): output_0[34] = input_0[18]; output_0[35] = input_0[18]; - output_1[0] = -input_0[0]*input_2[0] + input_0[6]*input_0[13] - - input_0[7]*input_1[0] + pydy_12 + input_3[0]; - output_1[1] = -input_0[1]*input_2[1] - input_0[8]*input_1[1] + pydy_12; - output_1[2] = -input_0[2]*input_2[2] - input_0[9]*input_1[2] + pydy_10 + - pydy_11 + pydy_4 + pydy_5 + pydy_6 + pydy_7 + pydy_8 + pydy_9; - output_1[3] = -input_0[3]*input_2[3] - input_0[10]*input_1[3] + pydy_10 + - pydy_11 + pydy_5 + pydy_6 + pydy_7 + pydy_9; - output_1[4] = -input_0[4]*input_2[4] - input_0[11]*input_1[4] + pydy_10 + - pydy_11 + pydy_6 + pydy_7; - output_1[5] = -input_0[5]*input_2[5] - input_0[12]*input_1[5] + pydy_11 + - pydy_7; + output_1[0] = -input_0[0] * input_2[0] + input_0[6] * input_0[13] - + input_0[7] * input_1[0] + pydy_12 + input_3[0]; + output_1[1] = -input_0[1] * input_2[1] - input_0[8] * input_1[1] + pydy_12; + output_1[2] = -input_0[2] * input_2[2] - input_0[9] * input_1[2] + pydy_10 + + pydy_11 + pydy_4 + pydy_5 + pydy_6 + pydy_7 + pydy_8 + pydy_9; + output_1[3] = -input_0[3] * input_2[3] - input_0[10] * input_1[3] + pydy_10 + + pydy_11 + pydy_5 + pydy_6 + pydy_7 + pydy_9; + output_1[4] = -input_0[4] * input_2[4] - input_0[11] * input_1[4] + pydy_10 + + pydy_11 + pydy_6 + pydy_7; + output_1[5] = -input_0[5] * input_2[5] - input_0[12] * input_1[5] + pydy_11 + + pydy_7; }\ """ diff --git a/pydy/utils.py b/pydy/utils.py index 14ef67c4..2e52e00d 100644 --- a/pydy/utils.py +++ b/pydy/utils.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import re import textwrap from pkg_resources import parse_version @@ -38,9 +39,15 @@ def wrap_and_indent(lines, indentation=4, width=79): # TODO : This will indent any lines that only contain a new line. Which # may not be preferable. new_lines = [] + + # add whitespace before and after [*/] binary operands between + # subexpressions and input/output + pattern = re.compile('(\w\])([*/])(\w)') for line in lines: if line != '\n': - wrapped = textwrap.wrap(line, width=width-indentation) + line = pattern.sub(lambda m: ' '.join(m.groups()), line) + wrapped = textwrap.wrap(line, width=width-indentation, + break_long_words=False) else: wrapped = [line] new_lines += wrapped