diff --git a/src/ast/descriptor.rs b/src/ast/descriptor.rs index c434cfa..5552fe5 100644 --- a/src/ast/descriptor.rs +++ b/src/ast/descriptor.rs @@ -35,15 +35,25 @@ impl Descriptor { impl fmt::Debug for Descriptor { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Descriptor({:?}, {:?})", - self.variable, self.descriptor_type - ) + if f.alternate() { + // Pretty: use full struct format with newlines + f.debug_struct("Descriptor") + .field("variable", &self.variable) + .field("label", &self.descriptor_type.label) + .field("properties", &self.descriptor_type.properties) + .finish() + } else { + // Compact: flattened tuple format + write!( + f, + "Descriptor({:?}, {:?}, {:?})", + self.variable, self.descriptor_type.label, self.descriptor_type.properties + ) + } } } -#[derive(PartialEq, Clone, Default)] +#[derive(PartialEq, Clone, Default, Debug)] pub struct DescriptorType { pub label: LabelType, pub properties: PropertyType, @@ -69,13 +79,7 @@ impl DescriptorType { } } -impl fmt::Debug for DescriptorType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "DescriptorType({:?}, {:?})", self.label, self.properties) - } -} - -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] pub enum PropertyType { Open(HashMap), Closed(HashMap), @@ -96,42 +100,3 @@ impl Default for PropertyType { Self::open() } } - -impl fmt::Debug for PropertyType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - PropertyType::Open(map) => { - if map.is_empty() { - write!(f, "Open({{}})") - } else { - let mut keys: Vec<_> = map.keys().collect(); - keys.sort(); - write!(f, "Open({{")?; - for (i, key) in keys.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{}: {:?}", key, map[*key])?; - } - write!(f, "}})") - } - } - PropertyType::Closed(map) => { - if map.is_empty() { - write!(f, "Closed({{}})") - } else { - let mut keys: Vec<_> = map.keys().collect(); - keys.sort(); - write!(f, "Closed({{")?; - for (i, key) in keys.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{}: {:?}", key, map[*key])?; - } - write!(f, "}})") - } - } - } - } -} diff --git a/src/ast/expr.rs b/src/ast/expr.rs index 681eb98..c6b9f40 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -1,113 +1,34 @@ use super::types::SimpleType; use super::var::Var; -use std::fmt; /// Base enum for all expressions in the query language. /// Expressions are used in filters (e.g., `WHERE` clauses). -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] pub enum Expr { Constant(Constant), TypeLiteral(SimpleType), - AttributeLookup(AttributeLookup), - Binop(Binop), - Unop(Unop), + AttributeLookup(Var, Var), + Binop(BinOpKind, Box, Box), + Unop(UnOpKind, Box), } impl Expr { pub fn binop(kind: BinOpKind, left: Expr, right: Expr) -> Self { - Expr::Binop(Binop::new(kind, left, right)) + Expr::Binop(kind, Box::new(left), Box::new(right)) } pub fn unop(kind: UnOpKind, expr: Expr) -> Self { - Expr::Unop(Unop::new(kind, expr)) + Expr::Unop(kind, Box::new(expr)) } - pub fn attr_lookup(e: Var, a: Var) -> Self { - Expr::AttributeLookup(AttributeLookup::new(e, a)) - } -} - -impl fmt::Display for Expr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Expr::Constant(c) => write!(f, "{}", c), - Expr::TypeLiteral(t) => write!(f, "{}", t), - Expr::AttributeLookup(a) => write!(f, "{}", a), - Expr::Binop(b) => write!(f, "{}", b), - Expr::Unop(u) => write!(f, "{}", u), - } - } -} - -impl fmt::Debug for Expr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Expr::Constant(c) => write!(f, "Constant({:?})", c), - Expr::TypeLiteral(t) => write!(f, "TypeLiteral({:?})", t), - Expr::AttributeLookup(a) => write!(f, "AttributeLookup({:?})", a), - Expr::Binop(b) => write!(f, "Binop({:?})", b), - Expr::Unop(u) => write!(f, "Unop({:?})", u), - } - } -} - -/// Binary operation expression, e.g., `x.age + 9`, `x.running IS bool` -#[derive(PartialEq, Clone)] -pub struct Binop { - pub op: BinOpKind, - pub e1: Box, - pub e2: Box, -} - -impl Binop { - pub fn new(op: BinOpKind, e1: Expr, e2: Expr) -> Self { - Binop { - op, - e1: Box::new(e1), - e2: Box::new(e2), - } - } -} - -impl fmt::Display for Binop { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({} {} {})", self.e1, self.op, self.e2) - } -} - -impl fmt::Debug for Binop { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Binop({:?}, {:?}, {:?})", self.op, self.e1, self.e2) - } -} - -/// Unary operation expression, e.g., `-x.age`, `NOT x.running`. -#[derive(PartialEq, Clone)] -pub struct Unop { - pub op: UnOpKind, - pub e: Box, -} - -impl Unop { - pub fn new(op: UnOpKind, e: Expr) -> Self { - Unop { op, e: Box::new(e) } - } -} - -impl fmt::Display for Unop { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} {}", self.op, self.e) - } -} - -impl fmt::Debug for Unop { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Unop({:?}, {:?})", self.op, self.e) + /// Creates `entity.attribute` lookup expression + pub fn attr_lookup(entity: Var, attribute: Var) -> Self { + Expr::AttributeLookup(entity, attribute) } } /// Represents a constant expression (string, int, or boolean). -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] pub enum Constant { String(String), Int(i64), @@ -138,53 +59,8 @@ impl From for Constant { } } -impl fmt::Display for Constant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Constant::String(s) => write!(f, "{}", s), - Constant::Int(i) => write!(f, "{}", i), - Constant::Bool(b) => write!(f, "{}", b), - } - } -} - -impl fmt::Debug for Constant { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Constant::String(s) => write!(f, "'{}'", s), - Constant::Int(i) => write!(f, "{}", i), - Constant::Bool(b) => write!(f, "{}", b), - } - } -} - -/// Expression of the form `e.a` that accesses the attribute `a` of the entity `e`. -#[derive(PartialEq, Clone)] -pub struct AttributeLookup { - pub e: Var, - pub a: Var, -} - -impl AttributeLookup { - pub fn new(e: Var, a: Var) -> Self { - AttributeLookup { e, a } - } -} - -impl fmt::Display for AttributeLookup { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}.{}", self.e.0, self.a.0) - } -} - -impl fmt::Debug for AttributeLookup { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "AttributeLookup({:?}, {:?})", self.e, self.a) - } -} - /// Binary operator kinds -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] pub enum BinOpKind { // Arithmetic Add, @@ -206,69 +82,9 @@ pub enum BinOpKind { As, } -impl fmt::Display for BinOpKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - BinOpKind::Add => write!(f, "+"), - BinOpKind::Sub => write!(f, "-"), - BinOpKind::Mul => write!(f, "*"), - BinOpKind::Div => write!(f, "/"), - BinOpKind::Lt => write!(f, "<"), - BinOpKind::Gt => write!(f, ">"), - BinOpKind::Le => write!(f, "<="), - BinOpKind::Ge => write!(f, ">="), - BinOpKind::Eq => write!(f, "="), - BinOpKind::Ne => write!(f, "!="), - BinOpKind::And => write!(f, "AND"), - BinOpKind::Or => write!(f, "OR"), - BinOpKind::Is => write!(f, "IS"), - BinOpKind::As => write!(f, "AS"), - } - } -} - -impl fmt::Debug for BinOpKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - BinOpKind::Add => write!(f, "Add"), - BinOpKind::Sub => write!(f, "Sub"), - BinOpKind::Mul => write!(f, "Mul"), - BinOpKind::Div => write!(f, "Div"), - BinOpKind::Lt => write!(f, "Lt"), - BinOpKind::Gt => write!(f, "Gt"), - BinOpKind::Le => write!(f, "Le"), - BinOpKind::Ge => write!(f, "Ge"), - BinOpKind::Eq => write!(f, "Eq"), - BinOpKind::Ne => write!(f, "Ne"), - BinOpKind::And => write!(f, "And"), - BinOpKind::Or => write!(f, "Or"), - BinOpKind::Is => write!(f, "Is"), - BinOpKind::As => write!(f, "As"), - } - } -} - /// Unary operator kinds -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] pub enum UnOpKind { Neg, // - Not, // not } - -impl fmt::Display for UnOpKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - UnOpKind::Neg => write!(f, "-"), - UnOpKind::Not => write!(f, "NOT"), - } - } -} - -impl fmt::Debug for UnOpKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - UnOpKind::Neg => write!(f, "Neg"), - UnOpKind::Not => write!(f, "Not"), - } - } -} diff --git a/src/ast/label.rs b/src/ast/label.rs index 1017033..27f403a 100644 --- a/src/ast/label.rs +++ b/src/ast/label.rs @@ -1,6 +1,4 @@ -use std::fmt; - -#[derive(PartialEq, Clone, Default)] +#[derive(PartialEq, Clone, Default, Debug)] pub enum LabelType { Label(String), #[default] @@ -18,14 +16,3 @@ impl LabelType { LabelType::Or(Box::new(l1), Box::new(l2)) } } - -impl fmt::Debug for LabelType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - LabelType::Label(s) => write!(f, "Label({})", s), - LabelType::Star => write!(f, "Star"), - LabelType::And(l1, l2) => write!(f, "And({:?}, {:?})", l1, l2), - LabelType::Or(l1, l2) => write!(f, "Or({:?}, {:?})", l1, l2), - } - } -} diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 89ad659..e6849ef 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -6,7 +6,7 @@ mod types; mod var; pub use descriptor::{Descriptor, DescriptorType, PropertyType}; -pub use expr::{AttributeLookup, BinOpKind, Binop, Constant, Expr, UnOpKind, Unop}; +pub use expr::{BinOpKind, Constant, Expr, UnOpKind}; pub use label::LabelType; pub use pattern::{EdgeDirection, PathPattern, Quantifier}; pub use types::{BaseType, SimpleType}; diff --git a/src/ast/pattern.rs b/src/ast/pattern.rs index a3cf866..5bf30bf 100644 --- a/src/ast/pattern.rs +++ b/src/ast/pattern.rs @@ -1,6 +1,5 @@ use super::descriptor::Descriptor; use super::expr::Expr; -use std::fmt; /// Quantifiers for path pattern repetition #[derive(PartialEq, Clone, Copy, Debug)] @@ -15,7 +14,7 @@ pub enum Quantifier { Range(Option, Option), } -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] pub enum PathPattern { Node(Descriptor), Filter(Box, Expr), @@ -72,20 +71,6 @@ impl From for PathPattern { } } -impl fmt::Debug for PathPattern { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - PathPattern::Node(desc) => write!(f, "Node({:?})", desc), - PathPattern::Filter(p, e) => write!(f, "Filter({:?}, {:?})", p, e), - PathPattern::Edge(dir, desc) => write!(f, "Edge({:?}, {:?})", dir, desc), - PathPattern::Concat(l, r) => write!(f, "Concat({:?}, {:?})", l, r), - PathPattern::Union(l, r) => write!(f, "Union({:?}, {:?})", l, r), - PathPattern::Questioned(p) => write!(f, "Questioned({:?})", p), - PathPattern::Quantified(p, q) => write!(f, "Quantified({:?}, {:?})", p, q), - } - } -} - #[derive(PartialEq, Clone, Copy, Debug)] pub enum EdgeDirection { Right, diff --git a/src/ast/types.rs b/src/ast/types.rs index 8b0eb69..6a4b20b 100644 --- a/src/ast/types.rs +++ b/src/ast/types.rs @@ -1,52 +1,12 @@ -use std::fmt; - -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] pub enum SimpleType { Base(BaseType), Star, } -impl fmt::Debug for SimpleType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - SimpleType::Base(b) => write!(f, "Base({:?})", b), - SimpleType::Star => write!(f, "Star"), - } - } -} - -impl fmt::Display for SimpleType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - SimpleType::Base(b) => write!(f, "{}", b), - SimpleType::Star => write!(f, "*"), - } - } -} - -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] pub enum BaseType { Int, Bool, String, } - -impl fmt::Display for BaseType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - BaseType::Int => write!(f, "int"), - BaseType::Bool => write!(f, "bool"), - BaseType::String => write!(f, "str"), - } - } -} - -impl fmt::Debug for BaseType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - BaseType::Int => write!(f, "Int"), - BaseType::Bool => write!(f, "Bool"), - BaseType::String => write!(f, "String"), - } - } -} diff --git a/src/ast/var.rs b/src/ast/var.rs index a68c75c..6339f24 100644 --- a/src/ast/var.rs +++ b/src/ast/var.rs @@ -1,6 +1,4 @@ -use std::fmt; - -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] pub struct Var(pub String); impl From<&str> for Var { @@ -14,9 +12,3 @@ impl From for Var { Var(s) } } - -impl fmt::Debug for Var { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Var({})", self.0) - } -} diff --git a/src/grammar/descriptor.lalrpop b/src/grammar/descriptor.lalrpop index 7fb1fe5..5895665 100644 --- a/src/grammar/descriptor.lalrpop +++ b/src/grammar/descriptor.lalrpop @@ -5,13 +5,13 @@ pub Descriptor: Descriptor = { => Descriptor::default(), }; -pub DescriptorType: DescriptorType = { +DescriptorType: DescriptorType = { => DescriptorType::new(label, props), => DescriptorType::with_label(label), => DescriptorType::with_properties(props), }; -pub PropertyType: PropertyType = { +PropertyType: PropertyType = { "{" "}" => PropertyType::open(), "{" "}" => PropertyType::Open(<>), "{{" "}}" => PropertyType::closed(), diff --git a/src/grammar/label.lalrpop b/src/grammar/label.lalrpop index 1ca1605..c9ed871 100644 --- a/src/grammar/label.lalrpop +++ b/src/grammar/label.lalrpop @@ -1,4 +1,4 @@ -pub LabelType: LabelType = { +LabelType: LabelType = { #[precedence(level="2")] #[assoc(side="left")] "|" => LabelType::or(l, r), diff --git a/src/grammar/types.lalrpop b/src/grammar/types.lalrpop index a9db185..b4f5dc9 100644 --- a/src/grammar/types.lalrpop +++ b/src/grammar/types.lalrpop @@ -1,4 +1,4 @@ -pub SimpleType: SimpleType = { +SimpleType: SimpleType = { => SimpleType::Base(<>), "*" => SimpleType::Star, }; diff --git a/src/lib.rs b/src/lib.rs index fa1d170..e573ae4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,21 +4,15 @@ pub mod ast; lalrpop_mod!(pub grammar); -pub use crate::grammar::{ - DescriptorParser, DescriptorTypeParser, ExprParser, LabelTypeParser, PathPatternParser, - PropertyTypeParser, SimpleTypeParser, -}; +pub use crate::grammar::{DescriptorParser, ExprParser, PathPatternParser}; #[cfg(test)] mod tests { use super::*; - use ast::{ - AttributeLookup, Binop, Descriptor, DescriptorType, EdgeDirection, PathPattern, Quantifier, - Unop, - }; use ast::{ BaseType, BinOpKind, Constant, Expr, LabelType, PropertyType, SimpleType, UnOpKind, Var, }; + use ast::{Descriptor, DescriptorType, EdgeDirection, PathPattern, Quantifier}; use std::collections::HashMap; // ========================================== @@ -155,9 +149,9 @@ mod tests { let expected = PathPattern::Node(Descriptor { variable: None, descriptor_type: DescriptorType { - label: LabelType::And( - Box::new(LabelType::Label("Person".to_string())), - Box::new(LabelType::Label("Company".to_string())), + label: LabelType::and( + LabelType::Label("Person".to_string()), + LabelType::Label("Company".to_string()), ), properties: PropertyType::open(), }, @@ -172,14 +166,14 @@ mod tests { #[test] fn test_edge_right_empty() { let result = PathPatternParser::new().parse("->").unwrap(); - let expected = PathPattern::edge(EdgeDirection::Right, Descriptor::default(), None); + let expected = PathPattern::Edge(EdgeDirection::Right, Descriptor::default()); assert_eq!(result, expected); } #[test] fn test_edge_right_empty_alt() { let result = PathPatternParser::new().parse("-[]->").unwrap(); - let expected = PathPattern::edge(EdgeDirection::Right, Descriptor::default(), None); + let expected = PathPattern::Edge(EdgeDirection::Right, Descriptor::default()); assert_eq!(result, expected); } @@ -190,7 +184,7 @@ mod tests { .unwrap(); let mut props = HashMap::new(); props.insert("a".to_string(), SimpleType::Base(BaseType::Int)); - let expected = PathPattern::edge( + let expected = PathPattern::Edge( EdgeDirection::Right, Descriptor { variable: Some(Var("x".to_string())), @@ -199,7 +193,6 @@ mod tests { properties: PropertyType::Open(props), }, }, - None, ); assert_eq!(result, expected); } @@ -207,14 +200,14 @@ mod tests { #[test] fn test_edge_left_empty() { let result = PathPatternParser::new().parse("<-").unwrap(); - let expected = PathPattern::edge(EdgeDirection::Left, Descriptor::default(), None); + let expected = PathPattern::Edge(EdgeDirection::Left, Descriptor::default()); assert_eq!(result, expected); } #[test] fn test_edge_left_empty_alt() { let result = PathPatternParser::new().parse("<-[]-").unwrap(); - let expected = PathPattern::edge(EdgeDirection::Left, Descriptor::default(), None); + let expected = PathPattern::Edge(EdgeDirection::Left, Descriptor::default()); assert_eq!(result, expected); } @@ -225,7 +218,7 @@ mod tests { .unwrap(); let mut props = HashMap::new(); props.insert("a".to_string(), SimpleType::Base(BaseType::Int)); - let expected = PathPattern::edge( + let expected = PathPattern::Edge( EdgeDirection::Left, Descriptor { variable: Some(Var("x".to_string())), @@ -234,7 +227,6 @@ mod tests { properties: PropertyType::Open(props), }, }, - None, ); assert_eq!(result, expected); } @@ -242,14 +234,14 @@ mod tests { #[test] fn test_edge_non_directional_empty() { let result = PathPatternParser::new().parse("~").unwrap(); - let expected = PathPattern::edge(EdgeDirection::None, Descriptor::default(), None); + let expected = PathPattern::Edge(EdgeDirection::None, Descriptor::default()); assert_eq!(result, expected); } #[test] fn test_edge_non_directional_empty_alt() { let result = PathPatternParser::new().parse("~[]~").unwrap(); - let expected = PathPattern::edge(EdgeDirection::None, Descriptor::default(), None); + let expected = PathPattern::Edge(EdgeDirection::None, Descriptor::default()); assert_eq!(result, expected); } @@ -260,7 +252,7 @@ mod tests { .unwrap(); let mut props = HashMap::new(); props.insert("a".to_string(), SimpleType::Base(BaseType::Int)); - let expected = PathPattern::edge( + let expected = PathPattern::Edge( EdgeDirection::None, Descriptor { variable: Some(Var("x".to_string())), @@ -269,7 +261,6 @@ mod tests { properties: PropertyType::Open(props), }, }, - None, ); assert_eq!(result, expected); } @@ -325,22 +316,19 @@ mod tests { #[test] fn test_filter_attribute_gt() { let result = PathPatternParser::new().parse("(x where x.a>10)").unwrap(); - let expected = PathPattern::Filter( - Box::new(PathPattern::Node(Descriptor { + let expected = PathPattern::filter( + PathPattern::Node(Descriptor { variable: Some(Var("x".to_string())), descriptor_type: DescriptorType { label: LabelType::Star, properties: PropertyType::open(), }, - })), - Expr::Binop(Binop::new( + }), + Expr::binop( BinOpKind::Gt, - Expr::AttributeLookup(AttributeLookup::new( - Var("x".to_string()), - Var("a".to_string()), - )), + Expr::attr_lookup(Var("x".to_string()), Var("a".to_string())), Expr::Constant(Constant::Int(10)), - )), + ), ); assert_eq!(result, expected); } @@ -350,35 +338,35 @@ mod tests { let result = PathPatternParser::new() .parse("(x where 11>10 and (1 = 2 or 3>='1'))") .unwrap(); - let expected = PathPattern::Filter( - Box::new(PathPattern::Node(Descriptor { + let expected = PathPattern::filter( + PathPattern::Node(Descriptor { variable: Some(Var("x".to_string())), descriptor_type: DescriptorType { label: LabelType::Star, properties: PropertyType::open(), }, - })), - Expr::Binop(Binop::new( + }), + Expr::binop( BinOpKind::And, - Expr::Binop(Binop::new( + Expr::binop( BinOpKind::Gt, Expr::Constant(Constant::Int(11)), Expr::Constant(Constant::Int(10)), - )), - Expr::Binop(Binop::new( + ), + Expr::binop( BinOpKind::Or, - Expr::Binop(Binop::new( + Expr::binop( BinOpKind::Eq, Expr::Constant(Constant::Int(1)), Expr::Constant(Constant::Int(2)), - )), - Expr::Binop(Binop::new( + ), + Expr::binop( BinOpKind::Ge, Expr::Constant(Constant::Int(3)), Expr::Constant(Constant::String("1".to_string())), - )), - )), - )), + ), + ), + ), ); assert_eq!(result, expected); } @@ -395,8 +383,8 @@ mod tests { properties: PropertyType::open(), }, }); - let y = PathPattern::Filter( - Box::new(PathPattern::Edge( + let y = PathPattern::filter( + PathPattern::Edge( EdgeDirection::Right, Descriptor { variable: Some(Var("y".to_string())), @@ -405,15 +393,12 @@ mod tests { properties: PropertyType::open(), }, }, - )), - Expr::Binop(Binop::new( + ), + Expr::binop( BinOpKind::Gt, - Expr::AttributeLookup(AttributeLookup::new( - Var("y".to_string()), - Var("a".to_string()), - )), + Expr::attr_lookup(Var("y".to_string()), Var("a".to_string())), Expr::Constant(Constant::Int(10)), - )), + ), ); let z = PathPattern::Node(Descriptor { variable: Some(Var("z".to_string())), @@ -431,35 +416,35 @@ mod tests { let result = PathPatternParser::new() .parse("(x where 11 = 10 and 1 = 2 or 1=2)") .unwrap(); - let expected = PathPattern::Filter( - Box::new(PathPattern::Node(Descriptor { + let expected = PathPattern::filter( + PathPattern::Node(Descriptor { variable: Some(Var("x".to_string())), descriptor_type: DescriptorType { label: LabelType::Star, properties: PropertyType::open(), }, - })), - Expr::Binop(Binop::new( + }), + Expr::binop( BinOpKind::Or, - Expr::Binop(Binop::new( + Expr::binop( BinOpKind::And, - Expr::Binop(Binop::new( + Expr::binop( BinOpKind::Eq, Expr::Constant(Constant::Int(11)), Expr::Constant(Constant::Int(10)), - )), - Expr::Binop(Binop::new( + ), + Expr::binop( BinOpKind::Eq, Expr::Constant(Constant::Int(1)), Expr::Constant(Constant::Int(2)), - )), - )), - Expr::Binop(Binop::new( + ), + ), + Expr::binop( BinOpKind::Eq, Expr::Constant(Constant::Int(1)), Expr::Constant(Constant::Int(2)), - )), - )), + ), + ), ); assert_eq!(result, expected); } @@ -469,23 +454,23 @@ mod tests { let result = PathPatternParser::new() .parse("(x where true and 1>2)") .unwrap(); - let expected = PathPattern::Filter( - Box::new(PathPattern::Node(Descriptor { + let expected = PathPattern::filter( + PathPattern::Node(Descriptor { variable: Some(Var("x".to_string())), descriptor_type: DescriptorType { label: LabelType::Star, properties: PropertyType::open(), }, - })), - Expr::Binop(Binop::new( + }), + Expr::binop( BinOpKind::And, Expr::Constant(Constant::Bool(true)), - Expr::Binop(Binop::new( + Expr::binop( BinOpKind::Gt, Expr::Constant(Constant::Int(1)), Expr::Constant(Constant::Int(2)), - )), - )), + ), + ), ); assert_eq!(result, expected); } @@ -495,29 +480,23 @@ mod tests { let result = PathPatternParser::new() .parse("(x where x.a>x.b>1)") .unwrap(); - let expected = PathPattern::Filter( - Box::new(PathPattern::Node(Descriptor { + let expected = PathPattern::filter( + PathPattern::Node(Descriptor { variable: Some(Var("x".to_string())), descriptor_type: DescriptorType { label: LabelType::Star, properties: PropertyType::open(), }, - })), - Expr::Binop(Binop::new( + }), + Expr::binop( BinOpKind::Gt, - Expr::Binop(Binop::new( + Expr::binop( BinOpKind::Gt, - Expr::AttributeLookup(AttributeLookup::new( - Var("x".to_string()), - Var("a".to_string()), - )), - Expr::AttributeLookup(AttributeLookup::new( - Var("x".to_string()), - Var("b".to_string()), - )), - )), + Expr::attr_lookup(Var("x".to_string()), Var("a".to_string())), + Expr::attr_lookup(Var("x".to_string()), Var("b".to_string())), + ), Expr::Constant(Constant::Int(1)), - )), + ), ); assert_eq!(result, expected); } @@ -527,21 +506,18 @@ mod tests { let result = PathPatternParser::new() .parse("(x WHERE not x.status)") .unwrap(); - let expected = PathPattern::Filter( - Box::new(PathPattern::Node(Descriptor { + let expected = PathPattern::filter( + PathPattern::Node(Descriptor { variable: Some(Var("x".to_string())), descriptor_type: DescriptorType { label: LabelType::Star, properties: PropertyType::open(), }, - })), - Expr::Unop(Unop::new( + }), + Expr::unop( UnOpKind::Not, - Expr::AttributeLookup(AttributeLookup::new( - Var("x".to_string()), - Var("status".to_string()), - )), - )), + Expr::attr_lookup(Var("x".to_string()), Var("status".to_string())), + ), ); assert_eq!(result, expected); } @@ -551,25 +527,22 @@ mod tests { let result = PathPatternParser::new() .parse("(x WHERE -x.status>0)") .unwrap(); - let expected = PathPattern::Filter( - Box::new(PathPattern::Node(Descriptor { + let expected = PathPattern::filter( + PathPattern::Node(Descriptor { variable: Some(Var("x".to_string())), descriptor_type: DescriptorType { label: LabelType::Star, properties: PropertyType::open(), }, - })), - Expr::Binop(Binop::new( + }), + Expr::binop( BinOpKind::Gt, - Expr::Unop(Unop::new( + Expr::unop( UnOpKind::Neg, - Expr::AttributeLookup(AttributeLookup::new( - Var("x".to_string()), - Var("status".to_string()), - )), - )), + Expr::attr_lookup(Var("x".to_string()), Var("status".to_string())), + ), Expr::Constant(Constant::Int(0)), - )), + ), ); assert_eq!(result, expected); } @@ -579,25 +552,22 @@ mod tests { let result = PathPatternParser::new() .parse("((x) WHERE -x.status>0)") .unwrap(); - let expected = PathPattern::Filter( - Box::new(PathPattern::Node(Descriptor { + let expected = PathPattern::filter( + PathPattern::Node(Descriptor { variable: Some(Var("x".to_string())), descriptor_type: DescriptorType { label: LabelType::Star, properties: PropertyType::open(), }, - })), - Expr::Binop(Binop::new( + }), + Expr::binop( BinOpKind::Gt, - Expr::Unop(Unop::new( + Expr::unop( UnOpKind::Neg, - Expr::AttributeLookup(AttributeLookup::new( - Var("x".to_string()), - Var("status".to_string()), - )), - )), + Expr::attr_lookup(Var("x".to_string()), Var("status".to_string())), + ), Expr::Constant(Constant::Int(0)), - )), + ), ); assert_eq!(result, expected); } diff --git a/src/main.rs b/src/main.rs index 296e6f6..1ecf2b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,16 +4,15 @@ use std::io::{self, Write}; fn main() { println!("=== FPPC Parser Interactive Console ==="); println!("Commands:"); - println!(" label - Parse as LabelType"); - println!(" simple - Parse as SimpleType"); - println!(" property - Parse as PropertyType"); - println!(" descriptor_type - Parse as DescriptorType"); + println!(" expr - Parse as Expr"); println!(" descriptor - Parse as Descriptor"); println!(" path - Parse as PathPattern"); - println!(" expr - Parse as Expr"); + println!(" pretty - Toggle pretty printing"); println!(" quit - Exit"); println!(); + let mut pretty = false; + loop { print!("> "); io::stdout().flush().unwrap(); @@ -30,51 +29,50 @@ fn main() { } if input == "quit" || input == "exit" { - println!("Goodbye!"); break; } + if input == "pretty" { + pretty = !pretty; + println!("Pretty printing: {}", if pretty { "on" } else { "off" }); + continue; + } + let parts: Vec<&str> = input.splitn(2, ' ').collect(); if parts.len() < 2 { - eprintln!("Error: Please provide a command and input. Example: node (p: Person)"); + eprintln!("Error: Please provide a command and input. Example: path (p: Person)"); continue; } let command = parts[0]; let parse_input = parts[1]; + macro_rules! print_result { + ($result:expr) => { + if pretty { + println!("✓ Valid: {:#?}", $result) + } else { + println!("✓ Valid: {:?}", $result) + } + }; + } + match command { - "label" => match LabelTypeParser::new().parse(parse_input) { - Ok(result) => println!("✓ Valid: {:?}", result), - Err(e) => eprintln!("✗ Parse error: {}", e), - }, - "simple" => match SimpleTypeParser::new().parse(parse_input) { - Ok(result) => println!("✓ Valid: {:?}", result), - Err(e) => eprintln!("✗ Parse error: {}", e), - }, - "property" => match PropertyTypeParser::new().parse(parse_input) { - Ok(result) => println!("✓ Valid: {:?}", result), - Err(e) => eprintln!("✗ Parse error: {}", e), - }, - "descriptor_type" => match DescriptorTypeParser::new().parse(parse_input) { - Ok(result) => println!("✓ Valid: {:?}", result), + "expr" => match ExprParser::new().parse(parse_input) { + Ok(result) => print_result!(result), Err(e) => eprintln!("✗ Parse error: {}", e), }, "descriptor" => match DescriptorParser::new().parse(parse_input) { - Ok(result) => println!("✓ Valid: {:?}", result), + Ok(result) => print_result!(result), Err(e) => eprintln!("✗ Parse error: {}", e), }, "path" => match PathPatternParser::new().parse(parse_input) { - Ok(result) => println!("✓ Valid: {:?}", result), - Err(e) => eprintln!("✗ Parse error: {}", e), - }, - "expr" => match ExprParser::new().parse(parse_input) { - Ok(result) => println!("✓ Valid: {:?}", result), + Ok(result) => print_result!(result), Err(e) => eprintln!("✗ Parse error: {}", e), }, _ => { eprintln!( - "Unknown command: {}. Use: label, simple, property, descriptor_type, descriptor, filler, node, or expr", + "Unknown command: {}. Use: expr, descriptor, or path", command ); }