Repository: radiasoft/sirepo

Issue:
Add array value parsing to CodeVar
(See also #6424) Currently when CodeVar's `__eval_python_stack()` analyzes an array value (e.g. `[1, 2, 3]`), it tokenizes the corresponding string into undefined symbols (`["[1", "2", "3]"]`). Instead each array element should be evaluated recursively.  This would cover nested arrays and arrays containing expressions (`["x + y", ...]`), but not expressions _referencing_ arrays (so "x + array[0]" would still fail) (would be nice in the future). A test should be added to cover a variety of useful examples.

#5807 will make use of this


Discussion:

Patch:
diff --git a/sirepo/template/code_variable.py b/sirepo/template/code_variable.py
index e551b359d..7eccf03c6 100644
--- a/sirepo/template/code_variable.py
+++ b/sirepo/template/code_variable.py
@@ -390,6 +390,16 @@ class PurePythonEval:
     def __eval_python_stack(self, expr, variables):
         if not CodeVar.is_var_value(expr):
             return expr, None
+        if isinstance(expr, list):
+            evs = []
+            # loop instead of map so we can fail out on the first error
+            for e in expr:
+                ev = self.__eval_python_stack(CodeVar.infix_to_postfix(e), variables)
+                if ev[1] is not None:
+                    return None, ev[1]
+                evs.append(ev[0])
+            return evs, None
+
         values = str(expr).split(" ")
         stack = []
         for v in values:


Test patch:
diff --git a/tests/template/code_variable_test.py b/tests/template/code_variable_test.py
index db041a522..f97c638c1 100644
--- a/tests/template/code_variable_test.py
+++ b/tests/template/code_variable_test.py
@@ -9,6 +9,48 @@ from __future__ import absolute_import, division, print_function
 import pytest
 
 
+def test_arrays():
+    from pykern.pkcollections import PKDict
+    from pykern.pkunit import pkeq, pkexcept
+    from sirepo.template.code_variable import CodeVar, PurePythonEval
+
+    code_var = CodeVar(
+        [
+            PKDict(
+                name="x",
+                value=123,
+            ),
+            PKDict(
+                name="numberArray",
+                value=[1, 2, 3],
+            ),
+            PKDict(
+                name="expressionArray",
+                value=["x + 1", "x + 2", "x + 3"],
+            ),
+            PKDict(
+                name="nestedArray",
+                value=[[1, 2, 3], [4, 5], ["x + 6"]],
+            ),
+            PKDict(
+                name="arrayExpression",
+                value="numberArray[0] + 1",
+            ),
+            PKDict(
+                name="invalidExpressionArray",
+                value=["x + 1", "y + 2", "x + 3"],
+            ),
+        ],
+        PurePythonEval(),
+    )
+    pkeq([1, 2, 3], code_var.eval_var("numberArray")[0])
+    pkeq([124, 125, 126], code_var.eval_var("expressionArray")[0])
+    pkeq([[1, 2, 3], [4, 5], [129]], code_var.eval_var("nestedArray")[0])
+    # expressions containing arrays are not currently handled
+    pkeq("unknown token: numberArray[0]", code_var.eval_var("arrayExpression")[1])
+    pkeq("unknown token: y", code_var.eval_var("invalidExpressionArray")[1])
+
+
 def test_cache():
     from pykern.pkcollections import PKDict
     from pykern.pkunit import pkeq