diff --git a/cgaal-engine/src/algorithms/certain_zero/search_strategy/linear_constraints.rs b/cgaal-engine/src/algorithms/certain_zero/search_strategy/linear_constraints.rs index aa4f2e2f..21efbd5d 100644 --- a/cgaal-engine/src/algorithms/certain_zero/search_strategy/linear_constraints.rs +++ b/cgaal-engine/src/algorithms/certain_zero/search_strategy/linear_constraints.rs @@ -1,7 +1,7 @@ -use std::collections::HashMap; -use std::fmt::{Display, Formatter}; use crate::game_structure::lcgs::symbol_table::SymbIdx; use crate::parsing::ast::{BinaryOpKind, Expr, ExprKind, UnaryOpKind}; +use std::collections::HashMap; +use std::fmt::{Display, Formatter}; /// All comparison operators #[derive(Hash, Eq, PartialEq, Copy, Clone, Debug)] @@ -209,6 +209,8 @@ mod test { }; use crate::game_structure::lcgs::intermediate::IntermediateLcgs; use crate::parsing::ast::DeclKind; + use crate::parsing::errors::ErrorLog; + use crate::parsing::parse_lcgs; #[test] fn simple_comparison_01() { @@ -217,13 +219,16 @@ mod test { x' = 0; label prop = x < 4; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Less, lin_expr.comparison); assert_eq!(-4.0, lin_expr.constant); - assert_eq!(Some(&1.0), lin_expr.terms.get(&":global.x".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + assert_eq!(Some(&1.0), lin_expr.terms.get(&x_idx)); } } @@ -234,13 +239,16 @@ mod test { x' = 0; label prop = 2 * x > 3; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Greater, lin_expr.comparison); assert_eq!(-3.0, lin_expr.constant); - assert_eq!(Some(&2.0), lin_expr.terms.get(&":global.x".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + assert_eq!(Some(&2.0), lin_expr.terms.get(&x_idx)); } } @@ -251,13 +259,16 @@ mod test { x' = 0; label prop = 0 > x * 2; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Greater, lin_expr.comparison); assert_eq!(0.0, lin_expr.constant); - assert_eq!(Some(&-2.0), lin_expr.terms.get(&":global.x".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + assert_eq!(Some(&-2.0), lin_expr.terms.get(&x_idx)); } } @@ -268,13 +279,16 @@ mod test { x' = 0; label prop = 0 == 5 * x; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(0.0, lin_expr.constant); - assert_eq!(Some(&-5.0), lin_expr.terms.get(&":global.x".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + assert_eq!(Some(&-5.0), lin_expr.terms.get(&x_idx)); } } @@ -289,14 +303,18 @@ mod test { z' = 0; label prop = 2 * x + 3 * y == -5; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(5.0, lin_expr.constant); - assert_eq!(Some(&2.0), lin_expr.terms.get(&":global.x".into())); - assert_eq!(Some(&3.0), lin_expr.terms.get(&":global.y".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + let y_idx = lcgs.get_decl_by_name("y").unwrap().index; + assert_eq!(Some(&2.0), lin_expr.terms.get(&x_idx)); + assert_eq!(Some(&3.0), lin_expr.terms.get(&y_idx)); } } @@ -311,14 +329,18 @@ mod test { z' = 0; label prop = 2 * x - 3 * y == 0; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(0.0, lin_expr.constant); - assert_eq!(Some(&2.0), lin_expr.terms.get(&":global.x".into())); - assert_eq!(Some(&-3.0), lin_expr.terms.get(&":global.y".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + let y_idx = lcgs.get_decl_by_name("y").unwrap().index; + assert_eq!(Some(&2.0), lin_expr.terms.get(&x_idx)); + assert_eq!(Some(&-3.0), lin_expr.terms.get(&y_idx)); } } @@ -333,15 +355,20 @@ mod test { z' = 0; label prop = 2 - x + y - z == 0; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(2.0, lin_expr.constant); - assert_eq!(Some(&-1.0), lin_expr.terms.get(&":global.x".into())); - assert_eq!(Some(&1.0), lin_expr.terms.get(&":global.y".into())); - assert_eq!(Some(&-1.0), lin_expr.terms.get(&":global.z".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + let y_idx = lcgs.get_decl_by_name("y").unwrap().index; + let z_idx = lcgs.get_decl_by_name("z").unwrap().index; + assert_eq!(Some(&-1.0), lin_expr.terms.get(&x_idx)); + assert_eq!(Some(&1.0), lin_expr.terms.get(&y_idx)); + assert_eq!(Some(&-1.0), lin_expr.terms.get(&z_idx)); } } @@ -356,15 +383,20 @@ mod test { z' = 0; label prop = 4 <= 1 * x + 2 * y - 3 * z; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::LessOrEq, lin_expr.comparison); assert_eq!(4.0, lin_expr.constant); - assert_eq!(Some(&-1.0), lin_expr.terms.get(&":global.x".into())); - assert_eq!(Some(&-2.0), lin_expr.terms.get(&":global.y".into())); - assert_eq!(Some(&3.0), lin_expr.terms.get(&":global.z".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + let y_idx = lcgs.get_decl_by_name("y").unwrap().index; + let z_idx = lcgs.get_decl_by_name("z").unwrap().index; + assert_eq!(Some(&-1.0), lin_expr.terms.get(&x_idx)); + assert_eq!(Some(&-2.0), lin_expr.terms.get(&y_idx)); + assert_eq!(Some(&3.0), lin_expr.terms.get(&z_idx)); } } @@ -375,13 +407,16 @@ mod test { x' = 0; label prop = 2 * x + x == 0; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(0.0, lin_expr.constant); - assert_eq!(Some(&3.0), lin_expr.terms.get(&":global.x".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + assert_eq!(Some(&3.0), lin_expr.terms.get(&x_idx)); } } @@ -392,13 +427,16 @@ mod test { x' = 0; label prop = 1 + 2 * x - 3 == 5; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(-7.0, lin_expr.constant); - assert_eq!(Some(&2.0), lin_expr.terms.get(&":global.x".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + assert_eq!(Some(&2.0), lin_expr.terms.get(&x_idx)); } } @@ -411,14 +449,18 @@ mod test { y' = 0; label prop = 2 * x == y; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(0.0, lin_expr.constant); - assert_eq!(Some(&2.0), lin_expr.terms.get(&":global.x".into())); - assert_eq!(Some(&-1.0), lin_expr.terms.get(&":global.y".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + let y_idx = lcgs.get_decl_by_name("y").unwrap().index; + assert_eq!(Some(&2.0), lin_expr.terms.get(&x_idx)); + assert_eq!(Some(&-1.0), lin_expr.terms.get(&y_idx)); } } @@ -433,15 +475,20 @@ mod test { z' = 0; label prop = x == (y - z) + 5; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(-5.0, lin_expr.constant); - assert_eq!(Some(&1.0), lin_expr.terms.get(&":global.x".into())); - assert_eq!(Some(&-1.0), lin_expr.terms.get(&":global.y".into())); - assert_eq!(Some(&1.0), lin_expr.terms.get(&":global.z".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + let y_idx = lcgs.get_decl_by_name("y").unwrap().index; + let z_idx = lcgs.get_decl_by_name("z").unwrap().index; + assert_eq!(Some(&1.0), lin_expr.terms.get(&x_idx)); + assert_eq!(Some(&-1.0), lin_expr.terms.get(&y_idx)); + assert_eq!(Some(&1.0), lin_expr.terms.get(&z_idx)); } } @@ -456,15 +503,20 @@ mod test { z' = 0; label prop = x + x - y - x == -3 * z; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(0.0, lin_expr.constant); - assert_eq!(Some(&1.0), lin_expr.terms.get(&":global.x".into())); - assert_eq!(Some(&-1.0), lin_expr.terms.get(&":global.y".into())); - assert_eq!(Some(&3.0), lin_expr.terms.get(&":global.z".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + let y_idx = lcgs.get_decl_by_name("y").unwrap().index; + let z_idx = lcgs.get_decl_by_name("z").unwrap().index; + assert_eq!(Some(&1.0), lin_expr.terms.get(&x_idx)); + assert_eq!(Some(&-1.0), lin_expr.terms.get(&y_idx)); + assert_eq!(Some(&3.0), lin_expr.terms.get(&z_idx)); } } @@ -477,14 +529,18 @@ mod test { y' = 0; label prop = 2 * x == (-2 * y); "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(0.0, lin_expr.constant); - assert_eq!(Some(&2.0), lin_expr.terms.get(&":global.x".into())); - assert_eq!(Some(&2.0), lin_expr.terms.get(&":global.y".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + let y_idx = lcgs.get_decl_by_name("y").unwrap().index; + assert_eq!(Some(&2.0), lin_expr.terms.get(&x_idx)); + assert_eq!(Some(&2.0), lin_expr.terms.get(&y_idx)); } } @@ -495,13 +551,16 @@ mod test { x' = 0; label prop = x + 2 * x + 3 * x + 4 * x == 0; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond).unwrap(); assert_eq!(ComparisonOp::Equal, lin_expr.comparison); assert_eq!(0.0, lin_expr.constant); - assert_eq!(Some(&10.0), lin_expr.terms.get(&":global.x".into())); + let x_idx = lcgs.get_decl_by_name("x").unwrap().index; + assert_eq!(Some(&10.0), lin_expr.terms.get(&x_idx)); } } @@ -512,10 +571,12 @@ mod test { x' = 0; label prop = x * x == 0; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond); assert!(lin_expr.is_none()); } } @@ -529,10 +590,12 @@ mod test { y' = 0; label prop = x * 2 * y == 0; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond); assert!(lin_expr.is_none()); } } @@ -544,10 +607,12 @@ mod test { x' = 0; label prop = 0 < x < 10; // not what you think anyway "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond); assert!(lin_expr.is_none()); } } @@ -559,10 +624,12 @@ mod test { x' = 0; label prop = 100 / x < 10; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond); assert!(lin_expr.is_none()); } } @@ -576,10 +643,12 @@ mod test { y' = 0; label prop = 2 * x + 4 * y < x + min(x, y); "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let decl = lcgs.get_decl(&Owner::Global.symbol_id("prop")).unwrap(); - if let DeclKind::Label(label) = &decl.kind { - let lin_expr = LinearConstraintExtractor::extract(&label.condition); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let decl = lcgs.get_decl_by_name("prop").unwrap(); + if let DeclKind::StateLabel(_, cond) = &decl.kind { + let lin_expr = LinearConstraintExtractor::extract(&cond); assert!(lin_expr.is_none()); } } diff --git a/cgaal-engine/src/edg/atledg/pmoves.rs b/cgaal-engine/src/edg/atledg/pmoves.rs index eec85451..c252310c 100644 --- a/cgaal-engine/src/edg/atledg/pmoves.rs +++ b/cgaal-engine/src/edg/atledg/pmoves.rs @@ -220,7 +220,8 @@ impl Iterator for PmovesIterator { self.position.0[roll_over_pos] = PartialMoveChoice::Specific(ActionIdx(0)); roll_over_pos += 1; } else { - self.position.0[roll_over_pos] = PartialMoveChoice::Specific(ActionIdx(new_value)); + self.position.0[roll_over_pos] = + PartialMoveChoice::Specific(ActionIdx(new_value)); break; } } @@ -289,7 +290,7 @@ mod test { use crate::edg::atledg::pmoves::{ DeltaIterator, PartialMove, PartialMoveChoice, PartialMoveIterator, PmovesIterator, }; - use crate::game_structure::{ActionIdx, DynVec, EagerGameStructure}; + use crate::game_structure::{ActionIdx, DynVec, EagerGameStructure, PlayerIdx, StateIdx}; #[test] fn partial_move_iterator_01() { @@ -300,10 +301,22 @@ mod test { ]); let mut iter = PartialMoveIterator::new(&partial_move); - assert_eq!(iter.next(), Some(vec![0, 1, 0])); - assert_eq!(iter.next(), Some(vec![0, 1, 1])); - assert_eq!(iter.next(), Some(vec![1, 1, 0])); - assert_eq!(iter.next(), Some(vec![1, 1, 1])); + assert_eq!( + iter.next(), + Some(vec![ActionIdx(0), ActionIdx(1), ActionIdx(0)]) + ); + assert_eq!( + iter.next(), + Some(vec![ActionIdx(0), ActionIdx(1), ActionIdx(1)]) + ); + assert_eq!( + iter.next(), + Some(vec![ActionIdx(1), ActionIdx(1), ActionIdx(0)]) + ); + assert_eq!( + iter.next(), + Some(vec![ActionIdx(1), ActionIdx(1), ActionIdx(1)]) + ); assert_eq!(iter.next(), None); } @@ -311,40 +324,40 @@ mod test { fn vars_iterator_01() { let moves = vec![2, 3, 2]; let mut players = HashSet::new(); - players.insert(0); - players.insert(2); + players.insert(PlayerIdx(0)); + players.insert(PlayerIdx(2)); let mut iter = PmovesIterator::new(moves, players); assert_eq!( &iter.next(), &Some(PartialMove(vec![ - PartialMoveChoice::Specific(0), + PartialMoveChoice::Specific(ActionIdx(0)), PartialMoveChoice::Range(3), - PartialMoveChoice::Specific(0) + PartialMoveChoice::Specific(ActionIdx(0)), ])) ); assert_eq!( &iter.next(), &Some(PartialMove(vec![ - PartialMoveChoice::Specific(1), + PartialMoveChoice::Specific(ActionIdx(1)), PartialMoveChoice::Range(3), - PartialMoveChoice::Specific(0) + PartialMoveChoice::Specific(ActionIdx(0)), ])) ); assert_eq!( &iter.next(), &Some(PartialMove(vec![ - PartialMoveChoice::Specific(0), + PartialMoveChoice::Specific(ActionIdx(0)), PartialMoveChoice::Range(3), - PartialMoveChoice::Specific(1) + PartialMoveChoice::Specific(ActionIdx(1)), ])) ); assert_eq!( &iter.next(), &Some(PartialMove(vec![ - PartialMoveChoice::Specific(1), + PartialMoveChoice::Specific(ActionIdx(1)), PartialMoveChoice::Range(3), - PartialMoveChoice::Specific(1) + PartialMoveChoice::Specific(ActionIdx(1)), ])) ); } @@ -352,23 +365,32 @@ mod test { #[test] fn vars_iterator_02() { let mut players = HashSet::new(); - players.insert(2); + players.insert(PlayerIdx(2)); let mut iter = PmovesIterator::new(vec![2, 3, 3], players); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Range(2)); - assert_eq!(value[1], PartialMoveChoice::Range(3)); - assert_eq!(value[2], PartialMoveChoice::Specific(0)); + assert_eq!(value[PlayerIdx(0)], PartialMoveChoice::Range(2)); + assert_eq!(value[PlayerIdx(1)], PartialMoveChoice::Range(3)); + assert_eq!( + value[PlayerIdx(2)], + PartialMoveChoice::Specific(ActionIdx(0)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Range(2)); - assert_eq!(value[1], PartialMoveChoice::Range(3)); - assert_eq!(value[2], PartialMoveChoice::Specific(1)); + assert_eq!(value[PlayerIdx(0)], PartialMoveChoice::Range(2)); + assert_eq!(value[PlayerIdx(1)], PartialMoveChoice::Range(3)); + assert_eq!( + value[PlayerIdx(2)], + PartialMoveChoice::Specific(ActionIdx(1)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Range(2)); - assert_eq!(value[1], PartialMoveChoice::Range(3)); - assert_eq!(value[2], PartialMoveChoice::Specific(2)); + assert_eq!(value[PlayerIdx(0)], PartialMoveChoice::Range(2)); + assert_eq!(value[PlayerIdx(1)], PartialMoveChoice::Range(3)); + assert_eq!( + value[PlayerIdx(2)], + PartialMoveChoice::Specific(ActionIdx(2)) + ); let value = iter.next(); assert_eq!(value, None); @@ -378,45 +400,99 @@ mod test { fn vars_iterator_03() { // Both players choose. So we should end up with every move vector let mut players = HashSet::new(); - players.insert(0); - players.insert(1); + players.insert(PlayerIdx(0)); + players.insert(PlayerIdx(1)); let mut iter = PmovesIterator::new(vec![3, 3], players); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Specific(0)); - assert_eq!(value[1], PartialMoveChoice::Specific(0)); + assert_eq!( + value[PlayerIdx(0)], + PartialMoveChoice::Specific(ActionIdx(0)) + ); + assert_eq!( + value[PlayerIdx(1)], + PartialMoveChoice::Specific(ActionIdx(0)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Specific(1)); - assert_eq!(value[1], PartialMoveChoice::Specific(0)); + assert_eq!( + value[PlayerIdx(0)], + PartialMoveChoice::Specific(ActionIdx(1)) + ); + assert_eq!( + value[PlayerIdx(1)], + PartialMoveChoice::Specific(ActionIdx(0)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Specific(2)); - assert_eq!(value[1], PartialMoveChoice::Specific(0)); + assert_eq!( + value[PlayerIdx(0)], + PartialMoveChoice::Specific(ActionIdx(2)) + ); + assert_eq!( + value[PlayerIdx(1)], + PartialMoveChoice::Specific(ActionIdx(0)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Specific(0)); - assert_eq!(value[1], PartialMoveChoice::Specific(1)); + assert_eq!( + value[PlayerIdx(0)], + PartialMoveChoice::Specific(ActionIdx(0)) + ); + assert_eq!( + value[PlayerIdx(1)], + PartialMoveChoice::Specific(ActionIdx(1)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Specific(1)); - assert_eq!(value[1], PartialMoveChoice::Specific(1)); + assert_eq!( + value[PlayerIdx(0)], + PartialMoveChoice::Specific(ActionIdx(1)) + ); + assert_eq!( + value[PlayerIdx(1)], + PartialMoveChoice::Specific(ActionIdx(1)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Specific(2)); - assert_eq!(value[1], PartialMoveChoice::Specific(1)); + assert_eq!( + value[PlayerIdx(0)], + PartialMoveChoice::Specific(ActionIdx(2)) + ); + assert_eq!( + value[PlayerIdx(1)], + PartialMoveChoice::Specific(ActionIdx(1)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Specific(0)); - assert_eq!(value[1], PartialMoveChoice::Specific(2)); + assert_eq!( + value[PlayerIdx(0)], + PartialMoveChoice::Specific(ActionIdx(0)) + ); + assert_eq!( + value[PlayerIdx(1)], + PartialMoveChoice::Specific(ActionIdx(2)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Specific(1)); - assert_eq!(value[1], PartialMoveChoice::Specific(2)); + assert_eq!( + value[PlayerIdx(0)], + PartialMoveChoice::Specific(ActionIdx(1)) + ); + assert_eq!( + value[PlayerIdx(1)], + PartialMoveChoice::Specific(ActionIdx(2)) + ); let value = iter.next().unwrap(); - assert_eq!(value[0], PartialMoveChoice::Specific(2)); - assert_eq!(value[1], PartialMoveChoice::Specific(2)); + assert_eq!( + value[PlayerIdx(0)], + PartialMoveChoice::Specific(ActionIdx(2)) + ); + assert_eq!( + value[PlayerIdx(1)], + PartialMoveChoice::Specific(ActionIdx(2)) + ); assert_eq!(iter.next(), None); } @@ -432,11 +508,11 @@ mod test { // player 3 Arc::new(DynVec::Nest(vec![ // Player 4 - Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(1))])), + Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(StateIdx(1)))])), // Player 4 - Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(2))])), + Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(StateIdx(2)))])), // Player 4 - Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(3))])), + Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(StateIdx(3)))])), ])), ])), // Player 2 @@ -444,94 +520,93 @@ mod test { // player 3 Arc::new(DynVec::Nest(vec![ // Player 4 - Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(4))])), + Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(StateIdx(4)))])), // Player 4 - Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(5))])), + Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(StateIdx(5)))])), // Player 4 - Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(1))])), + Arc::new(DynVec::Nest(vec![Arc::new(DynVec::Base(StateIdx(1)))])), ])), ])), ])), ]); - let game_structure = EagerGameStructure { - initial_state: 0, + let game = EagerGameStructure { + initial_state: StateIdx(0), player_count: 5, labeling: vec![], transitions: vec![transitions], moves: vec![], }; - let init_state = 0; let partial_move = PartialMove(vec![ - PartialMoveChoice::Specific(0), // player 0 - PartialMoveChoice::Range(2), // player 1 - PartialMoveChoice::Specific(0), // player 2 - PartialMoveChoice::Range(3), // player 3 - PartialMoveChoice::Specific(0), // player 4 + PartialMoveChoice::Specific(ActionIdx(0)), // player 0 + PartialMoveChoice::Range(2), // player 1 + PartialMoveChoice::Specific(ActionIdx(0)), // player 2 + PartialMoveChoice::Range(3), // player 3 + PartialMoveChoice::Specific(ActionIdx(0)), // player 4 ]); - let mut iter = DeltaIterator::new(&game_structure, init_state, &partial_move); + let mut iter = DeltaIterator::new(&game, game.initial_state, &partial_move); let (state, pmove) = iter.next().unwrap(); - assert_eq!(state, 1); + assert_eq!(state, StateIdx(1)); assert_eq!( pmove, PartialMove(vec![ - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), ]) ); let (state, pmove) = iter.next().unwrap(); - assert_eq!(state, 2); + assert_eq!(state, StateIdx(2)); assert_eq!( pmove, PartialMove(vec![ - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(1), - PartialMoveChoice::Specific(0), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(1)), + PartialMoveChoice::Specific(ActionIdx(0)), ]) ); let (state, pmove) = iter.next().unwrap(); - assert_eq!(state, 3); + assert_eq!(state, StateIdx(3)); assert_eq!( pmove, PartialMove(vec![ - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(2), - PartialMoveChoice::Specific(0), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(2)), + PartialMoveChoice::Specific(ActionIdx(0)), ]) ); let (state, pmove) = iter.next().unwrap(); - assert_eq!(state, 4); + assert_eq!(state, StateIdx(4)); assert_eq!( pmove, PartialMove(vec![ - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(1), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(0), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(1)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(0)), ]) ); let (state, pmove) = iter.next().unwrap(); - assert_eq!(state, 5); + assert_eq!(state, StateIdx(5)); assert_eq!( pmove, PartialMove(vec![ - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(1), - PartialMoveChoice::Specific(0), - PartialMoveChoice::Specific(1), - PartialMoveChoice::Specific(0), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(1)), + PartialMoveChoice::Specific(ActionIdx(0)), + PartialMoveChoice::Specific(ActionIdx(1)), + PartialMoveChoice::Specific(ActionIdx(0)), ]) ); diff --git a/cgaal-engine/src/game_structure/lcgs/intermediate.rs b/cgaal-engine/src/game_structure/lcgs/intermediate.rs index b5f57871..1e0e2e0d 100644 --- a/cgaal-engine/src/game_structure/lcgs/intermediate.rs +++ b/cgaal-engine/src/game_structure/lcgs/intermediate.rs @@ -297,12 +297,12 @@ impl GameStructure for IntermediateLcgs { mod test { use std::collections::HashMap; - use crate::game_structure::lcgs::ast::DeclKind; - use crate::game_structure::lcgs::ir::intermediate::{IntermediateLcgs, State}; - use crate::game_structure::lcgs::ir::symbol_table::Owner; - use crate::game_structure::lcgs::ir::symbol_table::SymbolIdentifier; - use crate::game_structure::lcgs::parse::parse_lcgs; - use crate::game_structure::GameStructure; + use crate::game_structure::lcgs::intermediate::{IntermediateLcgs, State}; + use crate::game_structure::lcgs::symbol_table::SymbIdx; + use crate::game_structure::{ActionIdx, GameStructure, PlayerIdx, PropIdx, StateIdx}; + use crate::parsing::ast::DeclKind; + use crate::parsing::errors::ErrorLog; + use crate::parsing::parse_lcgs; #[test] fn test_symbol_01() { @@ -322,20 +322,22 @@ mod test { [shoot] health > 0; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - assert_eq!(lcgs.symbols.len(), 12); - assert!(lcgs.symbols.get(&":global.max_health".into()).is_some()); - assert!(lcgs.symbols.get(&":global.alice".into()).is_some()); - assert!(lcgs.symbols.get(&":global.bob".into()).is_some()); - assert!(lcgs.symbols.get(&":global.gamer".into()).is_some()); - assert!(lcgs.symbols.get(&"alice.health".into()).is_some()); - assert!(lcgs.symbols.get(&"alice.alive".into()).is_some()); - assert!(lcgs.symbols.get(&"alice.wait".into()).is_some()); - assert!(lcgs.symbols.get(&"alice.shoot".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.health".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.alive".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.wait".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.shoot".into()).is_some()); + let errors = ErrorLog::new(); + let lcgs = IntermediateLcgs::create(parse_lcgs(input, &errors).unwrap(), &errors).unwrap(); + assert!(errors.is_empty()); + assert_eq!(lcgs.decls.len(), 12); + assert_eq!(&lcgs.decls[0].ident.to_string(), "max_health"); + assert_eq!(&lcgs.decls[1].ident.to_string(), "alice"); + assert_eq!(&lcgs.decls[2].ident.to_string(), "bob"); + assert_eq!(&lcgs.decls[3].ident.to_string(), "gamer"); + assert_eq!(&lcgs.decls[4].ident.to_string(), "alice.health"); + assert_eq!(&lcgs.decls[5].ident.to_string(), "alice.alive"); + assert_eq!(&lcgs.decls[6].ident.to_string(), "alice.wait"); + assert_eq!(&lcgs.decls[7].ident.to_string(), "alice.shoot"); + assert_eq!(&lcgs.decls[8].ident.to_string(), "bob.health"); + assert_eq!(&lcgs.decls[9].ident.to_string(), "bob.alive"); + assert_eq!(&lcgs.decls[10].ident.to_string(), "bob.wait"); + assert_eq!(&lcgs.decls[11].ident.to_string(), "bob.shoot"); } #[test] @@ -345,15 +347,18 @@ mod test { foo : [1 .. 10] init 1; foo' = foo; "; - let lcgs1 = IntermediateLcgs::create(parse_lcgs(input1).unwrap()).unwrap(); - assert_eq!(lcgs1.symbols.len(), 1); - assert!(lcgs1.symbols.get(&":global.foo".into()).is_some()); + let errors = ErrorLog::new(); + let lcgs1 = + IntermediateLcgs::create(parse_lcgs(input1, &errors).unwrap(), &errors).unwrap(); + assert!(errors.is_empty()); + assert_eq!(lcgs1.decls.len(), 1); + assert_eq!(&lcgs1.decls[0].ident.to_string(), "foo"); // But other declarations cannot refer to themselves let input2 = " label foo = foo > 0; "; - let lcgs2 = IntermediateLcgs::create(parse_lcgs(input2).unwrap()); + let lcgs2 = IntermediateLcgs::create(parse_lcgs(input2, &errors).unwrap(), &errors); assert!(lcgs2.is_err()); } @@ -362,8 +367,8 @@ mod test { // Check standard use of relabeling let input = " const max_health = 100; - player anna = gamer [enemy=bob]; - player bob = gamer [enemy=anna]; + player alice = gamer [enemy=bob]; + player bob = gamer [enemy=alice]; template gamer health : [0 .. max_health] init max_health; @@ -375,20 +380,23 @@ mod test { [shoot] health > 0 && enemy.health > 0; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - assert_eq!(lcgs.symbols.len(), 12); - assert!(lcgs.symbols.get(&":global.max_health".into()).is_some()); - assert!(lcgs.symbols.get(&":global.anna".into()).is_some()); - assert!(lcgs.symbols.get(&":global.bob".into()).is_some()); - assert!(lcgs.symbols.get(&":global.gamer".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.health".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.alive".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.wait".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.shoot".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.health".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.alive".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.wait".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.shoot".into()).is_some()); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + assert!(errors.is_empty()); + assert_eq!(lcgs.decls.len(), 12); + assert_eq!(&lcgs.decls[0].ident.to_string(), "max_health"); + assert_eq!(&lcgs.decls[1].ident.to_string(), "alice"); + assert_eq!(&lcgs.decls[2].ident.to_string(), "bob"); + assert_eq!(&lcgs.decls[3].ident.to_string(), "gamer"); + assert_eq!(&lcgs.decls[4].ident.to_string(), "alice.health"); + assert_eq!(&lcgs.decls[5].ident.to_string(), "alice.alive"); + assert_eq!(&lcgs.decls[6].ident.to_string(), "alice.wait"); + assert_eq!(&lcgs.decls[7].ident.to_string(), "alice.shoot"); + assert_eq!(&lcgs.decls[8].ident.to_string(), "bob.health"); + assert_eq!(&lcgs.decls[9].ident.to_string(), "bob.alive"); + assert_eq!(&lcgs.decls[10].ident.to_string(), "bob.wait"); + assert_eq!(&lcgs.decls[11].ident.to_string(), "bob.shoot"); } #[test] @@ -405,17 +413,20 @@ mod test { label prop = 1; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - assert_eq!(lcgs.symbols.len(), 9); - assert!(lcgs.symbols.get(&":global.anna".into()).is_some()); - assert!(lcgs.symbols.get(&":global.bob".into()).is_some()); - assert!(lcgs.symbols.get(&":global.human".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.apples".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.dance".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.happy".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.bananas".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.run".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.sad".into()).is_some()); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + assert!(errors.is_empty()); + assert_eq!(lcgs.decls.len(), 9); + assert_eq!(&lcgs.decls[0].ident.to_string(), "anna"); + assert_eq!(&lcgs.decls[1].ident.to_string(), "bob"); + assert_eq!(&lcgs.decls[2].ident.to_string(), "human"); + assert_eq!(&lcgs.decls[3].ident.to_string(), "anna.apples"); + assert_eq!(&lcgs.decls[4].ident.to_string(), "anna.dance"); + assert_eq!(&lcgs.decls[5].ident.to_string(), "anna.happy"); + assert_eq!(&lcgs.decls[6].ident.to_string(), "bob.bananas"); + assert_eq!(&lcgs.decls[7].ident.to_string(), "bob.run"); + assert_eq!(&lcgs.decls[8].ident.to_string(), "bob.sad"); } #[test] @@ -432,18 +443,20 @@ mod test { [act] 1; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - assert_eq!(lcgs.symbols.len(), 9); - assert!(lcgs.symbols.get(&":global.anna".into()).is_some()); - assert!(lcgs.symbols.get(&":global.bob".into()).is_some()); - assert!(lcgs.symbols.get(&":global.human".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.money".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.money".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.wait".into()).is_some()); - assert!(lcgs.symbols.get(&"anna.work".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.money".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.wait".into()).is_some()); - assert!(lcgs.symbols.get(&"bob.act".into()).is_some()); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + assert!(errors.is_empty()); + assert_eq!(lcgs.decls.len(), 9); + assert_eq!(&lcgs.decls[0].ident.to_string(), "anna"); + assert_eq!(&lcgs.decls[1].ident.to_string(), "bob"); + assert_eq!(&lcgs.decls[2].ident.to_string(), "human"); + assert_eq!(&lcgs.decls[3].ident.to_string(), "anna.money"); + assert_eq!(&lcgs.decls[4].ident.to_string(), "anna.wait"); + assert_eq!(&lcgs.decls[5].ident.to_string(), "anna.work"); + assert_eq!(&lcgs.decls[6].ident.to_string(), "bob.money"); + assert_eq!(&lcgs.decls[7].ident.to_string(), "bob.wait"); + assert_eq!(&lcgs.decls[8].ident.to_string(), "bob.act"); } #[test] @@ -455,8 +468,10 @@ mod test { bar : [0 .. 5] init 0; bar' = bar; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let index = 23; + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let index = StateIdx(23); let state = lcgs.state_from_index(index); let index2 = lcgs.index_of_state(&state); assert_eq!(index, index2); @@ -474,8 +489,10 @@ mod test { yum : [100 .. 102] init 100; yum' = yum; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let indexes = [12, 55, 126, 78, 99]; + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let indexes = [12, 55, 126, 78, 99].map(StateIdx); for i in &indexes { let state = lcgs.state_from_index(*i); let i2 = lcgs.index_of_state(&state); @@ -493,8 +510,10 @@ mod test { bar : [-5 .. -3] init -3; bar' = bar; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let index = 14; + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let index = StateIdx(14); let state = lcgs.state_from_index(index); let index2 = lcgs.index_of_state(&state); assert_eq!(index, index2); @@ -522,8 +541,10 @@ mod test { [wait] 1; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let indexes = [12, 55, 126, 78, 99, 150, 555, 992, 1001, 733]; + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let indexes = [12, 55, 126, 78, 99, 150, 555, 992, 1001, 733].map(StateIdx); for i in &indexes { let state = lcgs.state_from_index(*i); let i2 = lcgs.index_of_state(&state); @@ -543,8 +564,14 @@ mod test { "; // Index to state to index - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let indexes = [12_340, 1_987_158, 3_000_000_000]; + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let indexes = [ + StateIdx(12_340), + StateIdx(1_987_158), + StateIdx(3_000_000_000), + ]; for i in &indexes { let state = lcgs.state_from_index(*i); let i2 = lcgs.index_of_state(&state); @@ -552,9 +579,9 @@ mod test { } // State to index to state - let mut map: HashMap = HashMap::new(); - map.insert(":global.foo".into(), 2_000_000); - map.insert(":global.bar".into(), 2_000_000); + let mut map: HashMap = HashMap::new(); + map.insert(lcgs.get_decl_by_name("foo").unwrap().index, 2_000_000); + map.insert(lcgs.get_decl_by_name("bar").unwrap().index, 2_000_000); let state = State(map); let index = lcgs.index_of_state(&state); let state2 = lcgs.state_from_index(index); @@ -566,18 +593,22 @@ mod test { let input = " const t = -5; "; - let pp = parse_lcgs(input); - let lcgs = IntermediateLcgs::create(pp.unwrap()).unwrap(); - assert!(lcgs.symbols.get(&":global.t".into()).is_some()); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + assert!(lcgs.get_decl_by_name("t").is_some()); } /// Helper function to get the index of a label with the given symbol name - fn get_label_index(lcgs: &IntermediateLcgs, symbol_name: &str) -> usize { - let symbol = lcgs.symbols.get(&symbol_name.into()).unwrap(); - if let DeclKind::Label(label) = &symbol.kind { - label.index + fn get_label_index(lcgs: &IntermediateLcgs, label_name: &str) -> PropIdx { + if let Some(decl) = lcgs.get_decl_by_name(label_name) { + if let DeclKind::StateLabel(idx, _) = &decl.kind { + *idx + } else { + panic!("'{}' is not a state label", label_name) + } } else { - panic!("Symbol '{}' is not a label", symbol_name) + panic!("'{}' does not exist", label_name); } } @@ -591,10 +622,12 @@ mod test { bar' = bar; label cool = foo; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let labels = lcgs.labels(23); - assert!(labels.contains(&0usize)); - assert_eq!(get_label_index(&lcgs, ":global.cool"), 0usize); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let labels = lcgs.labels(StateIdx(23)); + assert!(labels.contains(&PropIdx(0))); + assert_eq!(get_label_index(&lcgs, "cool"), PropIdx(0)); } #[test] @@ -609,14 +642,16 @@ mod test { label great = bar == 0; label awesome = foo > bar; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let labels = lcgs.labels(46); - assert!(labels.contains(&0usize)); - assert_eq!(get_label_index(&lcgs, ":global.cool"), 0usize); - assert!(!labels.contains(&1usize)); - assert_eq!(get_label_index(&lcgs, ":global.great"), 1usize); - assert!(labels.contains(&2usize)); - assert_eq!(get_label_index(&lcgs, ":global.awesome"), 2usize); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let labels = lcgs.labels(StateIdx(46)); + assert!(labels.contains(&PropIdx(0))); + assert_eq!(get_label_index(&lcgs, "cool"), PropIdx(0)); + assert!(!labels.contains(&PropIdx(1))); + assert_eq!(get_label_index(&lcgs, "great"), PropIdx(1)); + assert!(labels.contains(&PropIdx(2))); + assert_eq!(get_label_index(&lcgs, "awesome"), PropIdx(2)); } #[test] @@ -634,14 +669,16 @@ mod test { [wait] 1; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let labels = lcgs.labels(5); - assert!(!labels.contains(&0usize)); - assert_eq!(get_label_index(&lcgs, ":global.no"), 0usize); - assert!(labels.contains(&1usize)); - assert_eq!(get_label_index(&lcgs, "p1.yes"), 1usize); - assert!(labels.contains(&2usize)); - assert_eq!(get_label_index(&lcgs, "p2.yes"), 2usize); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let labels = lcgs.labels(StateIdx(5)); + assert!(!labels.contains(&PropIdx(0))); + assert_eq!(get_label_index(&lcgs, "no"), PropIdx(0)); + assert!(labels.contains(&PropIdx(1))); + assert_eq!(get_label_index(&lcgs, "p1.yes"), PropIdx(1)); + assert!(labels.contains(&PropIdx(2))); + assert_eq!(get_label_index(&lcgs, "p2.yes"), PropIdx(2)); } #[test] @@ -661,8 +698,10 @@ mod test { [move] foo > 0; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let move_count = lcgs.move_count(4); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let move_count = lcgs.move_count(StateIdx(4)); assert_eq!(move_count[0], 1); assert_eq!(move_count[1], 2); } @@ -678,11 +717,13 @@ mod test { [swap] 1; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - let next_state = lcgs.transitions(0, vec![0]); - assert_eq!(1, next_state); - let next_next_state = lcgs.transitions(next_state, vec![0]); - assert_eq!(0, next_next_state); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + let next_state = lcgs.get_successor(StateIdx(0), &[ActionIdx(0)]); + assert_eq!(StateIdx(1), next_state); + let next_next_state = lcgs.get_successor(next_state, &[ActionIdx(0)]); + assert_eq!(StateIdx(0), next_next_state); } #[test] @@ -697,11 +738,25 @@ mod test { [set_foo] 1; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - assert_eq!(0, lcgs.transitions(0, vec![0])); - assert_eq!(1, lcgs.transitions(0, vec![1])); - assert_eq!(0, lcgs.transitions(1, vec![0])); - assert_eq!(1, lcgs.transitions(1, vec![1])); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + assert_eq!( + StateIdx(0), + lcgs.get_successor(StateIdx(0), &[ActionIdx(0)]) + ); + assert_eq!( + StateIdx(1), + lcgs.get_successor(StateIdx(0), &[ActionIdx(1)]) + ); + assert_eq!( + StateIdx(0), + lcgs.get_successor(StateIdx(1), &[ActionIdx(0)]) + ); + assert_eq!( + StateIdx(1), + lcgs.get_successor(StateIdx(1), &[ActionIdx(1)]) + ); } #[test] @@ -718,10 +773,12 @@ mod test { [available_action] 1; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); let init_state = lcgs.initial_state_index(); - assert_eq!(0, init_state); - assert_eq!(0, lcgs.transitions(init_state, vec![0])); + assert_eq!(StateIdx(0), init_state); + assert_eq!(StateIdx(0), lcgs.get_successor(init_state, &[ActionIdx(0)])); } #[test] @@ -733,8 +790,10 @@ mod test { bar : [0 .. 1] init 1; bar' = bar; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - assert_eq!(2, lcgs.initial_state_index()); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + assert_eq!(StateIdx(2), lcgs.initial_state_index()); } #[test] @@ -747,20 +806,22 @@ mod test { bar : [1 .. 6] init 1; bar' = bar; "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - assert_eq!(1, lcgs.initial_state_index()); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + assert_eq!(StateIdx(1), lcgs.initial_state_index()); } /// Helper function to get the index of a player with the given name - fn get_player_index(lcgs: &IntermediateLcgs, player_name: &str) -> usize { - let symbol = lcgs - .symbols - .get(&Owner::Global.symbol_id(player_name)) - .unwrap(); - if let DeclKind::Player(player) = &symbol.kind { - player.index + fn get_player_index(lcgs: &IntermediateLcgs, player_name: &str) -> PlayerIdx { + if let Some(decl) = lcgs.get_decl_by_name(player_name) { + if let DeclKind::Player(player) = &decl.kind { + player.index + } else { + panic!("'{}' is not a player", player_name) + } } else { - panic!("Symbol ':global.{}' is not a player", player_name) + panic!("'{}' does not exists", player_name); } } @@ -775,9 +836,11 @@ mod test { [wait] 1; endtemplate "; - let lcgs = IntermediateLcgs::create(parse_lcgs(input).unwrap()).unwrap(); - assert_eq!(get_player_index(&lcgs, "p1"), 0usize); - assert_eq!(get_player_index(&lcgs, "p2"), 1usize); - assert_eq!(get_player_index(&lcgs, "p3"), 2usize); + let errors = ErrorLog::new(); + let root = parse_lcgs(input, &errors).unwrap(); + let lcgs = IntermediateLcgs::create(root, &errors).unwrap(); + assert_eq!(get_player_index(&lcgs, "p1"), PlayerIdx(0)); + assert_eq!(get_player_index(&lcgs, "p2"), PlayerIdx(1)); + assert_eq!(get_player_index(&lcgs, "p3"), PlayerIdx(2)); } } diff --git a/cgaal-engine/src/game_structure/lcgs/relabeling.rs b/cgaal-engine/src/game_structure/lcgs/relabeling.rs index 1a9c1c4e..00d7bf5a 100644 --- a/cgaal-engine/src/game_structure/lcgs/relabeling.rs +++ b/cgaal-engine/src/game_structure/lcgs/relabeling.rs @@ -212,34 +212,56 @@ fn owned_ident_relabel_error(ident: Ident) -> SpannedError { #[cfg(test)] mod test { - use crate::game_structure::lcgs::ast::{ - BinaryOpKind, Decl, DeclKind, Expr, ExprKind, Identifier, LabelDecl, + use crate::game_structure::lcgs::relabeling::Relabeler; + use crate::game_structure::lcgs::symbol_table::SymbIdx; + use crate::game_structure::{PropIdx, INVALID_IDX}; + use crate::parsing::ast::{ + BinaryOpKind, Decl, DeclKind, Expr, ExprKind, Ident, OwnedIdent, RelabelCase, }; - use crate::game_structure::lcgs::ir::relabeling::Relabeler; - use crate::game_structure::lcgs::parse; + use crate::parsing::errors::ErrorLog; + use crate::parsing::lexer::Lexer; + use crate::parsing::parser::Parser; + use crate::parsing::span::Span; + + /// Helper function to parse a relabelling clause + fn parse_relabelling(input: &str) -> Vec { + let errors = ErrorLog::new(); + let lexer = Lexer::new(input.as_bytes(), &errors); + let mut parser = Parser::new(lexer, &errors); + parser.relabelling().expect("Invalid relabelling").1 + } + + /// Helper function to parse an expression + fn parse_expr(input: &str) -> Expr { + let errors = ErrorLog::new(); + let lexer = Lexer::new(input.as_bytes(), &errors); + let mut parser = Parser::new(lexer, &errors); + parser.expr().expect("Invalid expression") + } #[test] fn test_relabeling_expr_01() { // Check simple relabeling from one name to another - let relabeling = "[test=res]"; - let relabeling = parse::relabeling().parse(relabeling.as_bytes()).unwrap(); - let expr = "5 + test"; - let expr = parse::expr().parse(expr.as_bytes()).unwrap(); + let expr = parse_expr("5 + test"); + let relabeling = parse_relabelling("[test=res]"); let relabeler = Relabeler::new(&relabeling); - let new_expr = relabeler.relabel_expr(&expr).unwrap(); + let new_expr = relabeler.relabel_expr(expr).unwrap(); assert_eq!( new_expr, Expr { - kind: ExprKind::BinaryOp( - BinaryOpKind::Addition, + span: Span::new(0, 8), + kind: ExprKind::Binary( + BinaryOpKind::Add, Box::new(Expr { - kind: ExprKind::Number(5), + span: Span::new(0, 1), + kind: ExprKind::Num(5), }), Box::new(Expr { - kind: ExprKind::OwnedIdent(Box::new(Identifier::OptionalOwner { - owner: None, - name: "res".to_string() - })) + span: Span::new(6, 9), + kind: ExprKind::OwnedIdent(OwnedIdent::new( + None, + Ident::new(Span::new(6, 9), "res".to_string()) + )) }) ) } @@ -249,22 +271,23 @@ mod test { #[test] fn test_relabeling_expr_02() { // Check simple relabeling to number - let relabeling = "[test=4]"; - let relabeling = parse::relabeling().parse(relabeling.as_bytes()).unwrap(); - let expr = "5 + test"; - let expr = parse::expr().parse(expr.as_bytes()).unwrap(); + let expr = parse_expr("5 + test"); + let relabeling = parse_relabelling("[test=4]"); let relabeler = Relabeler::new(&relabeling); - let new_expr = relabeler.relabel_expr(&expr).unwrap(); + let new_expr = relabeler.relabel_expr(expr).unwrap(); assert_eq!( new_expr, Expr { - kind: ExprKind::BinaryOp( - BinaryOpKind::Addition, + span: Span::new(0, 8), + kind: ExprKind::Binary( + BinaryOpKind::Add, Box::new(Expr { - kind: ExprKind::Number(5), + span: Span::new(0, 1), + kind: ExprKind::Num(5), }), Box::new(Expr { - kind: ExprKind::Number(4), + span: Span::new(6, 7), + kind: ExprKind::Num(4), }), ) } @@ -274,28 +297,29 @@ mod test { #[test] fn test_relabeling_expr_03() { // Check simple relabeling of identifier part - let relabeling = "[bar=yum]"; - let relabeling = parse::relabeling().parse(relabeling.as_bytes()).unwrap(); - let expr = "foo.bar + bar.baz"; - let expr = parse::expr().parse(expr.as_bytes()).unwrap(); + let expr = parse_expr("foo.bar + bar.baz"); + let relabeling = parse_relabelling("[bar=yum]"); let relabeler = Relabeler::new(&relabeling); - let new_expr = relabeler.relabel_expr(&expr).unwrap(); + let new_expr = relabeler.relabel_expr(expr).unwrap(); assert_eq!( new_expr, Expr { - kind: ExprKind::BinaryOp( - BinaryOpKind::Addition, + span: Span::new(0, 17), + kind: ExprKind::Binary( + BinaryOpKind::Add, Box::new(Expr { - kind: ExprKind::OwnedIdent(Box::new(Identifier::OptionalOwner { - owner: Some("foo".to_string()), - name: "yum".to_string() - })) + span: Span::new(0, 7), + kind: ExprKind::OwnedIdent(OwnedIdent::new( + Some(Ident::new(Span::new(0, 3), "foo".into())), + Ident::new(Span::new(4, 7), "yum".into()), + )) }), Box::new(Expr { - kind: ExprKind::OwnedIdent(Box::new(Identifier::OptionalOwner { - owner: Some("yum".to_string()), - name: "baz".to_string() - })) + span: Span::new(10, 17), + kind: ExprKind::OwnedIdent(OwnedIdent::new( + Some(Ident::new(Span::new(10, 13), "yum".into())), + Ident::new(Span::new(14, 17), "baz".into()), + )) }), ) } @@ -305,27 +329,30 @@ mod test { #[test] fn test_relabeling_label_01() { // Check simple relabeling of label declaration name - let relabeling = "[foo=yum]"; - let relabeling = parse::relabeling().parse(relabeling.as_bytes()).unwrap(); - let decl = "label foo = bar.baz"; - let decl = parse::label_decl().parse(decl.as_bytes()).unwrap(); + let errors = ErrorLog::new(); + let lexer = Lexer::new("label foo = bar.baz".as_bytes(), &errors); + let mut parser = Parser::new(lexer, &errors); + let decl = parser.state_label_decl().expect("Invalid expression"); + + let relabeling = parse_relabelling("[foo=yum]"); let relabeler = Relabeler::new(&relabeling); - let new_decl = relabeler.relabel_label(&decl).unwrap(); + let new_decl = relabeler.relabel_decl(decl).unwrap(); assert_eq!( new_decl, Decl { - kind: DeclKind::Label(Box::new(LabelDecl { - index: 0usize, - condition: Expr { - kind: ExprKind::OwnedIdent(Box::new(Identifier::OptionalOwner { - owner: Some("bar".to_string()), - name: "baz".to_string() - })) - }, - name: Identifier::Simple { - name: "yum".to_string() - } - })) + span: Span::new(0, 19), + ident: OwnedIdent::new(None, Ident::new(Span::new(6, 9), "yum".into())), + index: SymbIdx(INVALID_IDX), + kind: DeclKind::StateLabel( + PropIdx(INVALID_IDX), + Expr::new( + Span::new(12, 19), + ExprKind::OwnedIdent(OwnedIdent::new( + Some(Ident::new(Span::new(12, 15), "bar".into())), + Ident::new(Span::new(16, 19), "baz".into()), + )) + ) + ), } ) } diff --git a/cgaal-engine/src/game_structure/lcgs/symbol_checker.rs b/cgaal-engine/src/game_structure/lcgs/symbol_checker.rs index cf04a980..1b0ba9cd 100644 --- a/cgaal-engine/src/game_structure/lcgs/symbol_checker.rs +++ b/cgaal-engine/src/game_structure/lcgs/symbol_checker.rs @@ -41,7 +41,13 @@ fn register_decls(root: LcgsRoot) -> Result { // Constants are evaluated immediately. // Players are put in a separate vector and handled afterwards. // Symbol table is given ownership of the declarations. - for Decl { span, ident, kind } in root.decls { + for Decl { + span, + ident, + index: _index, + kind, + } in root.decls + { match kind { DeclKind::Const(expr) => { // We can evaluate constants immediately as constants can only @@ -160,9 +166,10 @@ fn check_and_optimize_decls(symbols: &SymbolTable) -> Result<(), SpannedError> { // Optimize the declaration's expression(s) let mut decl_ref = symbol.borrow_mut(); let Decl { - span: _, - kind, + span: _, // unchanged ident, + index: _, // unchanged + kind, } = decl_ref.deref_mut(); match kind { DeclKind::StateLabel(_, expr) => { diff --git a/cgaal-engine/src/game_structure/lcgs/symbol_table.rs b/cgaal-engine/src/game_structure/lcgs/symbol_table.rs index 2d3cf15f..8aafb255 100644 --- a/cgaal-engine/src/game_structure/lcgs/symbol_table.rs +++ b/cgaal-engine/src/game_structure/lcgs/symbol_table.rs @@ -64,13 +64,14 @@ impl SymbolTable { /// Creates and inserts a symbol for the given declaration under the given owned name. /// Returns the index of the inserted symbol. /// If the name is already associated with a different symbol, an error is returned instead. - pub fn insert(&mut self, decl: Decl) -> Result { + pub fn insert(&mut self, mut decl: Decl) -> Result { if self.exists(&decl.ident.to_string()) { return Err(SpannedError::new( decl.ident.name.span, format!("The name '{}' is already declared", decl.ident), )); } + decl.index = SymbIdx(self.symbols.len()); self.symbols.push(Symbol::new(decl)); Ok(SymbIdx(self.symbols.len() - 1)) } diff --git a/cgaal-engine/src/parsing/ast.rs b/cgaal-engine/src/parsing/ast.rs index ec803193..1bf89fc3 100644 --- a/cgaal-engine/src/parsing/ast.rs +++ b/cgaal-engine/src/parsing/ast.rs @@ -1,9 +1,9 @@ -use std::fmt::{Display, Formatter}; -use std::ops::{Add, Div, Mul, RangeInclusive, Sub}; use crate::game_structure::lcgs::symbol_table::SymbIdx; -use crate::game_structure::{INVALID_IDX, PlayerIdx, PropIdx}; -use crate::parsing::span::{NO_SPAN, Span}; +use crate::game_structure::{PlayerIdx, PropIdx, INVALID_IDX}; +use crate::parsing::span::{Span, NO_SPAN}; use crate::parsing::token::TokenKind; +use std::fmt::{Display, Formatter}; +use std::ops::{Add, Div, Mul, RangeInclusive, Sub}; /// The root of an LCGS program. #[derive(Debug, Eq, PartialEq, Clone)] @@ -23,12 +23,18 @@ impl LcgsRoot { pub struct Decl { pub span: Span, pub ident: OwnedIdent, + pub index: SymbIdx, pub kind: DeclKind, } impl Decl { pub fn new(span: Span, ident: Ident, kind: DeclKind) -> Self { - Decl { span, ident: OwnedIdent::new(None, ident), kind } + Decl { + span, + ident: OwnedIdent::new(None, ident), + index: SymbIdx(INVALID_IDX), + kind, + } } pub fn new_error() -> Self { @@ -106,12 +112,7 @@ pub struct StateVarDecl { } impl StateVarDecl { - pub fn new( - range: RangeClause, - init: Expr, - update_ident: Ident, - update: Expr, - ) -> Self { + pub fn new(range: RangeClause, init: Expr, update_ident: Ident, update: Expr) -> Self { StateVarDecl { range, init, @@ -132,7 +133,12 @@ pub struct RangeClause { impl RangeClause { pub fn new(span: Span, min: Expr, max: Expr) -> Self { - RangeClause { span, min, max, val: 0..=0 } + RangeClause { + span, + min, + max, + val: 0..=0, + } } } @@ -228,7 +234,7 @@ impl From<&str> for OwnedIdent { 2 => OwnedIdent::new( Some(Ident::new(NO_SPAN, split[0].to_string())), Ident::new(NO_SPAN, split[1].to_string()), - ), + ), _ => panic!("Invalid owned identifier. Must consist of an owner and a name."), } } diff --git a/cgaal-engine/tests/parsing_expr.rs b/cgaal-engine/tests/parsing_expr.rs index ee5838b2..aba8264a 100644 --- a/cgaal-engine/tests/parsing_expr.rs +++ b/cgaal-engine/tests/parsing_expr.rs @@ -1,12 +1,13 @@ -use cgaal_engine::atl::convert::convert_expr_to_phi; -use cgaal_engine::game_structure::lcgs::ir::intermediate::IntermediateLcgs; -use cgaal_engine::game_structure::lcgs::parse::parse_lcgs; +use cgaal_engine::game_structure::lcgs::convert_expr_to_phi; +use cgaal_engine::game_structure::lcgs::intermediate::IntermediateLcgs; use cgaal_engine::parsing::ast::*; use cgaal_engine::parsing::errors::ErrorLog; use cgaal_engine::parsing::lexer::*; use cgaal_engine::parsing::parse_atl; +use cgaal_engine::parsing::parse_lcgs; use cgaal_engine::parsing::parser::*; use cgaal_engine::parsing::span::*; +use std::f32::consts::E; #[test] fn basic_expr_001() { @@ -84,10 +85,10 @@ fn basic_expr_003() { BinaryOpKind::Or, Expr::new( Span::new(0, 3), - ExprKind::OwnedIdent( + ExprKind::OwnedIdent(OwnedIdent::new( None, Ident::new(Span::new(0, 3), "foo".to_string()) - ) + )) ) .into(), Expr::new( @@ -97,10 +98,10 @@ fn basic_expr_003() { Expr::new(Span::new(7, 11), ExprKind::True).into(), Expr::new( Span::new(15, 22), - ExprKind::OwnedIdent( + ExprKind::OwnedIdent(OwnedIdent::new( Some(Ident::new(Span::new(15, 18), "bar".to_string())), Ident::new(Span::new(19, 22), "baz".to_string()) - ) + )) ) .into() ) @@ -146,12 +147,18 @@ fn basic_expr_004() { ExprKind::Max(vec![ Expr::new( Span::new(4, 5), - ExprKind::OwnedIdent(None, Ident::new(Span::new(4, 5), "a".to_string())) + ExprKind::OwnedIdent(OwnedIdent::new( + None, + Ident::new(Span::new(4, 5), "a".to_string()) + )) ) .into(), Expr::new( Span::new(7, 8), - ExprKind::OwnedIdent(None, Ident::new(Span::new(7, 8), "b".to_string())) + ExprKind::OwnedIdent(OwnedIdent::new( + None, + Ident::new(Span::new(7, 8), "b".to_string()) + )) ) .into(), Expr::new(Span::new(10, 11), ExprKind::Num(5)).into(), @@ -184,10 +191,10 @@ fn atl_expr_001() { UnaryOpKind::Eventually, Expr::new( Span::new(9, 13), - ExprKind::OwnedIdent( + ExprKind::OwnedIdent(OwnedIdent::new( None, Ident::new(Span::new(9, 13), "goal".to_string()) - ) + )) ) .into() ) @@ -225,10 +232,10 @@ fn atl_expr_002() { UnaryOpKind::Invariantly, Expr::new( Span::new(13, 17), - ExprKind::OwnedIdent( + ExprKind::OwnedIdent(OwnedIdent::new( None, Ident::new(Span::new(13, 17), "safe".to_string()) - ) + )) ) .into() ) @@ -263,18 +270,18 @@ fn atl_expr_003() { BinaryOpKind::Until, Expr::new( Span::new(6, 10), - ExprKind::OwnedIdent( + ExprKind::OwnedIdent(OwnedIdent::new( None, Ident::new(Span::new(6, 10), "safe".to_string()) - ) + )) ) .into(), Expr::new( Span::new(13, 17), - ExprKind::OwnedIdent( + ExprKind::OwnedIdent(OwnedIdent::new( None, Ident::new(Span::new(13, 17), "goal".to_string()) - ) + )) ) .into() ) @@ -309,10 +316,10 @@ fn atl_expr_004() { UnaryOpKind::Eventually, Expr::new( Span::new(9, 16), - ExprKind::OwnedIdent( + ExprKind::OwnedIdent(OwnedIdent::new( Some(Ident::new(Span::new(9, 11), "p1".to_string())), Ident::new(Span::new(12, 16), "attr".to_string()), - ), + )), ) .into(), ), @@ -347,10 +354,10 @@ fn atl_expr_005() { UnaryOpKind::Eventually, Expr::new( Span::new(10, 14), - ExprKind::OwnedIdent( + ExprKind::OwnedIdent(OwnedIdent::new( None, Ident::new(Span::new(10, 14), "safe".to_string()) - ) + )) ) .into() ) @@ -398,7 +405,10 @@ fn erroneous_expr_002() { expr, Expr::new( Span::new(0, 3), - ExprKind::OwnedIdent(None, Ident::new(Span::new(0, 3), "foo".to_string())) + ExprKind::OwnedIdent(OwnedIdent::new( + None, + Ident::new(Span::new(0, 3), "foo".to_string()) + )) ) ); } @@ -624,13 +634,13 @@ fn atl_expr_batch() { "[[p2]] (<> X p1.attr && !prop U true || false)", ]; - let root = parse_lcgs(lcgs_raw).unwrap(); - let game = IntermediateLcgs::create(root).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(lcgs_raw, &errors).unwrap(); + let game = IntermediateLcgs::create(root, &errors).unwrap(); for atl_raw in atls { - let errors = ErrorLog::new(); parse_atl(atl_raw, &errors) - .and_then(|expr| convert_expr_to_phi(&expr, &game, &errors)) + .and_then(|expr| convert_expr_to_phi(expr, &game, &errors)) .expect(&format!( "For '{}', ErrorLog is not empty: {:?}", atl_raw, errors @@ -671,18 +681,15 @@ fn atl_expr_erroneous_batch() { "p1.x", ]; - let root = parse_lcgs(lcgs_raw).unwrap(); - let game = IntermediateLcgs::create(root).unwrap(); + let errors = ErrorLog::new(); + let root = parse_lcgs(lcgs_raw, &errors).unwrap(); + let game = IntermediateLcgs::create(root, &errors).unwrap(); for atl_raw in atls { - let errors = ErrorLog::new(); - let is_none = parse_atl(atl_raw, &errors) - .and_then(|expr| convert_expr_to_phi(&expr, &game, &errors)) - .is_none(); - assert!( - is_none && errors.has_errors(), - "For '{}', ErrorLog is empty", - atl_raw - ); + let is_err = parse_atl(atl_raw, &errors) + .and_then(|expr| convert_expr_to_phi(expr, &game, &errors)) + .is_err(); + assert!(is_err, "For '{}', result is not Err", atl_raw); + assert!(errors.has_errors(), "For '{}', ErrorLog is empty", atl_raw); } } diff --git a/cgaal-engine/tests/parsing_lcgs.rs b/cgaal-engine/tests/parsing_lcgs.rs index ec281165..4d1a5641 100644 --- a/cgaal-engine/tests/parsing_lcgs.rs +++ b/cgaal-engine/tests/parsing_lcgs.rs @@ -1,3 +1,4 @@ +use cgaal_engine::game_structure::{PropIdx, INVALID_IDX}; use cgaal_engine::parsing::ast::*; use cgaal_engine::parsing::errors::ErrorLog; use cgaal_engine::parsing::lexer::*; @@ -39,7 +40,10 @@ fn state_label_decl_001() { Decl::new( Span::new(0, 13), Ident::new(Span::new(6, 9), "foo".into()), - DeclKind::StateLabel(Expr::new(Span::new(12, 13), ExprKind::Num(1),).into()) + DeclKind::StateLabel( + PropIdx(INVALID_IDX), + Expr::new(Span::new(12, 13), ExprKind::Num(1),) + ) ) ); } @@ -182,7 +186,10 @@ fn template_decl_002() { Decl::new( Span::new(13, 26), Ident::new(Span::new(19, 22), "bar".into()), - DeclKind::StateLabel(Expr::new(Span::new(25, 26), ExprKind::Num(1),).into()) + DeclKind::StateLabel( + PropIdx(INVALID_IDX), + Expr::new(Span::new(25, 26), ExprKind::Num(1),) + ) ), Decl::new( Span::new(28, 35), diff --git a/cgaal-engine/tests/partial_strategy_synthesis.rs b/cgaal-engine/tests/partial_strategy_synthesis.rs index cd930c6a..498f8a55 100644 --- a/cgaal-engine/tests/partial_strategy_synthesis.rs +++ b/cgaal-engine/tests/partial_strategy_synthesis.rs @@ -1,3 +1,5 @@ +use cgaal_engine::game_structure::lcgs::convert_expr_to_phi; +use cgaal_engine::game_structure::{ActionIdx, PlayerIdx, StateIdx}; use cgaal_engine::{ algorithms::{ certain_zero::{ @@ -8,13 +10,9 @@ use cgaal_engine::{ compute_game_strategy, error::Error, partial::PartialStrategy, WitnessStrategy, }, }, - atl::convert::convert_expr_to_phi, edg::atledg::{vertex::AtlVertex, AtlDependencyGraph}, - game_structure::{ - lcgs::{ir::intermediate::IntermediateLcgs, parse::parse_lcgs}, - GameStructure, - }, - parsing::{errors::ErrorLog, parse_atl}, + game_structure::{lcgs::intermediate::IntermediateLcgs, GameStructure}, + parsing::{errors::ErrorLog, parse_atl, parse_lcgs}, }; const GAME: &str = " @@ -38,19 +36,19 @@ label p2_ahead = p1.a < p2.a; "; // States, format is STATE_ -const STATE_00: usize = 0; -const STATE_01: usize = 1; -const STATE_02: usize = 2; -const STATE_10: usize = 3; -const STATE_11: usize = 4; -const STATE_12: usize = 5; -const STATE_20: usize = 6; -const STATE_21: usize = 7; -const STATE_22: usize = 8; - -const ACT_P1_WAIT: usize = 0; -const ACT_P1_GT1: usize = 1; -const ACT_P1_INC: usize = 2; +const STATE_00: StateIdx = StateIdx(0); +const STATE_01: StateIdx = StateIdx(1); +const STATE_02: StateIdx = StateIdx(2); +const STATE_10: StateIdx = StateIdx(3); +const STATE_11: StateIdx = StateIdx(4); +const STATE_12: StateIdx = StateIdx(5); +const STATE_20: StateIdx = StateIdx(6); +const STATE_21: StateIdx = StateIdx(7); +const STATE_22: StateIdx = StateIdx(8); + +const ACT_P1_WAIT: ActionIdx = ActionIdx(0); +const ACT_P1_GT1: ActionIdx = ActionIdx(1); +const ACT_P1_INC: ActionIdx = ActionIdx(2); const WORKER_COUNT: u64 = 4; @@ -91,9 +89,9 @@ macro_rules! assert_partial_strat_moves { ($move_map:ident; $state:ident => $($act:ident),+; $($rest:tt)*) => { { assert!( - $move_map.get(&$state).map(|pm| matches!(pm[0].unwrap_specific(), $($act)|+)).unwrap_or(false), + $move_map.get(&$state).map(|pm| matches!(pm[PlayerIdx(0)].unwrap_specific(), $($act)|+)).unwrap_or(false), concat!("Expected move in ", stringify!($state), " ({}) to be one of [", $(stringify!($act ({}))), +,"], but move was {:?}"), - &$state, $($act), *, &$move_map.get(&$state).map(|pm| &pm[0]) + &$state, $($act), *, &$move_map.get(&$state).map(|pm| &pm[PlayerIdx(0)]) ); } assert_partial_strat_moves!($move_map; $($rest)*); @@ -101,9 +99,9 @@ macro_rules! assert_partial_strat_moves { // Is None or one of .. ($move_map:ident; $state:ident => @, $($act:ident),+; $($rest:tt)*) => { { - assert!($move_map.get(&$state).map(|pm| matches!(pm[0].unwrap_specific(), $($act)|+)).unwrap_or(true), + assert!($move_map.get(&$state).map(|pm| matches!(pm[PlayerIdx(0)].unwrap_specific(), $($act)|+)).unwrap_or(true), concat!("Expected move in ", stringify!($state), " ({}) to be None or one of [", $(stringify!($act ({}))), +,"], but move was {:?}"), - &$state, $($act), *, &$move_map.get(&$state).map(|pm| &pm[0]) + &$state, $($act), *, &$move_map.get(&$state).map(|pm| &pm[PlayerIdx(0)]) ); } assert_partial_strat_moves!($move_map; $($rest)*); @@ -113,7 +111,7 @@ macro_rules! assert_partial_strat_moves { { assert!($move_map.get(&$state).is_none(), concat!("Expected move in ", stringify!($state), " ({}) to be None, but move was {:?}"), - &$state, &$move_map.get(&$state).map(|pm| &pm[0]) + &$state, &$move_map.get(&$state).map(|pm| &pm[PlayerIdx(0)]) ); } assert_partial_strat_moves!($move_map; $($rest)*); @@ -147,11 +145,11 @@ macro_rules! assert_partial_strat_moves { macro_rules! strat_synthesis_test { ($game:expr, $phi:expr, $($rest:tt)*) => { let errors = ErrorLog::new(); - let ast = parse_lcgs($game).unwrap(); - let game = IntermediateLcgs::create(ast).unwrap(); + let ast = parse_lcgs($game, &errors).unwrap(); + let game = IntermediateLcgs::create(ast, &errors).unwrap(); let phi = parse_atl($phi, &errors) - .and_then(|expr| convert_expr_to_phi(&expr, &game, &errors)) - .ok_or_else(|| format!("{}", errors.to_string($phi))) + .and_then(|expr| convert_expr_to_phi(expr, &game, &errors)) + .or_else(|_| Err(format!("{}", errors.to_string($phi)))) .unwrap(); let v0 = AtlVertex::Full { state: game.initial_state_index(), @@ -193,7 +191,7 @@ macro_rules! strat_synthesis_test { move_to_pick, }) = strat else { unreachable!() }; - assert_eq!(players.as_slice(), [0]); + assert_eq!(players.as_slice(), [PlayerIdx(0)]); assert_partial_strat_moves!(move_to_pick; $($moves)*); }; (@@ $v0:expr, $edg:expr, $ass:expr, NoStrategyExist) => {