def Instance(expr, _index_expr=_E_ATTR, _lvalue_flag=False, _noinstance=False, doc=None): """ This macro is assigned to a class attr to declare that its value should be a lazily-instantiated Instance of expr (by default). Assuming the arg is an expr (not yet checked?), turn into the expr _self._i_instance(hold_Expr(expr), _E_ATTR), which is free in the symbols _self and _E_ATTR. [#e _E_ATTR might be changed to _E_INDEX, or otherwise revised.] This function is also used internally to help implement the Arg and Option macros; for their use only, it has a private _index_expr option, giving an index expr other than _E_ATTR for the new Instance (which is used to suggest an ipath for the new instance, relative to that of self). Similarly, it helps implement ArgExpr etc, for whose sake it has a private option _noinstance. Devel scratch comment: Note that the Arg and Option macros may have handy, not expr itself, but a "grabarg" expr which needs to be evaluated (with _self bound) to produce the expr to be instantiated. What should they pass?? eval_Expr of the expr they have. [#doc - reword this] Other private options: _lvalue_flag, _noinstance (_noinstance is only supported when EVAL_REFORM is true) """ if doc: printnim( "Instance doc is not saved anywhere; should turn into a note to formulascanner to save it as metainfo, maybe" ) #e printnim( "review: same index is used for a public Option and a private Instance on an attr; maybe ok if no overlap possible???" ) ##e global _self # not needed, just fyi if EVAL_REFORM: if _lvalue_flag: assert not _noinstance # since it makes no sense to ask for this then, AFAIK (if ok for one, ok for all -- see below) #070119 bugfix to make Set(var,val) work again (eg when clicking a checkbox_pref) # rather than evalling var to its current value. This means _lvalue_flag never gets passed to _i_instance. res = call_Expr(getattr_Expr(_self, '_i_instance'), eval_to_lval_Expr(expr), _index_expr) ####e if this works, then try simplifying it to remove the _i_instance call! (assuming the lval is never needing make) # (or given this macro's name, maybe it makes more sense for LvalueArg to manage to not call it...) elif _noinstance: #070122 # we ignore _index_expr, but callers can't help but pass one, so don't complain when they do return expr # i.e. Instance(expr) == expr -- not useful directly, but useful as a passthru option from Arg etc. else: res = call_Expr(getattr_Expr(_self, '_i_instance'), expr, _index_expr) else: assert not _noinstance, "bug: _noinstance is only supported when EVAL_REFORM is true" res = call_Expr(getattr_Expr(_self, '_i_instance'), hold_Expr(expr), _index_expr, _lvalue_flag=_lvalue_flag) return res
def Instance(expr, _index_expr = _E_ATTR, _lvalue_flag = False, _noinstance = False, doc = None): """ This macro is assigned to a class attr to declare that its value should be a lazily-instantiated Instance of expr (by default). Assuming the arg is an expr (not yet checked?), turn into the expr _self._i_instance(hold_Expr(expr), _E_ATTR), which is free in the symbols _self and _E_ATTR. [#e _E_ATTR might be changed to _E_INDEX, or otherwise revised.] This function is also used internally to help implement the Arg and Option macros; for their use only, it has a private _index_expr option, giving an index expr other than _E_ATTR for the new Instance (which is used to suggest an ipath for the new instance, relative to that of self). Similarly, it helps implement ArgExpr etc, for whose sake it has a private option _noinstance. Devel scratch comment: Note that the Arg and Option macros may have handy, not expr itself, but a "grabarg" expr which needs to be evaluated (with _self bound) to produce the expr to be instantiated. What should they pass?? eval_Expr of the expr they have. [#doc - reword this] Other private options: _lvalue_flag, _noinstance (_noinstance is only supported when EVAL_REFORM is true) """ if doc: printnim("Instance doc is not saved anywhere; should turn into a note to formulascanner to save it as metainfo, maybe")#e printnim("review: same index is used for a public Option and a private Instance on an attr; maybe ok if no overlap possible???")##e global _self # not needed, just fyi if EVAL_REFORM: if _lvalue_flag: assert not _noinstance # since it makes no sense to ask for this then, AFAIK (if ok for one, ok for all -- see below) #070119 bugfix to make Set(var,val) work again (eg when clicking a checkbox_pref) # rather than evalling var to its current value. This means _lvalue_flag never gets passed to _i_instance. res = call_Expr( getattr_Expr(_self, '_i_instance'), eval_to_lval_Expr(expr), _index_expr ) ####e if this works, then try simplifying it to remove the _i_instance call! (assuming the lval is never needing make) # (or given this macro's name, maybe it makes more sense for LvalueArg to manage to not call it...) elif _noinstance:#070122 # we ignore _index_expr, but callers can't help but pass one, so don't complain when they do return expr # i.e. Instance(expr) == expr -- not useful directly, but useful as a passthru option from Arg etc. else: res = call_Expr( getattr_Expr(_self, '_i_instance'), expr, _index_expr ) else: assert not _noinstance, "bug: _noinstance is only supported when EVAL_REFORM is true" res = call_Expr( getattr_Expr(_self, '_i_instance'), hold_Expr(expr), _index_expr, _lvalue_flag = _lvalue_flag ) return res
def _ArgOption_helper(attr_expr, argpos_expr, type_expr, dflt_expr, _lvalue_flag=False, _arglist=False, **moreopts): """ [private helper for Arg, Option, and maybe ArgOrOption] attr_expr should be None, or some sort of expr (in practice always _E_ATTR so far) that will get replaced by a constant_Expr for the current attr (in ExprsMeta's FormulaScanner), according to whether the current attr should be part of the index and a public option-name for supplying the arg (we make sure those conditions are the same). [#e Note that if someday we wanted to include f(attr) in the index, but still use attr alone as an option name, we'd have to modify this to permit both f(attr) (or f) and attr to be passed.] argpos_expr should similarly be None, or some sort of expr (in practice a private subclass of internal_Expr) that will get replaced by a constant_Expr for the argument position (an int) that should be allocated to the current attr's arg (determined in ExprsMeta's FormulaScanner by allocating posns 0,1,2,etc to newly seen arg-attrs, whether or not the attr itself is public for that arg). type_expr ###doc, passed herein to canon_type dflt_expr ###doc, can also be _E_DFLT_FROM_TYPE_ or [handled in caller i think, but survives here unmatteringly] _E_REQUIRED_ARG_; will be passed through canon_expr _lvalue_flag is a private option used by LvalueArg. _arglist is a private option used by ArgList. """ if _lvalue_flag: printnim("_lvalue_flag's proper interaction with dflt_expr is nim" ) # in all cases below ### guess: we want it to be an expr for a default stateref global _self # fyi type_expr = canon_type(type_expr) printnim( "can type_expr legally be self-dependent and/or time-dependent? ###k I guess that's nim in current code!" ) #070115 comment if _arglist: # new feature 070321. The type is applied to each element, but the default value is for the entire list -- # OTOH, when would it ever be used, since even if no args are supplied, the list can be formed?? # Probably it would only be used when the list was 0 length, and could meaningfully be [], (), or another list-like thing... # this is all a guess and I probably won't even review this code for this issue now, unless it fails when tried. ####k type_expr = tuple_Expr( type_expr ) # type-coerce the value to a list of the given type [070321 guess] ###e or list_Expr??? if dflt_expr is _E_DFLT_FROM_TYPE_: dflt_expr = default_expr_from_type_expr(type_expr) ## note [070115], this would be impossible for time-dependent types! and for self-dep ones, possible but harder than current code. assert is_pure_expr(dflt_expr) #k guess 061105 else: dflt_expr = canon_expr( dflt_expr ) # hopefully this finally will fix dflt 10 bug, 061105 guesshope ###k [works for None, 061114] assert is_pure_expr( dflt_expr ) # not sure this is redundant, since not sure if canon_expr checks for Instance ###k printnim("not sure if canon_expr checks for Instance") # Note on why we use explicit call_Expr & getattr_Expr below, # rather than () and . notation like you can use in user-level formulae (which python turns into __call__ and getattr), # to construct Exprs like _self._i_grabarg( attr_expr, ...): # it's only to work around safety features which normally detect that kind of Expr-formation (getattr on _i_* or _e_*, # or getattr then call) as a likely error. These safety features are very important, catching errors that would often lead # to hard-to-diagnose bugs (when our code has an Expr but thinks it has an Instance), so it's worth the trouble. held_dflt_expr = hold_Expr(dflt_expr) # Note, this gets evalled back into dflt_expr (treated as inert, may or may not be an expr depending on what it is right here) # by the time _i_grabarg sees it (the eval is done when the call_Expr evals its args before doing the call). # So if we wanted _i_grabarg to want None rather than _E_REQUIRED_ARG_ as a special case, we could change to that (there & here). grabopts = {} if _arglist: grabopts.update(dict(_arglist=constant_Expr(_arglist))) grabarg_expr = call_Expr(getattr_Expr(_self, '_i_grabarg'), attr_expr, argpos_expr, held_dflt_expr, **grabopts) # comments 070115: # - This will eval to an expr which depends on self but not on time. We could optim by wrapping it # (or declaring it final) in a way which effectively replaced it with its value-expr when first used. # (But it's not obvious where to store the result of that, since the exprs being returned now are assigned to classes # and will never be specific to single selfs. Do we need an expr to use here, which can cache its own info in self?? # Note: AFAIK, self will be the same as what _self gets replaced with when this is used. (We ought to assert that.) ###e) # - Further, grabarg_expr is probably supposed to be wrapped *directly* by eval_Expr, not with type_expr inside. I think I'll # make that change right now and test it with EVAL_REFORM still False, since I think it's always been required, as said # in other comments here. DOING THIS NOW. if attr_expr is not None and argpos_expr is not None: # for ArgOrOption, use a tuple of a string and int (attr and argpos) as the index index_expr = tuple_Expr(attr_expr, argpos_expr) elif attr_expr is None and argpos_expr is None: assert 0, "attr_expr is None and argpos_expr is None ..." elif attr_expr is not None: # for Option, use a plain attr string as the index index_expr = attr_expr else: assert argpos_expr is not None # for Arg, use a plain int as the index # (note: ExprsMeta replaces argpos_expr with that int wrapped in constant_Expr, but later eval pulls out the raw int) index_expr = argpos_expr # see if this is fixed now, not that it means much since we were using a stub... but who knows, maybe the stub was buggy # and we compensated for that and this could if so cause a bug: ## printnim("I suspect type_expr (stub now) is included wrongly re eval_Expr in _ArgOption_helper, in hindsight 061117") ## ### I suspect the above, because grabarg expr needs to be evalled to get the expr whose type coercion we want to instantiate res = Instance(_type_coercion_expr(type_expr, eval_Expr(grabarg_expr)), _index_expr=index_expr, _lvalue_flag=_lvalue_flag, **moreopts) # note: moreopts might contain _noinstance = True, and if so, Instance normally returns its first arg unchanged # (depending on other options). # 070115 replaced eval_Expr( type_expr( grabarg_expr)) with _type_coercion_expr( type_expr, eval_Expr(grabarg_expr) ) return res # from _ArgOption_helper
def _ArgOption_helper( attr_expr, argpos_expr, type_expr, dflt_expr, _lvalue_flag = False, _arglist = False, **moreopts ): """ [private helper for Arg, Option, and maybe ArgOrOption] attr_expr should be None, or some sort of expr (in practice always _E_ATTR so far) that will get replaced by a constant_Expr for the current attr (in ExprsMeta's FormulaScanner), according to whether the current attr should be part of the index and a public option-name for supplying the arg (we make sure those conditions are the same). [#e Note that if someday we wanted to include f(attr) in the index, but still use attr alone as an option name, we'd have to modify this to permit both f(attr) (or f) and attr to be passed.] argpos_expr should similarly be None, or some sort of expr (in practice a private subclass of internal_Expr) that will get replaced by a constant_Expr for the argument position (an int) that should be allocated to the current attr's arg (determined in ExprsMeta's FormulaScanner by allocating posns 0,1,2,etc to newly seen arg-attrs, whether or not the attr itself is public for that arg). type_expr ###doc, passed herein to canon_type dflt_expr ###doc, can also be _E_DFLT_FROM_TYPE_ or [handled in caller i think, but survives here unmatteringly] _E_REQUIRED_ARG_; will be passed through canon_expr _lvalue_flag is a private option used by LvalueArg. _arglist is a private option used by ArgList. """ if _lvalue_flag: printnim("_lvalue_flag's proper interaction with dflt_expr is nim") # in all cases below ### guess: we want it to be an expr for a default stateref global _self # fyi type_expr = canon_type( type_expr) printnim("can type_expr legally be self-dependent and/or time-dependent? ###k I guess that's nim in current code!")#070115 comment if _arglist: # new feature 070321. The type is applied to each element, but the default value is for the entire list -- # OTOH, when would it ever be used, since even if no args are supplied, the list can be formed?? # Probably it would only be used when the list was 0 length, and could meaningfully be [], (), or another list-like thing... # this is all a guess and I probably won't even review this code for this issue now, unless it fails when tried. ####k type_expr = tuple_Expr(type_expr) # type-coerce the value to a list of the given type [070321 guess] ###e or list_Expr??? if dflt_expr is _E_DFLT_FROM_TYPE_: dflt_expr = default_expr_from_type_expr( type_expr) ## note [070115], this would be impossible for time-dependent types! and for self-dep ones, possible but harder than current code. assert is_pure_expr(dflt_expr) #k guess 061105 else: dflt_expr = canon_expr(dflt_expr) # hopefully this finally will fix dflt 10 bug, 061105 guesshope ###k [works for None, 061114] assert is_pure_expr(dflt_expr) # not sure this is redundant, since not sure if canon_expr checks for Instance ###k printnim("not sure if canon_expr checks for Instance") # Note on why we use explicit call_Expr & getattr_Expr below, # rather than () and . notation like you can use in user-level formulae (which python turns into __call__ and getattr), # to construct Exprs like _self._i_grabarg( attr_expr, ...): # it's only to work around safety features which normally detect that kind of Expr-formation (getattr on _i_* or _e_*, # or getattr then call) as a likely error. These safety features are very important, catching errors that would often lead # to hard-to-diagnose bugs (when our code has an Expr but thinks it has an Instance), so it's worth the trouble. held_dflt_expr = hold_Expr(dflt_expr) # Note, this gets evalled back into dflt_expr (treated as inert, may or may not be an expr depending on what it is right here) # by the time _i_grabarg sees it (the eval is done when the call_Expr evals its args before doing the call). # So if we wanted _i_grabarg to want None rather than _E_REQUIRED_ARG_ as a special case, we could change to that (there & here). grabopts = {} if _arglist: grabopts.update(dict(_arglist = constant_Expr(_arglist))) grabarg_expr = call_Expr( getattr_Expr(_self, '_i_grabarg'), attr_expr, argpos_expr, held_dflt_expr, **grabopts ) # comments 070115: # - This will eval to an expr which depends on self but not on time. We could optim by wrapping it # (or declaring it final) in a way which effectively replaced it with its value-expr when first used. # (But it's not obvious where to store the result of that, since the exprs being returned now are assigned to classes # and will never be specific to single selfs. Do we need an expr to use here, which can cache its own info in self?? # Note: AFAIK, self will be the same as what _self gets replaced with when this is used. (We ought to assert that.) ###e) # - Further, grabarg_expr is probably supposed to be wrapped *directly* by eval_Expr, not with type_expr inside. I think I'll # make that change right now and test it with EVAL_REFORM still False, since I think it's always been required, as said # in other comments here. DOING THIS NOW. if attr_expr is not None and argpos_expr is not None: # for ArgOrOption, use a tuple of a string and int (attr and argpos) as the index index_expr = tuple_Expr( attr_expr, argpos_expr ) elif attr_expr is None and argpos_expr is None: assert 0, "attr_expr is None and argpos_expr is None ..." elif attr_expr is not None: # for Option, use a plain attr string as the index index_expr = attr_expr else: assert argpos_expr is not None # for Arg, use a plain int as the index # (note: ExprsMeta replaces argpos_expr with that int wrapped in constant_Expr, but later eval pulls out the raw int) index_expr = argpos_expr # see if this is fixed now, not that it means much since we were using a stub... but who knows, maybe the stub was buggy # and we compensated for that and this could if so cause a bug: ## printnim("I suspect type_expr (stub now) is included wrongly re eval_Expr in _ArgOption_helper, in hindsight 061117") ## ### I suspect the above, because grabarg expr needs to be evalled to get the expr whose type coercion we want to instantiate res = Instance( _type_coercion_expr( type_expr, eval_Expr(grabarg_expr) ), _index_expr = index_expr, _lvalue_flag = _lvalue_flag, **moreopts ) # note: moreopts might contain _noinstance = True, and if so, Instance normally returns its first arg unchanged # (depending on other options). # 070115 replaced eval_Expr( type_expr( grabarg_expr)) with _type_coercion_expr( type_expr, eval_Expr(grabarg_expr) ) return res # from _ArgOption_helper