From c9df980e57aca4db8b5f09aac04d4b643fa90930 Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Fri, 6 Sep 2019 19:23:53 +0200
Subject: [PATCH] span examples updated

---
 examples/main_span_expr.rs            |  78 ++++----------
 examples/main_span_expr_custom_err.rs | 149 ++++++++++++++++++++++++++
 2 files changed, 167 insertions(+), 60 deletions(-)
 create mode 100644 examples/main_span_expr_custom_err.rs

diff --git a/examples/main_span_expr.rs b/examples/main_span_expr.rs
index 3efbe08..214f843 100644
--- a/examples/main_span_expr.rs
+++ b/examples/main_span_expr.rs
@@ -6,34 +6,13 @@ use nom::{
     character::complete::{digit1, multispace0},
     combinator::map,
     sequence::{preceded, tuple},
-    Err,
-    error,
+    IResult,
 };
 
 use nom_locate::LocatedSpan;
 
 type Span<'a> = LocatedSpan<&'a str>;
 
-#[derive(Debug)]
-pub struct Error<'a>(Span<'a>, Option<Span<'a>>, ErrorKind);
-type IResult<'a, I, O, E = Error<'a>> = Result<(I, O), Err<E>>;
-
-impl<'a> error::ParseError<Span<'a>> for Error<'a> {
-  fn from_error_kind(input: Span<'a>, kind: error::ErrorKind) -> Self {
-    Error(input, None, ErrorKind::Nom(kind))
-  }
-
-  fn append(_: Span<'a>, _: error::ErrorKind, other: Self) -> Self {
-    other
-  }
-}
-
-#[derive(Debug)]
-enum ErrorKind {
-    Parse,
-    Nom(error::ErrorKind)
-}
-
 #[derive(Debug, PartialEq)]
 pub enum Op {
     Add,
@@ -57,20 +36,13 @@ pub enum Expr<'a> {
 
 type SpanExpr<'a> = (Span<'a>, Expr<'a>);
 
-pub fn parse_i32<'a>(i: Span<'a>) -> IResult<Span<'a>, SpanExpr> {
-    let (i, digits) = digit1(i)?;
-    if let Ok(int) = digits.fragment.parse() {
-        Ok((
-            i,
-            (digits, Expr::Num(int)),
-        ))
-    } else {
-        Err(Err::Failure(Error(
-            i,
-            Some(digits),
-            ErrorKind::Parse,
-        )))
-    }
+pub fn parse_i32(i: Span) -> IResult<Span, SpanExpr> {
+    map(digit1, |digit_str: Span| {
+        (
+            digit_str,
+            Expr::Num(digit_str.fragment.parse::<i32>().unwrap()),
+        )
+    })(i)
 }
 
 fn parse_expr(i: Span) -> IResult<Span, SpanExpr> {
@@ -109,30 +81,16 @@ fn dump_expr(se: &SpanExpr) -> String {
 }
 
 fn main() {
-    let i = "\n    1+2+10000- \n3";
-    match parse_expr_ms(Span::new(i)) {
-        Ok((_, (s, e))) => {
-            println!(
-                "span for expression: {:?}, \nline: {:?}, \ncolumn: {:?}",
-                s,
-                s.line,
-                s.get_column()
-            );
-            println!("raw e: {:?}", &e);
-            println!("pretty e: {}", dump_expr(&(s, e)));
-        },
-        Err(Err::Failure(Error(_, Some(s), err))) => {
-            println!(
-                "{:?} error at:\n\tLine: {:?}\n\tOffset: {:?}\n\tValue: {:?}",
-                err,
-                s.line,
-                s.get_column(),
-                s.fragment,
-            );
-            println!("raw s: {:?}", &s);
-        }
-        Err(err) => Err(err).unwrap(),
-    }
+    let (_, (s, e)) = parse_expr_ms(Span::new("\n\n    1+2 - \n3")).unwrap();
+    println!(
+        "span for the whole,expression: {:?}, \nline: {:?}, \ncolumn: {:?}",
+        s,
+        s.line,
+        s.get_column()
+    );
+
+    println!("raw e: {:?}", &e);
+    println!("pretty e: {}", dump_expr(&(s, e)));
 }
 
 // In this example, we have a `parse_expr_ms` is the "top" level parser.
diff --git a/examples/main_span_expr_custom_err.rs b/examples/main_span_expr_custom_err.rs
new file mode 100644
index 0000000..5b5be5b
--- /dev/null
+++ b/examples/main_span_expr_custom_err.rs
@@ -0,0 +1,149 @@
+extern crate nom;
+
+use nom::{
+    branch::alt,
+    bytes::complete::tag,
+    character::complete::{digit1, multispace0},
+    combinator::map,
+    sequence::{preceded, tuple},
+    Err,
+    error,
+};
+
+use nom_locate::LocatedSpan;
+
+type Span<'a> = LocatedSpan<&'a str>;
+
+#[derive(Debug)]
+pub struct Error<'a>(Span<'a>, Option<Span<'a>>, ErrorKind);
+type IResult<'a, I, O, E = Error<'a>> = Result<(I, O), Err<E>>;
+
+impl<'a> error::ParseError<Span<'a>> for Error<'a> {
+  fn from_error_kind(input: Span<'a>, kind: error::ErrorKind) -> Self {
+    Error(input, None, ErrorKind::Nom(kind))
+  }
+
+  fn append(_: Span<'a>, _: error::ErrorKind, other: Self) -> Self {
+    other
+  }
+}
+
+#[derive(Debug)]
+enum ErrorKind {
+    Parse,
+    Nom(error::ErrorKind)
+}
+
+#[derive(Debug, PartialEq)]
+pub enum Op {
+    Add,
+    Sub,
+}
+
+type SpanOp<'a> = (Span<'a>, Op);
+
+fn parse_op(i: Span) -> IResult<Span, SpanOp> {
+    alt((
+        map(tag("+"), |s| (s, Op::Add)),
+        map(tag("-"), |s| (s, Op::Sub)),
+    ))(i)
+}
+
+#[derive(Debug, PartialEq)]
+pub enum Expr<'a> {
+    Num(i32),
+    BinOp(Box<SpanExpr<'a>>, SpanOp<'a>, Box<SpanExpr<'a>>),
+}
+
+type SpanExpr<'a> = (Span<'a>, Expr<'a>);
+
+pub fn parse_i32<'a>(i: Span<'a>) -> IResult<Span<'a>, SpanExpr> {
+    let (i, digits) = digit1(i)?;
+    if let Ok(int) = digits.fragment.parse() {
+        Ok((
+            i,
+            (digits, Expr::Num(int)),
+        ))
+    } else {
+        Err(Err::Failure(Error(
+            i,
+            Some(digits),
+            ErrorKind::Parse,
+        )))
+    }
+}
+
+fn parse_expr(i: Span) -> IResult<Span, SpanExpr> {
+    alt((
+        map(
+            tuple((parse_i32, preceded(multispace0, parse_op), parse_expr_ms)),
+            |(l, op, r)| (i, Expr::BinOp(Box::new(l), op, Box::new(r))),
+        ),
+        parse_i32,
+    ))(i)
+}
+
+fn parse_expr_ms(i: Span) -> IResult<Span, SpanExpr> {
+    preceded(multispace0, parse_expr)(i)
+}
+
+// dumps a Span into a String
+fn dump_span(s: &Span) -> String {
+    format!(
+        "[line :{:?}, col:{:?}, {:?}]",
+        s.line,
+        s.get_column(),
+        s.fragment
+    )
+}
+
+// dumps a SpanExpr into a String
+fn dump_expr(se: &SpanExpr) -> String {
+    let (s, e) = se;
+    match e {
+        Expr::Num(_) => dump_span(s),
+        Expr::BinOp(l, (sop, _), r) => {
+            format!("<{} {} {}>", dump_expr(l), dump_span(sop), dump_expr(r))
+        }
+    }
+}
+
+fn main() {
+    let i = "\n    1+2+10000- \n3";
+    // uncomment below for an error example
+    // let i = "\n    1+200000000000000000+a10000- \n3";
+    let pe = parse_expr_ms(Span::new(i));
+    println!("pe: {:?}\n", pe);
+    match pe {
+        Ok((_, (s, e))) => {
+            println!(
+                "ok, span for expression: {:?}, \n\tline: {:?}, \n\tcolumn: {:?}\n",
+                s,
+                s.line,
+                s.get_column()
+            );
+            println!("raw e: {:?}\n", &e);
+            println!("pretty e: {}\n", dump_expr(&(s, e)));
+        },
+        Err(Err::Failure(Error(_, Some(s), err))) => {
+            println!(
+                "{:?} error at:\n\tline: {:?}\n\tcolumn: {:?}\n\tValue: {:?}\n",
+                err,
+                s.line,
+                s.get_column(),
+                s.fragment,
+            );
+            println!("raw s: {:?}", &s);
+        }
+        Err(err) => Err(err).unwrap(),
+    }
+}
+
+// In this example, we have a `parse_expr_ms` is the "top" level parser.
+// It consumes white spaces, allowing the location information to reflect the exact
+// positions in the input file.
+//
+// The dump_expr will create a pretty printing of the expression with spans for
+// each terminal. This will be useful for later for precise type error reporting.
+//
+// The extra field is not used, it can be used for metadata, such as filename.
-- 
GitLab