implement match statement codegen in El
Add cg_match_stmt() to lower match-as-statement to proper C if/else if/else
chains. Previously, match in statement position fell through to cg_expr() which
emitted a GCC statement-expression — fine for expression arms but wrong for the
statement form. Now matched using the same dispatch pattern as If and For in the
Expr handler of cg_stmt().
Pattern dispatch mirrors cg_match (expression form):
LitStr -> str_eq(subj, EL_STR("..."))
LitInt -> subj == N
LitBool -> subj == 1 / 0
Binding -> else { el_val_t name = subj; body; }
Wildcard -> else { body; }
Subject is evaluated once into a scoped temporary to avoid double evaluation.
This commit is contained in:
@@ -862,6 +862,97 @@ fn cg_match(expr: Map<String, Any>) -> String {
|
||||
str_join(parts, "")
|
||||
}
|
||||
|
||||
// Lower a match statement (used for side effects, not as an expression) to a
|
||||
// chain of C if/else if/else blocks. The subject is evaluated once into a
|
||||
// scoped temporary; each arm generates a condition and a braced body; the
|
||||
// wildcard/binding arm becomes the final `else` branch.
|
||||
//
|
||||
// Pattern dispatch:
|
||||
// LitStr -> str_eq(subj, EL_STR("..."))
|
||||
// LitInt -> subj == N
|
||||
// LitBool -> subj == 1 / subj == 0
|
||||
// Binding -> else { el_val_t name = subj; <body> }
|
||||
// Wildcard -> else { <body> }
|
||||
fn cg_match_stmt(expr: Map<String, Any>, indent: String, declared: [String]) -> Void {
|
||||
let subject = expr["subject"]
|
||||
let arms = expr["arms"]
|
||||
let subj_c: String = cg_expr(subject)
|
||||
let id: String = next_match_id()
|
||||
let subj_var: String = "_match_subj_" + id
|
||||
let inner: String = indent + " "
|
||||
emit_line(indent + "{")
|
||||
emit_line(inner + "el_val_t " + subj_var + " = " + subj_c + ";")
|
||||
let n: Int = native_list_len(arms)
|
||||
let i = 0
|
||||
let first_cond: Bool = true
|
||||
while i < n {
|
||||
let arm = native_list_get(arms, i)
|
||||
let pat = arm["pattern"]
|
||||
let body = arm["body"]
|
||||
let pkind: String = pat["pattern"]
|
||||
let body_c: String = cg_expr(body)
|
||||
if str_eq(pkind, "LitStr") {
|
||||
let v: String = pat["value"]
|
||||
let cond_str = "str_eq(" + subj_var + ", EL_STR(" + c_str_lit(v) + "))"
|
||||
if first_cond {
|
||||
emit_line(inner + "if (" + cond_str + ") {")
|
||||
let first_cond = false
|
||||
} else {
|
||||
emit_line(inner + "} else if (" + cond_str + ") {")
|
||||
}
|
||||
emit_line(inner + " " + body_c + ";")
|
||||
} else {
|
||||
if str_eq(pkind, "LitInt") {
|
||||
let v: String = pat["value"]
|
||||
let cond_str = subj_var + " == " + v
|
||||
if first_cond {
|
||||
emit_line(inner + "if (" + cond_str + ") {")
|
||||
let first_cond = false
|
||||
} else {
|
||||
emit_line(inner + "} else if (" + cond_str + ") {")
|
||||
}
|
||||
emit_line(inner + " " + body_c + ";")
|
||||
} else {
|
||||
if str_eq(pkind, "LitBool") {
|
||||
let v: String = pat["value"]
|
||||
let bv = "0"
|
||||
if str_eq(v, "true") {
|
||||
let bv = "1"
|
||||
}
|
||||
let cond_str = subj_var + " == " + bv
|
||||
if first_cond {
|
||||
emit_line(inner + "if (" + cond_str + ") {")
|
||||
let first_cond = false
|
||||
} else {
|
||||
emit_line(inner + "} else if (" + cond_str + ") {")
|
||||
}
|
||||
emit_line(inner + " " + body_c + ";")
|
||||
} else {
|
||||
// Wildcard or Binding - becomes the else branch
|
||||
if first_cond {
|
||||
emit_line(inner + "{")
|
||||
} else {
|
||||
emit_line(inner + "} else {")
|
||||
}
|
||||
if str_eq(pkind, "Binding") {
|
||||
let bname: String = pat["name"]
|
||||
emit_line(inner + " el_val_t " + bname + " = " + subj_var + ";")
|
||||
}
|
||||
emit_line(inner + " " + body_c + ";")
|
||||
emit_line(inner + "}")
|
||||
let first_cond = true
|
||||
}
|
||||
}
|
||||
}
|
||||
let i = i + 1
|
||||
}
|
||||
// Close any open if/else-if chain (only reached when last arm was a literal pattern)
|
||||
if !first_cond {
|
||||
emit_line(inner + "}")
|
||||
}
|
||||
emit_line(indent + "}")
|
||||
}
|
||||
|
||||
// -- If-as-expression codegen -------------------------------------------------
|
||||
//
|
||||
// Lower `if cond { thenBody } else { elseBody }` used in expression position
|
||||
@@ -1114,6 +1205,10 @@ fn cg_stmt(stmt: Map<String, Any>, indent: String, declared: [String]) -> [Strin
|
||||
cg_for_stmt(val, indent, declared)
|
||||
return declared
|
||||
}
|
||||
if val_kind == "Match" {
|
||||
cg_match_stmt(val, indent, declared)
|
||||
return declared
|
||||
}
|
||||
let val_c: String = cg_expr(val)
|
||||
emit_line(indent + val_c + ";")
|
||||
return declared
|
||||
|
||||
Reference in New Issue
Block a user