feat: 新增块注释及测试

This commit is contained in:
0264408
2026-06-17 17:26:37 +08:00
parent df9ecb4de1
commit 99c9e9c9bd
2 changed files with 81 additions and 0 deletions
+29
View File
@@ -92,6 +92,9 @@ impl Lexer {
self.advance(); self.advance();
} }
return None; return None;
} else if self.match_char('*') {
// 多行注释 /* ... */
return self.block_comment(line, column, errors);
} else if self.match_char('=') { } else if self.match_char('=') {
TokenKind::SlashEqual TokenKind::SlashEqual
} else { } else {
@@ -225,6 +228,32 @@ impl Lexer {
self.current >= self.src.len() self.current >= self.src.len()
} }
/// consume multi-line comment, tracking line numbers for error reporting
fn block_comment(
&mut self,
start_line: usize,
start_column: usize,
errors: &mut Vec<RuntimeError>,
) -> Option<Token> {
while !self.is_at_end() {
let c = self.advance();
if c == '\n' {
self.line += 1;
self.column = 1;
} else if c == '*' && !self.is_at_end() && self.peek() == '/' {
self.advance(); // consume closing '/'
return None;
}
}
// EOF in block comment
errors.push(RuntimeError::lex(
"Unterminated block comment (missing */)",
start_line,
start_column,
));
None
}
fn string_literal( fn string_literal(
&mut self, &mut self,
line: usize, line: usize,
+52
View File
@@ -282,6 +282,58 @@ fn comment_between_tokens() {
assert_eq!(kinds, vec![TokenKind::Number(1.0), TokenKind::Number(2.0)]); assert_eq!(kinds, vec![TokenKind::Number(1.0), TokenKind::Number(2.0)]);
} }
// ----- block comments /* ... */ -----
#[test]
fn block_comment_ignored() {
let kinds = tokenize("42 /* comment */ 99");
assert_eq!(kinds, vec![TokenKind::Number(42.0), TokenKind::Number(99.0)]);
}
#[test]
fn empty_block_comment() {
let kinds = tokenize("42/**/99");
assert_eq!(kinds, vec![TokenKind::Number(42.0), TokenKind::Number(99.0)]);
}
#[test]
fn block_comment_multiline() {
let kinds = tokenize("1 /* line 1\nline 2\nline 3 */ 2");
assert_eq!(kinds, vec![TokenKind::Number(1.0), TokenKind::Number(2.0)]);
}
#[test]
fn block_comment_only() {
let kinds = tokenize("/* just a block comment */");
assert!(kinds.is_empty());
}
#[test]
fn block_comment_with_asterisks_inside() {
let kinds = tokenize("1 /*** weird ***/ 2");
assert_eq!(kinds, vec![TokenKind::Number(1.0), TokenKind::Number(2.0)]);
}
#[test]
fn block_comment_line_numbers_tracked() {
let (tokens, _errors) = tokenize_full("/* line1\nline2 */\n42");
let num = tokens.iter().find(|t| matches!(t.kind, TokenKind::Number(_))).unwrap();
assert_eq!(num.line, 3);
}
#[test]
fn unterminated_block_comment() {
let (_, errors) = tokenize_full("/* no closing");
assert_eq!(errors.len(), 1);
assert!(errors[0].to_string().contains("Unterminated block comment"));
}
#[test]
fn block_then_line_comment() {
let kinds = tokenize("/* block */ // line\n42");
assert_eq!(kinds, vec![TokenKind::Number(42.0)]);
}
// ----- whitespace ----- // ----- whitespace -----
#[test] #[test]