Skip to content

Commit

Permalink
Add whitespace to generated code to allow line breaks
Browse files Browse the repository at this point in the history
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 pydy#263.
  • Loading branch information
oliverlee committed Oct 21, 2015
1 parent 12ef6f8 commit e11f2fe
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 51 deletions.
102 changes: 52 additions & 50 deletions pydy/codegen/tests/test_c_code.py
Expand Up @@ -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];\
"""

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}\
"""
Expand Down
9 changes: 8 additions & 1 deletion pydy/utils.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python

import re
import textwrap

from pkg_resources import parse_version
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e11f2fe

Please sign in to comment.