draconic/src/reader.rs
Jason Travis Smith 99a816e2a5 The compiler can currently handle the include keyword.
Skipping the Lexer, the parser can find and replace the include statement
as long as it is on a line by itself.
2016-07-26 18:30:47 -04:00

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()
}
}