Return error instead of panic on failed parse

This commit is contained in:
2021-05-20 16:24:11 +02:00
parent 2d0875188e
commit 0af5d72005
6 changed files with 54 additions and 20 deletions

23
Cargo.lock generated
View File

@ -46,10 +46,11 @@ dependencies = [
[[package]] [[package]]
name = "blueprint" name = "blueprint"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"nom", "nom",
"structopt", "structopt",
"thiserror",
] ]
[[package]] [[package]]
@ -257,6 +258,26 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "thiserror"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.7.1" version = "1.7.1"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "blueprint" name = "blueprint"
version = "0.2.0" version = "0.3.0"
authors = ["Joakim Hulthe <joakim@hulthe.net>"] authors = ["Joakim Hulthe <joakim@hulthe.net>"]
description = "A simple templating library" description = "A simple templating library"
edition = "2018" edition = "2018"
@ -9,3 +9,4 @@ edition = "2018"
[dependencies] [dependencies]
nom = "6.1.2" nom = "6.1.2"
structopt = "0.3.21" structopt = "0.3.21"
thiserror = "1.0.24"

7
src/error.rs Normal file
View File

@ -0,0 +1,7 @@
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("Failed to parse template")]
ParseError,
}

View File

@ -1,10 +1,12 @@
mod ast; mod ast;
mod env; mod env;
mod error;
mod parser; mod parser;
pub use ast::{CmpOp, Expr, IfThen, Part, Template}; pub use ast::{CmpOp, Expr, IfThen, Part, Template};
pub use env::{Env, Value}; pub use env::{Env, Value};
pub use parser::parse_file; pub use error::Error;
pub use parser::parse_template;
#[cfg(test)] #[cfg(test)]
mod test { mod test {
@ -13,7 +15,7 @@ mod test {
#[test] #[test]
fn test_parse_empty() { fn test_parse_empty() {
let input = ""; let input = "";
let ast = parse_file(&input).expect("failed to parse"); let ast = parse_template(&input).expect("failed to parse");
eprintln!("{:#?}", ast); eprintln!("{:#?}", ast);
assert_eq!(ast, Template { parts: vec![] }); assert_eq!(ast, Template { parts: vec![] });
} }
@ -21,7 +23,7 @@ mod test {
#[test] #[test]
fn test_parse_text() { fn test_parse_text() {
let input = "hello there GENERAL KENOBI"; let input = "hello there GENERAL KENOBI";
let ast = parse_file(&input).expect("failed to parse"); let ast = parse_template(&input).expect("failed to parse");
eprintln!("{:#?}", ast); eprintln!("{:#?}", ast);
assert_eq!( assert_eq!(
ast, ast,
@ -34,7 +36,7 @@ mod test {
#[test] #[test]
fn test_parse_if() { fn test_parse_if() {
let input = "one {% if foo %} two {% end %} three"; let input = "one {% if foo %} two {% end %} three";
let ast = parse_file(&input).expect("failed to parse"); let ast = parse_template(&input).expect("failed to parse");
eprintln!("{:#?}", ast); eprintln!("{:#?}", ast);
assert_eq!( assert_eq!(
ast, ast,
@ -58,7 +60,7 @@ mod test {
#[test] #[test]
fn test_parse_if_str() { fn test_parse_if_str() {
let input = "one {% if foo >= \"bar\" %} two {% end %} three"; let input = "one {% if foo >= \"bar\" %} two {% end %} three";
let ast = parse_file(&input).expect("failed to parse"); let ast = parse_template(&input).expect("failed to parse");
eprintln!("{:#?}", ast); eprintln!("{:#?}", ast);
assert_eq!( assert_eq!(
ast, ast,
@ -86,7 +88,7 @@ mod test {
#[test] #[test]
fn test_parse_eq() { fn test_parse_eq() {
let input = "one {% if foo == bar %} two {% end %} three"; let input = "one {% if foo == bar %} two {% end %} three";
let ast = parse_file(&input).expect("failed to parse"); let ast = parse_template(&input).expect("failed to parse");
eprintln!("{:#?}", ast); eprintln!("{:#?}", ast);
assert_eq!( assert_eq!(
ast, ast,
@ -114,7 +116,7 @@ mod test {
#[test] #[test]
fn test_parse_if_elif_else() { fn test_parse_if_elif_else() {
let input = "one {% if foo %} two {% elif bar %} three {% else %} four {% end %} five"; let input = "one {% if foo %} two {% elif bar %} three {% else %} four {% end %} five";
let ast = parse_file(&input).expect("failed to parse"); let ast = parse_template(&input).expect("failed to parse");
eprintln!("{:#?}", ast); eprintln!("{:#?}", ast);
assert_eq!( assert_eq!(
ast, ast,
@ -141,7 +143,7 @@ mod test {
#[test] #[test]
fn test_parse_nested() { fn test_parse_nested() {
let input = "one {% if foo %} two {% if bar %} three {% end %} four {% end %} five"; let input = "one {% if foo %} two {% if bar %} three {% end %} four {% end %} five";
let ast = parse_file(&input).expect("failed to parse"); let ast = parse_template(&input).expect("failed to parse");
eprintln!("{:#?}", ast); eprintln!("{:#?}", ast);
let expected = Template { let expected = Template {
parts: vec![ parts: vec![

View File

@ -13,11 +13,11 @@ struct Opt {
fn main() { fn main() {
let opt = Opt::from_args(); let opt = Opt::from_args();
let file = read_to_string(&opt.template).expect("failed to load file"); let file = read_to_string(&opt.template).expect("failed to load file");
let template = blueprint::parse_file(&file).expect("failed to parse"); let template = blueprint::parse_template(&file).expect("failed to parse");
let env = opt let env = opt
.env .env
.into_iter() .into_iter()
.map(|key| (key, Value::Str("".into()))) .map(|key| (key, Value::Bool(true)))
.collect(); .collect();
let mut stdout = io::stdout(); let mut stdout = io::stdout();

View File

@ -1,4 +1,5 @@
use crate::ast::*; use crate::ast::{CmpOp, Expr, IfThen, Part, Template};
use crate::Error;
use nom::{ use nom::{
branch::alt, branch::alt,
bytes::complete::{is_not, tag, take_until}, bytes::complete::{is_not, tag, take_until},
@ -162,19 +163,21 @@ fn block(word: &'static str) -> impl Fn(&str) -> IResult<&str, ()> {
} }
} }
pub fn parse_file(file: &str) -> Result<Template, ()> { pub fn parse_template(template: &str) -> Result<Template, Error> {
match parts(file) { match parts(template) {
Ok((rest, parts)) => { Ok((rest, parts)) => {
//eprintln!("{:#?}", parts); //eprintln!("{:#?}", parts);
if rest != "" { if rest != "" {
panic!("failed to parse input. remainder: \"{}\"", rest); //panic!("failed to parse input. remainder: \"{}\"", rest);
} Err(Error::ParseError)
} else {
Ok(Template { parts }) Ok(Template { parts })
} }
Err(e) => { }
panic!("{:#?}", e); Err(_e) => {
//panic!("{:#?}", _e);
Err(Error::ParseError)
} }
} }
} }