Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,18 @@ impl Lexer {
length: length + 1,
})
}
Token {
kind: TokenKind::True,
..
} => TokenKind::FullyQualifiedIdentifier("\\true".into()),
Token {
kind: TokenKind::False,
..
} => TokenKind::FullyQualifiedIdentifier("\\false".into()),
Token {
kind: TokenKind::Null,
..
} => TokenKind::FullyQualifiedIdentifier("\\null".into()),
s => unreachable!("{:?}", s),
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/parser/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub enum ParseError {
CannotUsePositionalArgumentAfterNamedArgument(Span),
CannotUseReservedKeywordAsATypeName(String, Span),
CannotUseReservedKeywordAsAGoToLabel(String, Span),
CannotUseReservedKeywordAsAConstantName(String, Span),
}

impl From<SyntaxError> for ParseError {
Expand Down Expand Up @@ -132,6 +133,7 @@ impl Display for ParseError {
Self::CannotUsePositionalArgumentAfterNamedArgument(span) => write!(f, "Parse Error: cannot use positional argument after named argument on line {} column {}", span.0, span.1),
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),
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),
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),
}
}
}
26 changes: 17 additions & 9 deletions src/parser/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,30 +739,38 @@ expressions! {
shell_exec(state)
})

#[before(self_postfix), current(TokenKind::Identifier(_) | TokenKind::QualifiedIdentifier(_) | TokenKind::FullyQualifiedIdentifier(_))]
#[before(static_postfix), current(TokenKind::Identifier(_) | TokenKind::QualifiedIdentifier(_) | TokenKind::FullyQualifiedIdentifier(_))]
identifier(|state: &mut State| {
Ok(Expression::Identifier(Identifier::SimpleIdentifier(identifiers::full_name(state)?)))
})

#[before(static_postfix), current(TokenKind::Self_)]
self_postfix(|state: &mut State| {
#[before(self_identifier), current(TokenKind::Static)]
static_postfix(|state: &mut State| {
state.next();

postfix(state, Expression::Self_, &TokenKind::DoubleColon)
postfix(state, Expression::Static, &TokenKind::DoubleColon)
})

#[before(parent_postfix), current(TokenKind::Static)]
static_postfix(|state: &mut State| {
#[before(parent_identifier), current(TokenKind::Self_)]
self_identifier(|state: &mut State| {
let span = state.current.span;
state.next();

postfix(state, Expression::Static, &TokenKind::DoubleColon)
Ok(Expression::Identifier(Identifier::SimpleIdentifier( SimpleIdentifier {
span,
name: "self".into()
})))
})

#[before(left_parenthesis), current(TokenKind::Parent)]
parent_postfix(|state: &mut State| {
parent_identifier(|state: &mut State| {
let span = state.current.span;
state.next();

postfix(state, Expression::Parent, &TokenKind::DoubleColon)
Ok(Expression::Identifier(Identifier::SimpleIdentifier( SimpleIdentifier {
span,
name: "parent".into()
})))
})

#[before(r#match), current(TokenKind::LeftParen)]
Expand Down
4 changes: 2 additions & 2 deletions src/parser/internal/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn parse(state: &mut State) -> ParseResult<Constant> {
let mut entries = vec![];

loop {
let name = identifiers::identifier(state)?;
let name = identifiers::constant_identifier(state)?;

utils::skip(state, TokenKind::Equals)?;

Expand Down Expand Up @@ -52,7 +52,7 @@ pub fn classish(
let mut entries = vec![];

loop {
let name = identifiers::identifier_maybe_soft_reserved(state)?;
let name = identifiers::identifier_maybe_reserved(state)?;

utils::skip(state, TokenKind::Equals)?;

Expand Down
4 changes: 2 additions & 2 deletions src/parser/internal/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ fn unit_member(state: &mut State, enum_name: String) -> ParseResult<UnitEnumMemb
let start = state.current.span;
state.next();

let name = identifiers::type_identifier(state)?;
let name = identifiers::identifier_maybe_reserved(state)?;

if state.current.kind == TokenKind::Equals {
return Err(ParseError::CaseValueForUnitEnum(
Expand Down Expand Up @@ -150,7 +150,7 @@ fn backed_member(state: &mut State, enum_name: String) -> ParseResult<BackedEnum
let start = state.current.span;
state.next();

let name = identifiers::identifier(state)?;
let name = identifiers::identifier_maybe_reserved(state)?;

if state.current.kind == TokenKind::SemiColon {
return Err(ParseError::MissingCaseValueForBackedEnum(
Expand Down
34 changes: 33 additions & 1 deletion src/parser/internal/identifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn type_identifier(state: &mut State) -> ParseResult<SimpleIdentifier> {
}
}

/// Expect an unqualified identifier such as Foo or Bar for a class, interface, trait, or an enum name.
/// Expect an unqualified identifier such as foo or bar for a goto label name.
pub fn label_identifier(state: &mut State) -> ParseResult<SimpleIdentifier> {
match state.current.kind.clone() {
TokenKind::Identifier(name) => {
Expand Down Expand Up @@ -82,6 +82,38 @@ pub fn label_identifier(state: &mut State) -> ParseResult<SimpleIdentifier> {
}
}

/// Expect an unqualified identifier such as FOO or BAR for a constant name.
pub fn constant_identifier(state: &mut State) -> ParseResult<SimpleIdentifier> {
match state.current.kind.clone() {
TokenKind::Identifier(name) => {
let span = state.current.span;

state.next();

Ok(SimpleIdentifier { span, name })
}
TokenKind::Enum | TokenKind::From | TokenKind::Self_ | TokenKind::Parent => {
let span = state.current.span;
let name = state.current.kind.to_string().into();

state.next();

Ok(SimpleIdentifier { span, name })
}
t if is_reserved_identifier(&t) => {
Err(ParseError::CannotUseReservedKeywordAsAConstantName(
state.current.kind.to_string(),
state.current.span,
))
}
_ => Err(ParseError::ExpectedToken(
vec!["an identifier".to_owned()],
Some(state.current.kind.to_string()),
state.current.span,
)),
}
}

/// Expect an unqualified identifier such as Foo or Bar.
pub fn identifier(state: &mut State) -> ParseResult<SimpleIdentifier> {
if let TokenKind::Identifier(name) = state.current.kind.clone() {
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/0122/parser-error.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ExpectedToken(["an identifier"], Some("static"), (4, 11)) -> Parse Error: unexpected token `static`, expecting an identifier on line 4 column 11
ExpectedToken(["`=`"], Some("BAR"), (4, 18)) -> Parse Error: unexpected token `BAR`, expecting `=` on line 4 column 18
12 changes: 11 additions & 1 deletion tests/fixtures/0274/ast.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,17 @@
Return {
value: Some(
StaticMethodCall {
target: Parent,
target: Identifier(
SimpleIdentifier(
SimpleIdentifier {
span: (
6,
20,
),
name: "parent",
},
),
),
method: Identifier(
SimpleIdentifier(
SimpleIdentifier {
Expand Down
12 changes: 11 additions & 1 deletion tests/fixtures/0284/ast.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,17 @@
Arg {
name: None,
value: ConstFetch {
target: Self_,
target: Identifier(
SimpleIdentifier(
SimpleIdentifier {
span: (
6,
7,
),
name: "self",
},
),
),
constant: SimpleIdentifier {
span: (
6,
Expand Down
36 changes: 36 additions & 0 deletions tests/fixtures/0289-reserved-qualified/ast.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[
Constant(
Constant {
start: (
4,
1,
),
end: (
4,
16,
),
entries: [
ConstantEntry {
name: SimpleIdentifier {
span: (
4,
7,
),
name: "a",
},
value: Identifier(
SimpleIdentifier(
SimpleIdentifier {
span: (
4,
11,
),
name: "\null",
},
),
),
},
],
},
),
]
4 changes: 4 additions & 0 deletions tests/fixtures/0289-reserved-qualified/code.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php


const a = \null;
Loading