parser: support prefix expressions like !

This commit is contained in:
Ryan Chandler 2022-07-28 16:08:14 +01:00
parent 08e7c99f25
commit d955cd28da
No known key found for this signature in database
GPG Key ID: F113BCADDB3B0CCA
3 changed files with 35 additions and 0 deletions

3
phpast/samples/bang.php Normal file
View File

@ -0,0 +1,3 @@
<?php
! $foo;

View File

@ -273,6 +273,7 @@ pub enum Expression {
Bool(bool),
ArrayIndex(Box<Self>, Option<Box<Self>>),
Null,
BooleanNot(Box<Self>),
}
#[derive(Debug, Clone, PartialEq, Serialize)]

View File

@ -912,6 +912,16 @@ impl Parser {
Expression::New(Box::new(target), args)
},
_ if is_prefix(&self.current.kind) => {
let op = self.current.kind.clone();
self.next();
let rbp = prefix_binding_power(&op);
let rhs = self.expression(rbp)?;
prefix(&op, rhs)
},
_ => todo!("expr lhs: {:?}", self.current.kind),
};
@ -1077,6 +1087,27 @@ impl Parser {
}
}
fn is_prefix(op: &TokenKind) -> bool {
match op {
TokenKind::Bang => true,
_ => false
}
}
fn prefix_binding_power(op: &TokenKind) -> u8 {
match op {
TokenKind::Bang => 99,
_ => unreachable!()
}
}
fn prefix(op: &TokenKind, rhs: Expression) -> Expression {
match op {
TokenKind::Bang => Expression::BooleanNot(Box::new(rhs)),
_ => unreachable!()
}
}
fn infix(lhs: Expression, op: TokenKind, rhs: Expression) -> Expression {
if op == TokenKind::Equals {
return Expression::Assign(Box::new(lhs), Box::new(rhs));