summaryrefslogtreecommitdiff
path: root/cad/src/exprs/iterator_exprs.py
blob: 361f742888f3807a412540402a328e18cd671809 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# Copyright 2007 Nanorex, Inc.  See LICENSE file for details.
"""
iterator_exprs.py

$Id$
"""

from exprs.Exprs import list_Expr, constant_Expr
from exprs.Exprs import is_expr_Instance
from exprs.Exprs import is_pure_expr
from exprs.instance_helpers import DelegatingInstanceOrExpr
from exprs.attr_decl_macros import ArgExpr, Arg, Option
from exprs.ExprsConstants import Function
from exprs.__Symbols__ import _self

class MapListToExpr(DelegatingInstanceOrExpr): #e rename? should this be what map_Expr does, or does that need to be incremental-update?
    # note: this was modified from _MT_try2_kids_helper, which was then rewritten in terms of it.
    # args (#e should some be ArgOrOption? Note: that doesn't work right if it comes before Arg.)
    ###KLUGE: use ArgExpr to avoid problems when passing expr classes as functions -- not sure if generally ok (eg when ordinary callable is passed)#####
    function = ArgExpr(Function, doc = "a python function which maps members of elements to Instances or Exprs")
    elements = Arg(list_Expr, doc = "a list of elements (of whatever data type you want, suitable for passing to _my.function)")
    exprhead = ArgExpr(Function, doc = """a python function or expr which can be applied to a sequence of Instances
                    to produce an Expr we should instantiate as our _delegate, whenever our input list of elements changes.
                    Typical values include expr classes like SimpleColumn, or customized ones like SimpleRow(pixelgap = 2).
                    WARNING: due to logic bugs at present, expr classes passed to this argument (or to the function argument)
                    need to be wrapped in KLUGE_for_passing_expr_classes_as_functions_to_ArgExpr.
                    """
                )
    instance_function = Option(Function, _self.Instance,
                               doc = "a python function with the API of some IorE object's .Instance method, to produce the Instances we delegate to" )
        # I wanted to name this Instance, but I think that would cause infrecur when it used the default.
        # note: we pass it permit_expr_to_vary = True, which complicates the required API. But without this we could not pass someobj.Instance.
        # Maybe IorE needs a variant method of Instance with permit_expr_to_vary = True by default? VaryingInstance?
    # self._delegate recompute rule
    def _C__delegate(self):
        function = self.function
        elements = self.elements # usage tracked (that's important)
        exprhead = self.exprhead
        index = '_C__delegate'
        # compute the expr we need (see comment above for why we need a new one each time)
        elts = map( function, elements)
        def func2((elt, subindex)): #070320
            if is_expr_Instance(elt):
                res = elt
            elif is_pure_expr(elt):
                # new feature 070320: if function(element) gives an expr, instantiate it with a suitable choice of index
                eli = self.instance_function( elt, (subindex, index), permit_expr_to_vary = True)
                assert is_expr_Instance(eli) #e error message with elt and eli
                res = eli
            else:
                assert is_expr_Instance(elt) or is_pure_expr(elt) #e message
            assert is_expr_Instance(res) # sanity check, can remove when works
            return res
        elts = map( func2, zip(elts, range(len(elts))))
        expr = exprhead(*elts)
        # do we need to eval expr first? in theory i forget, but I think we do.
        # in practice it's very likely to eval to itself, so it doesn't matter for now. ###k
        ##e do we need to discard usage tracking during the following??
        res = self.instance_function( expr, ('notint', index), permit_expr_to_vary = True)
        return res
    pass # end of class MapListToExpr

def KLUGE_for_passing_expr_classes_as_functions_to_ArgExpr( exprclass ):
    return constant_Expr( exprclass( _KLUGE_fake_option = 1))
        # comment from when we tried everything simpler than this to pass SimpleColumn to MapListToExpr as its exprhead arg:
        # this kluge was not enough: passing constant_Expr(SimpleColumn) (several errors)
        # or was using ArgExpr in MapListToExpr
        # nor was this, by itself: exprclass( _KLUGE_fake_option = 1)
        # but using all three together, it works.
        # The things this klugetower avoids include:
        # - without ArgExpr we'd try to instantiate the function, ok for ordinary one but not for expr class let alone customized expr
        # - ArgExpr's grabarg wrapping the exprhead-as-function with a lexenv_ipath_Expr, which has no __call__:
        #   AssertionError: subclass 'lexenv_ipath_Expr' of Expr must implement __call__
        #   (and a trivial __call__ would be incorrect, as explained in demo_ui.py recently [070302]
        #   [thus the constant_Expr]
        # - AssertionError: pure exprs should not be returned from _i_instance: <class 'exprs.Column.SimpleColumn'> ) [thus the cust]

# end