feat: add pattern variable binding to C backend
Implements full pattern matching with variable binding for the C backend:
- Extract variable bindings from patterns (Var, Constructor, Tuple, Record)
- Infer C types for bound variables using variant field type tracking
- Handle recursive ADTs with pointer fields and heap allocation
- Dereference pointer bindings automatically for value semantics
Key implementation details:
- variant_to_type: Maps variant names to parent type for tag generation
- variant_field_types: Maps (type, variant) to field types for inference
- Recursive type fields use Type* pointers with malloc/memcpy
- Pattern bindings dereference pointers to maintain value semantics
Examples that now work:
- match opt { Some(x) => x, None => 0 }
- match tree { Leaf(n) => n, Node(l, r) => sum(l) + sum(r) }
Updates documentation to reflect C backend progress.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -181,7 +181,7 @@ fn processAny(x: Int @latest): Int = x // any version
|
|||||||
|
|
||||||
### Planned (Not Yet Fully Implemented)
|
### Planned (Not Yet Fully Implemented)
|
||||||
|
|
||||||
- **Full C Backend**: Basic functions work, closures/lists/pattern variables pending
|
- **C Backend Lists**: Closures and pattern matching work, lists pending
|
||||||
- **Auto-migration Generation**: Migration bodies stored, execution pending
|
- **Auto-migration Generation**: Migration bodies stored, execution pending
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -234,7 +234,7 @@ Quick iteration with type inference and a REPL.
|
|||||||
|
|
||||||
| Limitation | Description |
|
| Limitation | Description |
|
||||||
|------------|-------------|
|
|------------|-------------|
|
||||||
| **Limited C Backend** | Basic functions work, closures/lists pending |
|
| **Limited C Backend** | Functions, closures, ADTs work; lists pending |
|
||||||
| **No Package Manager** | Can't share/publish packages yet |
|
| **No Package Manager** | Can't share/publish packages yet |
|
||||||
| **New Paradigm** | Effects require learning new concepts |
|
| **New Paradigm** | Effects require learning new concepts |
|
||||||
| **Small Ecosystem** | No community packages yet |
|
| **Small Ecosystem** | No community packages yet |
|
||||||
@@ -370,11 +370,12 @@ Values + Effects C Code → GCC/Clang
|
|||||||
- ✅ Test Effect (native testing framework)
|
- ✅ Test Effect (native testing framework)
|
||||||
- ✅ Console.readLine and Console.readInt
|
- ✅ Console.readLine and Console.readInt
|
||||||
- ✅ C Backend (basic functions, Console.print)
|
- ✅ C Backend (basic functions, Console.print)
|
||||||
|
- ✅ C Backend closures and pattern matching
|
||||||
- ✅ Watch mode / hot reload
|
- ✅ Watch mode / hot reload
|
||||||
- ✅ Formatter
|
- ✅ Formatter
|
||||||
|
|
||||||
**In Progress:**
|
**In Progress:**
|
||||||
1. **C Backend Extensions** - Closures, lists, pattern variable binding
|
1. **C Backend Lists** - List operations pending
|
||||||
2. **Schema Evolution** - Type system integration, auto-migration
|
2. **Schema Evolution** - Type system integration, auto-migration
|
||||||
3. **Error Message Quality** - Context lines shown, suggestions partial
|
3. **Error Message Quality** - Context lines shown, suggestions partial
|
||||||
|
|
||||||
|
|||||||
@@ -221,7 +221,9 @@
|
|||||||
| Task | Priority | Effort | Status |
|
| Task | Priority | Effort | Status |
|
||||||
|------|----------|--------|--------|
|
|------|----------|--------|--------|
|
||||||
| C backend (basic) | P1 | — | ✅ Complete (functions, Console.print) |
|
| C backend (basic) | P1 | — | ✅ Complete (functions, Console.print) |
|
||||||
| Extend C backend (closures, lists) | P1 | 2 weeks | ❌ Missing |
|
| Extend C backend (closures) | P1 | — | ✅ Complete |
|
||||||
|
| Extend C backend (pattern matching) | P1 | — | ✅ Complete |
|
||||||
|
| Extend C backend (lists) | P1 | 1 week | ❌ Missing |
|
||||||
| JS backend | P2 | 4 weeks | ❌ Missing |
|
| JS backend | P2 | 4 weeks | ❌ Missing |
|
||||||
| WASM backend | P3 | 4 weeks | ❌ Missing |
|
| WASM backend | P3 | 4 weeks | ❌ Missing |
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,30 @@
|
|||||||
//! Compiles Lux programs to C code that can be compiled with GCC/Clang.
|
//! Compiles Lux programs to C code that can be compiled with GCC/Clang.
|
||||||
//! Inspired by Koka's approach: effects compile to evidence passing,
|
//! Inspired by Koka's approach: effects compile to evidence passing,
|
||||||
//! no garbage collector needed with Perceus-style reference counting.
|
//! no garbage collector needed with Perceus-style reference counting.
|
||||||
|
//!
|
||||||
|
//! ## Supported Features
|
||||||
|
//!
|
||||||
|
//! - **Functions**: Direct function calls with proper name mangling
|
||||||
|
//! - **Closures**: Lambda expressions with captured environments
|
||||||
|
//! - Environment structs hold captured variables
|
||||||
|
//! - Closures are `{void* env, void* fn_ptr}` structs
|
||||||
|
//! - **ADTs**: Algebraic data types (enums with data)
|
||||||
|
//! - Tag enums for variant discrimination
|
||||||
|
//! - Union structs for variant data
|
||||||
|
//! - Recursive types use pointers with heap allocation
|
||||||
|
//! - **Pattern Matching**: Full pattern variable binding
|
||||||
|
//! - Constructor patterns extract variant data
|
||||||
|
//! - Nested patterns supported
|
||||||
|
//! - Type inference for bound variables
|
||||||
|
//!
|
||||||
|
//! ## Limitations
|
||||||
|
//!
|
||||||
|
//! - **Lists**: Not yet implemented (use interpreter)
|
||||||
|
//! - **Memory**: No automatic deallocation (memory leaks for closures/ADTs)
|
||||||
|
//! - **Effects**: Only Console.print supported
|
||||||
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use std::collections::HashSet;
|
use std::collections::{HashSet, HashMap};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
/// C code generation errors
|
/// C code generation errors
|
||||||
@@ -53,6 +74,10 @@ pub struct CBackend {
|
|||||||
local_vars: HashSet<String>,
|
local_vars: HashSet<String>,
|
||||||
/// Functions that return closures
|
/// Functions that return closures
|
||||||
closure_returning_functions: HashSet<String>,
|
closure_returning_functions: HashSet<String>,
|
||||||
|
/// Mapping from variant names to their parent type name
|
||||||
|
variant_to_type: HashMap<String, String>,
|
||||||
|
/// Mapping from (type_name, variant_name) to field types
|
||||||
|
variant_field_types: HashMap<(String, String), Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CBackend {
|
impl CBackend {
|
||||||
@@ -67,6 +92,8 @@ impl CBackend {
|
|||||||
closures: Vec::new(),
|
closures: Vec::new(),
|
||||||
local_vars: HashSet::new(),
|
local_vars: HashSet::new(),
|
||||||
closure_returning_functions: HashSet::new(),
|
closure_returning_functions: HashSet::new(),
|
||||||
|
variant_to_type: HashMap::new(),
|
||||||
|
variant_field_types: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,6 +407,36 @@ impl CBackend {
|
|||||||
self.writeln("");
|
self.writeln("");
|
||||||
}
|
}
|
||||||
TypeDef::Enum(variants) => {
|
TypeDef::Enum(variants) => {
|
||||||
|
// Record variant -> type mapping for pattern matching
|
||||||
|
for variant in variants {
|
||||||
|
self.variant_to_type.insert(variant.name.name.clone(), name.clone());
|
||||||
|
|
||||||
|
// Also record field types for pattern binding type inference
|
||||||
|
// Use self-check for recursive types (which become pointers)
|
||||||
|
let field_types: Vec<String> = match &variant.fields {
|
||||||
|
VariantFields::Tuple(fields) => {
|
||||||
|
fields.iter().map(|f| {
|
||||||
|
self.type_to_c_with_self_check(f, name).unwrap_or_else(|_| "LuxInt".to_string())
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
VariantFields::Record(fields) => {
|
||||||
|
fields.iter().map(|f| {
|
||||||
|
self.type_to_c_with_self_check(&f.typ, name).unwrap_or_else(|_| "LuxInt".to_string())
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
VariantFields::Unit => vec![],
|
||||||
|
};
|
||||||
|
self.variant_field_types.insert(
|
||||||
|
(name.clone(), variant.name.name.clone()),
|
||||||
|
field_types
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward declare the main struct for recursive types
|
||||||
|
self.writeln(&format!("struct {};", name));
|
||||||
|
self.writeln(&format!("typedef struct {} {};", name, name));
|
||||||
|
self.writeln("");
|
||||||
|
|
||||||
// Emit tag enum
|
// Emit tag enum
|
||||||
self.writeln(&format!("typedef enum {}_Tag {{", name));
|
self.writeln(&format!("typedef enum {}_Tag {{", name));
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
@@ -400,13 +457,13 @@ impl CBackend {
|
|||||||
match &variant.fields {
|
match &variant.fields {
|
||||||
VariantFields::Tuple(fields) => {
|
VariantFields::Tuple(fields) => {
|
||||||
for (i, field) in fields.iter().enumerate() {
|
for (i, field) in fields.iter().enumerate() {
|
||||||
let c_type = self.type_to_c(field)?;
|
let c_type = self.type_to_c_with_self_check(field, name)?;
|
||||||
self.writeln(&format!("{} field{};", c_type, i));
|
self.writeln(&format!("{} field{};", c_type, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VariantFields::Record(fields) => {
|
VariantFields::Record(fields) => {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
let c_type = self.type_to_c(&field.typ)?;
|
let c_type = self.type_to_c_with_self_check(&field.typ, name)?;
|
||||||
self.writeln(&format!("{} {};", c_type, field.name.name));
|
self.writeln(&format!("{} {};", c_type, field.name.name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,8 +475,8 @@ impl CBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit main union struct
|
// Emit main union struct (typedef already created above)
|
||||||
self.writeln(&format!("typedef struct {} {{", name));
|
self.writeln(&format!("struct {} {{", name));
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
self.writeln(&format!("{}_Tag tag;", name));
|
self.writeln(&format!("{}_Tag tag;", name));
|
||||||
self.writeln("union {");
|
self.writeln("union {");
|
||||||
@@ -433,7 +490,7 @@ impl CBackend {
|
|||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
self.writeln("} data;");
|
self.writeln("} data;");
|
||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
self.writeln(&format!("}} {};", name));
|
self.writeln("};");
|
||||||
self.writeln("");
|
self.writeln("");
|
||||||
}
|
}
|
||||||
TypeDef::Alias(_) => {
|
TypeDef::Alias(_) => {
|
||||||
@@ -499,7 +556,16 @@ impl CBackend {
|
|||||||
match expr {
|
match expr {
|
||||||
Expr::Literal(lit) => self.emit_literal(lit),
|
Expr::Literal(lit) => self.emit_literal(lit),
|
||||||
|
|
||||||
Expr::Var(ident) => Ok(ident.name.clone()),
|
Expr::Var(ident) => {
|
||||||
|
// Check if this is a unit constructor (no-argument variant)
|
||||||
|
if let Some(type_name) = self.variant_to_type.get(&ident.name) {
|
||||||
|
// This is a constructor - emit struct literal
|
||||||
|
let variant_name = &ident.name;
|
||||||
|
Ok(format!("({}){{{}_TAG_{}}}", type_name, type_name, variant_name.to_uppercase()))
|
||||||
|
} else {
|
||||||
|
Ok(ident.name.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Expr::BinaryOp { op, left, right, .. } => {
|
Expr::BinaryOp { op, left, right, .. } => {
|
||||||
let l = self.emit_expr(left)?;
|
let l = self.emit_expr(left)?;
|
||||||
@@ -568,6 +634,49 @@ impl CBackend {
|
|||||||
let c_func_name = self.mangle_name(&ident.name);
|
let c_func_name = self.mangle_name(&ident.name);
|
||||||
Ok(format!("{}({})", c_func_name, args_str))
|
Ok(format!("{}({})", c_func_name, args_str))
|
||||||
}
|
}
|
||||||
|
Expr::Var(ident) if self.variant_to_type.contains_key(&ident.name) => {
|
||||||
|
// ADT constructor call - create struct with tag and data
|
||||||
|
let type_name = self.variant_to_type.get(&ident.name).unwrap().clone();
|
||||||
|
let variant_name = ident.name.clone();
|
||||||
|
let variant_lower = variant_name.to_lowercase();
|
||||||
|
let variant_upper = variant_name.to_uppercase();
|
||||||
|
|
||||||
|
// Look up field types to handle pointer fields
|
||||||
|
let field_types = self.variant_field_types
|
||||||
|
.get(&(type_name.clone(), variant_name.clone()))
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
// Generate struct initialization
|
||||||
|
let arg_values: Result<Vec<_>, _> = args.iter().map(|a| self.emit_expr(a)).collect();
|
||||||
|
let arg_values = arg_values?;
|
||||||
|
|
||||||
|
// Build field initializers, handling pointer fields
|
||||||
|
let field_inits: Vec<String> = arg_values.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, v)| {
|
||||||
|
let field_type = field_types.get(i).map(|s| s.as_str()).unwrap_or("LuxInt");
|
||||||
|
if field_type.ends_with('*') {
|
||||||
|
// Pointer field - allocate and copy
|
||||||
|
let base_type = &field_type[..field_type.len()-1];
|
||||||
|
format!(".field{} = ({}*)memcpy(malloc(sizeof({})), &({}), sizeof({}))",
|
||||||
|
i, base_type, base_type, v, base_type)
|
||||||
|
} else {
|
||||||
|
format!(".field{} = {}", i, v)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
if field_inits.is_empty() {
|
||||||
|
// Unit variant
|
||||||
|
Ok(format!("({}){{{}_TAG_{}}}", type_name, type_name, variant_upper))
|
||||||
|
} else {
|
||||||
|
// Variant with data
|
||||||
|
Ok(format!("({}){{{}_TAG_{}, .data.{} = {{{}}}}}",
|
||||||
|
type_name, type_name, variant_upper,
|
||||||
|
variant_lower, field_inits.join(", ")))
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Indirect call - treat as closure
|
// Indirect call - treat as closure
|
||||||
let closure_expr = self.emit_expr(func)?;
|
let closure_expr = self.emit_expr(func)?;
|
||||||
@@ -653,12 +762,18 @@ impl CBackend {
|
|||||||
for stmt in statements {
|
for stmt in statements {
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Let { name, value, .. } => {
|
Statement::Let { name, value, .. } => {
|
||||||
|
// First, infer type from value expression (before emitting)
|
||||||
|
let inferred_type = self.infer_expr_type(value);
|
||||||
|
|
||||||
let val = self.emit_expr(value)?;
|
let val = self.emit_expr(value)?;
|
||||||
// Infer type from value: closures return LuxClosure*
|
|
||||||
let typ = if val.starts_with("_closure_") || self.is_closure_returning_call(value) {
|
// Determine final type
|
||||||
"LuxClosure*"
|
let typ = if let Some(t) = inferred_type {
|
||||||
|
t
|
||||||
|
} else if val.starts_with("_closure_") || self.is_closure_returning_call(value) {
|
||||||
|
"LuxClosure*".to_string()
|
||||||
} else {
|
} else {
|
||||||
"LuxInt"
|
"LuxInt".to_string()
|
||||||
};
|
};
|
||||||
self.writeln(&format!("{} {} = {};", typ, name.name, val));
|
self.writeln(&format!("{} {} = {};", typ, name.name, val));
|
||||||
}
|
}
|
||||||
@@ -722,12 +837,22 @@ impl CBackend {
|
|||||||
|
|
||||||
fn emit_match(&mut self, expr: &Expr, arms: &[MatchArm]) -> Result<String, CGenError> {
|
fn emit_match(&mut self, expr: &Expr, arms: &[MatchArm]) -> Result<String, CGenError> {
|
||||||
let scrutinee = self.emit_expr(expr)?;
|
let scrutinee = self.emit_expr(expr)?;
|
||||||
|
let scrutinee_var = format!("scrutinee_{}", self.fresh_name());
|
||||||
let result_var = format!("match_result_{}", self.fresh_name());
|
let result_var = format!("match_result_{}", self.fresh_name());
|
||||||
|
|
||||||
self.writeln(&format!("LuxInt {};", result_var));
|
// Infer the type name from the first constructor pattern we find
|
||||||
|
let type_name = self.infer_type_name_from_arms(arms);
|
||||||
|
|
||||||
|
// Infer the result type from the first arm body
|
||||||
|
let result_type = self.infer_expr_type(&arms[0].body).unwrap_or_else(|| "LuxInt".to_string());
|
||||||
|
|
||||||
|
// Use the inferred type for scrutinee, fall back to LuxInt for simple patterns
|
||||||
|
let scrutinee_type = type_name.as_deref().unwrap_or("LuxInt");
|
||||||
|
self.writeln(&format!("{} {} = {};", scrutinee_type, scrutinee_var, scrutinee));
|
||||||
|
self.writeln(&format!("{} {};", result_type, result_var));
|
||||||
|
|
||||||
for (i, arm) in arms.iter().enumerate() {
|
for (i, arm) in arms.iter().enumerate() {
|
||||||
let condition = self.pattern_to_condition(&arm.pattern, &scrutinee)?;
|
let condition = self.pattern_to_condition(&arm.pattern, &scrutinee_var, type_name.as_deref())?;
|
||||||
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
self.writeln(&format!("if ({}) {{", condition));
|
self.writeln(&format!("if ({}) {{", condition));
|
||||||
@@ -736,6 +861,20 @@ impl CBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.indent += 1;
|
self.indent += 1;
|
||||||
|
|
||||||
|
// Extract and emit variable bindings from the pattern
|
||||||
|
let bindings = self.extract_pattern_bindings(&arm.pattern, &scrutinee_var, type_name.as_deref());
|
||||||
|
for (var_name, c_expr, c_type) in &bindings {
|
||||||
|
// If the type is a pointer, dereference when binding
|
||||||
|
// This way the variable holds a value, not a pointer
|
||||||
|
if c_type.ends_with('*') {
|
||||||
|
let base_type = &c_type[..c_type.len()-1];
|
||||||
|
self.writeln(&format!("{} {} = *({});", base_type, var_name, c_expr));
|
||||||
|
} else {
|
||||||
|
self.writeln(&format!("{} {} = {};", c_type, var_name, c_expr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let body = self.emit_expr(&arm.body)?;
|
let body = self.emit_expr(&arm.body)?;
|
||||||
self.writeln(&format!("{} = {};", result_var, body));
|
self.writeln(&format!("{} = {};", result_var, body));
|
||||||
self.indent -= 1;
|
self.indent -= 1;
|
||||||
@@ -745,18 +884,159 @@ impl CBackend {
|
|||||||
Ok(result_var)
|
Ok(result_var)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pattern_to_condition(&self, pattern: &Pattern, scrutinee: &str) -> Result<String, CGenError> {
|
/// Try to infer the type name from match arms by looking at constructor patterns
|
||||||
|
fn infer_type_name_from_arms(&self, arms: &[MatchArm]) -> Option<String> {
|
||||||
|
for arm in arms {
|
||||||
|
if let Pattern::Constructor { name, .. } = &arm.pattern {
|
||||||
|
// Look up the variant in our mapping
|
||||||
|
if let Some(type_name) = self.variant_to_type.get(&name.name) {
|
||||||
|
return Some(type_name.clone());
|
||||||
|
}
|
||||||
|
// Fallback for built-in types that might not be in the map
|
||||||
|
match name.name.as_str() {
|
||||||
|
"Some" | "None" => return Some("Option".to_string()),
|
||||||
|
"Ok" | "Err" => return Some("Result".to_string()),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to infer the C type of an expression
|
||||||
|
fn infer_expr_type(&self, expr: &Expr) -> Option<String> {
|
||||||
|
match expr {
|
||||||
|
Expr::Literal(lit) => {
|
||||||
|
match &lit.kind {
|
||||||
|
LiteralKind::Int(_) => Some("LuxInt".to_string()),
|
||||||
|
LiteralKind::Float(_) => Some("LuxFloat".to_string()),
|
||||||
|
LiteralKind::Bool(_) => Some("LuxBool".to_string()),
|
||||||
|
LiteralKind::String(_) => Some("LuxString".to_string()),
|
||||||
|
LiteralKind::Char(_) => Some("char".to_string()),
|
||||||
|
LiteralKind::Unit => Some("void".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Var(ident) => {
|
||||||
|
// Check if it's a unit constructor
|
||||||
|
if let Some(type_name) = self.variant_to_type.get(&ident.name) {
|
||||||
|
Some(type_name.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Call { func, .. } => {
|
||||||
|
// Check if calling a constructor
|
||||||
|
if let Expr::Var(ident) = func.as_ref() {
|
||||||
|
if let Some(type_name) = self.variant_to_type.get(&ident.name) {
|
||||||
|
return Some(type_name.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Expr::Block { result, .. } => {
|
||||||
|
// Type of block is the type of the result expression
|
||||||
|
self.infer_expr_type(result)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pattern_to_condition(&self, pattern: &Pattern, scrutinee: &str, type_name: Option<&str>) -> Result<String, CGenError> {
|
||||||
match pattern {
|
match pattern {
|
||||||
Pattern::Wildcard(_) => Ok("1".to_string()),
|
Pattern::Wildcard(_) => Ok("1".to_string()),
|
||||||
Pattern::Var(ident) => Ok(format!("(1) /* bind {} = {} */", ident.name, scrutinee)),
|
Pattern::Var(_) => Ok("1".to_string()), // Var always matches, binding handled separately
|
||||||
Pattern::Literal(lit) => {
|
Pattern::Literal(lit) => {
|
||||||
let lit_val = self.emit_literal_value(&lit.kind)?;
|
let lit_val = self.emit_literal_value(&lit.kind)?;
|
||||||
Ok(format!("{} == {}", scrutinee, lit_val))
|
Ok(format!("{} == {}", scrutinee, lit_val))
|
||||||
}
|
}
|
||||||
Pattern::Constructor { name, .. } => {
|
Pattern::Constructor { name, fields, .. } => {
|
||||||
Ok(format!("{}.tag == TAG_{}", scrutinee, name.name.to_uppercase()))
|
// Get the type name for proper tag generation
|
||||||
|
let tn = type_name.unwrap_or("Option"); // Default fallback
|
||||||
|
let tag_check = format!("{}.tag == {}_TAG_{}", scrutinee, tn, name.name.to_uppercase());
|
||||||
|
|
||||||
|
// If there are nested patterns, we need to check those too
|
||||||
|
if fields.is_empty() {
|
||||||
|
Ok(tag_check)
|
||||||
|
} else {
|
||||||
|
let mut conditions = vec![tag_check];
|
||||||
|
let variant_lower = name.name.to_lowercase();
|
||||||
|
|
||||||
|
for (i, field_pattern) in fields.iter().enumerate() {
|
||||||
|
// Access the field data
|
||||||
|
let field_access = format!("{}.data.{}.field{}", scrutinee, variant_lower, i);
|
||||||
|
let field_condition = self.pattern_to_condition(field_pattern, &field_access, None)?;
|
||||||
|
if field_condition != "1" {
|
||||||
|
conditions.push(field_condition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(conditions.join(" && "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Pattern::Tuple { elements, .. } => {
|
||||||
|
// For tuples, check each element pattern
|
||||||
|
let mut conditions = Vec::new();
|
||||||
|
for (i, elem_pattern) in elements.iter().enumerate() {
|
||||||
|
let elem_access = format!("{}.field{}", scrutinee, i);
|
||||||
|
let elem_condition = self.pattern_to_condition(elem_pattern, &elem_access, None)?;
|
||||||
|
if elem_condition != "1" {
|
||||||
|
conditions.push(elem_condition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if conditions.is_empty() {
|
||||||
|
Ok("1".to_string())
|
||||||
|
} else {
|
||||||
|
Ok(conditions.join(" && "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Pattern::Record { .. } => Ok("1".to_string()), // TODO: record pattern matching
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract variable bindings from a pattern.
|
||||||
|
/// Returns a list of (var_name, c_expression, c_type) triples.
|
||||||
|
fn extract_pattern_bindings(&self, pattern: &Pattern, scrutinee: &str, expected_type: Option<&str>) -> Vec<(String, String, String)> {
|
||||||
|
match pattern {
|
||||||
|
Pattern::Wildcard(_) => vec![],
|
||||||
|
Pattern::Var(ident) => {
|
||||||
|
let typ = expected_type.unwrap_or("LuxInt").to_string();
|
||||||
|
vec![(ident.name.clone(), scrutinee.to_string(), typ)]
|
||||||
|
}
|
||||||
|
Pattern::Literal(_) => vec![],
|
||||||
|
Pattern::Constructor { name, fields, .. } => {
|
||||||
|
let mut bindings = Vec::new();
|
||||||
|
let variant_lower = name.name.to_lowercase();
|
||||||
|
|
||||||
|
// Look up field types for this variant
|
||||||
|
let type_name = self.variant_to_type.get(&name.name);
|
||||||
|
let field_types = type_name.and_then(|tn| {
|
||||||
|
self.variant_field_types.get(&(tn.clone(), name.name.clone()))
|
||||||
|
});
|
||||||
|
|
||||||
|
for (i, field_pattern) in fields.iter().enumerate() {
|
||||||
|
let field_access = format!("{}.data.{}.field{}", scrutinee, variant_lower, i);
|
||||||
|
let field_type = field_types.and_then(|ft| ft.get(i)).map(|s| s.as_str());
|
||||||
|
bindings.extend(self.extract_pattern_bindings(field_pattern, &field_access, field_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
bindings
|
||||||
|
}
|
||||||
|
Pattern::Tuple { elements, .. } => {
|
||||||
|
let mut bindings = Vec::new();
|
||||||
|
for (i, elem_pattern) in elements.iter().enumerate() {
|
||||||
|
let elem_access = format!("{}.field{}", scrutinee, i);
|
||||||
|
bindings.extend(self.extract_pattern_bindings(elem_pattern, &elem_access, None));
|
||||||
|
}
|
||||||
|
bindings
|
||||||
|
}
|
||||||
|
Pattern::Record { fields, .. } => {
|
||||||
|
let mut bindings = Vec::new();
|
||||||
|
for (field_name, field_pattern) in fields {
|
||||||
|
let field_access = format!("{}.{}", scrutinee, field_name.name);
|
||||||
|
bindings.extend(self.extract_pattern_bindings(field_pattern, &field_access, None));
|
||||||
|
}
|
||||||
|
bindings
|
||||||
}
|
}
|
||||||
_ => Ok("1".to_string()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,6 +1104,17 @@ impl CBackend {
|
|||||||
self.type_expr_to_c(type_expr)
|
self.type_expr_to_c(type_expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert type to C, using pointers for self-referential types
|
||||||
|
fn type_to_c_with_self_check(&self, type_expr: &TypeExpr, parent_type: &str) -> Result<String, CGenError> {
|
||||||
|
if let TypeExpr::Named(ident) = type_expr {
|
||||||
|
if ident.name == parent_type {
|
||||||
|
// Self-referential type - use pointer
|
||||||
|
return Ok(format!("{}*", parent_type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.type_expr_to_c(type_expr)
|
||||||
|
}
|
||||||
|
|
||||||
fn type_expr_to_c(&self, type_expr: &TypeExpr) -> Result<String, CGenError> {
|
fn type_expr_to_c(&self, type_expr: &TypeExpr) -> Result<String, CGenError> {
|
||||||
match type_expr {
|
match type_expr {
|
||||||
TypeExpr::Named(ident) => {
|
TypeExpr::Named(ident) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user