Merge pull request #85 from ryangjchandler/feature/first-class-callables

This commit is contained in:
Ryan Chandler 2022-09-15 01:10:26 +01:00 committed by GitHub
commit 8b27266f05
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 0 deletions

View File

@ -414,6 +414,7 @@ pub struct Use {
#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
Empty,
VariadicPlaceholder,
ErrorSuppress {
expr: Box<Self>,
},

View File

@ -2028,6 +2028,16 @@ impl Parser {
unpack = true;
}
if unpack && self.current.kind == TokenKind::RightParen {
args.push(Arg {
name: None,
unpack: false,
value: Expression::VariadicPlaceholder,
});
break;
}
let value = self.expression(Precedence::Lowest)?;
args.push(Arg {
@ -2100,6 +2110,16 @@ impl Parser {
unpack = true;
}
if unpack && self.current.kind == TokenKind::RightParen {
args.push(Arg {
name: None,
unpack: false,
value: Expression::VariadicPlaceholder,
});
break;
}
let value = self.expression(Precedence::Lowest)?;
args.push(Arg {
@ -2161,6 +2181,16 @@ impl Parser {
unpack = true;
}
if unpack && self.current.kind == TokenKind::RightParen {
args.push(Arg {
name: None,
unpack: false,
value: Expression::VariadicPlaceholder,
});
break;
}
let value = self.expression(Precedence::Lowest)?;
args.push(Arg {
@ -3999,6 +4029,55 @@ mod tests {
);
}
#[test]
fn first_class_callables() {
assert_ast(
"<?php foo(...);",
&[expr!(Expression::Call {
target: Box::new(Expression::Identifier { name: "foo".into() }),
args: vec![Arg {
name: None,
unpack: false,
value: Expression::VariadicPlaceholder
}]
})],
);
}
#[test]
fn first_class_callable_method() {
assert_ast(
"<?php $this->foo(...);",
&[expr!(Expression::MethodCall {
target: Box::new(Expression::Variable {
name: "this".into()
}),
method: Box::new(Expression::Identifier { name: "foo".into() }),
args: vec![Arg {
name: None,
unpack: false,
value: Expression::VariadicPlaceholder
}]
})],
);
}
#[test]
fn first_class_callable_static_method() {
assert_ast(
"<?php A::foo(...);",
&[expr!(Expression::StaticMethodCall {
target: Box::new(Expression::Identifier { name: "A".into() }),
method: "foo".into(),
args: vec![Arg {
name: None,
unpack: false,
value: Expression::VariadicPlaceholder
}]
})],
);
}
fn assert_ast(source: &str, expected: &[Statement]) {
let mut lexer = Lexer::new(None);
let tokens = lexer.tokenize(source).unwrap();