{% switch %} statement
sagotch opened this issue · 13 comments
Pattern matching would be really useful in order to avoid long series of {% if foo == ... %}
with foo being the same in each elif
case. I plan to add a switch
statement to jingoo.
{% switch foo.bar %}
{% case "foo" %}{{ 1 }}
{% case "bar" %}{{ 2 }}
{% case baz case toto %}{{ 3 }}
{% default %}{{ -1 }}
{% endswitch %}
Also, it would be a more efficient way to compare values (if the value to compare needs some calculation for instead, you would need to use a set
or every elif
would be a waste of ressources.)
Any idea/objection?
EDIT:
{% case baz case toto %}
Would be a problem for the parser if you want to allow 'no statements' as right hand part of the case
{% switch foo.bar %}
{% case "foo" %}
{% case "bar" %}{{ 2 }}
{% endswitch %}
Would be the same as
{% switch foo.bar %}
{% case "foo" case "bar" %}{{ 2 }}
{% endswitch %}
Which is obviously not what is wanted.
Hmm, in my rough understanding, statement structure will be like bellow?
SwitchStatement of expr * (tvalue, ast) list * ast option
and if switch case is like
switch(expr){
case "foo":
case "bar": ast1
case 100: ast2
default: ast3
}
it becomes
SwitchStatement(
expr, [
(Tstr "foo", ast1); (* case label "foo" *)
(Tstr "bar", ast1); (* case label "bar" *)
(Tint 100, ast2); (* case label 100 *)
], Some ast3) (* default *)
then expr
is evaluated only once(unlike if else statement), and matched case is searched by
let value = value_of_expr env ctx expr in
if jg_eq_eq value (Tstr "foo") then ast1
else if jg_eq_eq value (Tint 100) then ast2
else match ast3 with Some ast3 -> ast3 | None -> []
Both expr value and label value of case are tvalue, then we can compare them by using jg_eq_eq
.
Is it the "pattern matching" you said?
See geneanet@1d220ad for a first draft. It does not handle multiple case
evaluating to same value yet.
Thanks for reference, I've read it, compact and beautiful implementation!
With geneanet@c026c28
You can use {% case foo || bar || baz %}
. What do you think about this syntax?
After reading code, I can understand the meaning easily, but in first look, foo || bar || baz
part seems like boolean value?
if ((foo || bar || baz) === true){ ... }
But it's my own feeling...
I should have written
{% switch x %}
{% case "foo" || "bar" || "baz" %}{{ ... }}
{% default %} {{ ... }}
{% endswitch %}
Are case values allowed for direct value only?
In current impl, it seems it can be variable.
SwitchStatement of expression * (expression list * ast) list
If only for direct value, this should be like this?
SwitchStatement of expression * (tvalue list * ast) list
But if it's only allowed for direct values, {% case "foo" || "bar" || "baz" %}
seems short and good syntax.
I am actually using it with variable in my code.
{%- set T_ROOT = 0 -%}
...
{%- set T_WITNESS = 7 -%}
{%- set T_GODPARENT = 8 -%}
...
{%- switch r -%}
{% case T_ROOT || T_WITNESS || T_GODPARENT %}{{ ... }}
{%- default -%}{{... }}
{%- endswitch -%}
Would you say that {% case "foo" case "bar" case "baz" %}
would be a better/good choice. Or something else?
What I worry about is confliction like this,
{% set a = false %}
{% set b = true %}
{% set c = false %}
{# good! #}
{% case a || b || c %} {{ ast }} -> Case([a,b,c], {{ ast }})
{# oops! #}
{% case a || b || c %} {{ ast }} -> {% case (a || b || c) %}{{ast}} -> Case([b], {{ast}})
If this kind of reducing never happen, I'm ok, but I've not read all current parser yet, so I can't judge.
What happens here is that it is parsed as:
{% case a || b || c %} {{ ast }} -> {% case (a || b || c) %}{{ast}}
But parsed output is processed (in the parser):
let rec extract = function
| OrOpExpr (e1, e2) -> extract e1 @ extract e2
| e -> [e] in
SwitchStatement ( e
, List.fold_right
(fun (a, b) acc -> ([a], b) :: acc) (cases)
(match default with None -> [] | Some stmts -> [ ([], stmts) ]))
Thanks for reply. OrOpExpr
is not evaluated before building SwitchStatement
, and always generates list by extract
, then I'm OK.
EDIT: In this argument, I totally forgot about that expr isn't evaluated before statement is evaluated...
Apparently {% case "a" case "b" %}
is hard to type, I agree with you.
Edit: I miss pushed the close issue button... but if more points are remain, re-open please.