For my multidimensional array library, I'm providing syntactic sugar (_, ^, not declaring stepping with |) to allow constructs like these to slice the array:

echo foo[1..3, 2..4] echo foo[2.._, 3] echo foo[^2..0|-2, 3] echo foo[^2..0|-2, _]

From an array foo

Tensor of shape 5x5 of type "int" on backend "Cpu"
|1      1       1       1       1|
|2      4       8       16      32|
|3      9       27      81      243|
|4      16      64      256     1024|
|5      25      125     625     3125|

Results are

echo foo[1..3, 2..4]
Tensor of shape 3x3 of type "int" on backend "Cpu"
|8      16      32|
|27     81      243|
|64     256     1024|

echo foo[2.._, 3]
Tensor of shape 3x1 of type "int" on backend "Cpu"

echo foo[^2..0|-2, 3]
Tensor of shape 2x1 of type "int" on backend "Cpu"

echo foo[^2..0|-2, _]
Tensor of shape 2x5 of type "int" on backend "Cpu"
|4      16      64      256     1024|
|2      4       8       16      32|

This is working fine, however my macro is a huge spaghetti monster (120 lines) of if, elif, else with lots of repetition to handle all the cases. Incriminated code is here

What approach can I use to make this easier on the eyes and maintainable?

There are some nesting levels I could probably do without as I'm calling elif nnk[1].kind == nnkPrefix: or elif nnk[2].kind == nnkInfix: just to check if I can then call nnk[1][0] and nnk[2][0]

I'm reading on Finite State Machine, Component-Entity-System, Chain-of-responsibility pattern, Functional/Declarative DOM/XML tree manipulation to get some inspirations. But apart from Finite State Machine, the last 3 seems like very complicated beasts wrt to my "only" 4 deep nesting.

And wrt to FSM, I don't think I can use that in a macro/AST context, can I?

2017-05-19 06:33:22

I would suggest to pre-create trees of NimNodes and then compare them to encountered ones. It may slow down the compilation process but will definitely reduce the cyclomatic complexity of the code.

Another way is to make the syntax rules of the sugar more strict to prevent infixes like this "..|-" and to separate parts of the expression in more obvious way.

2017-05-19 09:28:54
In the end I separated the code in two parts:
  • a part to check all the conditions. (Does node x exist and is it "_")
  • a part to act on a composition on those conditions.

It's a bit longer than before (more documentation) but code is flatter, no redundant branches and much more readable in my opinion. End code here.

2017-05-19 17:08:19