Skipping the Lexer, the parser can find and replace the include statement as long as it is on a line by itself.
226 lines
5.4 KiB
Rust
226 lines
5.4 KiB
Rust
use std::fs::File;
|
|
use std::io::Read;
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
// TODO: Make this work on only a predetermined size of a buffer.
|
|
|
|
|
|
/// Stores some input and allows it to be
|
|
/// read on a character by character basis.
|
|
///
|
|
pub struct Reader
|
|
{
|
|
/// The current position in the buffer.
|
|
position: usize,
|
|
|
|
/// The buffer of the input data to be read.
|
|
buffer: Vec<char>
|
|
}
|
|
|
|
|
|
|
|
impl Reader
|
|
{
|
|
/// Create a new empty Reader.
|
|
pub fn new() -> Reader
|
|
{
|
|
Reader
|
|
{
|
|
position: 0usize,
|
|
buffer: Vec::new(),
|
|
}
|
|
}
|
|
|
|
/// Create a new reader from a File.
|
|
pub fn from_file<F>(filepath: F) -> Reader
|
|
where F: AsRef<Path>
|
|
{
|
|
let mut reader: Reader;
|
|
|
|
// Create a new Reader and load the data
|
|
// for it from the file at the given filepath.
|
|
reader = Reader::new();
|
|
reader.load_from_file(filepath);
|
|
|
|
reader
|
|
}
|
|
|
|
/// Create a new reader from a String.
|
|
pub fn from_string(data: String) -> Reader
|
|
{
|
|
let mut reader: Reader;
|
|
|
|
// Create a new Reader and load the data to it.
|
|
reader = Reader::new();
|
|
reader.load_from_string(data);
|
|
|
|
reader
|
|
}
|
|
|
|
/// Reset the Reader back to the starting position.
|
|
pub fn reset(&mut self)
|
|
{
|
|
// Move back to the start of the buffer.
|
|
self.position = 0usize;
|
|
}
|
|
|
|
/// Clear the Reader of all data.
|
|
pub fn clear(&mut self)
|
|
{
|
|
self.buffer = Vec::new();
|
|
self.reset();
|
|
}
|
|
|
|
/// Clears the Reader and sets it to read from a File.
|
|
pub fn load_from_file<F>(&mut self, filepath: F)
|
|
where F: AsRef<Path>
|
|
{
|
|
let mut data: String;
|
|
|
|
// Open the file for reading and load the
|
|
// data into a String that will be parsed.
|
|
data = String::new();
|
|
match File::open(filepath.as_ref())
|
|
{
|
|
Ok(mut file) =>
|
|
{
|
|
match file.read_to_string(&mut data)
|
|
{
|
|
Ok(bytes_read) =>
|
|
{
|
|
info!("{} bytes read from {:?}",
|
|
bytes_read, filepath.as_ref());
|
|
}
|
|
|
|
Err(error) =>
|
|
{
|
|
error!("{}", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
Err(error) =>
|
|
{
|
|
error!("{}", error);
|
|
}
|
|
}
|
|
|
|
// Load the String read from the file.
|
|
self.load_from_string(data);
|
|
}
|
|
|
|
/// Clears the Reader and sets it to read from the given data.
|
|
pub fn load_from_string(&mut self, data: String)
|
|
{
|
|
// Clear the Reader.
|
|
self.clear();
|
|
|
|
// Parse the String that the reader is
|
|
// reading from as a set of characters
|
|
// in the Reader's buffer.
|
|
for character in data.chars()
|
|
{
|
|
self.buffer.push(character);
|
|
}
|
|
}
|
|
|
|
/// Get the current character.
|
|
pub fn get_char(&self) -> Result<char, &'static str>
|
|
{
|
|
// Make sure we are not at the end of the buffer.
|
|
if self.is_eob() == false
|
|
{
|
|
// Return the character at the current position.
|
|
Ok(self.buffer[self.position])
|
|
}
|
|
else
|
|
{
|
|
// There was an error.
|
|
Err("Unable to read character. \
|
|
No characters left in the input buffer.")
|
|
}
|
|
}
|
|
|
|
/// Get the current character and move the
|
|
/// Reader on to the next character.
|
|
pub fn consume_char(&mut self) -> Result<char, &'static str>
|
|
{
|
|
let character: char;
|
|
|
|
// Get the current character and move the position
|
|
// in the buffer forward.
|
|
character = try!(self.get_char());
|
|
self.position += 1;
|
|
|
|
// Return the character that was retrieved.
|
|
Ok(character)
|
|
}
|
|
|
|
/// Get a line of text from the current character to the next
|
|
/// newline character, including the current character.
|
|
pub fn get_line(&mut self) -> Result<String, &'static str>
|
|
{
|
|
let mut index: usize;
|
|
let mut buffer: String;
|
|
|
|
// Create a new buffer to hold the line created.
|
|
buffer = String::new();
|
|
|
|
// Now get the current position the reader is at.
|
|
index = self.position;
|
|
while index < self.buffer.len() && self.buffer[index] != '\n'
|
|
{
|
|
buffer.push(self.buffer[index]);
|
|
index += 1;
|
|
}
|
|
|
|
// Read the newline character if the reader did not run out of buffer.
|
|
if index < self.buffer.len() && self.buffer[index] == '\n'
|
|
{
|
|
buffer.push(self.buffer[index]);
|
|
}
|
|
|
|
// Return the buffer of characters that was created.
|
|
Ok(buffer)
|
|
}
|
|
|
|
/// Get a line of text from the current character to the next
|
|
/// newline character, including the current character and newline.
|
|
/// This will consume all the characters and move the position
|
|
/// of the reader.
|
|
pub fn consume_line(&mut self) -> Result<String, &'static str>
|
|
{
|
|
let mut continue_consuming: bool;
|
|
let mut current_char: char;
|
|
let mut buffer: String;
|
|
|
|
// Create a new buffer to hold the line created.
|
|
buffer = String::new();
|
|
|
|
// Consume all the characters of the line
|
|
// and add them to the buffer.
|
|
continue_consuming = true;
|
|
while continue_consuming == true
|
|
{
|
|
current_char = try!(self.consume_char());
|
|
buffer.push(current_char);
|
|
|
|
if current_char == '\n'
|
|
{
|
|
continue_consuming = false;
|
|
}
|
|
}
|
|
|
|
// Return the buffer of characters that was created.
|
|
Ok(buffer)
|
|
}
|
|
|
|
/// Check to see if we have reached the end of the buffer.
|
|
pub fn is_eob(&self) -> bool
|
|
{
|
|
self.position >= self.buffer.len()
|
|
}
|
|
}
|