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"var" => TokenKind::Var,
b"yield" => TokenKind::Yield, b"yield" => TokenKind::Yield,
b"__DIR__" => TokenKind::DirConstant, 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"while" => TokenKind::While,
b"insteadof" => TokenKind::Insteadof, b"insteadof" => TokenKind::Insteadof,
b"list" => TokenKind::List, b"list" => TokenKind::List,

View File

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

View File

@ -188,7 +188,7 @@ fn create(state: &mut State) -> ParseResult<Expression> {
} }
macro_rules! expressions { 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)] #[inline(never)]
fn $expr(state: &mut State) -> ParseResult<Expression> { fn $expr(state: &mut State) -> ParseResult<Expression> {
@ -481,107 +481,286 @@ expressions! {
arrays::legacy_array_expression(state) arrays::legacy_array_expression(state)
}) })
#[before(fallback), current(TokenKind::LeftBracket)] #[before(new), current(TokenKind::LeftBracket)]
left_bracket(|state: &mut State| { left_bracket(|state: &mut State| {
arrays::array_expression(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> { fn unexpected_token(state: &mut State) -> ParseResult<Expression> {
let expr = match &state.current.kind { Err(ParseError::UnexpectedToken(
TokenKind::New => { state.current.kind.to_string(),
utils::skip(state, TokenKind::New)?; state.current.span,
))
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 postfix(state: &mut State, lhs: Expression, op: &TokenKind) -> Result<Expression, ParseError> { 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 e
} }
TokenKind::Minus => { TokenKind::Minus => {
let span = state.current.span;
state.next(); state.next();
if let TokenKind::LiteralInteger(i) = &state.current.kind { if let TokenKind::LiteralInteger(i) = &state.current.kind {
let e = Expression::Negate { let e = Expression::Negate {
span,
value: Box::new(Expression::LiteralInteger { i: i.clone() }), value: Box::new(Expression::LiteralInteger { i: i.clone() }),
}; };
state.next(); 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 { fn is_infix(t: &TokenKind) -> bool {
matches!( matches!(
t, t,

View File

@ -1,11 +1,11 @@
use crate::lexer::token::TokenKind; use crate::lexer::token::TokenKind;
use crate::parser;
use crate::parser::ast::Statement; use crate::parser::ast::Statement;
use crate::parser::error::ParseResult; use crate::parser::error::ParseResult;
use crate::parser::expressions; use crate::parser::expressions;
use crate::parser::internal::blocks; use crate::parser::internal::blocks;
use crate::parser::internal::utils; use crate::parser::internal::utils;
use crate::parser::state::State; use crate::parser::state::State;
use crate::parser;
pub fn foreach_loop(state: &mut State) -> ParseResult<Statement> { pub fn foreach_loop(state: &mut State) -> ParseResult<Statement> {
utils::skip(state, TokenKind::Foreach)?; 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 { let body = if state.current.kind == TokenKind::SemiColon {
utils::skip_semicolon(state)?; utils::skip_semicolon(state)?;
vec![] 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 { } else {
if state.current.kind == TokenKind::Colon { vec![parser::statement(state)?]
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)?]
}
}; };
Ok(Statement::While { condition, body }) Ok(Statement::While { condition, body })

View File

@ -41,16 +41,6 @@ pub enum Precedence {
} }
impl 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 { pub fn infix(kind: &TokenKind) -> Self {
use TokenKind::*; use TokenKind::*;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -219,6 +219,10 @@
[ [
Expression { Expression {
expr: Print { expr: Print {
span: (
11,
5,
),
value: Infix { value: Infix {
lhs: Variable( lhs: Variable(
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__;