diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 4d76cadf867df4dc36f55d9c3012bb91000d9304..cecc9e8c2cb32e1e507578d9fed23a5c7b6c55bb 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,11 +4,16 @@ "version": "2.0.0", "tasks": [ { - "type": "cargo", - "subcommand": "build", + "type": "shell", + "label": "cargo check --example main_span_expr", + "command": "cargo check --example main_span_expr", "problemMatcher": [ "$rustc" - ] + ], + "group": { + "kind": "build", + "isDefault": true + } } ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index cb26762684ba80d49d43c5c785395782e77ec6c7..2e2899c867e521b006534f256466ce84c5ec7f0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,10 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "bytecount" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.9" @@ -10,6 +15,7 @@ name = "first" version = "0.1.0" dependencies = [ "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom_locate 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -39,6 +45,16 @@ dependencies = [ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nom_locate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -98,10 +114,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f861d9ce359f56dbcb6e0c2a1cb84e52ad732cadb57b806adeb3c7668caccbd8" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum lexical-core 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b0f90c979adde96d19eb10eb6431ba0c441e2f9e9bdff868b2f6f5114ff519" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c618b63422da4401283884e6668d39f819a106ef51f5f59b81add00075da35ca" +"checksum nom_locate 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f932834fd8e391fc7710e2ba17e8f9f8645d846b55aa63207e17e110a1e1ce35" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" diff --git a/examples/main_locate.rs b/examples/main_locate.rs index 3ee29998f7abc3846049f39ceef6ed33ced71876..fdf884f5f69839630a866bb39945faf626934d2f 100644 --- a/examples/main_locate.rs +++ b/examples/main_locate.rs @@ -26,12 +26,14 @@ pub enum Expr<'a> { BinOp(Span<'a>, Box<Expr<'a>>, Op, Box<Expr<'a>>), } +// this is the definititon of IResult // type IResult<I, O, E = u32> = Result<(I, O), Err<I, E>>; pub fn parse_i32(i: Span) -> IResult<Span, Expr> { map(digit1, |digit_str: Span| { Expr::Num(digit_str, digit_str.fragment.parse::<i32>().unwrap()) })(i) + // below is just an exapmle on howto generate an Error explicitly // Err(Err::Error((i, ErrorKind::Alpha))) } diff --git a/examples/main_span_expr.rs b/examples/main_span_expr.rs new file mode 100644 index 0000000000000000000000000000000000000000..139857ace9b12f370846b990b90960aeb7fd755b --- /dev/null +++ b/examples/main_span_expr.rs @@ -0,0 +1,104 @@ +extern crate nom; + +use nom::{ + branch::alt, + bytes::complete::tag, + character::complete::{digit1, multispace0}, + combinator::map, + sequence::{preceded, tuple}, + IResult, +}; + +use nom_locate::LocatedSpan; + +type Span<'a> = LocatedSpan<&'a str>; + +#[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(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> { + 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 (_, (s, e)) = parse_expr_ms(Span::new("\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. +// 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 exrtra field is not used, it can be used for metadata, such as filename.