mirror of
https://github.com/danog/parser.git
synced 2024-11-26 20:04:57 +01:00
lexer: support more flags
This commit is contained in:
parent
8b143869a8
commit
92b457c87a
@ -3,4 +3,8 @@
|
||||
class Foo
|
||||
{
|
||||
var $bar;
|
||||
}
|
||||
|
||||
class Bar {
|
||||
public $baz;
|
||||
}
|
4
phpast/samples/final-abstract.php
Normal file
4
phpast/samples/final-abstract.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
|
||||
final class Foo {}
|
||||
abstract class Bar {}
|
@ -339,6 +339,8 @@ fn identifier_to_keyword(ident: &str) -> Option<TokenKind> {
|
||||
"static" => TokenKind::Static,
|
||||
"extends" => TokenKind::Extends,
|
||||
"implements" => TokenKind::Implements,
|
||||
"final" => TokenKind::Final,
|
||||
"abstract" => TokenKind::Abstract,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ pub enum TokenKind {
|
||||
Protected,
|
||||
Private,
|
||||
Static,
|
||||
Final,
|
||||
Abstract,
|
||||
If,
|
||||
Else,
|
||||
ElseIf,
|
||||
|
@ -52,6 +52,12 @@ pub enum MethodFlag {
|
||||
Static,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub enum ClassFlag {
|
||||
Final,
|
||||
Abstract,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub enum Statement {
|
||||
InlineHtml(String),
|
||||
@ -71,6 +77,7 @@ pub enum Statement {
|
||||
extends: Option<Identifier>,
|
||||
implements: Vec<Identifier>,
|
||||
body: Block,
|
||||
flag: Option<ClassFlag>,
|
||||
},
|
||||
Method {
|
||||
name: Identifier,
|
||||
|
@ -69,52 +69,7 @@ impl Parser {
|
||||
|
||||
Statement::If { condition, then }
|
||||
},
|
||||
TokenKind::Class => {
|
||||
self.next();
|
||||
|
||||
let name = expect!(self, TokenKind::Identifier(i), i, "expected class name");
|
||||
let mut extends: Option<Identifier> = None;
|
||||
|
||||
if self.current.kind == TokenKind::Extends {
|
||||
self.next();
|
||||
extends = expect!(self, TokenKind::Identifier(i), Some(i.into()), "expected identifier");
|
||||
}
|
||||
|
||||
let mut implements = Vec::new();
|
||||
if self.current.kind == TokenKind::Implements {
|
||||
self.next();
|
||||
|
||||
while self.current.kind != TokenKind::LeftBrace {
|
||||
if self.current.kind == TokenKind::Comma {
|
||||
self.next();
|
||||
}
|
||||
|
||||
implements.push(expect!(self, TokenKind::Identifier(i), i.into(), "expected identifier"));
|
||||
}
|
||||
}
|
||||
|
||||
expect!(self, TokenKind::LeftBrace, "expected left-brace");
|
||||
|
||||
let mut body = Vec::new();
|
||||
while ! self.is_eof() && self.current.kind != TokenKind::RightBrace {
|
||||
let statement = match self.statement()? {
|
||||
Statement::Function { name, params, body } => {
|
||||
Statement::Method { name, params, body, flags: vec![] }
|
||||
},
|
||||
Statement::Var { var } => {
|
||||
Statement::Property { var }
|
||||
},
|
||||
s @ Statement::Method { .. } => s,
|
||||
_ => return Err(ParseError::InvalidClassStatement("Classes can only contain properties, constants and methods.".to_string(), self.current.span))
|
||||
};
|
||||
|
||||
body.push(statement);
|
||||
}
|
||||
|
||||
expect!(self, TokenKind::RightBrace, "expected right-brace");
|
||||
|
||||
Statement::Class { name: name.into(), extends, implements, body }
|
||||
},
|
||||
TokenKind::Class => self.class()?,
|
||||
TokenKind::Echo => {
|
||||
self.next();
|
||||
|
||||
@ -178,22 +133,6 @@ impl Parser {
|
||||
|
||||
Statement::Function { name: name.into(), params, body }
|
||||
},
|
||||
_ if is_method_visibility_modifier(&self.current.kind) => {
|
||||
let mut flags = vec![visibility_token_to_flag(&self.current.kind)];
|
||||
self.next();
|
||||
|
||||
while ! self.is_eof() && is_method_visibility_modifier(&self.current.kind) {
|
||||
flags.push(visibility_token_to_flag(&self.current.kind));
|
||||
self.next();
|
||||
}
|
||||
|
||||
match self.statement()? {
|
||||
Statement::Function { name, params, body } => {
|
||||
Statement::Method { name, params, body, flags }
|
||||
},
|
||||
_ => return Err(ParseError::InvalidClassStatement("Classes can only contain properties, constants and methods.".into(), self.current.span))
|
||||
}
|
||||
},
|
||||
TokenKind::Var => {
|
||||
self.next();
|
||||
|
||||
@ -213,6 +152,53 @@ impl Parser {
|
||||
})
|
||||
}
|
||||
|
||||
fn class(&mut self) -> Result<Statement, ParseError> {
|
||||
self.next();
|
||||
|
||||
let name = expect!(self, TokenKind::Identifier(i), i, "expected class name");
|
||||
let mut extends: Option<Identifier> = None;
|
||||
|
||||
if self.current.kind == TokenKind::Extends {
|
||||
self.next();
|
||||
extends = expect!(self, TokenKind::Identifier(i), Some(i.into()), "expected identifier");
|
||||
}
|
||||
|
||||
let mut implements = Vec::new();
|
||||
if self.current.kind == TokenKind::Implements {
|
||||
self.next();
|
||||
|
||||
while self.current.kind != TokenKind::LeftBrace {
|
||||
if self.current.kind == TokenKind::Comma {
|
||||
self.next();
|
||||
}
|
||||
|
||||
implements.push(expect!(self, TokenKind::Identifier(i), i.into(), "expected identifier"));
|
||||
}
|
||||
}
|
||||
|
||||
expect!(self, TokenKind::LeftBrace, "expected left-brace");
|
||||
|
||||
let mut body = Vec::new();
|
||||
while ! self.is_eof() && self.current.kind != TokenKind::RightBrace {
|
||||
let statement = match self.statement()? {
|
||||
Statement::Function { name, params, body } => {
|
||||
Statement::Method { name, params, body, flags: vec![] }
|
||||
},
|
||||
Statement::Var { var } => {
|
||||
Statement::Property { var }
|
||||
},
|
||||
s @ Statement::Method { .. } => s,
|
||||
_ => return Err(ParseError::InvalidClassStatement("Classes can only contain properties, constants and methods.".to_string(), self.current.span))
|
||||
};
|
||||
|
||||
body.push(statement);
|
||||
}
|
||||
|
||||
expect!(self, TokenKind::RightBrace, "expected right-brace");
|
||||
|
||||
Ok(Statement::Class { name: name.into(), extends, implements, body, flag: None })
|
||||
}
|
||||
|
||||
fn expression(&mut self, bp: u8) -> Result<Expression, ParseError> {
|
||||
if self.is_eof() {
|
||||
return Err(ParseError::UnexpectedEndOfFile);
|
||||
@ -335,20 +321,6 @@ impl Parser {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_method_visibility_modifier(kind: &TokenKind) -> bool {
|
||||
[TokenKind::Public, TokenKind::Protected, TokenKind::Private, TokenKind::Static].contains(kind)
|
||||
}
|
||||
|
||||
fn visibility_token_to_flag(kind: &TokenKind) -> MethodFlag {
|
||||
match kind {
|
||||
TokenKind::Public => MethodFlag::Public,
|
||||
TokenKind::Protected => MethodFlag::Protected,
|
||||
TokenKind::Private => MethodFlag::Private,
|
||||
TokenKind::Static => MethodFlag::Static,
|
||||
_ => unreachable!("{:?}", kind)
|
||||
}
|
||||
}
|
||||
|
||||
fn infix(lhs: Expression, op: TokenKind, rhs: Expression) -> Expression {
|
||||
if op == TokenKind::Equals {
|
||||
return Expression::Assign(Box::new(lhs), Box::new(rhs));
|
||||
@ -413,6 +385,7 @@ mod tests {
|
||||
body: vec![],
|
||||
extends: None,
|
||||
implements: vec![],
|
||||
flag: None,
|
||||
}
|
||||
};
|
||||
($name:literal, $body:expr) => {
|
||||
@ -421,6 +394,7 @@ mod tests {
|
||||
body: $body.to_vec(),
|
||||
extends: None,
|
||||
implements: vec![],
|
||||
flag: None,
|
||||
}
|
||||
};
|
||||
($name:literal, $extends:expr, $implements:expr, $body:expr) => {
|
||||
@ -429,6 +403,7 @@ mod tests {
|
||||
body: $body.to_vec(),
|
||||
extends: $extends,
|
||||
implements: $implements.to_vec(),
|
||||
flag: None,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user