From 8e4bdd39423c3347a9f0669f0ea9367543f6bfde Mon Sep 17 00:00:00 2001 From: Sienna Meridian Satterwhite Date: Sat, 14 Feb 2026 14:03:21 +0000 Subject: [PATCH] refactor(ast): rename value types to Number/Decimal/Text/Boolean Renamed AST value types for v0.3 naming convention: - Value::Int -> Value::Number - Value::Float -> Value::Decimal - Value::String -> Value::Text - Value::Bool -> Value::Boolean - Expr::IntLit -> Expr::NumberLit - Expr::FloatLit -> Expr::DecimalLit - Expr::StringLit -> Expr::TextLit - Expr::BoolLit -> Expr::BooleanLit Updated all references across parser, resolver, validator, LSP, query engine, tests, and editor. --- src/error_showcase_tests.rs | 16 +++---- src/lsp/code_actions.rs | 24 +++++----- src/lsp/completion.rs | 8 ++-- src/lsp/hover.rs | 16 +++---- src/lsp/inlay_hints.rs | 10 ++-- src/lsp/semantic_tokens.rs | 8 ++-- src/query.rs | 16 +++---- src/resolve/convert.rs | 58 ++++++++++++------------ src/resolve/convert_integration_tests.rs | 28 ++++++------ src/resolve/convert_prop_tests.rs | 28 ++++++------ src/resolve/links.rs | 2 +- src/resolve/links_prop_tests.rs | 2 +- src/resolve/merge.rs | 28 ++++++------ src/resolve/merge_prop_tests.rs | 14 +++--- src/resolve/validate.rs | 22 ++++----- src/resolve/validate_prop_tests.rs | 20 ++++---- src/syntax/ast.rs | 16 +++---- src/syntax/parser.lalrpop | 24 +++++----- src/syntax/parser.rs | 22 ++++----- storybook-editor/src/ui/main_editor.rs | 8 ++-- tests/validate_examples.rs | 6 +-- 21 files changed, 188 insertions(+), 188 deletions(-) diff --git a/src/error_showcase_tests.rs b/src/error_showcase_tests.rs index f82051d..10224ad 100644 --- a/src/error_showcase_tests.rs +++ b/src/error_showcase_tests.rs @@ -216,7 +216,7 @@ fn test_unknown_life_arc_state_error() { on_enter: None, transitions: vec![Transition { to: "adult".to_string(), // 'adult' exists - condition: Expr::BoolLit(true), + condition: Expr::BooleanLit(true), span: Span::new(0, 10), }], span: Span::new(0, 50), @@ -226,7 +226,7 @@ fn test_unknown_life_arc_state_error() { on_enter: None, transitions: vec![Transition { to: "senior".to_string(), // 'senior' doesn't exist! - condition: Expr::BoolLit(true), + condition: Expr::BooleanLit(true), span: Span::new(50, 60), }], span: Span::new(50, 100), @@ -252,7 +252,7 @@ fn test_unknown_life_arc_state_error() { fn test_trait_out_of_range_error_bond() { let fields = vec![Field { name: "bond".to_string(), - value: Value::Float(1.5), // Out of range! + value: Value::Decimal(1.5), // Out of range! span: Span::new(0, 10), }]; @@ -276,7 +276,7 @@ fn test_trait_out_of_range_error_bond() { fn test_trait_out_of_range_error_age() { let fields = vec![Field { name: "age".to_string(), - value: Value::Int(200), // Out of range! + value: Value::Number(200), // Out of range! span: Span::new(0, 10), }]; @@ -297,7 +297,7 @@ fn test_trait_out_of_range_error_age() { fn test_trait_out_of_range_negative() { let fields = vec![Field { name: "trust".to_string(), - value: Value::Float(-0.2), // Negative! + value: Value::Decimal(-0.2), // Negative! span: Span::new(0, 10), }]; @@ -411,7 +411,7 @@ fn test_relationship_bond_out_of_range() { participants: vec![], fields: vec![Field { name: "bond".to_string(), - value: Value::Float(2.5), // Way out of range! + value: Value::Decimal(2.5), // Way out of range! span: Span::new(0, 10), }], span: Span::new(0, 50), @@ -438,12 +438,12 @@ fn test_duplicate_field_in_convert() { fields: vec![ Field { name: "age".to_string(), - value: Value::Int(34), + value: Value::Number(34), span: Span::new(0, 10), }, Field { name: "age".to_string(), // Duplicate! - value: Value::Int(35), + value: Value::Number(35), span: Span::new(10, 20), }, ], diff --git a/src/lsp/code_actions.rs b/src/lsp/code_actions.rs index 2217144..08cf603 100644 --- a/src/lsp/code_actions.rs +++ b/src/lsp/code_actions.rs @@ -2389,10 +2389,10 @@ fn get_default_value_for_type(field_type: &crate::syntax::ast::Value) -> String } }, | Value::List(_) => String::from("[]"), - | Value::String(_) => String::from("\"\""), - | Value::Int(_) => String::from("0"), - | Value::Float(_) => String::from("0.0"), - | Value::Bool(_) => String::from("false"), + | Value::Text(_) => String::from("\"\""), + | Value::Number(_) => String::from("0"), + | Value::Decimal(_) => String::from("0.0"), + | Value::Boolean(_) => String::from("false"), | Value::Object(_) => String::from("{}"), | Value::Range(_, _) => String::from("0..10"), | Value::Time(_) => String::from("00:00"), @@ -2408,10 +2408,10 @@ fn format_value(value: &crate::syntax::ast::Value) -> String { use crate::syntax::ast::Value; match value { - | Value::String(s) => format!("\"{}\"", s), - | Value::Int(n) => n.to_string(), - | Value::Float(f) => f.to_string(), - | Value::Bool(b) => b.to_string(), + | Value::Text(s) => format!("\"{}\"", s), + | Value::Number(n) => n.to_string(), + | Value::Decimal(f) => f.to_string(), + | Value::Boolean(b) => b.to_string(), | Value::Identifier(path) => path.join("."), | Value::List(items) => { let formatted: Vec = items.iter().map(format_value).collect(); @@ -2443,10 +2443,10 @@ fn infer_type_from_value(value: &crate::syntax::ast::Value) -> String { use crate::syntax::ast::Value; match value { - | Value::String(_) => String::from("String"), - | Value::Int(_) => String::from("Int"), - | Value::Float(_) => String::from("Float"), - | Value::Bool(_) => String::from("Bool"), + | Value::Text(_) => String::from("Text"), + | Value::Number(_) => String::from("Number"), + | Value::Decimal(_) => String::from("Decimal"), + | Value::Boolean(_) => String::from("Boolean"), | Value::Identifier(path) => path.join("."), // Reference type | Value::List(items) => { if items.is_empty() { diff --git a/src/lsp/completion.rs b/src/lsp/completion.rs index 6d7832a..d19d039 100644 --- a/src/lsp/completion.rs +++ b/src/lsp/completion.rs @@ -209,10 +209,10 @@ fn is_typing_declaration_name(text: &str, offset: usize) -> bool { fn format_value_type(value: &Value) -> String { match value { | Value::Identifier(path) => path.join("."), - | Value::String(_) => "String".to_string(), - | Value::Int(_) => "Int".to_string(), - | Value::Float(_) => "Float".to_string(), - | Value::Bool(_) => "Bool".to_string(), + | Value::Text(_) => "Text".to_string(), + | Value::Number(_) => "Number".to_string(), + | Value::Decimal(_) => "Decimal".to_string(), + | Value::Boolean(_) => "Boolean".to_string(), | Value::List(items) => { if items.is_empty() { "List".to_string() diff --git a/src/lsp/hover.rs b/src/lsp/hover.rs index 0830498..666b1e1 100644 --- a/src/lsp/hover.rs +++ b/src/lsp/hover.rs @@ -526,10 +526,10 @@ fn format_behavior_node_preview(node: &crate::syntax::ast::BehaviorNode, depth: fn format_value_as_type(value: &Value) -> String { match value { | Value::Identifier(path) => path.join("."), - | Value::String(_) => "String".to_string(), - | Value::Int(_) => "Int".to_string(), - | Value::Float(_) => "Float".to_string(), - | Value::Bool(_) => "Bool".to_string(), + | Value::Text(_) => "Text".to_string(), + | Value::Number(_) => "Number".to_string(), + | Value::Decimal(_) => "Decimal".to_string(), + | Value::Boolean(_) => "Boolean".to_string(), | Value::List(items) => { if items.is_empty() { "List".to_string() @@ -557,10 +557,10 @@ fn format_value_as_type(value: &Value) -> String { fn format_value_preview(value: &Value) -> String { match value { | Value::Identifier(path) => format!("`{}`", path.join(".")), - | Value::String(s) => format!("\"{}\"", truncate(s, 50)), - | Value::Int(n) => n.to_string(), - | Value::Float(f) => f.to_string(), - | Value::Bool(b) => b.to_string(), + | Value::Text(s) => format!("\"{}\"", truncate(s, 50)), + | Value::Number(n) => n.to_string(), + | Value::Decimal(f) => f.to_string(), + | Value::Boolean(b) => b.to_string(), | Value::List(items) => { if items.is_empty() { "[]".to_string() diff --git a/src/lsp/inlay_hints.rs b/src/lsp/inlay_hints.rs index 9e7958f..39d3a1f 100644 --- a/src/lsp/inlay_hints.rs +++ b/src/lsp/inlay_hints.rs @@ -145,7 +145,7 @@ fn add_type_hint( // Only add hints for non-obvious types // Skip if the type is clear from the literal (e.g., "string", 123, true) let should_hint = match &field.value { - | Value::String(_) | Value::Int(_) | Value::Float(_) | Value::Bool(_) => false, + | Value::Text(_) | Value::Number(_) | Value::Decimal(_) | Value::Boolean(_) => false, | Value::Identifier(_) => true, // Show type for identifier references | Value::List(_) => true, // Show list element type | Value::Object(_) => false, // Object structure is visible @@ -183,10 +183,10 @@ fn add_type_hint( fn infer_value_type(value: &Value) -> String { match value { | Value::Identifier(path) => path.join("."), - | Value::String(_) => "String".to_string(), - | Value::Int(_) => "Int".to_string(), - | Value::Float(_) => "Float".to_string(), - | Value::Bool(_) => "Bool".to_string(), + | Value::Text(_) => "Text".to_string(), + | Value::Number(_) => "Number".to_string(), + | Value::Decimal(_) => "Decimal".to_string(), + | Value::Boolean(_) => "Boolean".to_string(), | Value::List(items) => { if items.is_empty() { "[]".to_string() diff --git a/src/lsp/semantic_tokens.rs b/src/lsp/semantic_tokens.rs index 222d494..fd09f07 100644 --- a/src/lsp/semantic_tokens.rs +++ b/src/lsp/semantic_tokens.rs @@ -411,14 +411,14 @@ fn highlight_field(builder: &mut SemanticTokensBuilder, field: &Field) { /// Helper to highlight a value fn highlight_value(builder: &mut SemanticTokensBuilder, value: &Value) { match value { - | Value::String(_s) => { - // String literals are already highlighted by the grammar + | Value::Text(_s) => { + // Text literals are already highlighted by the grammar // but we could add semantic highlighting here if needed }, - | Value::Int(_) | Value::Float(_) => { + | Value::Number(_) | Value::Decimal(_) => { // Number literals are already highlighted by the grammar }, - | Value::Bool(_) => { + | Value::Boolean(_) => { // Boolean literals are already highlighted by the grammar }, | Value::Identifier(_path) => { diff --git a/src/query.rs b/src/query.rs index cd8c73e..b7a58a9 100644 --- a/src/query.rs +++ b/src/query.rs @@ -50,7 +50,7 @@ where max: i64, ) -> Box + 'a> { Box::new(self.filter(move |c| { - if let Some(Value::Int(age)) = c.fields.get("age") { + if let Some(Value::Number(age)) = c.fields.get("age") { *age >= min && *age <= max } else { false @@ -65,7 +65,7 @@ where max: f64, ) -> Box + 'a> { Box::new(self.filter(move |c| { - if let Some(Value::Float(value)) = c.fields.get(trait_name) { + if let Some(Value::Decimal(value)) = c.fields.get(trait_name) { *value >= min && *value <= max } else { false @@ -121,7 +121,7 @@ where max: f64, ) -> Box + 'a> { Box::new(self.filter(move |r| { - if let Some(Value::Float(bond)) = r.fields.get("bond") { + if let Some(Value::Decimal(bond)) = r.fields.get("bond") { *bond >= min && *bond <= max } else { false @@ -178,8 +178,8 @@ mod tests { fn make_character(name: &str, age: i64, trust: f64) -> ResolvedCharacter { let mut fields = HashMap::new(); - fields.insert("age".to_string(), Value::Int(age)); - fields.insert("trust".to_string(), Value::Float(trust)); + fields.insert("age".to_string(), Value::Number(age)); + fields.insert("trust".to_string(), Value::Decimal(trust)); ResolvedCharacter { name: name.to_string(), @@ -248,7 +248,7 @@ mod tests { let mut char1 = make_character("Alice", 25, 0.8); char1 .fields - .insert("job".to_string(), Value::String("baker".to_string())); + .insert("job".to_string(), Value::Text("baker".to_string())); let char2 = make_character("Bob", 35, 0.6); @@ -263,10 +263,10 @@ mod tests { #[test] fn test_relationship_with_bond_range() { let mut fields1 = HashMap::new(); - fields1.insert("bond".to_string(), Value::Float(0.9)); + fields1.insert("bond".to_string(), Value::Decimal(0.9)); let mut fields2 = HashMap::new(); - fields2.insert("bond".to_string(), Value::Float(0.5)); + fields2.insert("bond".to_string(), Value::Decimal(0.5)); let relationships = [ ResolvedRelationship { diff --git a/src/resolve/convert.rs b/src/resolve/convert.rs index a1d8ba2..06ad686 100644 --- a/src/resolve/convert.rs +++ b/src/resolve/convert.rs @@ -384,12 +384,12 @@ mod tests { fields: vec![ Field { name: "age".to_string(), - value: Value::Int(34), + value: Value::Number(34), span: Span::new(0, 10), }, Field { name: "health".to_string(), - value: Value::Float(0.8), + value: Value::Decimal(0.8), span: Span::new(10, 20), }, ], @@ -403,8 +403,8 @@ mod tests { assert_eq!(resolved.name, "Martha"); assert_eq!(resolved.fields.len(), 2); - assert_eq!(resolved.fields.get("age"), Some(&Value::Int(34))); - assert_eq!(resolved.fields.get("health"), Some(&Value::Float(0.8))); + assert_eq!(resolved.fields.get("age"), Some(&Value::Number(34))); + assert_eq!(resolved.fields.get("health"), Some(&Value::Decimal(0.8))); assert_eq!(resolved.prose_blocks.len(), 0); } @@ -422,7 +422,7 @@ mod tests { fields: vec![ Field { name: "age".to_string(), - value: Value::Int(34), + value: Value::Number(34), span: Span::new(0, 10), }, Field { @@ -441,7 +441,7 @@ mod tests { assert_eq!(resolved.name, "Martha"); assert_eq!(resolved.fields.len(), 1); - assert_eq!(resolved.fields.get("age"), Some(&Value::Int(34))); + assert_eq!(resolved.fields.get("age"), Some(&Value::Number(34))); assert_eq!(resolved.prose_blocks.len(), 1); assert_eq!(resolved.prose_blocks.get("backstory"), Some(&prose_block)); } @@ -454,12 +454,12 @@ mod tests { fields: vec![ Field { name: "age".to_string(), - value: Value::Int(34), + value: Value::Number(34), span: Span::new(0, 10), }, Field { name: "age".to_string(), - value: Value::Int(35), + value: Value::Number(35), span: Span::new(10, 20), }, ], @@ -481,7 +481,7 @@ mod tests { species: None, fields: vec![Field { name: "age".to_string(), - value: Value::Int(34), + value: Value::Number(34), span: Span::new(0, 10), }], template: None, @@ -550,7 +550,7 @@ mod tests { let fields = vec![ Field { name: "age".to_string(), - value: Value::Int(30), + value: Value::Number(30), span: Span::new(0, 10), }, Field { @@ -560,7 +560,7 @@ mod tests { }, Field { name: "active".to_string(), - value: Value::Bool(true), + value: Value::Boolean(true), span: Span::new(30, 40), }, ]; @@ -568,8 +568,8 @@ mod tests { let (field_map, prose_map) = extract_fields_and_prose(&fields).unwrap(); assert_eq!(field_map.len(), 2); - assert_eq!(field_map.get("age"), Some(&Value::Int(30))); - assert_eq!(field_map.get("active"), Some(&Value::Bool(true))); + assert_eq!(field_map.get("age"), Some(&Value::Number(30))); + assert_eq!(field_map.get("active"), Some(&Value::Boolean(true))); assert_eq!(prose_map.len(), 1); assert_eq!(prose_map.get("description"), Some(&prose_block)); @@ -585,7 +585,7 @@ mod tests { name: "Person".to_string(), fields: vec![Field { name: "type".to_string(), // Changed from "species" - value: Value::String("human".to_string()), + value: Value::Text("human".to_string()), span: Span::new(0, 10), }], strict: false, @@ -600,7 +600,7 @@ mod tests { species: None, fields: vec![Field { name: "age".to_string(), - value: Value::Int(34), + value: Value::Number(34), span: Span::new(0, 10), }], template: Some(vec!["Person".to_string()]), @@ -624,10 +624,10 @@ mod tests { assert_eq!(resolved.name, "Martha"); assert_eq!(resolved.fields.len(), 2); - assert_eq!(resolved.fields.get("age"), Some(&Value::Int(34))); + assert_eq!(resolved.fields.get("age"), Some(&Value::Number(34))); assert_eq!( resolved.fields.get("type"), - Some(&Value::String("human".to_string())) + Some(&Value::Text("human".to_string())) ); } @@ -639,7 +639,7 @@ mod tests { name: "Physical".to_string(), fields: vec![Field { name: "height".to_string(), - value: Value::Int(0), + value: Value::Number(0), span: Span::new(0, 10), }], strict: false, @@ -653,7 +653,7 @@ mod tests { name: "Mental".to_string(), fields: vec![Field { name: "iq".to_string(), - value: Value::Int(0), + value: Value::Number(0), span: Span::new(0, 10), }], strict: false, @@ -669,12 +669,12 @@ mod tests { fields: vec![ Field { name: "height".to_string(), - value: Value::Int(165), + value: Value::Number(165), span: Span::new(0, 10), }, Field { name: "iq".to_string(), - value: Value::Int(120), + value: Value::Number(120), span: Span::new(10, 20), }, ], @@ -700,8 +700,8 @@ mod tests { assert_eq!(resolved.name, "Martha"); assert_eq!(resolved.fields.len(), 2); - assert_eq!(resolved.fields.get("height"), Some(&Value::Int(165))); - assert_eq!(resolved.fields.get("iq"), Some(&Value::Int(120))); + assert_eq!(resolved.fields.get("height"), Some(&Value::Number(165))); + assert_eq!(resolved.fields.get("iq"), Some(&Value::Number(120))); } #[test] @@ -712,7 +712,7 @@ mod tests { name: "Human".to_string(), fields: vec![Field { name: "type".to_string(), // Changed from "species" - value: Value::String("human".to_string()), + value: Value::Text("human".to_string()), span: Span::new(0, 10), }], strict: false, @@ -726,7 +726,7 @@ mod tests { name: "Person".to_string(), fields: vec![Field { name: "age".to_string(), - value: Value::Int(0), + value: Value::Number(0), span: Span::new(0, 10), }], strict: false, @@ -751,10 +751,10 @@ mod tests { assert_eq!(resolved.name, "Person"); assert_eq!(resolved.fields.len(), 2); - assert_eq!(resolved.fields.get("age"), Some(&Value::Int(0))); + assert_eq!(resolved.fields.get("age"), Some(&Value::Number(0))); assert_eq!( resolved.fields.get("type"), - Some(&Value::String("human".to_string())) + Some(&Value::Text("human".to_string())) ); } @@ -765,7 +765,7 @@ mod tests { species: None, fields: vec![Field { name: "species".to_string(), // Reserved keyword! - value: Value::String("human".to_string()), + value: Value::Text("human".to_string()), span: Span::new(0, 10), }], template: None, @@ -793,7 +793,7 @@ mod tests { name: "Person".to_string(), fields: vec![Field { name: "age".to_string(), - value: Value::Range(Box::new(Value::Int(18)), Box::new(Value::Int(65))), + value: Value::Range(Box::new(Value::Number(18)), Box::new(Value::Number(65))), span: Span::new(0, 10), }], strict: true, diff --git a/src/resolve/convert_integration_tests.rs b/src/resolve/convert_integration_tests.rs index 7423462..71344d3 100644 --- a/src/resolve/convert_integration_tests.rs +++ b/src/resolve/convert_integration_tests.rs @@ -32,8 +32,8 @@ fn test_simple_character_end_to_end() { | ResolvedDeclaration::Character(c) => { assert_eq!(c.name, "Martha"); assert_eq!(c.fields.len(), 2); - assert_eq!(c.fields.get("age"), Some(&Value::Int(34))); - assert_eq!(c.fields.get("health"), Some(&Value::Float(0.8))); + assert_eq!(c.fields.get("age"), Some(&Value::Number(34))); + assert_eq!(c.fields.get("health"), Some(&Value::Decimal(0.8))); }, | _ => panic!("Expected Character"), } @@ -58,7 +58,7 @@ She loved baking from a young age. | ResolvedDeclaration::Character(c) => { assert_eq!(c.name, "Martha"); assert_eq!(c.fields.len(), 1); - assert_eq!(c.fields.get("age"), Some(&Value::Int(34))); + assert_eq!(c.fields.get("age"), Some(&Value::Number(34))); assert_eq!(c.prose_blocks.len(), 1); let backstory = c.prose_blocks.get("backstory").unwrap(); @@ -108,7 +108,7 @@ fn test_relationship_end_to_end() { | ResolvedDeclaration::Relationship(r) => { assert_eq!(r.name, "Spousal"); assert_eq!(r.participants.len(), 2); - assert_eq!(r.fields.get("bond"), Some(&Value::Float(0.9))); + assert_eq!(r.fields.get("bond"), Some(&Value::Decimal(0.9))); }, | _ => panic!("Expected Relationship"), } @@ -208,8 +208,8 @@ fn test_institution_end_to_end() { match &resolved[0] { | ResolvedDeclaration::Institution(i) => { assert_eq!(i.name, "Bakery"); - assert_eq!(i.fields.get("employees"), Some(&Value::Int(5))); - assert_eq!(i.fields.get("revenue"), Some(&Value::Int(50000))); + assert_eq!(i.fields.get("employees"), Some(&Value::Number(5))); + assert_eq!(i.fields.get("revenue"), Some(&Value::Number(50000))); }, | _ => panic!("Expected Institution"), } @@ -230,8 +230,8 @@ fn test_location_end_to_end() { match &resolved[0] { | ResolvedDeclaration::Location(l) => { assert_eq!(l.name, "Bakery"); - assert_eq!(l.fields.get("x"), Some(&Value::Int(100))); - assert_eq!(l.fields.get("y"), Some(&Value::Int(200))); + assert_eq!(l.fields.get("x"), Some(&Value::Number(100))); + assert_eq!(l.fields.get("y"), Some(&Value::Number(200))); }, | _ => panic!("Expected Location"), } @@ -252,8 +252,8 @@ fn test_species_end_to_end() { match &resolved[0] { | ResolvedDeclaration::Species(s) => { assert_eq!(s.name, "Human"); - assert_eq!(s.fields.get("lifespan"), Some(&Value::Int(80))); - assert_eq!(s.fields.get("intelligence"), Some(&Value::Float(0.9))); + assert_eq!(s.fields.get("lifespan"), Some(&Value::Number(80))); + assert_eq!(s.fields.get("intelligence"), Some(&Value::Decimal(0.9))); }, | _ => panic!("Expected Species"), } @@ -375,12 +375,12 @@ fn test_all_value_types_convert() { let resolved = parse_and_convert(source).unwrap(); match &resolved[0] { | ResolvedDeclaration::Character(c) => { - assert_eq!(c.fields.get("int_val"), Some(&Value::Int(42))); - assert_eq!(c.fields.get("float_val"), Some(&Value::Float(3.5))); - assert_eq!(c.fields.get("bool_val"), Some(&Value::Bool(true))); + assert_eq!(c.fields.get("int_val"), Some(&Value::Number(42))); + assert_eq!(c.fields.get("float_val"), Some(&Value::Decimal(3.5))); + assert_eq!(c.fields.get("bool_val"), Some(&Value::Boolean(true))); assert_eq!( c.fields.get("string_val"), - Some(&Value::String("hello".to_string())) + Some(&Value::Text("hello".to_string())) ); }, | _ => panic!("Expected Character"), diff --git a/src/resolve/convert_prop_tests.rs b/src/resolve/convert_prop_tests.rs index 6930d93..218f93a 100644 --- a/src/resolve/convert_prop_tests.rs +++ b/src/resolve/convert_prop_tests.rs @@ -54,12 +54,12 @@ fn valid_ident() -> impl Strategy { fn valid_value() -> impl Strategy { prop_oneof![ - (-1000i64..1000).prop_map(Value::Int), + (-1000i64..1000).prop_map(Value::Number), (-1000.0..1000.0) .prop_filter("finite", |f: &f64| f.is_finite()) - .prop_map(Value::Float), - any::().prop_map(Value::Bool), - "[a-zA-Z0-9 ]{0,30}".prop_map(Value::String), + .prop_map(Value::Decimal), + any::().prop_map(Value::Boolean), + "[a-zA-Z0-9 ]{0,30}".prop_map(Value::Text), ] } @@ -296,22 +296,22 @@ mod edge_cases { fields: vec![ Field { name: "int_field".to_string(), - value: Value::Int(int_val), + value: Value::Number(int_val), span: Span::new(0, 10), }, Field { name: "float_field".to_string(), - value: Value::Float(float_val), + value: Value::Decimal(float_val), span: Span::new(10, 20), }, Field { name: "bool_field".to_string(), - value: Value::Bool(bool_val), + value: Value::Boolean(bool_val), span: Span::new(20, 30), }, Field { name: "string_field".to_string(), - value: Value::String(string_val.clone()), + value: Value::Text(string_val.clone()), span: Span::new(30, 40), }, ], @@ -322,10 +322,10 @@ mod edge_cases { }; let resolved = convert_character(&character).unwrap(); - assert_eq!(resolved.fields.get("int_field"), Some(&Value::Int(int_val))); - assert_eq!(resolved.fields.get("float_field"), Some(&Value::Float(float_val))); - assert_eq!(resolved.fields.get("bool_field"), Some(&Value::Bool(bool_val))); - assert_eq!(resolved.fields.get("string_field"), Some(&Value::String(string_val))); + assert_eq!(resolved.fields.get("int_field"), Some(&Value::Number(int_val))); + assert_eq!(resolved.fields.get("float_field"), Some(&Value::Decimal(float_val))); + assert_eq!(resolved.fields.get("bool_field"), Some(&Value::Boolean(bool_val))); + assert_eq!(resolved.fields.get("string_field"), Some(&Value::Text(string_val))); } #[test] @@ -341,7 +341,7 @@ mod edge_cases { species: None, fields: vec![Field { name: field_name.clone(), - value: Value::String(string_val.clone()), + value: Value::Text(string_val.clone()), span: Span::new(0, 10), }], template: None, @@ -354,7 +354,7 @@ mod edge_cases { assert_eq!(resolved.name, name); assert_eq!( resolved.fields.get(&field_name), - Some(&Value::String(string_val)) + Some(&Value::Text(string_val)) ); } } diff --git a/src/resolve/links.rs b/src/resolve/links.rs index 85aa21a..e8a5e48 100644 --- a/src/resolve/links.rs +++ b/src/resolve/links.rs @@ -194,7 +194,7 @@ mod tests { fn make_field(name: &str, value: i64) -> Field { Field { name: name.to_string(), - value: Value::Int(value), + value: Value::Number(value), span: Span::new(0, 10), } } diff --git a/src/resolve/links_prop_tests.rs b/src/resolve/links_prop_tests.rs index d30799d..d7f4c2a 100644 --- a/src/resolve/links_prop_tests.rs +++ b/src/resolve/links_prop_tests.rs @@ -48,7 +48,7 @@ fn valid_ident() -> impl Strategy { fn valid_field() -> impl Strategy { (valid_ident(), 0i64..100).prop_map(|(name, value)| Field { name, - value: Value::Int(value), + value: Value::Number(value), span: Span::new(0, 10), }) } diff --git a/src/resolve/merge.rs b/src/resolve/merge.rs index ef72b9f..9ef6ab9 100644 --- a/src/resolve/merge.rs +++ b/src/resolve/merge.rs @@ -430,7 +430,7 @@ mod tests { fn make_field(name: &str, value: i64) -> Field { Field { name: name.to_string(), - value: Value::Int(value), + value: Value::Number(value), span: Span::new(0, 10), } } @@ -445,7 +445,7 @@ mod tests { assert_eq!(result.len(), 2); let age_field = result.iter().find(|f| f.name == "age").unwrap(); - assert_eq!(age_field.value, Value::Int(30)); + assert_eq!(age_field.value, Value::Number(30)); } #[test] @@ -526,7 +526,7 @@ mod tests { assert_eq!(result.len(), 3); let age = result.iter().find(|f| f.name == "age").unwrap(); - assert_eq!(age.value, Value::Int(30)); + assert_eq!(age.value, Value::Number(30)); assert!(!result.iter().any(|f| f.name == "energy")); assert!(result.iter().any(|f| f.name == "strength")); @@ -612,7 +612,7 @@ mod tests { assert_eq!(result.len(), 1); assert_eq!(result[0].name, "age"); - assert_eq!(result[0].value, Value::Int(25)); + assert_eq!(result[0].value, Value::Number(25)); } #[test] @@ -682,8 +682,8 @@ mod tests { assert_eq!(result.len(), 1); assert_eq!(result[0].name, "age"); - assert_eq!(result[0].value, Value::Int(25)); // Should be overridden - // value + assert_eq!(result[0].value, Value::Number(25)); // Should be overridden + // value } #[test] @@ -702,8 +702,8 @@ mod tests { assert_eq!(result.len(), 1); assert_eq!(result[0].name, "age"); - assert_eq!(result[0].value, Value::Int(34)); // Character's value - // overrides template + assert_eq!(result[0].value, Value::Number(34)); // Character's value + // overrides template } #[test] @@ -729,10 +729,10 @@ mod tests { assert_eq!(result.len(), 2); assert!(result .iter() - .any(|f| f.name == "height" && f.value == Value::Int(165))); + .any(|f| f.name == "height" && f.value == Value::Number(165))); assert!(result .iter() - .any(|f| f.name == "iq" && f.value == Value::Int(120))); + .any(|f| f.name == "iq" && f.value == Value::Number(120))); } #[test] @@ -758,10 +758,10 @@ mod tests { assert_eq!(result.len(), 2); assert!(result .iter() - .any(|f| f.name == "age" && f.value == Value::Int(34))); + .any(|f| f.name == "age" && f.value == Value::Number(34))); assert!(result .iter() - .any(|f| f.name == "name" && f.value == Value::Int(1))); + .any(|f| f.name == "name" && f.value == Value::Number(1))); } #[test] @@ -786,7 +786,7 @@ mod tests { "Person", vec![Field { name: "age".to_string(), - value: Value::Range(Box::new(Value::Int(18)), Box::new(Value::Int(65))), + value: Value::Range(Box::new(Value::Number(18)), Box::new(Value::Number(65))), span: Span::new(0, 10), }], vec![], @@ -837,7 +837,7 @@ mod tests { assert_eq!(result.len(), 2); let age = result.iter().find(|f| f.name == "age").unwrap(); - assert_eq!(age.value, Value::Int(30)); + assert_eq!(age.value, Value::Number(30)); } #[test] diff --git a/src/resolve/merge_prop_tests.rs b/src/resolve/merge_prop_tests.rs index e279470..a1817ef 100644 --- a/src/resolve/merge_prop_tests.rs +++ b/src/resolve/merge_prop_tests.rs @@ -19,7 +19,7 @@ fn valid_ident() -> impl Strategy { fn valid_field() -> impl Strategy { (valid_ident(), 0i64..1000).prop_map(|(name, value)| Field { name, - value: Value::Int(value), + value: Value::Number(value), span: Span::new(0, 10), }) } @@ -186,12 +186,12 @@ proptest! { ) { let field1 = Field { name: name.clone(), - value: Value::Int(val1), + value: Value::Number(val1), span: Span::new(0, 10), }; let field2 = Field { name: name.clone(), - value: Value::Int(val2), + value: Value::Number(val2), span: Span::new(0, 10), }; @@ -251,12 +251,12 @@ proptest! { ) { let field1 = Field { name: name.clone(), - value: Value::Int(val1), + value: Value::Number(val1), span: Span::new(0, 10), }; let field2 = Field { name: name.clone(), - value: Value::Int(val2), + value: Value::Number(val2), span: Span::new(0, 10), }; @@ -277,8 +277,8 @@ proptest! { let value1 = result1.iter().find(|f| f.name == name).unwrap().value.clone(); let value2 = result2.iter().find(|f| f.name == name).unwrap().value.clone(); - assert_eq!(value1, Value::Int(val2)); - assert_eq!(value2, Value::Int(val1)); + assert_eq!(value1, Value::Number(val2)); + assert_eq!(value2, Value::Number(val1)); } #[test] diff --git a/src/resolve/validate.rs b/src/resolve/validate.rs index 9951a1e..8e88e8b 100644 --- a/src/resolve/validate.rs +++ b/src/resolve/validate.rs @@ -83,7 +83,7 @@ pub fn validate_no_reserved_keywords(fields: &[Field], collector: &mut ErrorColl pub fn validate_trait_ranges(fields: &[Field], collector: &mut ErrorCollector) { for field in fields { match &field.value { - | Value::Float(f) => { + | Value::Decimal(f) => { // Normalized trait values should be 0.0 .. 1.0 if (field.name.ends_with("_normalized") || field.name == "bond" || @@ -99,7 +99,7 @@ pub fn validate_trait_ranges(fields: &[Field], collector: &mut ErrorCollector) { }); } }, - | Value::Int(i) => { + | Value::Number(i) => { // Age should be reasonable if field.name == "age" && (*i < 0 || *i > 150) { collector.add(ResolveError::TraitOutOfRange { @@ -120,7 +120,7 @@ pub fn validate_relationship_bonds(relationships: &[Relationship], collector: &m for rel in relationships { for field in &rel.fields { if field.name == "bond" { - if let Value::Float(f) = field.value { + if let Value::Decimal(f) = field.value { if !(0.0..=1.0).contains(&f) { collector.add(ResolveError::TraitOutOfRange { field: "bond".to_string(), @@ -457,12 +457,12 @@ mod tests { let fields = vec![ Field { name: "bond".to_string(), - value: Value::Float(0.8), + value: Value::Decimal(0.8), span: Span::new(0, 10), }, Field { name: "age".to_string(), - value: Value::Int(30), + value: Value::Number(30), span: Span::new(0, 10), }, ]; @@ -476,7 +476,7 @@ mod tests { fn test_invalid_bond_value_too_high() { let fields = vec![Field { name: "bond".to_string(), - value: Value::Float(1.5), + value: Value::Decimal(1.5), span: Span::new(0, 10), }]; @@ -489,7 +489,7 @@ mod tests { fn test_invalid_bond_value_negative() { let fields = vec![Field { name: "bond".to_string(), - value: Value::Float(-0.1), + value: Value::Decimal(-0.1), span: Span::new(0, 10), }]; @@ -502,7 +502,7 @@ mod tests { fn test_invalid_age_negative() { let fields = vec![Field { name: "age".to_string(), - value: Value::Int(-5), + value: Value::Number(-5), span: Span::new(0, 10), }]; @@ -515,7 +515,7 @@ mod tests { fn test_invalid_age_too_high() { let fields = vec![Field { name: "age".to_string(), - value: Value::Int(200), + value: Value::Number(200), span: Span::new(0, 10), }]; @@ -531,7 +531,7 @@ mod tests { participants: vec![], fields: vec![Field { name: "bond".to_string(), - value: Value::Float(0.9), + value: Value::Decimal(0.9), span: Span::new(0, 10), }], span: Span::new(0, 100), @@ -549,7 +549,7 @@ mod tests { participants: vec![], fields: vec![Field { name: "bond".to_string(), - value: Value::Float(1.2), + value: Value::Decimal(1.2), span: Span::new(0, 10), }], span: Span::new(0, 100), diff --git a/src/resolve/validate_prop_tests.rs b/src/resolve/validate_prop_tests.rs index 15a20ad..3a4f4f9 100644 --- a/src/resolve/validate_prop_tests.rs +++ b/src/resolve/validate_prop_tests.rs @@ -17,7 +17,7 @@ use crate::{ fn valid_bond_field() -> impl Strategy { (0.0..=1.0).prop_map(|f| Field { name: "bond".to_string(), - value: Value::Float(f), + value: Value::Decimal(f), span: Span::new(0, 10), }) } @@ -26,12 +26,12 @@ fn invalid_bond_field() -> impl Strategy { prop_oneof![ (-100.0..0.0).prop_map(|f| Field { name: "bond".to_string(), - value: Value::Float(f), + value: Value::Decimal(f), span: Span::new(0, 10), }), (1.0..100.0).prop_map(|f| Field { name: "bond".to_string(), - value: Value::Float(f), + value: Value::Decimal(f), span: Span::new(0, 10), }), ] @@ -40,7 +40,7 @@ fn invalid_bond_field() -> impl Strategy { fn valid_age_field() -> impl Strategy { (0i64..=150).prop_map(|age| Field { name: "age".to_string(), - value: Value::Int(age), + value: Value::Number(age), span: Span::new(0, 10), }) } @@ -49,12 +49,12 @@ fn invalid_age_field() -> impl Strategy { prop_oneof![ (-100i64..-1).prop_map(|age| Field { name: "age".to_string(), - value: Value::Int(age), + value: Value::Number(age), span: Span::new(0, 10), }), (151i64..300).prop_map(|age| Field { name: "age".to_string(), - value: Value::Int(age), + value: Value::Number(age), span: Span::new(0, 10), }), ] @@ -99,7 +99,7 @@ proptest! { fn test_bond_exact_bounds(f in 0.0f64..=1.0) { let field = Field { name: "bond".to_string(), - value: Value::Float(f), + value: Value::Decimal(f), span: Span::new(0, 10), }; let mut collector = ErrorCollector::new(); @@ -116,7 +116,7 @@ proptest! { participants: vec![], fields: vec![Field { name: "bond".to_string(), - value: Value::Float(bond_value), + value: Value::Decimal(bond_value), span: Span::new(0, 10), }], span: Span::new(0, 100), @@ -136,7 +136,7 @@ proptest! { participants: vec![], fields: vec![Field { name: "bond".to_string(), - value: Value::Float(bond_value), + value: Value::Decimal(bond_value), span: Span::new(0, 10), }], span: Span::new(0, 100), @@ -164,7 +164,7 @@ proptest! { on_enter: None, transitions: vec![Transition { to: state2_name.clone(), - condition: Expr::BoolLit(true), + condition: Expr::BooleanLit(true), span: Span::new(0, 10), }], span: Span::new(0, 50), diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 137451a..c450bc3 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -158,10 +158,10 @@ pub struct Field { /// Field value types #[derive(Debug, Clone, PartialEq)] pub enum Value { - Int(i64), - Float(f64), - String(String), - Bool(bool), + Number(i64), + Decimal(f64), + Text(String), + Boolean(bool), Range(Box, Box), // For templates: 20..40 Time(Time), Duration(Duration), @@ -466,10 +466,10 @@ pub enum Condition { /// Expression AST for conditions and queries #[derive(Debug, Clone, PartialEq)] pub enum Expr { - IntLit(i64), - FloatLit(f64), - StringLit(String), - BoolLit(bool), + NumberLit(i64), + DecimalLit(f64), + TextLit(String), + BooleanLit(bool), Identifier(Vec), FieldAccess(Box, String), Comparison(Box, CompOp, Box), diff --git a/src/syntax/parser.lalrpop b/src/syntax/parser.lalrpop index 222ba94..f752e27 100644 --- a/src/syntax/parser.lalrpop +++ b/src/syntax/parser.lalrpop @@ -244,18 +244,18 @@ Field: Field = { }; Value: Value = { - => Value::Int(<>), - => Value::Float(<>), - => Value::String(<>), - => Value::Bool(<>), + => Value::Number(<>), + => Value::Decimal(<>), + => Value::Text(<>), + => Value::Boolean(<>), "any" => Value::Any, ".." => Value::Range( - Box::new(Value::Int(lo)), - Box::new(Value::Int(hi)) + Box::new(Value::Number(lo)), + Box::new(Value::Number(hi)) ), ".." => Value::Range( - Box::new(Value::Float(lo)), - Box::new(Value::Float(hi)) + Box::new(Value::Decimal(lo)), + Box::new(Value::Decimal(hi)) ), => Value::Time(t), => Value::Duration(d), @@ -949,10 +949,10 @@ InequalityOp: CompOp = { }; Literal: Expr = { - => Expr::IntLit(<>), - => Expr::FloatLit(<>), - => Expr::StringLit(<>), - => Expr::BoolLit(<>), + => Expr::NumberLit(<>), + => Expr::DecimalLit(<>), + => Expr::TextLit(<>), + => Expr::BooleanLit(<>), }; // ===== Helpers ===== diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index dfe6ac3..c61b93e 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -1,5 +1,5 @@ // auto-generated: "lalrpop 0.21.0" -// sha3: 74aa329f2c008adb120b171834cf36dcc8e33b949ab1a2fe8bd5e54d42b398af +// sha3: 18bbe1925e11ceeec53b1eb8484775a415600ddf99220fba53d408b46198a3aa use crate::syntax::{ ast::*, lexer::Token, @@ -13528,7 +13528,7 @@ fn __action46((_, pb, _): (usize, ProseBlock, usize)) -> Field { clippy::just_underscores_and_digits )] fn __action47((_, __0, _): (usize, i64, usize)) -> Value { - Value::Int(__0) + Value::Number(__0) } #[allow( @@ -13537,7 +13537,7 @@ fn __action47((_, __0, _): (usize, i64, usize)) -> Value { clippy::just_underscores_and_digits )] fn __action48((_, __0, _): (usize, f64, usize)) -> Value { - Value::Float(__0) + Value::Decimal(__0) } #[allow( @@ -13546,7 +13546,7 @@ fn __action48((_, __0, _): (usize, f64, usize)) -> Value { clippy::just_underscores_and_digits )] fn __action49((_, __0, _): (usize, String, usize)) -> Value { - Value::String(__0) + Value::Text(__0) } #[allow( @@ -13555,7 +13555,7 @@ fn __action49((_, __0, _): (usize, String, usize)) -> Value { clippy::just_underscores_and_digits )] fn __action50((_, __0, _): (usize, bool, usize)) -> Value { - Value::Bool(__0) + Value::Boolean(__0) } #[allow( @@ -13577,7 +13577,7 @@ fn __action52( (_, _, _): (usize, Token, usize), (_, hi, _): (usize, i64, usize), ) -> Value { - Value::Range(Box::new(Value::Int(lo)), Box::new(Value::Int(hi))) + Value::Range(Box::new(Value::Number(lo)), Box::new(Value::Number(hi))) } #[allow( @@ -13590,7 +13590,7 @@ fn __action53( (_, _, _): (usize, Token, usize), (_, hi, _): (usize, f64, usize), ) -> Value { - Value::Range(Box::new(Value::Float(lo)), Box::new(Value::Float(hi))) + Value::Range(Box::new(Value::Decimal(lo)), Box::new(Value::Decimal(hi))) } #[allow( @@ -15225,7 +15225,7 @@ fn __action161((_, __0, _): (usize, Token, usize)) -> CompOp { clippy::just_underscores_and_digits )] fn __action162((_, __0, _): (usize, i64, usize)) -> Expr { - Expr::IntLit(__0) + Expr::NumberLit(__0) } #[allow( @@ -15234,7 +15234,7 @@ fn __action162((_, __0, _): (usize, i64, usize)) -> Expr { clippy::just_underscores_and_digits )] fn __action163((_, __0, _): (usize, f64, usize)) -> Expr { - Expr::FloatLit(__0) + Expr::DecimalLit(__0) } #[allow( @@ -15243,7 +15243,7 @@ fn __action163((_, __0, _): (usize, f64, usize)) -> Expr { clippy::just_underscores_and_digits )] fn __action164((_, __0, _): (usize, String, usize)) -> Expr { - Expr::StringLit(__0) + Expr::TextLit(__0) } #[allow( @@ -15252,7 +15252,7 @@ fn __action164((_, __0, _): (usize, String, usize)) -> Expr { clippy::just_underscores_and_digits )] fn __action165((_, __0, _): (usize, bool, usize)) -> Expr { - Expr::BoolLit(__0) + Expr::BooleanLit(__0) } #[allow( diff --git a/storybook-editor/src/ui/main_editor.rs b/storybook-editor/src/ui/main_editor.rs index d7dfd20..c865519 100644 --- a/storybook-editor/src/ui/main_editor.rs +++ b/storybook-editor/src/ui/main_editor.rs @@ -73,10 +73,10 @@ fn character_editor_view<'a>(editor: &'a Editor, char_name: &str) -> Element<'a, // Show all fields with soft metadata styling for (field_name, field_value) in &char.fields { let value_text = match field_value { - | Value::Int(n) => format!("{}", n), - | Value::Float(n) => format!("{}", n), - | Value::String(s) => s.clone(), - | Value::Bool(b) => format!("{}", b), + | Value::Number(n) => format!("{}", n), + | Value::Decimal(n) => format!("{}", n), + | Value::Text(s) => s.clone(), + | Value::Boolean(b) => format!("{}", b), | Value::List(items) => { format!("[{} items]", items.len()) }, diff --git a/tests/validate_examples.rs b/tests/validate_examples.rs index 7a09cdd..50ee418 100644 --- a/tests/validate_examples.rs +++ b/tests/validate_examples.rs @@ -106,15 +106,15 @@ fn test_baker_family_field_values() { let martha = project.find_character("Martha").unwrap(); // Martha sets age: 34 (overriding Person template range 0..100) - if let Some(storybook::syntax::ast::Value::Int(age)) = martha.fields.get("age") { + if let Some(storybook::syntax::ast::Value::Number(age)) = martha.fields.get("age") { assert_eq!(*age, 34, "Martha's age should be 34"); } else { - panic!("age should be an Int"); + panic!("age should be a Number"); } // Martha sets specialty: "sourdough" (overriding Baker template default // "bread") - if let Some(storybook::syntax::ast::Value::String(specialty)) = martha.fields.get("specialty") { + if let Some(storybook::syntax::ast::Value::Text(specialty)) = martha.fields.get("specialty") { assert_eq!( specialty, "sourdough", "Martha's specialty should be sourdough"