diff --git a/huia-parser/src/ast/atom.rs b/huia-parser/src/ast/atom.rs index 13077eb..f8ecaef 100644 --- a/huia-parser/src/ast/atom.rs +++ b/huia-parser/src/ast/atom.rs @@ -35,7 +35,7 @@ impl<'a> From> for Atom { let len = value.len(); let value = value.get(1..len).unwrap().to_string(); Atom { - value: value, + value, location: InputLocation::from(pair.into_span()), } } @@ -44,14 +44,14 @@ impl<'a> From> for Atom { let len = value.len(); let value = value.get(0..len - 1).unwrap().to_string(); Atom { - value: value, + value, location: InputLocation::from(pair.into_span()), } } Rule::ident => { let value = pair.clone().into_span().as_str().to_string(); Atom { - value: value, + value, location: InputLocation::from(pair.into_span()), } } diff --git a/huia-parser/src/ast/binary.rs b/huia-parser/src/ast/binary.rs index c19d97b..019fa10 100644 --- a/huia-parser/src/ast/binary.rs +++ b/huia-parser/src/ast/binary.rs @@ -24,6 +24,7 @@ pub enum Operator { LessThanOrEqual, LogicalAnd, LogicalOr, + Method, Minus, Modulus, Multiply, @@ -106,6 +107,10 @@ impl<'a> From> for Binary { value: Operator::LogicalOr, location: InputLocation::from(pair.into_span()), }, + Rule::method => Binary { + value: Operator::Method, + location: InputLocation::from(pair.into_span()), + }, Rule::minus => Binary { value: Operator::Minus, location: InputLocation::from(pair.into_span()), diff --git a/huia-parser/src/ast/float.rs b/huia-parser/src/ast/float.rs index 8a5e34e..bf22087 100644 --- a/huia-parser/src/ast/float.rs +++ b/huia-parser/src/ast/float.rs @@ -33,7 +33,7 @@ impl<'a> From> for Float { Rule::float => { let value = pair.clone().into_span().as_str().parse().unwrap(); Float { - value: value, + value, location: InputLocation::from(pair.into_span()), } } diff --git a/huia-parser/src/ast/identifier.rs b/huia-parser/src/ast/identifier.rs index c92e6b3..b41de29 100644 --- a/huia-parser/src/ast/identifier.rs +++ b/huia-parser/src/ast/identifier.rs @@ -33,7 +33,7 @@ impl<'a> From> for Identifier { Rule::ident => { let value = pair.clone().into_span().as_str().to_string(); Identifier { - value: value, + value, location: InputLocation::from(pair.into_span()), } } diff --git a/huia-parser/src/ast/local.rs b/huia-parser/src/ast/local.rs index f2a9bcf..912cb0a 100644 --- a/huia-parser/src/ast/local.rs +++ b/huia-parser/src/ast/local.rs @@ -33,7 +33,7 @@ impl<'a> From> for Local { Rule::local => { let value = pair.clone().into_span().as_str().to_string(); Local { - value: value, + value, location: InputLocation::from(pair.into_span()), } } diff --git a/huia-parser/src/ast/string.rs b/huia-parser/src/ast/string.rs index d1a6fda..bb2ee4a 100644 --- a/huia-parser/src/ast/string.rs +++ b/huia-parser/src/ast/string.rs @@ -23,7 +23,7 @@ impl<'a> From> for String { .as_str() .to_string(); String { - value: value, + value, location: InputLocation::from(pair.into_span()), } } diff --git a/huia-parser/src/ast/term.rs b/huia-parser/src/ast/term.rs index f6d09ca..faa58d7 100644 --- a/huia-parser/src/ast/term.rs +++ b/huia-parser/src/ast/term.rs @@ -39,7 +39,6 @@ pub enum NodeType { Declaration, Definition, Local, - MethodCall, } #[derive(Debug, Clone)] @@ -63,7 +62,6 @@ enum Inner { Integer(Integer), Local(Local), Map(Vec<(Term, Term)>), - MethodCall(Identifier, Box, Vec), String(String), Unary(Unary, Box), } @@ -105,7 +103,6 @@ impl Term { Inner::Integer(_) => NodeType::Integer, Inner::Local(_) => NodeType::Local, Inner::Map(_) => NodeType::Map, - Inner::MethodCall(_, _, _) => NodeType::MethodCall, Inner::String(_) => NodeType::String, Inner::Unary(_, _) => NodeType::Unary, } @@ -212,15 +209,6 @@ impl Term { } } - pub fn method_call(&self) -> Option<(&Identifier, &Term, &Vec)> { - match self.inner { - Inner::MethodCall(ref name, ref receiver, ref arguments) => { - Some((name, receiver, arguments)) - } - _ => None, - } - } - pub fn string(&self) -> Option<&String> { match self.inner { Inner::String(ref node) => Some(node), @@ -373,25 +361,25 @@ impl<'a> From> for Term { inner: Inner::Map(contents), } } - Rule::method_call => { - let mut inner = pair.clone().into_inner(); - let receiver = Term::from(inner.next().unwrap()); - let mut call = inner.next().unwrap().into_inner(); - let name = Identifier::from(call.next().unwrap()); - let mut args = Vec::new(); - for argument in call { - match argument.as_rule() { - Rule::call_argument => { - args.push(Term::from(argument.into_inner().next().unwrap())) - } - _ => unreachable!("Expected method_call argument but found {:?}", argument), - } - } - Term { - location: InputLocation::from(pair), - inner: Inner::MethodCall(name, Box::new(receiver), args), - } - } + // Rule::method_call => { + // let mut inner = pair.clone().into_inner(); + // let receiver = Term::from(inner.next().unwrap()); + // let mut call = inner.next().unwrap().into_inner(); + // let name = Identifier::from(call.next().unwrap()); + // let mut args = Vec::new(); + // for argument in call { + // match argument.as_rule() { + // Rule::call_argument => { + // args.push(Term::from(argument.into_inner().next().unwrap())) + // } + // _ => unreachable!("Expected method_call argument but found {:?}", argument), + // } + // } + // Term { + // location: InputLocation::from(pair), + // inner: Inner::MethodCall(name, Box::new(receiver), args), + // } + // } Rule::string => Term { location: InputLocation::from(pair.clone()), inner: Inner::String(String::from(pair)), @@ -770,30 +758,74 @@ mod test { #[test] fn test_method_call() { let terms = Term::input("greeter.hello(\"Marty\", \"McFly\")").unwrap(); - assert_eq!(terms[0].node_type(), NodeType::MethodCall); + assert_eq!(terms[0].node_type(), NodeType::Binary); - let (method_name, receiver, arguments) = terms[0].method_call().unwrap(); + let (op, lhs, rhs) = terms[0].binary().unwrap(); + assert_eq!(op.value_ref(), &binary::Operator::Method); + + assert_eq!(lhs.node_type(), NodeType::Local); + assert_eq!(lhs.local().unwrap().value_ref(), "greeter"); + + assert_eq!(rhs.node_type(), NodeType::Call); + let (method_name, arguments) = rhs.call().unwrap(); assert_eq!(method_name.value_ref(), "hello"); - assert_eq!(receiver.local().unwrap().value_ref(), "greeter"); assert_eq!(arguments[0].string().unwrap().value_ref(), "Marty"); assert_eq!(arguments[1].string().unwrap().value_ref(), "McFly"); } + #[test] + fn test_method_call_multi() { + let terms = Term::input("delorean.target_year(1985).accellerate(88)").unwrap(); + + let (op0, lhs0, rhs0) = terms[0].binary().unwrap(); + assert_eq!(op0.value_ref(), &binary::Operator::Method); + + assert_eq!(lhs0.node_type(), NodeType::Local); + assert_eq!(lhs0.local().unwrap().value_ref(), "delorean"); + assert_eq!(rhs0.node_type(), NodeType::Binary); + + let (op1, lhs1, rhs1) = rhs0.binary().unwrap(); + assert_eq!(op1.value_ref(), &binary::Operator::Method); + + assert_eq!(lhs1.node_type(), NodeType::Call); + let (method_name0, arguments0) = lhs1.call().unwrap(); + assert_eq!(method_name0.value_ref(), "target_year"); + assert_eq!(*arguments0[0].integer().unwrap().value_ref(), 1985); + + let (method_name1, arguments1) = rhs1.call().unwrap(); + assert_eq!(method_name1.value_ref(), "accellerate"); + assert_eq!(*arguments1[0].integer().unwrap().value_ref(), 88); + } + #[test] fn test_method_call_empty() { let terms = Term::input("greeter.hello()").unwrap(); - let (method_name, receiver, arguments) = terms[0].method_call().unwrap(); + + let (op, lhs, rhs) = terms[0].binary().unwrap(); + assert_eq!(op.value_ref(), &binary::Operator::Method); + + assert_eq!(lhs.node_type(), NodeType::Local); + assert_eq!(lhs.local().unwrap().value_ref(), "greeter"); + + assert_eq!(rhs.node_type(), NodeType::Call); + let (method_name, arguments) = rhs.call().unwrap(); assert_eq!(method_name.value_ref(), "hello"); - assert_eq!(receiver.local().unwrap().value_ref(), "greeter"); assert_eq!(arguments.len(), 0); } #[test] fn test_method_call_on_typename() { let terms = Term::input("My.Greeter.hello()").unwrap(); - let (method_name, receiver, arguments) = terms[0].method_call().unwrap(); + + let (op, lhs, rhs) = terms[0].binary().unwrap(); + assert_eq!(op.value_ref(), &binary::Operator::Method); + + assert_eq!(lhs.node_type(), NodeType::Ty); + assert_eq!(lhs.ty().unwrap().value_ref(), "My.Greeter"); + + assert_eq!(rhs.node_type(), NodeType::Call); + let (method_name, arguments) = rhs.call().unwrap(); assert_eq!(method_name.value_ref(), "hello"); - assert_eq!(receiver.ty().unwrap().value_ref(), "My.Greeter"); assert_eq!(arguments.len(), 0); } diff --git a/huia-parser/src/ast/ty.rs b/huia-parser/src/ast/ty.rs index 4caacde..9c1c2ad 100644 --- a/huia-parser/src/ast/ty.rs +++ b/huia-parser/src/ast/ty.rs @@ -39,7 +39,7 @@ impl<'a> From> for Ty { Rule::typename => { let value = pair.clone().into_span().as_str().to_string(); Ty { - value: value, + value, location: InputLocation::from(pair.into_span()), } } diff --git a/huia-parser/src/grammar.pest b/huia-parser/src/grammar.pest index efd8e3c..1a19923 100644 --- a/huia-parser/src/grammar.pest +++ b/huia-parser/src/grammar.pest @@ -7,15 +7,13 @@ reserved = { "end" | "let" | "true" | "false" } expression = _{ infix | expression_inner } infix = { expression_inner ~ (binary_operator ~ expression_inner)+ } -expression_inner = _{ call | method_call | definition | declaration | unary | literal | local | braced_expression } +expression_inner = _{ call | definition | declaration | unary | literal | local | braced_expression } braced_expression = _{ "(" ~ expression ~ ")" } declaration = { "let" ~ ident ~ assign ~ expression } unary = { unary_operator ~ (literal | local | braced_expression) } -method_call = { (literal | local | unary | braced_expression) ~ "." ~ call } - call = { ident ~ call_arguments } call_arguments = _{ "(" ~ (call_argument ~ ("," ~ call_argument)* )? ~ ")" } call_argument = { expression } @@ -94,6 +92,7 @@ bitwise_and = { "&" } bitwise_or = { "|" } bitwise_xor = { "^" } assign = { "=" } +method = { "." } all_operators = _{ exponent | multiply | divide | modulus | @@ -104,7 +103,7 @@ all_operators = _{ not_equal | equal | logical_and | logical_or | logical_not | bitwise_and | bitwise_or | bitwise_xor | - assign + assign | method } binary_operator = _{ exponent | @@ -115,7 +114,8 @@ binary_operator = _{ greater_than_or_equal | greater_than | not_equal | equal | logical_and | logical_or | - bitwise_and | bitwise_or | bitwise_xor + bitwise_and | bitwise_or | bitwise_xor | + method } unary_operator = _{ plus | minus | logical_not } diff --git a/huia-parser/src/precedence.rs b/huia-parser/src/precedence.rs index 8d80e91..32c62c1 100644 --- a/huia-parser/src/precedence.rs +++ b/huia-parser/src/precedence.rs @@ -12,23 +12,34 @@ lazy_static! { fn build_precedence_climber() -> PrecClimber { PrecClimber::new(vec![ - Operator::new(Rule::assign, Assoc::Right), + Operator::new(Rule::method, Assoc::Right), + Operator::new(Rule::logical_or, Assoc::Left), Operator::new(Rule::logical_and, Assoc::Left), - Operator::new(Rule::equal, Assoc::Right) | Operator::new(Rule::not_equal, Assoc::Right), + + Operator::new(Rule::equal, Assoc::Right) + | Operator::new(Rule::not_equal, Assoc::Right), + Operator::new(Rule::greater_than_or_equal, Assoc::Left) | Operator::new(Rule::less_than_or_equal, Assoc::Left) | Operator::new(Rule::greater_than, Assoc::Left) | Operator::new(Rule::less_than, Assoc::Left), + Operator::new(Rule::bitwise_xor, Assoc::Left) | Operator::new(Rule::bitwise_or, Assoc::Left), + Operator::new(Rule::bitwise_and, Assoc::Left), + Operator::new(Rule::shift_right, Assoc::Left) | Operator::new(Rule::shift_left, Assoc::Left), - Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Left), + + Operator::new(Rule::plus, Assoc::Left) + | Operator::new(Rule::minus, Assoc::Left), + Operator::new(Rule::modulus, Assoc::Left) | Operator::new(Rule::divide, Assoc::Left) | Operator::new(Rule::multiply, Assoc::Left), + Operator::new(Rule::exponent, Assoc::Right), ]) }