parser: support blockless statements

Closes #33.
This commit is contained in:
Ryan Chandler 2022-12-08 19:32:13 +00:00
parent 2db9d4641b
commit 00834ed3ff
No known key found for this signature in database
GPG Key ID: F113BCADDB3B0CCA
5 changed files with 321 additions and 46 deletions

View File

@ -264,11 +264,14 @@ pub fn if_statement(state: &mut State) -> ParseResult<Statement> {
utils::skip_right_parenthesis(state)?;
let body = if state.current.kind == TokenKind::LeftBrace {
utils::skip_left_brace(state)?;
let body = blocks::body(state, &TokenKind::RightBrace)?;
let then = blocks::body(state, &TokenKind::RightBrace)?;
utils::skip_right_brace(state)?;
then
} else {
vec![parser::statement(state)?]
};
else_ifs.push(ElseIf { condition, body });
} else {

View File

@ -5,6 +5,7 @@ use crate::parser::expressions;
use crate::parser::internal::blocks;
use crate::parser::internal::utils;
use crate::parser::state::State;
use crate::parser;
pub fn foreach_loop(state: &mut State) -> ParseResult<Statement> {
utils::skip(state, TokenKind::Foreach)?;
@ -38,22 +39,20 @@ pub fn foreach_loop(state: &mut State) -> ParseResult<Statement> {
utils::skip_right_parenthesis(state)?;
let end_token = if state.current.kind == TokenKind::Colon {
let body = if state.current.kind == TokenKind::Colon {
utils::skip_colon(state)?;
TokenKind::EndForeach
} else {
utils::skip_left_brace(state)?;
TokenKind::RightBrace
};
let body = blocks::body(state, &end_token)?;
if end_token == TokenKind::EndForeach {
let then = blocks::body(state, &TokenKind::EndForeach)?;
utils::skip(state, TokenKind::EndForeach)?;
utils::skip_semicolon(state)?;
} else {
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::Foreach {
expr,
@ -119,21 +118,19 @@ pub fn for_loop(state: &mut State) -> ParseResult<Statement> {
utils::skip_right_parenthesis(state)?;
let end_token = if state.current.kind == TokenKind::Colon {
let then = if state.current.kind == TokenKind::Colon {
utils::skip_colon(state)?;
TokenKind::EndFor
} else {
utils::skip_left_brace(state)?;
TokenKind::RightBrace
};
let then = blocks::body(state, &end_token)?;
if end_token == TokenKind::EndFor {
let then = blocks::body(state, &TokenKind::EndFor)?;
utils::skip(state, TokenKind::EndFor)?;
utils::skip_semicolon(state)?;
} else {
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::For {
@ -147,9 +144,14 @@ pub fn for_loop(state: &mut State) -> ParseResult<Statement> {
pub fn do_loop(state: &mut State) -> ParseResult<Statement> {
utils::skip(state, TokenKind::Do)?;
let body = if state.current.kind == TokenKind::LeftBrace {
utils::skip_left_brace(state)?;
let body = blocks::body(state, &TokenKind::RightBrace)?;
utils::skip_right_brace(state)?;
body
} else {
vec![parser::statement(state)?]
};
utils::skip(state, TokenKind::While)?;
@ -174,24 +176,20 @@ pub fn while_loop(state: &mut State) -> ParseResult<Statement> {
utils::skip_semicolon(state)?;
vec![]
} else {
let end_token = if state.current.kind == TokenKind::Colon {
if state.current.kind == TokenKind::Colon {
utils::skip_colon(state)?;
TokenKind::EndWhile
} else {
utils::skip_left_brace(state)?;
TokenKind::RightBrace
};
let body = blocks::body(state, &end_token)?;
if end_token == TokenKind::RightBrace {
utils::skip_right_brace(state)?;
} else {
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)?]
}
body
};
Ok(Statement::While { condition, body })

View File

@ -243,9 +243,11 @@ fn statement(state: &mut State) -> ParseResult<Statement> {
utils::skip(state, TokenKind::EndDeclare)?;
utils::skip_semicolon(state)?;
b
} else {
} else if state.current.kind == TokenKind::SemiColon {
utils::skip_semicolon(state)?;
vec![]
} else {
vec![statement(state)?]
};
Statement::Declare { declares, body }

257
tests/fixtures/0276/ast.txt vendored Normal file
View File

@ -0,0 +1,257 @@
[
If {
condition: Variable(
Variable {
start: (
3,
5,
),
name: "a",
end: (
3,
7,
),
},
),
then: [
Expression {
expr: Variable(
Variable {
start: (
3,
9,
),
name: "A",
end: (
3,
11,
),
},
),
},
],
else_ifs: [
ElseIf {
condition: Variable(
Variable {
start: (
4,
9,
),
name: "b",
end: (
4,
11,
),
},
),
body: [
Expression {
expr: Variable(
Variable {
start: (
4,
13,
),
name: "B",
end: (
4,
15,
),
},
),
},
],
},
],
else: Some(
[
Expression {
expr: Variable(
Variable {
start: (
5,
6,
),
name: "C",
end: (
5,
8,
),
},
),
},
],
),
},
For {
init: [],
condition: [],
loop: [],
then: [
Expression {
expr: Variable(
Variable {
start: (
7,
10,
),
name: "foo",
end: (
7,
14,
),
},
),
},
],
},
Foreach {
expr: Variable(
Variable {
start: (
9,
10,
),
name: "a",
end: (
9,
13,
),
},
),
by_ref: false,
key_var: None,
value_var: Variable(
Variable {
start: (
9,
16,
),
name: "b",
end: (
9,
18,
),
},
),
body: [
Expression {
expr: Variable(
Variable {
start: (
9,
20,
),
name: "AB",
end: (
9,
23,
),
},
),
},
],
},
While {
condition: Variable(
Variable {
start: (
11,
8,
),
name: "a",
end: (
11,
10,
),
},
),
body: [
Expression {
expr: Variable(
Variable {
start: (
11,
12,
),
name: "A",
end: (
11,
14,
),
},
),
},
],
},
DoWhile {
condition: Variable(
Variable {
start: (
13,
15,
),
name: "a",
end: (
13,
17,
),
},
),
body: [
Expression {
expr: Variable(
Variable {
start: (
13,
4,
),
name: "A",
end: (
13,
6,
),
},
),
},
],
},
Declare {
declares: [
DeclareItem {
key: Identifier {
start: (
15,
10,
),
name: "a",
end: (
15,
11,
),
},
value: LiteralString {
value: "b",
},
},
],
body: [
Expression {
expr: Variable(
Variable {
start: (
15,
17,
),
name: "C",
end: (
15,
19,
),
},
),
},
],
},
]

15
tests/fixtures/0276/code.php vendored Normal file
View File

@ -0,0 +1,15 @@
<?php
if ($a) $A;
elseif ($b) $B;
else $C;
for (;;) $foo;
foreach ($a as $b) $AB;
while ($a) $A;
do $A; while ($a);
declare (a='b') $C;