lexer: support looking ahead based on string literal

This commit is contained in:
Ryan Chandler 2022-08-09 00:46:50 +01:00
parent fb678c1e64
commit 30e0e5da60
No known key found for this signature in database
GPG Key ID: F113BCADDB3B0CCA
2 changed files with 47 additions and 1 deletions

View File

@ -605,7 +605,15 @@ impl Lexer {
},
'(' => {
self.col += 1;
TokenKind::LeftParen
if self.try_read("string)") {
self.col += 7;
self.skip(8);
TokenKind::StringCast
} else {
TokenKind::LeftParen
}
},
')' => {
self.col += 1;
@ -721,6 +729,34 @@ impl Lexer {
self.state = state;
}
fn char_at(&self, idx: usize) -> Option<&char> {
self.chars.get(idx)
}
fn try_read(&self, search: &'static str) -> bool {
if self.current.is_none() || self.peek.is_none() {
return false;
}
let start = self.cursor.saturating_sub(1);
let mut buffer = String::new();
for i in 0..search.len() {
match self.char_at(start + i) {
Some(char) => buffer.push(char.clone()),
_ => return false,
};
}
buffer.as_str() == search
}
fn skip(&mut self, count: usize) {
for _ in 0..count {
self.next();
}
}
fn next(&mut self) {
self.current = self.peek.clone();
self.peek = self.chars.get(self.cursor).cloned();
@ -862,6 +898,14 @@ mod tests {
]);
}
#[test]
fn casts() {
assert_tokens("<?php (string)", &[
open!(),
TokenKind::StringCast,
]);
}
#[test]
fn constant_single_quote_strings() {
assert_tokens(r#"<?php 'Hello, world!' 'I\'m a developer.' 'This is a backslash \\.' 'This is a multi-line

View File

@ -124,6 +124,7 @@ pub enum TokenKind {
SemiColon,
Slash,
Static,
StringCast,
Switch,
Throw,
Trait,
@ -262,6 +263,7 @@ impl Display for TokenKind {
Self::SemiColon => ";",
Self::Slash => "/",
Self::Static => "static",
Self::StringCast => "(string)",
Self::Switch => "switch",
Self::Throw => "throw",
Self::Trait => "trait",