Skip to content

Commit

Permalink
Merge pull request #1 from flick-lang/feature-line-numbers
Browse files Browse the repository at this point in the history
Add line number tracking for Errors
  • Loading branch information
maxslarsson authored May 28, 2022
2 parents ddee899 + f9d1ba7 commit 0038847
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 70 deletions.
9 changes: 5 additions & 4 deletions examples/bad_strs.fl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
x = "
y = "\w"
z = "\x3 ninety"
w = "\x3 ninety \u38"
x = "abscscsc
y = "abscscsc
z = "\w"
w = "\x3 ninety"
j = "\x3 ninety \u38"
36 changes: 33 additions & 3 deletions src/lexer/error.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,51 @@
use crate::lexer::location::Location;
use colored::Colorize;
use std::fmt::{Display, Formatter};

#[derive(Debug, PartialEq)]
pub struct Error {
pub(crate) loc: Location,
pub(crate) kind: ErrorKind,
}

impl Error {
pub fn new(kind: ErrorKind) -> Self {
Self { kind }
pub fn new(loc: impl Into<Location>, kind: ErrorKind) -> Self {
Self {
loc: loc.into(),
kind,
}
}
}
impl std::error::Error for Error {}

impl Display for Error {
// TODO: What if n digit numbers for rows and cols?
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", "error".red(), self.kind)
writeln!(
f,
"{}: {}",
"error".red().bold(),
self.kind.to_string().bold()
)?;
writeln!(
f,
" {} {}:{}:{}",
"-->".blue().bold(),
"temp-file-path",
self.loc.line,
self.loc.col
)?;
writeln!(f, " {}", "|".blue().bold())?;
writeln!(
f,
"{:>2} {} {}",
self.loc.line.to_string().bold(),
"|".blue().bold(),
"pub fn temp_line() {}"
)?;
writeln!(f, " {}", "|".blue().bold())?;
writeln!(f, " {}", "|".blue().bold())?;
Ok(())
}
}

Expand Down
17 changes: 17 additions & 0 deletions src/lexer/location.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct Location {
pub(crate) line: usize,
pub(crate) col: usize,
}

impl Location {
pub fn new(line: usize, col: usize) -> Self {
Self { line, col }
}
}

impl Into<Location> for (usize, usize) {
fn into(self) -> Location {
Location::new(self.0, self.1)
}
}
1 change: 1 addition & 0 deletions src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod error;
mod source_iterator;
mod token;
mod tokens;
mod location;

pub use token::Bracket;
pub use token::Comment;
Expand Down
63 changes: 61 additions & 2 deletions src/lexer/source_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
use crate::lexer::location::Location;
use std::iter::{Enumerate, Peekable};
use std::str::Chars;

#[derive(Debug)]
pub struct SourceIterator<'a> {
/// Location of character that self.next() will return next time it is called
next_loc: Option<Location>,
/// Location of what self.next() returned last time it was called
cur_loc: Option<Location>,
src: Peekable<Enumerate<Chars<'a>>>,
}

impl<'a> SourceIterator<'a> {
pub fn new(source: &'a str) -> Self {
Self {
next_loc: Some(Location::new(1, 1)),
cur_loc: None,
src: source.chars().enumerate().peekable(),
}
}
Expand All @@ -19,7 +26,7 @@ impl<'a> SourceIterator<'a> {

pub fn skip(&mut self, n: usize) {
for _ in 0..n {
if self.src.next().is_none() {
if self.next().is_none() {
break;
}
}
Expand Down Expand Up @@ -56,8 +63,31 @@ impl<'a> SourceIterator<'a> {
}
}

/// Returns the next character of the iterator and steps the iterator. This functions also
/// keeps track of line and column numbers.
///
/// Assumption: Every function that steps the iterator does so through this function
pub fn next(&mut self) -> Option<char> {
self.src.next().map(|(_, c)| c)
let next = self.src.next().map(|(_, c)| c);

self.cur_loc = self.next_loc;

// Safe to unwrap self.next_loc when next is Some() because next_loc is only set to None
// when self.src runs out of chars to yield
match next {
Some('\n') => {
self.next_loc.as_mut().unwrap().line += 1;
self.next_loc.as_mut().unwrap().col = 1;
}
Some(_) => self.next_loc.as_mut().unwrap().col += 1,
None => self.next_loc = None,
}

next
}

pub fn loc(&self) -> Option<Location> {
self.cur_loc
}
}

Expand Down Expand Up @@ -117,4 +147,33 @@ mod tests {
iter.skip(100);
assert_eq!(iter.next(), None);
}

#[test]
fn line_count() {
let mut iter = SourceIterator::new("line 1\nline 2\nline 3");
iter.skip(1);
assert_eq!(iter.loc().map(|loc| loc.line), Some(1));
iter.skip(7);
assert_eq!(iter.loc().map(|loc| loc.line), Some(2));
iter.skip(7);
assert_eq!(iter.loc().map(|loc| loc.line), Some(3));
iter.skip(5);
assert_eq!(iter.loc().map(|loc| loc.line), Some(3));
iter.skip(1);
assert_eq!(iter.next(), None);
assert_eq!(iter.loc(), None);
}

#[test]
fn col_count() {
let mut iter = SourceIterator::new("123456789\n123456789");
iter.skip(6);
assert_eq!(iter.loc().map(|loc| loc.col), Some(6));
iter.skip(6);
assert_eq!(iter.loc().map(|loc| loc.col), Some(2));
iter.skip(1);
assert_eq!(iter.loc().map(|loc| loc.col), Some(3));
iter.skip(100);
assert_eq!(iter.next(), None);
}
}
Loading

0 comments on commit 0038847

Please sign in to comment.