chore: remove fallback expression parser (#181)

Signed-off-by: azjezz <azjezz@protonmail.com>
This commit is contained in:
Saif Eddin Gmati 2022-12-08 21:34:16 +01:00 committed by GitHub
parent 00834ed3ff
commit bd2023c3c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 473 additions and 200 deletions

View File

@ -1514,6 +1514,13 @@ fn identifier_to_keyword(ident: &[u8]) -> Option<TokenKind> {
b"var" => TokenKind::Var,
b"yield" => TokenKind::Yield,
b"__DIR__" => TokenKind::DirConstant,
b"__FILE__" => TokenKind::FileConstant,
b"__LINE__" => TokenKind::LineConstant,
b"__FUNCTION__" => TokenKind::FunctionConstant,
b"__CLASS__" => TokenKind::ClassConstant,
b"__METHOD__" => TokenKind::MethodConstant,
b"__TRAIT__" => TokenKind::TraitConstant,
b"__NAMESPACE__" => TokenKind::NamespaceConstant,
b"while" => TokenKind::While,
b"insteadof" => TokenKind::Insteadof,
b"list" => TokenKind::List,

View File

@ -391,6 +391,7 @@ pub enum Expression {
Empty,
VariadicPlaceholder,
ErrorSuppress {
span: Span,
expr: Box<Self>,
},
Increment {
@ -415,6 +416,7 @@ pub enum Expression {
rhs: Box<Self>,
},
Include {
span: Span,
kind: IncludeKind,
path: Box<Expression>,
},
@ -496,9 +498,11 @@ pub enum Expression {
},
Null,
BooleanNot {
span: Span,
value: Box<Self>,
},
MagicConst {
span: Span,
constant: MagicConst,
},
Ternary {
@ -529,24 +533,31 @@ pub enum Expression {
value: Box<Self>,
},
Negate {
span: Span,
value: Box<Self>,
},
UnaryPlus {
span: Span,
value: Box<Self>,
},
BitwiseNot {
span: Span,
value: Box<Self>,
},
PreDecrement {
span: Span,
value: Box<Self>,
},
PreIncrement {
span: Span,
value: Box<Self>,
},
Print {
span: Span,
value: Box<Self>,
},
Cast {
span: Span,
kind: CastKind,
value: Box<Self>,
},
@ -578,7 +589,14 @@ pub struct MatchArm {
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum MagicConst {
Dir,
Directory,
File,
Line,
Class,
Function,
Method,
Namespace,
Trait,
}
#[derive(Debug, PartialEq, Clone)]

View File

@ -188,7 +188,7 @@ fn create(state: &mut State) -> ParseResult<Expression> {
}
macro_rules! expressions {
($(#[before($else:ident), current($( $current:pat_param )|+) $(, peek($( $peek:pat_param )|+))?] $expr:ident($out:expr))+) => {
($(#[before($else:ident), current($(|)? $( $current:pat_param )|+) $(, peek($(|)? $( $peek:pat_param )|+))?] $expr:ident($out:expr))+) => {
$(
#[inline(never)]
fn $expr(state: &mut State) -> ParseResult<Expression> {
@ -481,107 +481,286 @@ expressions! {
arrays::legacy_array_expression(state)
})
#[before(fallback), current(TokenKind::LeftBracket)]
#[before(new), current(TokenKind::LeftBracket)]
left_bracket(|state: &mut State| {
arrays::array_expression(state)
})
#[before(directory_magic_constant), current(TokenKind::New)]
new(|state: &mut State| {
state.next();
let target = match state.current.kind {
TokenKind::Self_ => {
if !state.has_class_scope {
return Err(ParseError::CannotFindTypeInCurrentScope(
state.current.kind.to_string(),
state.current.span,
));
}
state.next();
Expression::Self_
}
TokenKind::Static => {
if !state.has_class_scope {
return Err(ParseError::CannotFindTypeInCurrentScope(
state.current.kind.to_string(),
state.current.span,
));
}
state.next();
Expression::Static
}
TokenKind::Parent => {
if !state.has_class_scope {
return Err(ParseError::CannotFindTypeInCurrentScope(
state.current.kind.to_string(),
state.current.span,
));
}
state.next();
Expression::Parent
}
_ => clone_or_new_precedence(state)?,
};
let mut args = vec![];
if state.current.kind == TokenKind::LeftParen {
args = parameters::args_list(state)?;
}
Ok(Expression::New{target:Box::new(target),args,})
})
#[before(file_magic_constant), current(TokenKind::DirConstant)]
directory_magic_constant(|state: &mut State| {
let span = state.current.span;
state.next();
Ok(Expression::MagicConst {
span,
constant: MagicConst::Directory
})
})
#[before(line_magic_constant), current(TokenKind::FileConstant)]
file_magic_constant(|state: &mut State| {
let span = state.current.span;
state.next();
Ok(Expression::MagicConst {
span,
constant: MagicConst::File
})
})
#[before(function_magic_constant), current(TokenKind::LineConstant)]
line_magic_constant(|state: &mut State| {
let span = state.current.span;
state.next();
Ok(Expression::MagicConst {
span,
constant: MagicConst::Line
})
})
#[before(class_magic_constant), current(TokenKind::FunctionConstant)]
function_magic_constant(|state: &mut State| {
let span = state.current.span;
state.next();
Ok(Expression::MagicConst {
span,
constant: MagicConst::Function,
})
})
#[before(method_magic_constant), current(TokenKind::ClassConstant)]
class_magic_constant(|state: &mut State| {
let span = state.current.span;
state.next();
Ok(Expression::MagicConst {
span,
constant: MagicConst::Class,
})
})
#[before(namespace_magic_constant), current(TokenKind::MethodConstant)]
method_magic_constant(|state: &mut State| {
let span = state.current.span;
state.next();
Ok(Expression::MagicConst {
span,
constant: MagicConst::Method,
})
})
#[before(trait_magic_constant), current(TokenKind::NamespaceConstant)]
namespace_magic_constant(|state: &mut State| {
let span = state.current.span;
state.next();
Ok(Expression::MagicConst {
span,
constant: MagicConst::Namespace,
})
})
#[before(include), current(TokenKind::TraitConstant)]
trait_magic_constant(|state: &mut State| {
let span = state.current.span;
state.next();
Ok(Expression::MagicConst {
span,
constant: MagicConst::Trait
})
})
#[before(cast_prefix), current(TokenKind::Include | TokenKind::IncludeOnce | TokenKind::Require | TokenKind::RequireOnce)]
include(|state: &mut State| {
let kind: IncludeKind = (&state.current.kind).into();
let span = state.current.span;
state.next();
let path = lowest_precedence(state)?;
Ok(Expression::Include {
span,
kind,
path:Box::new(path)
})
})
#[before(numeric_prefix), current(
| TokenKind::StringCast | TokenKind::BinaryCast | TokenKind::ObjectCast
| TokenKind::BoolCast | TokenKind::BooleanCast | TokenKind::IntCast
| TokenKind::IntegerCast | TokenKind::FloatCast | TokenKind::DoubleCast
| TokenKind::RealCast | TokenKind::UnsetCast | TokenKind::ArrayCast
)]
cast_prefix(|state: &mut State| {
let span = state.current.span;
let kind = state.current.kind.clone().into();
state.next();
let rhs = for_precedence(state, Precedence::Prefix)?;
Ok(Expression::Cast {
span,
kind,
value: Box::new(rhs),
})
})
#[before(bang_prefix), current(TokenKind::Decrement | TokenKind::Increment | TokenKind::Minus | TokenKind::Plus)]
numeric_prefix(|state: &mut State| {
let span = state.current.span;
let op = state.current.kind.clone();
state.next();
let rhs = for_precedence(state, Precedence::Prefix)?;
let expr = match op {
TokenKind::Minus => Expression::Negate {
span,
value: Box::new(rhs),
},
TokenKind::Plus => Expression::UnaryPlus {
span,
value: Box::new(rhs),
},
TokenKind::Decrement => Expression::PreDecrement {
span,
value: Box::new(rhs),
},
TokenKind::Increment => Expression::PreIncrement {
span,
value: Box::new(rhs),
},
_ => unreachable!(),
};
Ok(expr)
})
#[before(at_prefix), current(TokenKind::Bang)]
bang_prefix(|state: &mut State| {
let span = state.current.span;
state.next();
let rhs = for_precedence(state, Precedence::Bang)?;
Ok(Expression::BooleanNot {
span,
value: Box::new(rhs)
})
})
#[before(print_prefix), current(TokenKind::At)]
at_prefix(|state: &mut State| {
let span = state.current.span;
state.next();
let rhs = for_precedence(state, Precedence::Prefix)?;
Ok(Expression::ErrorSuppress {
span,
expr: Box::new(rhs)
})
})
#[before(bitwise_prefix), current(TokenKind::Print)]
print_prefix(|state: &mut State| {
let span = state.current.span;
state.next();
let rhs = for_precedence(state, Precedence::Prefix)?;
Ok(Expression::Print {
span,
value: Box::new(rhs)
})
})
#[before(dynamic_variable), current(TokenKind::BitwiseNot)]
bitwise_prefix(|state: &mut State| {
let span = state.current.span;
state.next();
let rhs = for_precedence(state, Precedence::Prefix)?;
Ok(Expression::BitwiseNot {
span,
value: Box::new(rhs)
})
})
#[before(unexpected_token), current(TokenKind::Dollar)]
dynamic_variable(|state: &mut State| {
variables::dynamic_variable(state)
})
}
fn fallback(state: &mut State) -> ParseResult<Expression> {
let expr = match &state.current.kind {
TokenKind::New => {
utils::skip(state, TokenKind::New)?;
let target = match state.current.kind {
TokenKind::Self_ => {
if !state.has_class_scope {
return Err(ParseError::CannotFindTypeInCurrentScope(
state.current.kind.to_string(),
state.current.span,
));
}
state.next();
Expression::Self_
}
TokenKind::Static => {
if !state.has_class_scope {
return Err(ParseError::CannotFindTypeInCurrentScope(
state.current.kind.to_string(),
state.current.span,
));
}
state.next();
Expression::Static
}
TokenKind::Parent => {
if !state.has_class_scope {
return Err(ParseError::CannotFindTypeInCurrentScope(
state.current.kind.to_string(),
state.current.span,
));
}
state.next();
Expression::Parent
}
_ => clone_or_new_precedence(state)?,
};
let mut args = vec![];
if state.current.kind == TokenKind::LeftParen {
args = parameters::args_list(state)?;
}
Expression::New {
target: Box::new(target),
args,
}
}
TokenKind::DirConstant => {
state.next();
Expression::MagicConst {
constant: MagicConst::Dir,
}
}
TokenKind::Include
| TokenKind::IncludeOnce
| TokenKind::Require
| TokenKind::RequireOnce => {
let kind: IncludeKind = (&state.current.kind).into();
state.next();
let path = lowest_precedence(state)?;
Expression::Include {
kind,
path: Box::new(path),
}
}
_ if is_prefix(&state.current.kind) => {
let op = state.current.kind.clone();
state.next();
let rpred = Precedence::prefix(&op);
let rhs = for_precedence(state, rpred)?;
prefix(&op, rhs)
}
TokenKind::Dollar => variables::dynamic_variable(state)?,
_ => {
return Err(ParseError::UnexpectedToken(
state.current.kind.to_string(),
state.current.span,
))
}
};
Ok(expr)
fn unexpected_token(state: &mut State) -> ParseResult<Expression> {
Err(ParseError::UnexpectedToken(
state.current.kind.to_string(),
state.current.span,
))
}
fn postfix(state: &mut State, lhs: Expression, op: &TokenKind) -> Result<Expression, ParseError> {
@ -949,9 +1128,11 @@ fn interpolated_string_part(state: &mut State) -> ParseResult<Option<StringPart>
e
}
TokenKind::Minus => {
let span = state.current.span;
state.next();
if let TokenKind::LiteralInteger(i) = &state.current.kind {
let e = Expression::Negate {
span,
value: Box::new(Expression::LiteralInteger { i: i.clone() }),
};
state.next();
@ -1014,79 +1195,6 @@ fn interpolated_string_part(state: &mut State) -> ParseResult<Option<StringPart>
})
}
#[inline(always)]
fn is_prefix(op: &TokenKind) -> bool {
matches!(
op,
TokenKind::Bang
| TokenKind::Print
| TokenKind::BitwiseNot
| TokenKind::Decrement
| TokenKind::Increment
| TokenKind::Minus
| TokenKind::Plus
| TokenKind::StringCast
| TokenKind::BinaryCast
| TokenKind::ObjectCast
| TokenKind::BoolCast
| TokenKind::BooleanCast
| TokenKind::IntCast
| TokenKind::IntegerCast
| TokenKind::FloatCast
| TokenKind::DoubleCast
| TokenKind::RealCast
| TokenKind::UnsetCast
| TokenKind::ArrayCast
| TokenKind::At
)
}
#[inline(always)]
fn prefix(op: &TokenKind, rhs: Expression) -> Expression {
match op {
TokenKind::Print => Expression::Print {
value: Box::new(rhs),
},
TokenKind::Bang => Expression::BooleanNot {
value: Box::new(rhs),
},
TokenKind::Minus => Expression::Negate {
value: Box::new(rhs),
},
TokenKind::Plus => Expression::UnaryPlus {
value: Box::new(rhs),
},
TokenKind::BitwiseNot => Expression::BitwiseNot {
value: Box::new(rhs),
},
TokenKind::Decrement => Expression::PreDecrement {
value: Box::new(rhs),
},
TokenKind::Increment => Expression::PreIncrement {
value: Box::new(rhs),
},
TokenKind::StringCast
| TokenKind::BinaryCast
| TokenKind::ObjectCast
| TokenKind::BoolCast
| TokenKind::BooleanCast
| TokenKind::IntCast
| TokenKind::IntegerCast
| TokenKind::FloatCast
| TokenKind::DoubleCast
| TokenKind::RealCast
| TokenKind::UnsetCast
| TokenKind::ArrayCast => Expression::Cast {
kind: op.into(),
value: Box::new(rhs),
},
TokenKind::At => Expression::ErrorSuppress {
expr: Box::new(rhs),
},
_ => unreachable!(),
}
}
fn is_infix(t: &TokenKind) -> bool {
matches!(
t,

View File

@ -1,11 +1,11 @@
use crate::lexer::token::TokenKind;
use crate::parser;
use crate::parser::ast::Statement;
use crate::parser::error::ParseResult;
use crate::parser::expressions;
use crate::parser::internal::blocks;
use crate::parser::internal::utils;
use crate::parser::state::State;
use crate::parser;
pub fn foreach_loop(state: &mut State) -> ParseResult<Statement> {
utils::skip(state, TokenKind::Foreach)?;
@ -175,21 +175,19 @@ pub fn while_loop(state: &mut State) -> ParseResult<Statement> {
let body = if state.current.kind == TokenKind::SemiColon {
utils::skip_semicolon(state)?;
vec![]
} else if state.current.kind == TokenKind::Colon {
utils::skip_colon(state)?;
let then = blocks::body(state, &TokenKind::EndWhile)?;
utils::skip(state, TokenKind::EndWhile)?;
utils::skip_semicolon(state)?;
then
} else if state.current.kind == TokenKind::LeftBrace {
utils::skip_left_brace(state)?;
let then = blocks::body(state, &TokenKind::RightBrace)?;
utils::skip_right_brace(state)?;
then
} else {
if state.current.kind == TokenKind::Colon {
utils::skip_colon(state)?;
let then = blocks::body(state, &TokenKind::EndWhile)?;
utils::skip(state, TokenKind::EndWhile)?;
utils::skip_semicolon(state)?;
then
} else if state.current.kind == TokenKind::LeftBrace {
utils::skip_left_brace(state)?;
let then = blocks::body(state, &TokenKind::RightBrace)?;
utils::skip_right_brace(state)?;
then
} else {
vec![parser::statement(state)?]
}
vec![parser::statement(state)?]
};
Ok(Statement::While { condition, body })

View File

@ -41,16 +41,6 @@ pub enum Precedence {
}
impl Precedence {
pub fn prefix(kind: &TokenKind) -> Self {
use TokenKind::*;
match kind {
Bang => Self::Bang,
Clone | New => Self::CloneOrNew,
_ => Self::Prefix,
}
}
pub fn infix(kind: &TokenKind) -> Self {
use TokenKind::*;

View File

@ -22,7 +22,7 @@ pub fn skip_semicolon(state: &mut State) -> ParseResult<Span> {
return Err(ParseError::ExpectedToken(
vec!["`;`".to_string()],
found,
state.current.span,
end,
));
} else {
state.next();

View File

@ -1,6 +1,10 @@
[
Expression {
expr: Include {
span: (
3,
1,
),
kind: Include,
path: LiteralString {
value: "foo.php",
@ -9,6 +13,10 @@
},
Expression {
expr: Include {
span: (
5,
1,
),
kind: IncludeOnce,
path: LiteralString {
value: "bar.php",
@ -17,6 +25,10 @@
},
Expression {
expr: Include {
span: (
7,
1,
),
kind: Require,
path: LiteralString {
value: "baz.php",
@ -25,6 +37,10 @@
},
Expression {
expr: Include {
span: (
9,
1,
),
kind: RequireOnce,
path: LiteralString {
value: "qux.php",

View File

@ -532,6 +532,10 @@
Arg {
name: None,
value: BitwiseNot {
span: (
16,
13,
),
value: LiteralInteger {
i: "2",
},

View File

@ -792,6 +792,10 @@
Arg {
name: None,
value: BitwiseNot {
span: (
16,
13,
),
value: Variable(
Variable {
start: (

View File

@ -50,6 +50,10 @@
),
op: Assign,
rhs: UnaryPlus {
span: (
4,
6,
),
value: LiteralInteger {
i: "1",
},
@ -73,6 +77,10 @@
),
op: Assign,
rhs: BitwiseNot {
span: (
5,
6,
),
value: LiteralInteger {
i: "2",
},
@ -96,6 +104,10 @@
),
op: Assign,
rhs: PreDecrement {
span: (
6,
6,
),
value: Variable(
Variable {
start: (
@ -129,6 +141,10 @@
),
op: Assign,
rhs: PreIncrement {
span: (
7,
6,
),
value: Variable(
Variable {
start: (

View File

@ -1,6 +1,10 @@
[
Expression {
expr: ErrorSuppress {
span: (
1,
7,
),
expr: Call {
target: Identifier(
Identifier {

View File

@ -1,6 +1,10 @@
[
Expression {
expr: Print {
span: (
1,
7,
),
value: Variable(
Variable {
start: (

View File

@ -1,10 +1,18 @@
[
Expression {
expr: Include {
span: (
3,
1,
),
kind: Require,
path: Infix {
lhs: MagicConst {
constant: Dir,
span: (
3,
9,
),
constant: Directory,
},
op: Concat,
rhs: LiteralString {

View File

@ -16,10 +16,18 @@
),
op: Assign,
rhs: Include {
span: (
3,
8,
),
kind: Require,
path: Infix {
lhs: MagicConst {
constant: Dir,
span: (
3,
16,
),
constant: Directory,
},
op: Concat,
rhs: LiteralString {

View File

@ -219,6 +219,10 @@
[
Expression {
expr: Print {
span: (
11,
5,
),
value: Infix {
lhs: Variable(
Variable {

74
tests/fixtures/0276 copy/ast.txt vendored Normal file
View File

@ -0,0 +1,74 @@
[
Expression {
expr: MagicConst {
span: (
3,
1,
),
constant: Directory,
},
},
Expression {
expr: MagicConst {
span: (
4,
1,
),
constant: File,
},
},
Expression {
expr: MagicConst {
span: (
5,
1,
),
constant: Line,
},
},
Expression {
expr: MagicConst {
span: (
6,
1,
),
constant: Namespace,
},
},
Expression {
expr: MagicConst {
span: (
7,
1,
),
constant: Class,
},
},
Expression {
expr: MagicConst {
span: (
8,
1,
),
constant: Method,
},
},
Expression {
expr: MagicConst {
span: (
9,
1,
),
constant: Trait,
},
},
Expression {
expr: MagicConst {
span: (
10,
1,
),
constant: Function,
},
},
]

10
tests/fixtures/0276 copy/code.php vendored Normal file
View File

@ -0,0 +1,10 @@
<?php
__DIR__;
__FILE__;
__LINE__;
__NAMESPACE__;
__CLASS__;
__METHOD__;
__TRAIT__;
__FUNCTION__;