Start splitting up parsing
This commit is contained in:
parent
0718883a80
commit
dc24bbc883
5 changed files with 84 additions and 44 deletions
|
|
@ -31,7 +31,7 @@ fn main() {
|
||||||
|
|
||||||
let mut parser = Parser::new(file, content);
|
let mut parser = Parser::new(file, content);
|
||||||
|
|
||||||
let commands = match parser.parse() {
|
let commands = match parser.parse(parser::commands::parse) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
Err(es) => {
|
Err(es) => {
|
||||||
files.emit_all(&es);
|
files.emit_all(&es);
|
||||||
|
|
|
||||||
109
src/parser.rs
109
src/parser.rs
|
|
@ -1,10 +1,12 @@
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||||
|
|
||||||
use crate::source::{SourceFile, SourceSpan};
|
use crate::source::{SourceFile, SourceSpan};
|
||||||
|
|
||||||
|
pub mod commands;
|
||||||
|
mod task;
|
||||||
|
|
||||||
// TODO Add warnings for things like trailing whitespace
|
// TODO Add warnings for things like trailing whitespace
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -38,40 +40,64 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek(&self, amount: usize) -> &'a str {
|
pub fn peek(&self, amount: usize) -> &'a str {
|
||||||
|
// self.offset is always a valid start since take() ensures it is in the
|
||||||
|
// range 0..self.content.len()
|
||||||
let end = min(self.content.len(), self.offset + amount);
|
let end = min(self.content.len(), self.offset + amount);
|
||||||
&self.content[self.offset..end]
|
&self.content[self.offset..end]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_rest(&self) -> &'a str {
|
pub fn peek_rest(&self) -> &'a str {
|
||||||
|
// self.offset is always a valid start since take() ensures it is in the
|
||||||
|
// range 0..self.content.len()
|
||||||
&self.content[self.offset..]
|
&self.content[self.offset..]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn at_eof(&self) -> bool {
|
pub fn peek_line(&self) -> &'a str {
|
||||||
|
if let Some(i) = self.peek_rest().find('\n') {
|
||||||
|
self.peek(i)
|
||||||
|
} else {
|
||||||
|
self.peek_rest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn at(&self) -> usize {
|
||||||
|
self.offset
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn at_eof(&self) -> bool {
|
||||||
self.offset >= self.content.len()
|
self.offset >= self.content.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take(&mut self, amount: usize) {
|
pub fn take(&mut self, amount: usize) {
|
||||||
self.offset += amount;
|
// Ensure the offset always stays in the range 0..self.content.len()
|
||||||
|
self.offset = min(self.content.len(), self.offset + amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_line(&mut self) {
|
||||||
|
self.take(self.peek_line().len() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&self, at: usize, error: impl ToString) -> ParseError {
|
fn error(&self, at: usize, error: impl ToString) -> ParseError {
|
||||||
ParseError(self.file.span(at..at), error.to_string())
|
ParseError(self.file.span(at..at), error.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn uncritical(&mut self, at: usize, error: impl ToString) {
|
pub fn uncritical(&mut self, at: usize, error: impl ToString) {
|
||||||
self.errors.push(self.error(at, error));
|
self.errors.push(self.error(at, error));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn critical(&self, at: usize, error: impl ToString) -> ParseResult<()> {
|
pub fn critical<T>(&self, at: usize, error: impl ToString) -> ParseResult<T> {
|
||||||
Err(self.error(at, error))
|
Err(self.error(at, error))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self) -> Result<Vec<Command>, Vec<ParseError>> {
|
pub fn parse<T>(
|
||||||
match self.parse_commands() {
|
&mut self,
|
||||||
Ok(commands) => {
|
f: impl FnOnce(&mut Self) -> ParseResult<T>,
|
||||||
|
) -> Result<T, Vec<ParseError>> {
|
||||||
|
match f(self) {
|
||||||
|
Ok(result) => {
|
||||||
if self.errors.is_empty() {
|
if self.errors.is_empty() {
|
||||||
return Ok(commands);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
|
|
@ -82,39 +108,38 @@ impl<'a> Parser<'a> {
|
||||||
Err(self.errors.split_off(0))
|
Err(self.errors.split_off(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_commands(&mut self) -> ParseResult<Vec<Command>> {
|
// fn parse_commands(&mut self) -> ParseResult<Vec<Command>> {
|
||||||
let mut commands = vec![];
|
// let mut commands = vec![];
|
||||||
|
|
||||||
self.skip_empty_lines();
|
// self.skip_empty_lines();
|
||||||
while !self.at_eof() {
|
// while !self.at_eof() {
|
||||||
commands.push(self.parse_command()?);
|
// commands.push(self.parse_command()?);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if !self.at_eof() {
|
// if !self.at_eof() {
|
||||||
self.uncritical(self.offset, "expected EOF");
|
// self.uncritical(self.offset, "Expected EOF");
|
||||||
}
|
// }
|
||||||
|
|
||||||
Ok(commands)
|
// Ok(commands)
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn skip_empty_lines(&mut self) {
|
// fn skip_empty_lines(&mut self) {
|
||||||
loop {
|
// while self.peek_line().chars().all(|c| c.is_whitespace()) {
|
||||||
if let Some(i) = self.peek_rest().find('\n') {
|
// self.take_line();
|
||||||
if self.peek(i).chars().all(|c| c.is_whitespace()) {
|
// }
|
||||||
self.take(i + 1); // Include the newline
|
// }
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if self.peek_rest().chars().all(|c| c.is_whitespace()) {
|
|
||||||
self.take(self.peek_rest().len());
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_command(&mut self) -> ParseResult<Command> {
|
// fn parse_command(&mut self) -> ParseResult<Command> {
|
||||||
self.critical(self.offset, "idk, ded")?;
|
// let rest = self.peek_rest();
|
||||||
todo!()
|
// if rest.starts_with("TASK") {
|
||||||
}
|
// let task = self.parse_task()?;
|
||||||
|
// Ok(Command::Task(task))
|
||||||
|
// } else if rest.starts_with("NOTE") {
|
||||||
|
// todo!() // TODO Implement parsing NOTE command
|
||||||
|
// } else if rest.starts_with("BIRTHDAY") {
|
||||||
|
// todo!() // TODO Implement parsing BIRTHDAY command
|
||||||
|
// } else {
|
||||||
|
// self.critical(self.offset, "Expected command")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
src/parser/commands.rs
Normal file
7
src/parser/commands.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
use crate::commands::Command;
|
||||||
|
|
||||||
|
use super::{ParseResult, Parser};
|
||||||
|
|
||||||
|
pub fn parse(p: &mut Parser<'_>) -> ParseResult<Vec<Command>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
7
src/parser/task.rs
Normal file
7
src/parser/task.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
use crate::commands::Task;
|
||||||
|
|
||||||
|
use super::{ParseResult, Parser};
|
||||||
|
|
||||||
|
fn parse_task(p: &mut Parser<'_>) -> ParseResult<Task> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
@ -45,7 +45,8 @@ impl SourceFiles {
|
||||||
|
|
||||||
for diagnostic in diagnostics {
|
for diagnostic in diagnostics {
|
||||||
let diagnostic: Diagnostic<usize> = diagnostic.into();
|
let diagnostic: Diagnostic<usize> = diagnostic.into();
|
||||||
term::emit(&mut stderr.lock(), &config, &self.files, &diagnostic);
|
term::emit(&mut stderr.lock(), &config, &self.files, &diagnostic)
|
||||||
|
.expect("failed to print errors");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue