feat: Scanning of nested comments

master
Araozu 2024-07-29 17:01:35 -05:00
parent 14c1b6f8d8
commit 9b75323dc9
1 changed files with 47 additions and 8 deletions

View File

@ -35,7 +35,7 @@ fn scan_any_except_new_line(
pub fn scan_multiline(chars: &Vec<char>, start_pos: usize) -> LexResult { pub fn scan_multiline(chars: &Vec<char>, start_pos: usize) -> LexResult {
match multiline_impl(chars, start_pos + 2) { match multiline_impl(chars, start_pos + 2) {
Some((value, next_position)) => LexResult::Some( Some((value, next_position)) => LexResult::Some(
Token::new_multiline_comment(value, start_pos), Token::new_multiline_comment(value.iter().collect(), start_pos),
next_position, next_position,
), ),
None => { None => {
@ -49,17 +49,39 @@ pub fn scan_multiline(chars: &Vec<char>, start_pos: usize) -> LexResult {
} }
} }
fn multiline_impl(chars: &Vec<char>, start_pos: usize) -> Option<(String, usize)> { fn multiline_impl(chars: &Vec<char>, start_pos: usize) -> Option<(Vec<char>, usize)> {
let mut current_position = start_pos; let mut current_position = start_pos;
let mut result = Vec::<char>::new(); let mut result = Vec::<char>::new();
loop { loop {
match chars.get(current_position) { match chars.get(current_position) {
Some('/') => { Some('/') => {
// TODO: Check for a nested comment instead of
// appending match chars.get(current_position + 1) {
Some('*') => {
// Scan nested comment
let (mut nested, next_position) = match multiline_impl(chars, current_position + 2)
{
Some(v) => v,
None => {
// The nested comment is not closed.
return None;
}
};
result.push('/'); result.push('/');
current_position += 1; result.push('*');
result.append(&mut nested);
result.push('*');
result.push('/');
current_position = next_position;
}
Some(c) => {
// Append both characters
result.push('/');
result.push(*c);
}
None => return None,
}
} }
Some('*') => { Some('*') => {
// Check for the end of a comment // Check for the end of a comment
@ -67,7 +89,7 @@ fn multiline_impl(chars: &Vec<char>, start_pos: usize) -> Option<(String, usize)
Some('/') => { Some('/') => {
// Create and return the token, // Create and return the token,
// ignoring the `*/` // ignoring the `*/`
return Some((result.iter().collect(), current_position + 2)); return Some((result, current_position + 2));
} }
Some(c) => { Some(c) => {
// Append both and continue // Append both and continue
@ -87,7 +109,6 @@ fn multiline_impl(chars: &Vec<char>, start_pos: usize) -> Option<(String, usize)
current_position += 1; current_position += 1;
} }
None => { None => {
// Throw an error
// TODO: Also return the position where this token ends, // TODO: Also return the position where this token ends,
// to display better error messages. // to display better error messages.
// Requires LexError to implement an end_position field // Requires LexError to implement an end_position field
@ -231,4 +252,22 @@ mod tests {
} }
} }
} }
#[test]
fn shoud_scan_nested_multiline_comments() {
let input = str_to_vec("/* my /* comment */ */");
let result = scan_multiline(&input, 0);
match result {
LexResult::Some(t, next) => {
assert_eq!(22, next);
assert_eq!(" my /* comment */ ", t.value);
assert_eq!(0, t.position);
assert_eq!(TokenType::MultilineComment, t.token_type);
}
_ => {
panic!("Expected a multine comment")
}
}
}
} }