Merge pull request #31 from edsrzf/parse-include

This commit is contained in:
Ryan Chandler 2022-09-12 11:45:51 +01:00 committed by GitHub
commit 0f0629ff8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 97 additions and 27 deletions

View File

@ -846,6 +846,8 @@ fn identifier_to_keyword(ident: &str) -> Option<TokenKind> {
"foreach" => TokenKind::Foreach, "foreach" => TokenKind::Foreach,
"function" => TokenKind::Function, "function" => TokenKind::Function,
"if" => TokenKind::If, "if" => TokenKind::If,
"include" => TokenKind::Include,
"include_once" => TokenKind::IncludeOnce,
"implements" => TokenKind::Implements, "implements" => TokenKind::Implements,
"interface" => TokenKind::Interface, "interface" => TokenKind::Interface,
"instanceof" => TokenKind::Instanceof, "instanceof" => TokenKind::Instanceof,

View File

@ -90,6 +90,8 @@ pub enum TokenKind {
Identifier(String), Identifier(String),
If, If,
Implements, Implements,
Include,
IncludeOnce,
Increment, Increment,
InlineHtml(String), InlineHtml(String),
Instanceof, Instanceof,

View File

@ -143,6 +143,26 @@ pub struct StaticVar {
pub default: Option<Expression>, pub default: Option<Expression>,
} }
#[derive(Debug, PartialEq, Clone, Serialize)]
pub enum IncludeKind {
Include,
IncludeOnce,
Require,
RequireOnce,
}
impl From<&TokenKind> for IncludeKind {
fn from(k: &TokenKind) -> Self {
match k {
TokenKind::Include => IncludeKind::Include,
TokenKind::IncludeOnce => IncludeKind::IncludeOnce,
TokenKind::Require => IncludeKind::Require,
TokenKind::RequireOnce => IncludeKind::RequireOnce,
_ => unreachable!(),
}
}
}
#[derive(Debug, PartialEq, Clone, Serialize)] #[derive(Debug, PartialEq, Clone, Serialize)]
pub enum Statement { pub enum Statement {
InlineHtml(String), InlineHtml(String),
@ -166,10 +186,8 @@ pub enum Statement {
value_var: Expression, value_var: Expression,
body: Block, body: Block,
}, },
Require { Include {
path: Expression, kind: IncludeKind,
},
RequireOnce {
path: Expression, path: Expression,
}, },
Var { Var {

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
ast::{ ast::{
Arg, ArrayItem, BackedEnumType, ClassFlag, ClosureUse, ElseIf, MagicConst, MethodFlag, Arg, ArrayItem, BackedEnumType, ClassFlag, ClosureUse, ElseIf, IncludeKind, MagicConst,
StaticVar, Use, UseKind, MethodFlag, StaticVar, Use, UseKind,
}, },
Block, Case, Catch, Expression, Identifier, MatchArm, Program, Statement, Type, Block, Case, Catch, Expression, Identifier, MatchArm, Program, Statement, Type,
}; };
@ -208,23 +208,18 @@ impl Parser {
Statement::While { condition, body } Statement::While { condition, body }
} }
TokenKind::Require => { TokenKind::Include
| TokenKind::IncludeOnce
| TokenKind::Require
| TokenKind::RequireOnce => {
let kind: IncludeKind = (&self.current.kind).into();
self.next(); self.next();
let path = self.expression(0)?; let path = self.expression(0)?;
self.semi()?; self.semi()?;
Statement::Require { path } Statement::Include { kind, path }
}
TokenKind::RequireOnce => {
self.next();
let path = self.expression(0)?;
self.semi()?;
Statement::RequireOnce { path }
} }
TokenKind::For => { TokenKind::For => {
self.next(); self.next();
@ -2089,7 +2084,7 @@ impl Display for ParseError {
mod tests { mod tests {
use super::Parser; use super::Parser;
use crate::{ use crate::{
ast::{Arg, ArrayItem, ElseIf, InfixOp, MethodFlag, PropertyFlag}, ast::{Arg, ArrayItem, ElseIf, IncludeKind, InfixOp, MethodFlag, PropertyFlag},
Expression, Identifier, Param, Statement, Type, Expression, Identifier, Param, Statement, Type,
}; };
use trunk_lexer::Lexer; use trunk_lexer::Lexer;
@ -2161,6 +2156,49 @@ mod tests {
}; };
} }
#[test]
fn include() {
assert_ast(
"<?php include 'foo.php';",
&[Statement::Include {
path: Expression::ConstantString {
value: "foo.php".into(),
},
kind: IncludeKind::Include,
}],
);
assert_ast(
"<?php include_once 'foo.php';",
&[Statement::Include {
path: Expression::ConstantString {
value: "foo.php".into(),
},
kind: IncludeKind::IncludeOnce,
}],
);
assert_ast(
"<?php require 'foo.php';",
&[Statement::Include {
path: Expression::ConstantString {
value: "foo.php".into(),
},
kind: IncludeKind::Require,
}],
);
assert_ast(
"<?php require_once 'foo.php';",
&[Statement::Include {
path: Expression::ConstantString {
value: "foo.php".into(),
},
kind: IncludeKind::RequireOnce,
}],
);
}
#[test] #[test]
fn instanceof() { fn instanceof() {
assert_ast( assert_ast(
@ -2631,7 +2669,7 @@ mod tests {
assert_ast( assert_ast(
"\ "\
<?php <?php
class Foo { class Foo {
function bar() { function bar() {
echo 1; echo 1;
@ -2657,7 +2695,7 @@ mod tests {
assert_ast( assert_ast(
"\ "\
<?php <?php
class Foo extends Bar {} class Foo extends Bar {}
", ",
&[class!("Foo", Some("Bar".to_string().into()), &[], &[])], &[class!("Foo", Some("Bar".to_string().into()), &[], &[])],
@ -2669,7 +2707,7 @@ mod tests {
assert_ast( assert_ast(
"\ "\
<?php <?php
class Foo implements Bar, Baz {} class Foo implements Bar, Baz {}
", ",
&[class!( &[class!(
@ -2986,15 +3024,25 @@ mod tests {
#[test] #[test]
fn comment_at_end_of_class() { fn comment_at_end_of_class() {
assert_ast("<?php assert_ast(
"<?php
class MyClass { class MyClass {
protected $a; protected $a;
// my comment // my comment
}", &[ }",
Statement::Class { name: "MyClass".into(), extends: None, implements: vec![], body: vec![ &[Statement::Class {
Statement::Property { var: "a".into(), value: None, r#type: None, flags: vec![PropertyFlag::Protected] } name: "MyClass".into(),
], flag: None } extends: None,
]); implements: vec![],
body: vec![Statement::Property {
var: "a".into(),
value: None,
r#type: None,
flags: vec![PropertyFlag::Protected],
}],
flag: None,
}],
);
} }
fn assert_ast(source: &str, expected: &[Statement]) { fn assert_ast(source: &str, expected: &[Statement]) {