Skip to content

Commit

Permalink
First steps up to and including error handling in Ch. 4 Scanning
Browse files Browse the repository at this point in the history
  • Loading branch information
Vegard committed May 7, 2022
0 parents commit 965a3ac
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 0 deletions.
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "seid"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "3.0", features = ["derive"] }
thiserror = "1.0"
anyhow = "1.0"
rustyline = "6.1.2"
19 changes: 19 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use thiserror::Error;

#[derive(Debug, Error, Clone)]
pub enum Error {
#[error("Usage: seid <filename> <[params]>")]
InputError(String),
#[error("REPL: {0}")]
Repl(String),
#[error("[line {0}] Error{1}: {2}")]
SyntaxError(String, String, String),
#[error("Anyhow: {0}")]
Anyhow(String),
}

impl std::convert::From<anyhow::Error> for Error {
fn from(e: anyhow::Error) -> Self {
Error::Anyhow(e.to_string())
}
}
162 changes: 162 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
use clap::Parser;
use std::{
fmt,
path::PathBuf,
};
use anyhow::{Context, Result};
mod error;
pub use error::Error;
mod scanner;
pub use scanner::Scanner;
mod token;
pub use token::Token;
use rustyline::error::ReadlineError;
use rustyline::Editor;

pub struct Repl {
history_path: String,
readline: Editor<()>,
}

impl Repl {
pub fn new() -> Repl {
let history_path = format!("{}/.seid_history", std::env::var("HOME").unwrap());
let mut readline = Editor::<()>::new();
// Attempt to read history if it exists
let _ = readline.load_history(&history_path);
Repl {
history_path,
readline,
}
}
}

#[derive(Parser)]
#[clap(about = "A runtime for mysterious bytes...")]
struct Args {
#[clap(
parse(from_os_str),
help = "Path to Seid file"
)]
file_name: PathBuf,
#[clap(
short,
long,
help = "Arguments to the input file",
default_value = vec![]
)]
prog_args: Vec<String>,
}

impl fmt::Display for Args {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "file name: {:?}", self.file_name)
}
}

fn main() -> Result<(), anyhow::Error>{
let args = Args::parse();

Ok(())
}

struct Seid {
file_name: PathBuf,
repl: Repl,
had_error: bool,
use_prompt: bool,
}

impl Seid{
fn new(arg: &Args) -> Self {
let mut run_prompt: bool = false;
let mut file_name = PathBuf::from("");
if std::env::args().len() < 2 {
run_prompt = true;
}
else {
file_name = arg.file_name;
}
Seid {
file_name: file_name,
repl: Repl::new(),
had_error: false,
use_prompt: run_prompt,
}
}

fn start(&self) -> Result<(), Error> {
if self.use_prompt {
match self.run_prompt() {
Ok(()) => {},
Err(e) => self.handle_error(e),
};
}
else {
match self.run_file() {
Ok(()) => {},
Err(e) => self.handle_error(e),
}
}
Ok(())
}

fn handle_error(&self, e: Error) {
match e {
Error::InputError(s) => {
eprintln!("{:?}", e)
},
Error::Repl(s) => {
eprintln!("{:?}", e)
},
Error::SyntaxError(s1, s2, s3) => {
eprintln!("{:?}", e);
self.had_error = true;
}
Error::Anyhow(s) => {
eprintln!("{:?}", e)
},
}
}

fn run_prompt(&self) -> Result<(), Error> {
loop {
match self.repl.readline.readline("(seid) > ") {
Err(ReadlineError::Interrupted) => {
// User pressed ctrl+c. Ignore it
println!("Type \"exit()\" to exit");
}
Err(ReadlineError::Eof) => {
// User pressed ctrl+d. Ignore it
println!("Type \"exit()\" to exit");
}
Err(err) => {
return Err(Error::Repl(err.to_string()))
}
Ok(line) => {
if line.eq("exit()") {
return Ok(());
}
self.run(&line)?;
}
}
}
}

fn run_file(&self) -> Result<(), Error> {
let contents = std::fs::read_to_string(self.file_name)
.with_context(|| format!("could not read file `{}`", self.file_name.to_str().unwrap()))?;
self.run(&contents)?;
Ok(())
}

fn run(&self, source: &str) -> Result<(), Error> {
let mut scanner: Scanner = Scanner::new(source);
let tokens: Vec<Token> = scanner.scan_tokens()?;

for token in tokens {
println!("{:?}", token);
}
Ok(())
}
}
18 changes: 18 additions & 0 deletions src/scanner.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use crate::Token;
use crate::Error;

pub struct Scanner {
source: String,
}

impl Scanner {
pub fn new(source: &str) -> Self {
Scanner {
source: String::from(source),
}
}

pub fn scan_tokens(&self) -> Result<Vec<Token>, Error> {
Ok(Vec::<Token>::new())
}
}
2 changes: 2 additions & 0 deletions src/token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#[derive(Debug)]
pub struct Token;

0 comments on commit 965a3ac

Please sign in to comment.