Skip to content

Commit

Permalink
Use string buffer to store generated code (#211)
Browse files Browse the repository at this point in the history
  • Loading branch information
StrikerRUS committed May 19, 2020
1 parent ecf9444 commit 182a53e
Show file tree
Hide file tree
Showing 15 changed files with 53 additions and 21 deletions.
2 changes: 1 addition & 1 deletion m2cgen/interpreters/c/interpreter.py
Expand Up @@ -63,7 +63,7 @@ def interpret(self, expr):
if self.with_math_module:
self._cg.add_dependency("<math.h>")

return self._cg.code
return self._cg.finalize_and_get_generated_code()

# Both methods supporting linear algebra do several things:
#
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/c_sharp/interpreter.py
Expand Up @@ -58,4 +58,4 @@ def interpret(self, expr):
if self.with_math_module:
self._cg.add_dependency("System.Math")

return self._cg.code
return self._cg.finalize_and_get_generated_code()
43 changes: 37 additions & 6 deletions m2cgen/interpreters/code_generator.py
@@ -1,4 +1,6 @@
from io import StringIO
from string import Template
from weakref import finalize


class CodeTemplate:
Expand Down Expand Up @@ -29,11 +31,38 @@ class BaseCodeGenerator:

def __init__(self, indent=4):
self._indent = indent
self._code_buf = None
self.reset_state()

def reset_state(self):
self._current_indent = 0
self.code = ""
self._finalize_buffer()
self._code_buf = StringIO()
self._code = None
self._finalizer = finalize(self, self._finalize_buffer)

def _finalize_buffer(self):
if self._code_buf is not None and not self._code_buf.closed:
self._code_buf.close()

def _write_to_code_buffer(self, text, prepend=False):
if self._code_buf.closed:
raise BufferError(
"Cannot modify code after getting generated code and "
"closing the underlying buffer!\n"
"Call reset_state() to allocate new buffer.")
if prepend:
self._code_buf.seek(0)
old_content = self._code_buf.read()
self._code_buf.seek(0)
text += old_content
self._code_buf.write(text)

def finalize_and_get_generated_code(self):
if not self._code_buf.closed:
self._code = self._code_buf.getvalue()
self._finalize_buffer()
return self._code if self._code is not None else ""

def increase_indent(self):
self._current_indent += self._indent
Expand All @@ -48,22 +77,24 @@ def decrease_indent(self):
def add_code_line(self, line):
if not line:
return
indent = " " * self._current_indent
self.code += indent + line + "\n"
self.add_code_lines([line.strip()])

def add_code_lines(self, lines):
if isinstance(lines, str):
lines = lines.strip().split("\n")
indent = " " * self._current_indent
self.code += indent + "\n{}".format(indent).join(lines) + "\n"
self._write_to_code_buffer(
indent + "\n{}".format(indent).join(lines) + "\n")

def prepend_code_line(self, line):
self.code = line + "\n" + self.code
if not line:
return
self.prepend_code_lines([line.strip()])

def prepend_code_lines(self, lines):
if isinstance(lines, str):
lines = lines.strip().split("\n")
self.code = "\n".join(lines) + "\n" + self.code
self._write_to_code_buffer("\n".join(lines) + "\n", prepend=True)

# Following methods simply compute expressions using templates without
# changing result.
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/dart/interpreter.py
Expand Up @@ -62,7 +62,7 @@ def interpret(self, expr):
if self.with_math_module:
self._cg.add_dependency("dart:math")

return self._cg.code
return self._cg.finalize_and_get_generated_code()

def interpret_tanh_expr(self, expr, **kwargs):
self.with_tanh_expr = True
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/go/interpreter.py
Expand Up @@ -50,4 +50,4 @@ def interpret(self, expr):
if self.with_math_module:
self._cg.add_dependency("math")

return self._cg.code
return self._cg.finalize_and_get_generated_code()
5 changes: 3 additions & 2 deletions m2cgen/interpreters/haskell/interpreter.py
Expand Up @@ -52,7 +52,7 @@ def interpret(self, expr):
self._cg.prepend_code_line(self._cg.tpl_module_definition(
module_name=self.module_name))

return self._cg.code
return self._cg.finalize_and_get_generated_code()

def interpret_if_expr(self, expr, if_code_gen=None, **kwargs):
if if_code_gen is None:
Expand All @@ -72,7 +72,8 @@ def interpret_if_expr(self, expr, if_code_gen=None, **kwargs):
code_gen.add_if_termination()

if not nested:
return self._cache_reused_expr(expr, code_gen.code)
return self._cache_reused_expr(
expr, code_gen.finalize_and_get_generated_code())

def interpret_pow_expr(self, expr, **kwargs):
base_result = self._do_interpret(expr.base_expr, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/java/interpreter.py
Expand Up @@ -60,7 +60,7 @@ def interpret(self, expr):
os.path.dirname(__file__), "linear_algebra.java")
top_cg.add_code_lines(utils.get_file_content(filename))

return top_cg.code
return top_cg.finalize_and_get_generated_code()

# Required by SubroutinesMixin to create new code generator for
# each subroutine.
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/javascript/interpreter.py
Expand Up @@ -49,4 +49,4 @@ def interpret(self, expr):
os.path.dirname(__file__), "linear_algebra.js")
self._cg.add_code_lines(utils.get_file_content(filename))

