ENH: Add Support for dict unpacking in csp.node - #730
Conversation
Signed-off-by: Aadya Chinubhai <aadyachinubhai@gmail.com>
AdamGlustein
left a comment
There was a problem hiding this comment.
Thanks for the contribution, this is great! Just some minor comments to address.
| proxy = outputs_by_name[k] | ||
| except KeyError: | ||
| raise KeyError(f"unrecognized output '{k}'") from None | ||
| proxy + v |
There was a problem hiding this comment.
Please add a comment here noting we override the ast.Add operator to output a value, elsewise this code looks like it's dead. You may also need to do a ruff noqa to tell ruff to ignore it
| _CSP_ENGINE_START_TIME_FUNC = "_engine_start_time" | ||
| _CSP_ENGINE_END_TIME_FUNC = "_engine_end_time" | ||
| _CSP_ENGINE_STATS_FUNC = "_csp_engine_stats" | ||
| _CSP_OUTPUT_KWARGS_FUNC = "_csp_output_kwargs" |
There was a problem hiding this comment.
Nit: you can remove _CSP_OUTPUT_KWARGS_FUNC from the dicts here and just call _csp_output_kwargs in the ast.Call node directly. These dictionaries are meant for functions defined in the C++ code.
| # A **expr unpack, resolved at runtime, can't statically verify | ||
| # which outputs it covers, so assume it may cover all of them. | ||
| self._returned_outputs.update(o.name for o in self._signature._outputs if o.name is not None) | ||
| nodes.append( |
There was a problem hiding this comment.
we can try to avoid the function call overhead and generator the for loop AST directly here instead
note you can use @node( debug_print=True ) to dump the generated readable code for debugging
There was a problem hiding this comment.
Yes, I'm working on it, I saw the dict creation per tick is actually more expensive than the jump to the function call, so hopefully minimizing that too, so the same dict can be reused with different runtime values.
Reference Issue:
Closes #725
Dict Unpacking via
**now works as shown above instead of aCspParseError.This includes the following:
Single dict Unpacking:
Nested dicts:
Multiple dicts
How
Named outputs get resolved at parse time:
csp.output(a=1)rewrites to#outp_0 + 1. That can't work for**values, since the keys only exist once the node ticks.So the parser detects the unpack (
ast.keywordwitharg=None) and emits a call to a small runtime helper, passing a statically-built{name: proxy}map alongside the unpacked expression. The helper iterates the dict at runtime and ticks each output via the same proxy + value mechanism the generated code already uses. No C++ changes needed, sincePyOutputProxyalready exposes this throughnb_add.