From a6d90f71a65278f562be0915b4f465722bca68f7 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 5 Mar 2018 13:07:25 -0600 Subject: [PATCH 1/3] Apply the loopy resolution to the issue of generation of nested of ternary operators in Python. Plus, replace uses of ' with " for consistency. --- dagrt/codegen/expressions.py | 28 +++++++++++++++------------- dagrt/expression.py | 3 ++- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/dagrt/codegen/expressions.py b/dagrt/codegen/expressions.py index e20d440..6f530ad 100644 --- a/dagrt/codegen/expressions.py +++ b/dagrt/codegen/expressions.py @@ -1,6 +1,6 @@ """Code generation of expressions""" from pymbolic.mapper.stringifier import ( - StringifyMapper, PREC_NONE, PREC_CALL, PREC_PRODUCT) + StringifyMapper, PREC_NONE, PREC_CALL, PREC_PRODUCT, PREC_LOGICAL_OR) import numpy as np @@ -139,7 +139,7 @@ class PythonExpressionMapper(StringifyMapper): """Converts expressions to Python code.""" def __init__(self, name_manager, function_registry, - numpy='numpy'): + numpy="numpy"): """name_manager is a map from a variable name (as a string) to its representation (as a string). @@ -152,7 +152,7 @@ class PythonExpressionMapper(StringifyMapper): def map_foreign(self, expr, *args): if expr is None: - return 'None' + return "None" elif isinstance(expr, str): return repr(expr) else: @@ -165,11 +165,11 @@ class PythonExpressionMapper(StringifyMapper): def map_numpy_array(self, expr, *args): if len(expr.shape) > 1: - raise ValueError('Representing multidimensional arrays is ' + - 'not supported') + raise ValueError( + "Representing multidimensional arrays is not supported") elements = [self.rec(element, *args) for element in expr] - return '{numpy}.array([{elements}],dtype=\'object\')'.format( - numpy=self._numpy, elements=', '.join(elements)) + return "{numpy}.array([{elements}],dtype=\'object\')".format( + numpy=self._numpy, elements=", ".join(elements)) def map_generic_call(self, symbol, args, kwargs): arg_strs_dict = {} @@ -187,12 +187,12 @@ class PythonExpressionMapper(StringifyMapper): self.rec(val, PREC_NONE) for val in args ] + [ - '{name}={expr}'.format( + "{name}={expr}".format( name=name, expr=self.rec(val, PREC_NONE)) for name, val in kwargs.items()] - return '{rhs}({args})'.format( + return "{rhs}({args})".format( rhs=self._name_manager.name_function(symbol.name), args=", ".join(args_strs)) @@ -212,10 +212,12 @@ class PythonExpressionMapper(StringifyMapper): from dagrt.expression import PREC_IFTHENELSE return self.parenthesize_if_needed( "{then} if {cond} else {else_}".format( - then=self.rec(expr.then, PREC_IFTHENELSE), - cond=self.rec(expr.condition, PREC_IFTHENELSE), - else_=self.rec(expr.else_, PREC_IFTHENELSE)), - enclosing_prec, PREC_NONE) + # "1 if 0 if 1 else 2 else 3" is not valid Python. + # So force parens by using an artificially higher precedence. + then=self.rec(expr.then, PREC_LOGICAL_OR), + cond=self.rec(expr.condition, PREC_LOGICAL_OR), + else_=self.rec(expr.else_, PREC_LOGICAL_OR)), + enclosing_prec, PREC_IFTHENELSE) # }}} diff --git a/dagrt/expression.py b/dagrt/expression.py index 41f5318..63f1b7c 100644 --- a/dagrt/expression.py +++ b/dagrt/expression.py @@ -32,6 +32,7 @@ from pymbolic.mapper.unifier import UnidirectionalUnifier from pymbolic.primitives import Variable, is_constant from pymbolic.parser import Parser, _less, _greater, _identifier from pymbolic.primitives import If as IfThenElse # noqa +from pymbolic.mapper.stringifier import PREC_LOGICAL_OR import logging import operator @@ -42,7 +43,7 @@ logger = logging.getLogger(__name__) # Precedence constant for IfThenElse. -PREC_IFTHENELSE = 1 +PREC_IFTHENELSE = PREC_LOGICAL_OR - 1 class ExtendedDependencyMapper(DependencyMapper): -- GitLab From ecdedfb99e40387414d9d053b87717ce7802a046 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 5 Mar 2018 13:13:19 -0600 Subject: [PATCH 2/3] Eliminate relative imports --- dagrt/codegen/__init__.py | 4 ++-- dagrt/codegen/codegen_base.py | 2 +- dagrt/codegen/data.py | 2 +- dagrt/codegen/fortran.py | 18 +++++++++--------- dagrt/codegen/python.py | 15 ++++++--------- dagrt/language.py | 10 ++++++++++ 6 files changed, 29 insertions(+), 22 deletions(-) diff --git a/dagrt/codegen/__init__.py b/dagrt/codegen/__init__.py index ea14edc..a2def1f 100644 --- a/dagrt/codegen/__init__.py +++ b/dagrt/codegen/__init__.py @@ -22,8 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from . import analysis -from . import python +import dagrt.codegen.analysis as analysis +import dagrt.codegen.python as python CodeGenerationError = analysis.CodeGenerationError diff --git a/dagrt/codegen/codegen_base.py b/dagrt/codegen/codegen_base.py index 897df17..2547439 100644 --- a/dagrt/codegen/codegen_base.py +++ b/dagrt/codegen/codegen_base.py @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from .ast import Block, IfThen, IfThenElse, InstructionWrapper +from dagrt.codegen.ast import Block, IfThen, IfThenElse, InstructionWrapper class StructuredCodeGenerator(object): diff --git a/dagrt/codegen/data.py b/dagrt/codegen/data.py index 824e33a..0ff82c7 100644 --- a/dagrt/codegen/data.py +++ b/dagrt/codegen/data.py @@ -410,7 +410,7 @@ class SymbolKindFinder(object): result = SymbolKindTable() - from .ast import get_instructions_in_ast + from dagrt.codegen.ast import get_instructions_in_ast def make_kim(func_name, check): return KindInferenceMapper( diff --git a/dagrt/codegen/fortran.py b/dagrt/codegen/fortran.py index ce839bd..813167e 100644 --- a/dagrt/codegen/fortran.py +++ b/dagrt/codegen/fortran.py @@ -28,8 +28,8 @@ from functools import partial import re # noqa import six -from .expressions import FortranExpressionMapper -from .codegen_base import StructuredCodeGenerator +from dagrt.codegen.expressions import FortranExpressionMapper +from dagrt.codegen.codegen_base import StructuredCodeGenerator from dagrt.utils import is_state_variable from dagrt.codegen.data import UserType from pytools.py_codegen import ( @@ -38,7 +38,7 @@ from pytools.py_codegen import ( from pymbolic.primitives import (Call, CallWithKwargs, Variable, Subscript, Lookup) from pymbolic.mapper import IdentityMapper -from .utils import (wrap_line_base, KeyToUniqueNameMap, +from dagrt.codegen.utils import (wrap_line_base, KeyToUniqueNameMap, make_identifier_from_name) @@ -1028,10 +1028,10 @@ class CodeGenerator(StructuredCodeGenerator): "used more than once") self.used = True - from .analysis import verify_code + from dagrt.codegen.analysis import verify_code verify_code(dag) - from .transform import ( + from dagrt.codegen.transform import ( eliminate_self_dependencies, isolate_function_arguments, isolate_function_calls, @@ -1046,7 +1046,7 @@ class CodeGenerator(StructuredCodeGenerator): # {{{ produce function name / function AST pairs - from .ast import create_ast_from_phase + from dagrt.codegen.ast import create_ast_from_phase from collections import namedtuple NameASTPair = namedtuple("NameASTPair", "name, ast") # noqa @@ -1064,7 +1064,7 @@ class CodeGenerator(StructuredCodeGenerator): [fd.name for fd in fdescrs], [fd.ast for fd in fdescrs]) - from .analysis import collect_ode_component_names_from_dag + from dagrt.codegen.analysis import collect_ode_component_names_from_dag component_ids = collect_ode_component_names_from_dag(dag) if not component_ids <= set(self.user_type_map): @@ -1204,7 +1204,7 @@ class CodeGenerator(StructuredCodeGenerator): self.emit(l) self.emit('') - from .analysis import collect_time_ids_from_dag + from dagrt.codegen.analysis import collect_time_ids_from_dag for i, time_id in enumerate(sorted(collect_time_ids_from_dag(dag))): self.emit("integer dagrt_time_{time_id}".format(time_id=time_id)) self.emit("parameter (dagrt_time_{time_id} = {i})".format( @@ -1226,7 +1226,7 @@ class CodeGenerator(StructuredCodeGenerator): # {{{ component name constants - from .analysis import collect_ode_component_names_from_dag + from dagrt.codegen.analysis import collect_ode_component_names_from_dag component_ids = collect_ode_component_names_from_dag(dag) for i, comp_id in enumerate(sorted(component_ids)): diff --git a/dagrt/codegen/python.py b/dagrt/codegen/python.py index b02c758..f55092e 100644 --- a/dagrt/codegen/python.py +++ b/dagrt/codegen/python.py @@ -22,9 +22,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from .expressions import PythonExpressionMapper -from .codegen_base import StructuredCodeGenerator -from .utils import (wrap_line_base, exec_in_new_namespace, +from dagrt.codegen.expressions import PythonExpressionMapper +from dagrt.codegen.codegen_base import StructuredCodeGenerator +from dagrt.codegen.utils import (wrap_line_base, exec_in_new_namespace, KeyToUniqueNameMap) from pytools.py_codegen import ( PythonCodeGenerator as PythonEmitter, @@ -34,9 +34,6 @@ from functools import partial import six -# from .ir import YieldStateInst - - def pad_python(line, width): line += ' ' * (width - 1 - len(line)) line += '\\' @@ -203,10 +200,10 @@ class CodeGenerator(StructuredCodeGenerator): self._name_manager, function_registry, numpy='self._numpy') def __call__(self, dag): - from .analysis import verify_code + from dagrt.codegen.analysis import verify_code verify_code(dag) - from .ast import create_ast_from_phase + from dagrt.codegen.ast import create_ast_from_phase self.begin_emit(dag) for phase_name in six.iterkeys(dag.phases): @@ -220,7 +217,7 @@ class CodeGenerator(StructuredCodeGenerator): def _pre_lower(self, ast): self._has_yield_inst = False from dagrt.language import YieldState - from .ast import get_instructions_in_ast + from dagrt.codegen.ast import get_instructions_in_ast for inst in get_instructions_in_ast(ast): if isinstance(inst, YieldState): self._has_yield_inst = True diff --git a/dagrt/language.py b/dagrt/language.py index 4441ff5..6130ceb 100644 --- a/dagrt/language.py +++ b/dagrt/language.py @@ -106,6 +106,8 @@ Instructions Assignment Instructions ^^^^^^^^^^^^^^^^^^^^^^^ +These instructions perform updates to the execution state, i.e. the variables. + .. autoclass:: AssignSolved .. autoclass:: AssignExpression .. autoclass:: AssignFunctionCall @@ -113,12 +115,20 @@ Assignment Instructions Control Instructions ^^^^^^^^^^^^^^^^^^^^ +These instructions affect the execution of a phase, or cause a phase to interact +with user code. + .. autoclass:: YieldState .. autoclass:: Raise .. autoclass:: FailStep .. autoclass:: ExitStep .. autoclass:: PhaseTransition +Miscellaneous Instructions +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: Nop + Code Container ~~~~~~~~~~~~~~ -- GitLab From fa32ac78461e4d8fe2294951b57015255cb76f40 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 5 Mar 2018 13:31:49 -0600 Subject: [PATCH 3/3] Eliminate name shadowing of the ast module and fix the top level import. --- dagrt/codegen/__init__.py | 8 ++------ dagrt/codegen/codegen_base.py | 2 +- dagrt/codegen/{ast.py => dag_ast.py} | 0 dagrt/codegen/data.py | 2 +- dagrt/codegen/fortran.py | 2 +- dagrt/codegen/python.py | 4 ++-- test/test_ast.py | 2 +- 7 files changed, 8 insertions(+), 12 deletions(-) rename dagrt/codegen/{ast.py => dag_ast.py} (100%) diff --git a/dagrt/codegen/__init__.py b/dagrt/codegen/__init__.py index a2def1f..982be02 100644 --- a/dagrt/codegen/__init__.py +++ b/dagrt/codegen/__init__.py @@ -22,9 +22,5 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -import dagrt.codegen.analysis as analysis -import dagrt.codegen.python as python - - -CodeGenerationError = analysis.CodeGenerationError -PythonCodeGenerator = python.CodeGenerator +from dagrt.codegen.analysis import CodeGenerationError # noqa +from dagrt.codegen.python import CodeGenerator as PythonCodeGenerator # noqa diff --git a/dagrt/codegen/codegen_base.py b/dagrt/codegen/codegen_base.py index 2547439..7bab08e 100644 --- a/dagrt/codegen/codegen_base.py +++ b/dagrt/codegen/codegen_base.py @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from dagrt.codegen.ast import Block, IfThen, IfThenElse, InstructionWrapper +from dagrt.codegen.dag_ast import Block, IfThen, IfThenElse, InstructionWrapper class StructuredCodeGenerator(object): diff --git a/dagrt/codegen/ast.py b/dagrt/codegen/dag_ast.py similarity index 100% rename from dagrt/codegen/ast.py rename to dagrt/codegen/dag_ast.py diff --git a/dagrt/codegen/data.py b/dagrt/codegen/data.py index 0ff82c7..61176fb 100644 --- a/dagrt/codegen/data.py +++ b/dagrt/codegen/data.py @@ -410,7 +410,7 @@ class SymbolKindFinder(object): result = SymbolKindTable() - from dagrt.codegen.ast import get_instructions_in_ast + from dagrt.codegen.dag_ast import get_instructions_in_ast def make_kim(func_name, check): return KindInferenceMapper( diff --git a/dagrt/codegen/fortran.py b/dagrt/codegen/fortran.py index 813167e..e4c8a5d 100644 --- a/dagrt/codegen/fortran.py +++ b/dagrt/codegen/fortran.py @@ -1046,7 +1046,7 @@ class CodeGenerator(StructuredCodeGenerator): # {{{ produce function name / function AST pairs - from dagrt.codegen.ast import create_ast_from_phase + from dagrt.codegen.dag_ast import create_ast_from_phase from collections import namedtuple NameASTPair = namedtuple("NameASTPair", "name, ast") # noqa diff --git a/dagrt/codegen/python.py b/dagrt/codegen/python.py index f55092e..cf09a68 100644 --- a/dagrt/codegen/python.py +++ b/dagrt/codegen/python.py @@ -203,7 +203,7 @@ class CodeGenerator(StructuredCodeGenerator): from dagrt.codegen.analysis import verify_code verify_code(dag) - from dagrt.codegen.ast import create_ast_from_phase + from dagrt.codegen.dag_ast import create_ast_from_phase self.begin_emit(dag) for phase_name in six.iterkeys(dag.phases): @@ -217,7 +217,7 @@ class CodeGenerator(StructuredCodeGenerator): def _pre_lower(self, ast): self._has_yield_inst = False from dagrt.language import YieldState - from dagrt.codegen.ast import get_instructions_in_ast + from dagrt.codegen.dag_ast import get_instructions_in_ast for inst in get_instructions_in_ast(ast): if isinstance(inst, YieldState): self._has_yield_inst = True diff --git a/test/test_ast.py b/test/test_ast.py index 1cd726a..aa6c451 100755 --- a/test/test_ast.py +++ b/test/test_ast.py @@ -27,7 +27,7 @@ from pymbolic import var from pymbolic.primitives import LogicalNot -from dagrt.codegen.ast import (IfThen, IfThenElse, Block, InstructionWrapper, +from dagrt.codegen.dag_ast import (IfThen, IfThenElse, Block, InstructionWrapper, create_ast_from_phase, simplify_ast) from dagrt.language import Instruction, DAGCode -- GitLab