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

Commit 1e94506

Browse files
parser: use separate tokens for heredocs/nowdocs
1 parent f18ab96 commit 1e94506

File tree

12 files changed

+64
-37
lines changed

12 files changed

+64
-37
lines changed

src/parser/ast.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,12 @@ pub enum Expression {
663663
InterpolatedString {
664664
parts: Vec<StringPart>,
665665
},
666+
Heredoc {
667+
parts: Vec<StringPart>,
668+
},
669+
Nowdoc {
670+
value: ByteString,
671+
},
666672
PropertyFetch {
667673
target: Box<Self>,
668674
property: Box<Self>,

src/parser/mod.rs

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::parser::error::ParseResult;
1313
use crate::parser::internal::ident::is_reserved_ident;
1414
use crate::parser::internal::precedence::{Associativity, Precedence};
1515
use crate::parser::state::State;
16+
use crate::prelude::ByteString;
1617
use crate::prelude::DefaultMatchArm;
1718

1819
pub mod ast;
@@ -1052,9 +1053,11 @@ impl Parser {
10521053
e
10531054
}
10541055
TokenKind::StringPart(_) => self.interpolated_string(state)?,
1055-
TokenKind::StartHeredoc(_, kind) => {
1056+
TokenKind::StartHeredoc(label, kind) => {
10561057
let kind = kind.clone();
1057-
self.doc_string(state, kind)?
1058+
let label = label.clone();
1059+
1060+
self.doc_string(state, label, kind)?
10581061
},
10591062
TokenKind::True => {
10601063
let e = Expression::Bool { value: true };
@@ -1568,44 +1571,57 @@ impl Parser {
15681571
Ok(Expression::InterpolatedString { parts })
15691572
}
15701573

1571-
fn doc_string(&self, state: &mut State, kind: DocStringKind) -> ParseResult<Expression> {
1574+
fn doc_string(&self, state: &mut State, label: ByteString, kind: DocStringKind) -> ParseResult<Expression> {
15721575
state.next();
15731576

1574-
let mut parts = Vec::new();
1577+
Ok(match kind {
1578+
DocStringKind::Heredoc => {
1579+
let mut parts = Vec::new();
15751580

1576-
while !matches!(state.current.kind, TokenKind::EndHeredoc(_, _, _)) {
1577-
if let Some(part) = self.interpolated_string_part(state)? {
1578-
parts.push(part);
1579-
}
1580-
}
1581+
while !matches!(state.current.kind, TokenKind::EndHeredoc(_, _, _)) {
1582+
if let Some(part) = self.interpolated_string_part(state)? {
1583+
parts.push(part);
1584+
}
1585+
}
15811586

1582-
let (indentation_type, indentation_amount) = match state.current.kind {
1583-
TokenKind::EndHeredoc(_, indentation_type, indentation_amount) => (indentation_type, indentation_amount),
1584-
_ => unreachable!(),
1585-
};
1586-
1587-
state.next();
1587+
let (indentation_type, indentation_amount) = match state.current.kind {
1588+
TokenKind::EndHeredoc(_, indentation_type, indentation_amount) => (indentation_type, indentation_amount),
1589+
_ => unreachable!(),
1590+
};
1591+
1592+
state.next();
15881593

1589-
// FIXME: Can we move this logic above into the loop, by peeking ahead in
1590-
// the token stream for the EndHeredoc? Might be more performant.
1591-
if let Some(indentation_type) = indentation_type {
1592-
let search_char: u8 = indentation_type.into();
1593-
1594-
for part in parts.iter_mut() {
1595-
match part {
1596-
StringPart::Const(bytes) => {
1597-
for _ in 0..indentation_amount {
1598-
if bytes.starts_with(&[search_char]) {
1599-
bytes.remove(0);
1600-
}
1594+
// FIXME: Can we move this logic above into the loop, by peeking ahead in
1595+
// the token stream for the EndHeredoc? Might be more performant.
1596+
if let Some(indentation_type) = indentation_type {
1597+
let search_char: u8 = indentation_type.into();
1598+
1599+
for part in parts.iter_mut() {
1600+
match part {
1601+
StringPart::Const(bytes) => {
1602+
for _ in 0..indentation_amount {
1603+
if bytes.starts_with(&[search_char]) {
1604+
bytes.remove(0);
1605+
}
1606+
}
1607+
},
1608+
_ => continue,
16011609
}
1602-
},
1603-
_ => continue,
1610+
}
16041611
}
1605-
}
1606-
}
16071612

1608-
Ok(Expression::InterpolatedString { parts })
1613+
Expression::Heredoc { parts }
1614+
},
1615+
DocStringKind::Nowdoc => {
1616+
// FIXME: This feels hacky. We should probably produce different tokens from the lexer
1617+
// but since I already had the logic in place for parsing heredocs, this was
1618+
// the fastest way to get nowdocs working too.
1619+
let s = expect_token!([TokenKind::StringPart(s) => s], state, "constant string");
1620+
expect_token!([TokenKind::EndHeredoc(..)], state, "label");
1621+
1622+
Expression::Nowdoc { value: s }
1623+
},
1624+
})
16091625
}
16101626

16111627
fn interpolated_string_part(&self, state: &mut State) -> ParseResult<Option<StringPart>> {

tests/0224/ast.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[
22
Expression {
3-
expr: InterpolatedString {
3+
expr: Heredoc {
44
parts: [
55
Const(
66
"Hello, world!",

tests/0224/tokens.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Token {
1212
kind: StartHeredoc(
1313
"EOF",
14+
Heredoc,
1415
),
1516
span: (
1617
3,

tests/0225/ast.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[
22
Expression {
3-
expr: InterpolatedString {
3+
expr: Heredoc {
44
parts: [
55
Const(
66
"Hello, world!",

tests/0225/tokens.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Token {
1212
kind: StartHeredoc(
1313
"TXT",
14+
Heredoc,
1415
),
1516
span: (
1617
3,

tests/0228/ast.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[
22
Expression {
3-
expr: InterpolatedString {
3+
expr: Heredoc {
44
parts: [
55
Const(
66
"Hello, world!\n",

tests/0228/tokens.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Token {
1212
kind: StartHeredoc(
1313
"EOF",
14+
Heredoc,
1415
),
1516
span: (
1617
3,

tests/0229/ast.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[
22
Expression {
3-
expr: InterpolatedString {
3+
expr: Heredoc {
44
parts: [
55
Const(
66
"Hello, world!",

tests/0229/tokens.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Token {
1212
kind: StartHeredoc(
1313
"EOF",
14+
Heredoc,
1415
),
1516
span: (
1617
3,

0 commit comments

Comments
 (0)