I have a code-generated Go program I'm trying to port (as is, without changing the overall structure) and I'm running into issues with rather long case block, the compiler spits out the AST and halts. Is there a hard limit somewhere, and if so why? Could the limit be removed? Go doesn't seem to have a problem so I'm not sure why this limit exists. Thanks for any info!
Hi! Could you share such code?
So, I just tried this:
a = 1
{% begin %}
case 1
{% for i in 1..4_000 %}
when a
{{i}}
{% end %}
end
{% end %}
And yes, it hangs. The reason is that a case translates to a series of if/elsif, and that's actually a series of if with nested if inside the else.
Since we use a visitor to compile, every if we analyze means another frame in the stack. If they are very nested it hits stack overflow.
That's the limitation. It can't be fixed without a serious rewrite of how the code is analyzed.
@asterite Thanks for the quick reply! Yes, that is the issue I'm running into. And thanks for the background. But that's a bummer! Any idea how many frames cause this issue (so I can split my code into multiple functions)? I ask because your code compiles just fine for me but bombs at 4086. So this is unpredictable and depends on system memory perhaps? Which means if something like this lands in a library somewhere then it may or may not compile?
Could you maybe share the code that you want to write? I want to understand why a case with more than 4000 branches is needed.
The compiler works by recursion. Right now there's a limit to how much code you can nest, or how many call frames you can have. It's a known limitation (at least by me). I don't think there's anything you can do to overcome this, unless you write your code in a different way.
Thank you, I understand and that's what I intend to do now (write it differently). I'd love to share the code but can't -- but I can tell you the code is a rules engine dealing with the US Bankruptcy Code. I understand this usage is definitely an outlier. I'll close this comment if that's ok with you since you mentioned there's nothing much we can do about this for now.
Given this is generated code, you should be able to rewrite it just to
def my_case(expr)
if expr === cond1
return stmts1
end
if expr === cond2
return stmts2
end
# ...
if expr === condN
return stmtsN
end
elseStmts
end
I guess eventually the compiler could do that for case statements and/or if/elsif chains with some threshold value of branches.
It could also be interesting to see how much of the current compiler code could easily be transformed into tail recursion friendly calls.
@jhass Great idea! It works.
Most helpful comment
Given this is generated code, you should be able to rewrite it just to
I guess eventually the compiler could do that for
casestatements and/orif/elsifchains with some threshold value of branches.It could also be interesting to see how much of the current compiler code could easily be transformed into tail recursion friendly calls.