Reimplement method calls as binary operations.
This commit is contained in:
parent
dece06f8c6
commit
78f7593520
10 changed files with 102 additions and 54 deletions
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -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),
|
||||
])
|
||||
}
|
||||
|
|
Reference in a new issue