Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit fa003cc

Browse files
authored
fix multiple parse errors, and error for magic methods on enums (#206)
Signed-off-by: azjezz <azjezz@protonmail.com>
1 parent 78b79cc commit fa003cc

File tree

30 files changed

+274
-22
lines changed

30 files changed

+274
-22
lines changed

src/parser/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub enum ParseError {
5353
CannotUseReservedKeywordAsATypeName(String, Span),
5454
CannotUseReservedKeywordAsAGoToLabel(String, Span),
5555
CannotUseReservedKeywordAsAConstantName(String, Span),
56+
EnumMayNotIncludesMagicMethod(String, String, Span),
5657
}
5758

5859
impl From<SyntaxError> for ParseError {
@@ -134,6 +135,7 @@ impl Display for ParseError {
134135
Self::CannotUseReservedKeywordAsATypeName(ty, span) => write!(f, "Parse Error: cannot use `{}` as a type name as it is reserved on line {} column {}", ty, span.0, span.1),
135136
Self::CannotUseReservedKeywordAsAGoToLabel(ty, span) => write!(f, "Parse Error: cannot use `{}` as a goto label as it is reserved on line {} column {}", ty, span.0, span.1),
136137
Self::CannotUseReservedKeywordAsAConstantName(ty, span) => write!(f, "Parse Error: cannot use `{}` as a constant name as it is reserved on line {} column {}", ty, span.0, span.1),
138+
Self::EnumMayNotIncludesMagicMethod(ty, method, span) => write!(f, "Parse Error: Enum `{}` may not include magic method `{}` on line {} column {}", ty, method, span.0, span.1),
137139
}
138140
}
139141
}

