use vb6parse::io::{Comparator, SourceStream};
fn main() {
let vb6_code = r#"Private Sub Form_Load()
Dim x As Integer
Dim message As String
x = 42
message = "Hello, World!"
MsgBox message
End Sub
' This is a comment
Public Function Calculate(a As Integer, b As Integer) As Integer
Calculate = a + b
End Function"#;
let mut stream = SourceStream::new("example.bas", vb6_code);
println!("=== SourceStream Example ===");
println!("File: {}", stream.file_name());
println!("Content length: {} characters", stream.contents.len());
println!("Initial offset: {}\n", stream.offset());
println!("=== Example 1: Basic Navigation ===");
if let Some(peek_text) = stream.peek(7) {
println!("Peeking at first 7 characters: '{peek_text}'");
}
if let Some(private_text) = stream.peek_text("Private", Comparator::CaseSensitive) {
println!("Found 'Private' at current position: '{private_text}'");
stream.forward(7); }
println!("Offset after moving past 'Private': {}", stream.offset());
if let Some(whitespace) = stream.take_ascii_whitespaces() {
println!("Consumed whitespace: '{whitespace:?}'");
}
if let Some(sub_keyword) = stream.take_ascii_alphabetics() {
println!("Found keyword: '{sub_keyword}'");
}
println!();
println!("=== Example 2: Line Operations ===");
stream.offset = 0;
if let Some((line, newline)) = stream.take_until_newline() {
println!("First line: '{line}'");
if let Some(nl) = newline {
println!("Newline character(s): '{nl:?}'");
}
}
let start_of_line = stream.start_of_line();
let end_of_line = stream.end_of_line();
println!("Start of current line: {start_of_line}");
println!("End of current line: {end_of_line}");
println!("\n=== Example 3: Parsing Tokens ===");
stream.offset = 0;
let mut tokens = Vec::new();
while !stream.is_empty() {
if stream.take_ascii_whitespaces().is_some() {
continue;
}
if let Some(identifier) = stream.take_ascii_underscore_alphanumerics() {
tokens.push(("Identifier", identifier));
}
else if let Some(punctuation) = stream.take_ascii_punctuation() {
tokens.push(("Punctuation", punctuation));
}
else if stream.peek_text("\"", Comparator::CaseSensitive).is_some() {
stream.forward(1); if let Some((string_content, _)) = stream.take_until("\"", Comparator::CaseSensitive) {
stream.forward(1); tokens.push(("String", string_content));
}
}
else if let Some(digits) = stream.take_ascii_digits() {
tokens.push(("Number", digits));
}
else if stream.take_newline().is_some() {
tokens.push(("Newline", "\\n"));
}
else {
stream.forward(1);
}
if tokens.len() >= 20 {
break;
}
}
println!("First 20 tokens:");
for (i, (token_type, value)) in tokens.iter().enumerate() {
println!(" {:2}: {:12} = '{}'", i + 1, token_type, value);
}
println!("\n=== Example 4: Case-Insensitive Operations ===");
stream.offset = 0;
let keywords_to_find = ["private", "PUBLIC", "Function", "MSGBOX"];
for keyword in &keywords_to_find {
let mut search_stream = stream.clone();
let mut found_positions = Vec::new();
while !search_stream.is_empty() {
if search_stream
.peek_text(*keyword, Comparator::CaseInsensitive)
.is_some()
{
found_positions.push(search_stream.offset());
search_stream.forward(keyword.len());
} else {
search_stream.forward(1);
}
if found_positions.len() >= 3 {
break;
}
}
if !found_positions.is_empty() {
println!("Found '{keyword}' at positions: {found_positions:?}");
}
}
println!("\n=== Example 5: Pattern-based Extraction ===");
stream.offset = 0;
while !stream.is_empty() {
if stream
.peek_text("Function", Comparator::CaseInsensitive)
.is_some()
{
let function_start = stream.offset();
if let Some((signature, _)) = stream.take_until_newline() {
println!(
"Found function at offset {}: '{}'",
function_start,
signature.trim()
);
}
} else {
stream.forward(1);
}
}
println!("\n=== Example 6: Bounds and Error Handling ===");
stream.offset = 0;
let beyond_end = stream.peek(stream.contents.len() + 10);
println!("Peeking beyond end result: {beyond_end:?}");
let original_len = stream.contents.len();
stream.forward(original_len - 10);
println!("Moved to near end, offset: {}", stream.offset());
println!("Is empty: {}", stream.is_empty());
if let Some(remaining) = stream.peek(20) {
println!("Last characters: '{remaining}'");
} else {
println!("Cannot peek 20 characters from current position");
}
let remaining_count = stream.contents.len() - stream.offset();
if let Some(final_chars) = stream.take_count(remaining_count) {
println!("Final {remaining_count} characters: '{final_chars:?}'");
}
println!("Stream is empty: {}", stream.is_empty());
println!("Final offset: {}", stream.offset());
println!("\n=== SourceStream Example Complete ===");
}