def _e_override_replace(self, scanner): """ This gets called by a formula scanner when it hits this object in an expr... it knows lots of private stuff about FormulaScanner. """ attr = scanner.replacements[ _E_ATTR] # a constant_Expr, or an indication of error if this happens (maybe missing then?) attr = attr._e_constant_value if 1: # quick & dirty check for two attrs claiming one arg... come to think of it, is this wrong re inclusion? # no, as long as overall replace (of this) happens before this gets called, it'll be ok. # but, a better check & better errmsg can be done in scanner if we pass our own args to it. # WAIT, i bet this won't actually catch the error, since the replace would actually occur... have to do it in the scanner. printnim( "improve quick & dirty check for two attrs claiming one arg (it may not even work)" ) ###e self.attrs_ive_seen[attr] = 1 assert len( self.attrs_ive_seen ) <= 1, "these attrs claim the same arg: %r" % self.attrs_ive_seen.keys( ) # WARNING: if this works, it will break the use of Arg in future things like lambda_expr or _e_extend # where the same Arg() object might get passed to multiple class/attr contexts in runtime-generated exprs with Arg decls. # If/when that happens, this object needs to be made immutable, which can be done by removing this code (inside 'if 1'), # since it's probably either not working or redundant, according to the comments above and my best guess now. [070321 comment] required = self._e_is_required arglist = self._e_is_arglist pos = scanner.argpos(attr, required, arglist=arglist) res = constant_Expr( pos) # this gets included in the scanner's processed expr return res
def _e_override_replace(self, scanner): """ This gets called by a formula scanner when it hits this object in an expr... it knows lots of private stuff about FormulaScanner. """ attr = scanner.replacements[_E_ATTR] # a constant_Expr, or an indication of error if this happens (maybe missing then?) attr = attr._e_constant_value if 1: # quick & dirty check for two attrs claiming one arg... come to think of it, is this wrong re inclusion? # no, as long as overall replace (of this) happens before this gets called, it'll be ok. # but, a better check & better errmsg can be done in scanner if we pass our own args to it. # WAIT, i bet this won't actually catch the error, since the replace would actually occur... have to do it in the scanner. printnim("improve quick & dirty check for two attrs claiming one arg (it may not even work)")###e self.attrs_ive_seen[attr] = 1 assert len(self.attrs_ive_seen) <= 1, "these attrs claim the same arg: %r" % self.attrs_ive_seen.keys() # WARNING: if this works, it will break the use of Arg in future things like lambda_expr or _e_extend # where the same Arg() object might get passed to multiple class/attr contexts in runtime-generated exprs with Arg decls. # If/when that happens, this object needs to be made immutable, which can be done by removing this code (inside 'if 1'), # since it's probably either not working or redundant, according to the comments above and my best guess now. [070321 comment] required = self._e_is_required arglist = self._e_is_arglist pos = scanner.argpos(attr, required, arglist = arglist) res = constant_Expr(pos) # this gets included in the scanner's processed expr 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 KLUGE_for_passing_expr_classes_as_functions_to_ArgExpr(exprclass): return constant_Expr(exprclass(_KLUGE_fake_option=1))
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 KLUGE_for_passing_expr_classes_as_functions_to_ArgExpr( exprclass ): return constant_Expr( exprclass( _KLUGE_fake_option = 1))