1""" 2Contains a simple codegen helper 3""" 4 5 6class CodeGen(object): 7 def __init__(self, indent=" ", cgen=False): 8 self.indent_lvl = 0 9 self.indent_tab = indent 10 self.data = [] 11 self.cgen = cgen 12 13 def indent(self, lvl=1): 14 """ 15 Indents the code one or more levels 16 """ 17 18 self.indent_lvl += lvl 19 20 def dedent(self, lvl=1): 21 """ 22 Dedents the code one or more levels 23 """ 24 25 self.indent_lvl -= lvl 26 if self.indent_lvl < 0: 27 last_lines = "\n".join(self.data[-4:]) 28 raise ValueError("Indent level is negative! Last lines:\n\n%s" % last_lines) 29 30 def write(self, line, endl=None): 31 """ 32 Write a line with the current indent 33 """ 34 shift = self.indent_lvl * self.indent_tab 35 if self.cgen and (endl is None) and ("//" not in line) and ("#" not in line): 36 endl = ";" 37 if endl is None: 38 endl = "" 39 40 self.data.append(shift + line + endl) 41 42 def blankline(self): 43 """ 44 Inserts a blankline 45 """ 46 self.data.append("") 47 48 def repr(self, filename=None, combine="\n", clang_format=False): 49 """ 50 Combine the data into a single string, optionally write to file, and format. 51 """ 52 tmp = combine.join(self.data) 53 if clang_format: 54 if self.cgen is False: 55 raise KeyError("clang_format is only valid for c generation.") 56 try: 57 tmp = run_clang_format(tmp) 58 except (OSError, AttributeError) as e: 59 print(str(e)) 60 61 if filename is not None: 62 with open(filename, "w") as outfile: 63 outfile.write(tmp) 64 return tmp 65 66 def start_c_block(self, line=None): 67 """ 68 Opens a C block with open brackets and indention 69 """ 70 71 if self.cgen is False: 72 raise KeyError("Start c block only valid for c generation.") 73 74 if line is None: 75 self.write("{", endl="") 76 else: 77 self.write(line + " {", endl="") 78 79 self.indent() 80 81 def close_c_block(self): 82 """ 83 Ends a c block with a dedent and close line 84 """ 85 if self.cgen is False: 86 raise KeyError("Start c block only valid for c generation.") 87 88 self.dedent() 89 self.write("}", endl="") 90 91 92def run_clang_format(text): 93 import subprocess as sp 94 import shutil 95 import os 96 97 cf_path = None 98 try: 99 cf_path = shutil.which("clang-format") 100 except AttributeError: 101 # Python 3.2 or less 102 for path in os.environ["PATH"].split(":"): 103 path = os.path.join(path, "clang-format") 104 if os.path.exists(path): 105 cf_path = path 106 break 107 108 if cf_path is None: 109 return text 110 111 fname = "codegen.cf.tmp" 112 113 with open(fname, "w") as cfile: 114 cfile.write(text) 115 116 # Run and check output code 117 retcode = sp.call([cf_path, "-i", fname], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE) 118 if retcode: 119 raise OSError("Clang-format failed, skipping.") 120 121 with open(fname, "r") as cfile: 122 text = cfile.read() 123 124 os.unlink(fname) 125 return text 126