src/parser/expressions.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ macro_rules! expressions {
504504
($(#[before($else:ident), current($(|)? $( $current:pat_param )|+) $(, peek($(|)? $( $peek:pat_param )|+))?] $expr:ident($out:expr))+) => {
505505
$(
506506
#[inline(never)]
507-
fn $expr(state: &mut State) -> ParseResult<Expression> {
507+
pub(in crate::parser) fn $expr(state: &mut State) -> ParseResult<Expression> {
508508
state.skip_comments();
509509

510510
match &state.current.kind {
@@ -587,7 +587,7 @@ expressions! {
587587

588588
#[before(throw), current(TokenKind::New), peek(TokenKind::Class | TokenKind::Attribute)]
589589
anonymous_class(|state: &mut State| {
590-
classes::parse_anonymous(state)
590+
classes::parse_anonymous(state, None)
591591
})
592592

593593
#[before(r#yield), current(TokenKind::Throw)]
@@ -802,6 +802,11 @@ expressions! {
802802
let span = state.current.span;
803803

804804
state.next();
805+
state.skip_comments();
806+
807+
if state.current.kind == TokenKind::Class || state.current.kind == TokenKind::Attribute {
808+
return classes::parse_anonymous(state, Some(span));
809+
};
805810

806811
let target = match state.current.kind {
807812
TokenKind::Self_ => {

src/parser/internal/classes.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::lexer::token::Span;
12
use crate::lexer::token::TokenKind;
23
use crate::parser::ast::classes::AnonymousClass;
34
use crate::parser::ast::classes::Class;
@@ -91,8 +92,11 @@ pub fn parse(state: &mut State) -> ParseResult<Statement> {
9192
}))
9293
}
9394

94-
pub fn parse_anonymous(state: &mut State) -> ParseResult<Expression> {
95-
let span = utils::skip(state, TokenKind::New)?;
95+
pub fn parse_anonymous(state: &mut State, span: Option<Span>) -> ParseResult<Expression> {
96+
let span = match span {
97+
Some(span) => span,
98+
None => utils::skip(state, TokenKind::New)?,
99+
};
96100

97101
attributes::gather_attributes(state)?;
98102

src/parser/internal/enums.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::lexer::token::Span;
12
use crate::lexer::token::TokenKind;
23
use crate::parser::ast::enums::BackedEnum;
34
use crate::parser::ast::enums::BackedEnumCase;
@@ -6,6 +7,7 @@ use crate::parser::ast::enums::BackedEnumType;
67
use crate::parser::ast::enums::UnitEnum;
78
use crate::parser::ast::enums::UnitEnumCase;
89
use crate::parser::ast::enums::UnitEnumMember;
10+
use crate::parser::ast::functions::Method;
911
use crate::parser::ast::Statement;
1012
use crate::parser::error::ParseError;
1113
use crate::parser::error::ParseResult;
@@ -138,7 +140,7 @@ fn unit_member(state: &mut State, enum_name: String) -> ParseResult<UnitEnumMemb
138140
.map(UnitEnumMember::Constant);
139141
}
140142

141-
functions::method(state, modifiers::enum_method_group(modifiers)?).map(UnitEnumMember::Method)
143+
method(state, modifiers, enum_name).map(UnitEnumMember::Method)
142144
}
143145

144146
fn backed_member(state: &mut State, enum_name: String) -> ParseResult<BackedEnumMember> {
@@ -182,5 +184,27 @@ fn backed_member(state: &mut State, enum_name: String) -> ParseResult<BackedEnum
182184
.map(BackedEnumMember::Constant);
183185
}
184186

185-
functions::method(state, modifiers::enum_method_group(modifiers)?).map(BackedEnumMember::Method)
187+
method(state, modifiers, enum_name).map(BackedEnumMember::Method)
188+
}
189+
190+
fn method(
191+
state: &mut State,
192+
modifiers: Vec<(Span, TokenKind, Span)>,
193+
enum_name: String,
194+
) -> ParseResult<Method> {
195+
let method = functions::method(state, modifiers::enum_method_group(modifiers)?)?;
196+
197+
match method.name.name[..].to_ascii_lowercase().as_slice() {
198+
b"__get" | b"__set" | b"__call" | b"__callstatic" | b"__invoke" | b"__serialize"
199+
| b"__unserialize" | b"__destruct" | b"__wakeup" | b"__sleep" => {
200+
return Err(ParseError::EnumMayNotIncludesMagicMethod(
201+
state.named(&enum_name),
202+
method.name.to_string(),
203+
method.name.span,
204+
))
205+
}
206+
_ => {}
207+
}
208+
209+
Ok(method)
186210
}

src/parser/internal/parameters.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ pub fn function_parameter_list(state: &mut State) -> Result<FunctionParameterLis
6868
});
6969

7070
state.skip_comments();
71-
7271
if state.current.kind == TokenKind::Comma {
7372
state.next();
73+
state.skip_comments();
7474
} else {
7575
break;
7676
}
@@ -219,9 +219,9 @@ pub fn method_parameter_list(state: &mut State) -> Result<MethodParameterList, P
219219
});
220220

221221
state.skip_comments();
222-
223222
if state.current.kind == TokenKind::Comma {
224223
state.next();
224+
state.skip_comments();
225225
} else {
226226
break;
227227
}

src/parser/internal/uses.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,19 @@ use crate::parser::state::State;
99

1010
pub fn use_statement(state: &mut State) -> ParseResult<Statement> {
1111
state.next();
12+
state.skip_comments();
1213

1314
let kind = match state.current.kind {
1415
TokenKind::Function => {
1516
state.next();
17+
18+
state.skip_comments();
1619
UseKind::Function
1720
}
1821
TokenKind::Const => {
1922
state.next();
23+
24+
state.skip_comments();
2025
UseKind::Const
2126
}
2227
_ => UseKind::Normal,
@@ -25,21 +30,26 @@ pub fn use_statement(state: &mut State) -> ParseResult<Statement> {
2530
if state.peek.kind == TokenKind::LeftBrace {
2631
let prefix = identifiers::full_name(state)?;
2732
state.next();
33+
state.skip_comments();
2834

2935
let mut uses = Vec::new();
3036
while state.current.kind != TokenKind::RightBrace {
31-
let name = identifiers::full_name(state)?;
37+
let name = identifiers::full_type_name(state)?;
3238
let mut alias = None;
39+
state.skip_comments();
3340

3441
if state.current.kind == TokenKind::As {
3542
state.next();
36-
alias = Some(identifiers::identifier(state)?);
43+
alias = Some(identifiers::type_identifier(state)?);
44+
state.skip_comments();
3745
}
3846

3947
uses.push(Use { name, alias });
4048

49+
state.skip_comments();
4150
if state.current.kind == TokenKind::Comma {
4251
state.next();
52+
state.skip_comments();
4353
continue;
4454
}
4555
}
@@ -51,12 +61,14 @@ pub fn use_statement(state: &mut State) -> ParseResult<Statement> {
5161
} else {
5262
let mut uses = Vec::new();
5363
while !state.is_eof() {
54-
let name = identifiers::full_name(state)?;
64+
let name = identifiers::full_type_name(state)?;
5565
let mut alias = None;
66+
state.skip_comments();
5667

5768
if state.current.kind == TokenKind::As {
5869
state.next();
59-
alias = Some(identifiers::identifier(state)?);
70+
alias = Some(identifiers::type_identifier(state)?);
71+
state.skip_comments();
6072
}
6173

6274
uses.push(Use { name, alias });
@@ -66,6 +78,7 @@ pub fn use_statement(state: &mut State) -> ParseResult<Statement> {
6678
continue;
6779
}
6880

81+
state.skip_comments();
6982
utils::skip_semicolon(state)?;
7083
break;
7184
}

src/parser/mod.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::parser::ast::comments::Comment;
55
use crate::parser::ast::comments::CommentFormat;
66
use crate::parser::ast::variables::Variable;
77
use crate::parser::ast::{DeclareItem, Expression, Program, Statement, StaticVar};
8-
use crate::parser::error::ParseError;
98
use crate::parser::error::ParseResult;
109
use crate::parser::internal::attributes;
1110
use crate::parser::internal::blocks;
@@ -151,13 +150,9 @@ fn statement(state: &mut State) -> ParseResult<Statement> {
151150
functions::function(state)?
152151
}
153152
}
154-
_ => {
155-
// Note, we can get attributes and know their span, maybe use that in the
156-
// error in the future?
157-
return Err(ParseError::ExpectedItemDefinitionAfterAttributes(
158-
state.current.span,
159-
));
160-
}
153+
_ => Statement::Expression {
154+
expr: expressions::attributes(state)?,
155+
},
161156
}
162157
} else {
163158
match &state.current.kind {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
enum EnumWithSerialize {
4+
public function __serialize() {}
5+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
EnumMayNotIncludesMagicMethod("EnumWithSerialize", "__serialize", (4, 21)) -> Parse Error: Enum `EnumWithSerialize` may not include magic method `__serialize` on line 4 column 21
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
enum EnumWithUnserialize {
4+
public function __unserialize(array $data) {}
5+
}

0 commit comments

Comments
 (0)