Reimplement method calls as binary operations.

This commit is contained in:
James Harton 2019-03-07 11:07:51 +13:00
parent dece06f8c6
commit 78f7593520
10 changed files with 102 additions and 54 deletions

View file

@ -35,7 +35,7 @@ impl<'a> From<Pair<'a, Rule>> 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<Pair<'a, Rule>> 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()),
}
}

View file

@ -24,6 +24,7 @@ pub enum Operator {
LessThanOrEqual,
LogicalAnd,
LogicalOr,
Method,
Minus,
Modulus,
Multiply,
@ -106,6 +107,10 @@ impl<'a> From<Pair<'a, Rule>> 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()),

View file

@ -33,7 +33,7 @@ impl<'a> From<Pair<'a, Rule>> for Float {
Rule::float => {
let value = pair.clone().into_span().as_str().parse().unwrap();
Float {
value: value,
value,
location: InputLocation::from(pair.into_span()),
}
}

View file

@ -33,7 +33,7 @@ impl<'a> From<Pair<'a, Rule>> for Identifier {
Rule::ident => {
let value = pair.clone().into_span().as_str().to_string();
Identifier {
value: value,
value,
location: InputLocation::from(pair.into_span()),
}
}

View file

@ -33,7 +33,7 @@ impl<'a> From<Pair<'a, Rule>> for Local {
Rule::local => {
let value = pair.clone().into_span().as_str().to_string();
Local {
value: value,
value,
location: InputLocation::from(pair.into_span()),
}
}

View file

@ -23,7 +23,7 @@ impl<'a> From<Pair<'a, Rule>> for String {
.as_str()
.to_string();
String {
value: value,
value,
location: InputLocation::from(pair.into_span()),
}
}

View file

@ -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<Term>, Vec<Term>),
String(String),
Unary(Unary, Box<Term>),
}
@ -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<Term>)> {
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<Pair<'a, Rule>> 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);
}

View file

@ -39,7 +39,7 @@ impl<'a> From<Pair<'a, Rule>> for Ty {
Rule::typename => {
let value = pair.clone().into_span().as_str().to_string();
Ty {
value: value,
value,
location: InputLocation::from(pair.into_span()),
}
}

View file

@ -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 }

View file

@ -12,23 +12,34 @@ lazy_static! {
fn build_precedence_climber() -> PrecClimber<Rule> {
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),
])
}