return self._cg.code
return self._cg.finalize_and_get_generated_code()
2 changes: 1 addition & 1 deletion m2cgen/interpreters/mixins.py
Expand Up @@ -187,7 +187,7 @@ def _process_subroutine(self, subroutine):
last_result = self._do_interpret(subroutine.expr)
self._cg.add_return_statement(last_result)

return self._cg.code
return self._cg.finalize_and_get_generated_code()

def _get_subroutine_name(self):
subroutine_name = "subroutine" + str(self._subroutine_idx)
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/php/interpreter.py
Expand Up @@ -45,4 +45,4 @@ def interpret(self, expr):

self._cg.prepend_code_line("<?php")

return self._cg.code
return self._cg.finalize_and_get_generated_code()
2 changes: 1 addition & 1 deletion m2cgen/interpreters/powershell/interpreter.py
Expand Up @@ -46,7 +46,7 @@ def interpret(self, expr):
os.path.dirname(__file__), "linear_algebra.ps1")
self._cg.prepend_code_lines(utils.get_file_content(filename))

return self._cg.code
return self._cg.finalize_and_get_generated_code()

def interpret_exp_expr(self, expr, **kwargs):
nested_result = self._do_interpret(expr.expr, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/python/interpreter.py
Expand Up @@ -37,7 +37,7 @@ def interpret(self, expr):
if self.with_linear_algebra:
self._cg.add_dependency("numpy", alias="np")

return self._cg.code
return self._cg.finalize_and_get_generated_code()

def interpret_bin_vector_expr(self, expr, **kwargs):
self.with_linear_algebra = True
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/r/interpreter.py
Expand Up @@ -38,7 +38,7 @@ def interpret(self, expr):
self.enqueue_subroutine(self.function_name, expr)
self.process_subroutine_queue(top_cg)

return top_cg.code
return top_cg.finalize_and_get_generated_code()

def create_code_generator(self):
return RCodeGenerator(indent=self.indent)
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/ruby/interpreter.py
Expand Up @@ -42,7 +42,7 @@ def interpret(self, expr):
os.path.dirname(__file__), "linear_algebra.rb")
self._cg.prepend_code_lines(utils.get_file_content(filename))

return self._cg.code
return self._cg.finalize_and_get_generated_code()

def interpret_bin_num_expr(self, expr, **kwargs):
if expr.op == ast.BinNumOpType.DIV:
Expand Down
2 changes: 1 addition & 1 deletion m2cgen/interpreters/visual_basic/interpreter.py
Expand Up @@ -60,7 +60,7 @@ def interpret(self, expr):
self._cg.add_code_line(self._cg.tpl_block_termination(
block_name="Module"))

return self._cg.code
return self._cg.finalize_and_get_generated_code()

def interpret_pow_expr(self, expr, **kwargs):
base_result = self._do_interpret(expr.base_expr, **kwargs)
Expand Down

0 comments on commit 182a53e

Please sign in to comment.