From d6683acee79af339010f33332881cbd84e958bc7 Mon Sep 17 00:00:00 2001 From: Priyanshu Dangare Date: Thu, 5 Feb 2026 07:04:52 +0530 Subject: [PATCH] Implement struct field index queries (fixes #216) Add support for index queries on struct list fields: - Implement expr_dot method to handle struct field access (list.field) - Extend BinOp::In handling to support Expr::Dot RHS - Generate qualified names for struct list fields - Add comprehensive test cases Example usage: index = "02/02/2026" in my_struct_list.date; has_alice = "Alice" in my_struct_list.name; Fixes #216 --- src/codegen/expr.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++- tests/lists/main.gs | 30 ++++++++++++++++++++-- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/src/codegen/expr.rs b/src/codegen/expr.rs index 7d767931..a1a11c34 100644 --- a/src/codegen/expr.rs +++ b/src/codegen/expr.rs @@ -5,6 +5,7 @@ use std::io::{ }; use logos::Span; +use serde_json::json; use super::{ input::{ @@ -246,6 +247,38 @@ where T: Write + Seek return self.list_contains(s, d, this_id, parent_id, &qualified_name, lhs); } } + // Handle struct field access: "value" in struct_list.field + if let Expr::Dot { + lhs, + rhs, + rhs_span: _, + } = rhs + { + if let Expr::Name(name) = lhs.as_ref() { + if let Some(QualifiedName::List(list_name, _)) = s.qualify_name(Some(d), name) { + let list = s.get_list(&list_name).unwrap(); + if let Some((type_name, _type_span)) = list.type_.struct_() { + let struct_ = s.get_struct(type_name).unwrap(); + // Verify the field exists in the struct + if struct_ + .fields + .iter() + .any(|field| field.name == rhs.as_str()) + { + let qualified_name = qualify_struct_var_name(rhs, name.basename()); + return self.list_contains( + s, + d, + this_id, + parent_id, + &qualified_name, + lhs, + ); + } + } + } + } + } } let lhs_id = self.id.new_id(); let rhs_id = self.id.new_id(); @@ -433,7 +466,7 @@ where T: Write + Seek pub fn expr_dot( &mut self, s: S, - _d: D, + d: D, _this_id: NodeID, _parent_id: NodeID, lhs: &Expr, @@ -444,6 +477,33 @@ where T: Write + Seek if let Some(_enum_) = s.get_enum(name.basename()) { return Ok(()); } + + // Check if this is a struct list field access + // First check if this is a list directly + if let Some(list) = s.get_list(name.basename()) { + if let Some((type_name, _type_span)) = list.type_.struct_() { + // This is a struct list, check if field exists in struct + let struct_ = s.get_struct(type_name).unwrap(); + // Verify the field exists in the struct + if struct_ + .fields + .iter() + .any(|field| field.name == rhs.as_str()) + { + let qualified_name = qualify_struct_var_name(rhs, name.basename()); + let qualified_list_name = QualifiedName::List(qualified_name, Type::Value); + match qualified_list_name { + QualifiedName::Var(qname, _) => { + write!(self, "[3,[12,{},{}],", json!(*qname), json!(*qname))?; + } + QualifiedName::List(qname, _) => { + write!(self, "[3,[13,{},{}],", json!(*qname), json!(*qname))?; + } + } + return write!(self, "[10, \"\"]]"); + } + } + } } eprintln!("attempted to codegen Expr::Dot lhs = {lhs:#?}, rhs = {rhs:#?}"); Ok(()) diff --git a/tests/lists/main.gs b/tests/lists/main.gs index 48b2fbea..15b4812c 100644 --- a/tests/lists/main.gs +++ b/tests/lists/main.gs @@ -1,5 +1,31 @@ costumes "blank.svg"; -onflag { - say "Hello, World!"; +struct MyStruct { + name, + date, +} + +list MyStruct my_struct_list; + +proc main { + # Test basic struct field access + add MyStruct { name: "Alice", date: "01/01/2026" } to my_struct_list; + add MyStruct { name: "Bob", date: "02/02/2026" } to my_struct_list; + add MyStruct { name: "Charlie", date: "03/03/2026" } to my_struct_list; + + # Test struct field index query + index = "02/02/2026" in my_struct_list.date; + say "Index: " & index; + + # Test another field + has_alice = "Alice" in my_struct_list.name; + say "Has Alice: " & has_alice; + + # Test non-existent value + has_nonexistent = "04/04/2026" in my_struct_list.date; + say "Has non-existent date: " & has_nonexistent; } + +onflag { + main; +} \ No newline at end of file