Skip to content

Commit 16eba9b

Browse files
lang: Migrate to nom 4.0.0
As a workaround to rust-bakery/nom#544, migrate to nom 4 to ensure that the verbose-errors feature becomes additive and therefore portus compiles when used as a dependency. There were two classes of changes to the parser structure: 1. Error handling, as predicted and outlined here: https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_4.md#replacing-parser-result-matchers 2. Migration to "CompleteByteSlice". This was predicted in the migration notes: https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_4.md#dealing-with-incomplete-usage but caused underlying errors as reported here: rust-bakery/nom#790 (comment) To address this, shadow nom's `named!` macro with our own, `named_complete!`, which replaces the types appropriately. This is the solution proposed here: rust-bakery/nom#795 (comment)
1 parent b1cd757 commit 16eba9b

File tree

4 files changed

+172
-103
lines changed

4 files changed

+172
-103
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ bytes = "0.4.5"
1414
clap = "2.29"
1515
libc = "0.2"
1616
nix = "0.9.0"
17-
nom = "^3.2"
17+
nom = "^4"
1818
slog = "2"
1919
slog-async = "2"
2020
slog-term = "2"

src/lang/ast.rs

Lines changed: 68 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use nom::IResult;
1+
use nom;
22
use super::{Error, Result};
33

44
#[derive(Clone, Debug, PartialEq)]
@@ -51,7 +51,7 @@ pub enum Expr {
5151
}
5252

5353
use std::str;
54-
named!(
54+
named_complete!(
5555
op<Result<Op>>,
5656
alt!(
5757
alt!(tag!("+") | tag!("add")) => { |_| Ok(Op::Add) } |
@@ -90,7 +90,7 @@ fn check_expr(op: Op, left: Expr, right: Expr) -> Result<Expr> {
9090
}
9191

9292
use nom::multispace;
93-
named!(
93+
named_complete!(
9494
sexp<Result<Expr>>,
9595
ws!(delimited!(
9696
tag!("("),
@@ -111,26 +111,25 @@ named!(
111111
);
112112

113113
use nom::digit;
114+
use nom::types::CompleteByteSlice;
114115
use std::str::FromStr;
115-
named!(
116+
named_complete!(
116117
pub num<u64>,
117118
map_res!(
118-
map_res!(digit, str::from_utf8),
119-
FromStr::from_str
119+
digit,
120+
|d: CompleteByteSlice| {
121+
let st = str::from_utf8(d.0)?;
122+
FromStr::from_str(st).map_err(Error::from)
123+
}
120124
)
121125
);
122126

123127
use nom::is_alphanumeric;
124-
named!(
125-
name_raw<&[u8]>,
126-
take_while1!(|u: u8| is_alphanumeric(u) || u == b'.' || u == b'_')
127-
);
128-
129-
named!(
128+
named_complete!(
130129
pub name<String>,
131130
map_res!(
132-
name_raw,
133-
|n: &[u8]| str::from_utf8(n).map_err(Error::from).and_then(|s|
131+
take_while1!(|u: u8| is_alphanumeric(u) || u == b'.' || u == b'_'),
132+
|n: CompleteByteSlice| str::from_utf8(n.0).map_err(Error::from).and_then(|s|
134133
if s.starts_with("__") {
135134
Err(Error::from(
136135
format!("Names beginning with \"__\" are reserved for internal use: {:?}", s),
@@ -142,7 +141,7 @@ named!(
142141
)
143142
);
144143

145-
named!(
144+
named_complete!(
146145
pub atom<Result<Expr>>,
147146
ws!(do_parse!(
148147
val: alt!(
@@ -156,7 +155,7 @@ named!(
156155
))
157156
);
158157

159-
named!(
158+
named_complete!(
160159
command<Result<Expr>>,
161160
ws!(delimited!(
162161
tag!("("),
@@ -171,7 +170,7 @@ named!(
171170
))
172171
);
173172

174-
named!(
173+
named_complete!(
175174
pub comment<Result<Expr>>,
176175
ws!(do_parse!(
177176
tag!("#") >>
@@ -180,12 +179,12 @@ named!(
180179
))
181180
);
182181

183-
named!(
182+
named_complete!(
184183
pub expr<Result<Expr>>,
185184
alt_complete!(comment | sexp | command | atom)
186185
);
187186

188-
named!(
187+
named_complete!(
189188
pub exprs<Vec<Result<Expr>>>,
190189
many1!(expr)
191190
);
@@ -194,14 +193,15 @@ impl Expr {
194193
// TODO make return Iter
195194
pub fn new(src: &[u8]) -> Result<Vec<Self>> {
196195
use nom::Needed;
197-
match exprs(src) {
198-
IResult::Done(_, me) => me.into_iter().filter(|e| match e {
196+
match exprs(CompleteByteSlice(src)) {
197+
Ok((_, me)) => me.into_iter().filter(|e| match e {
199198
Ok(Expr::None) => false,
200199
_ => true,
201200
}).collect(),
202-
IResult::Error(e) => Err(Error::from(e)),
203-
IResult::Incomplete(Needed::Unknown) => Err(Error::from("need more src")),
204-
IResult::Incomplete(Needed::Size(s)) => Err(
201+
Err(nom::Err::Error(e)) |
202+
Err(nom::Err::Failure(e)) => Err(Error::from(e)),
203+
Err(nom::Err::Incomplete(Needed::Unknown)) => Err(Error::from("need more src")),
204+
Err(nom::Err::Incomplete(Needed::Size(s))) => Err(
205205
Error::from(format!("need {} more bytes", s)),
206206
),
207207
}
@@ -235,47 +235,77 @@ impl Expr {
235235

236236
#[cfg(test)]
237237
mod tests {
238+
use nom::types::CompleteByteSlice;
238239
use super::{Command, Expr, Op, Prim};
239240

240241
#[test]
241-
fn atom() {
242+
fn atom_0() {
243+
use super::name;
244+
let foo = b"foo";
245+
let er = name(CompleteByteSlice(foo));
246+
println!("{:?}", er.expect("parse single atom"));
247+
}
248+
249+
#[test]
250+
fn atom_1() {
242251
let foo = b"1";
243252
let er = Expr::new(foo);
244253
let e = er.unwrap();
245254
assert_eq!(e, vec![Expr::Atom(Prim::Num(1))]);
246-
255+
}
256+
257+
#[test]
258+
fn atom_2() {
247259
let foo = b"1 ";
248260
let er = Expr::new(foo);
249261
let e = er.unwrap();
250262
assert_eq!(e, vec![Expr::Atom(Prim::Num(1))]);
263+
}
251264

265+
#[test]
266+
fn atom_3() {
252267
let foo = b"+";
253268
let er = Expr::new(foo);
254269
match er {
255270
Ok(e) => panic!("false ok: {:?}", e),
256271
Err(_) => (),
257272
}
273+
}
258274

275+
#[test]
276+
fn atom_4() {
259277
let foo = b"true";
260278
let er = Expr::new(foo);
261279
let e = er.unwrap();
262280
assert_eq!(e, vec![Expr::Atom(Prim::Bool(true))]);
281+
}
263282

283+
#[test]
284+
fn atom_5() {
264285
let foo = b"false";
265286
let er = Expr::new(foo);
266287
let e = er.unwrap();
267288
assert_eq!(e, vec![Expr::Atom(Prim::Bool(false))]);
289+
}
268290

291+
#[test]
292+
fn atom_6() {
269293
let foo = b"x";
270294
let er = Expr::new(foo);
271295
let e = er.unwrap();
272296
assert_eq!(e, vec![Expr::Atom(Prim::Name(String::from("x")))]);
297+
}
273298

299+
#[test]
300+
fn atom_7() {
274301
let foo = b"acbdefg";
275302
let er = Expr::new(foo);
276303
let e = er.unwrap();
277304
assert_eq!(e, vec![Expr::Atom(Prim::Name(String::from("acbdefg")))]);
278-
305+
}
306+
307+
#[test]
308+
fn atom_8() {
279309
let foo = b"blah 10 20";
280310
let er = Expr::new(foo);
281311
let e = er.unwrap();
@@ -288,7 +318,7 @@ mod tests {
288318
]
289319
);
290320
}
291-
321+
292322
#[test]
293323
fn simple_exprs() {
294324
let foo = b"(+ 10 20)";
@@ -353,13 +383,14 @@ mod tests {
353383

354384
#[test]
355385
fn expr_leftover() {
386+
use nom;
356387
let foo = b"(+ 10 20))";
357-
use nom::{IResult, Needed};
388+
use nom::Needed;
358389
use super::exprs;
359-
use lang::{Error, Result};
360-
match exprs(foo) {
361-
IResult::Done(r, me) => {
362-
assert_eq!(r, b")");
390+
use lang::Result;
391+
match exprs(CompleteByteSlice(foo)) {
392+
Ok((r, me)) => {
393+
assert_eq!(r, CompleteByteSlice(b")"));
363394
assert_eq!(
364395
me.into_iter().collect::<Result<Vec<Expr>>>().unwrap(),
365396
vec![
@@ -371,11 +402,10 @@ mod tests {
371402
],
372403
);
373404
},
374-
IResult::Error(e) => panic!(e),
375-
IResult::Incomplete(Needed::Unknown) => panic!("need more src"),
376-
IResult::Incomplete(Needed::Size(s)) => panic!(
377-
Error::from(format!("need {} more bytes", s)),
378-
),
405+
Err(nom::Err::Error(e)) |
406+
Err(nom::Err::Failure(e)) => panic!(e),
407+
Err(nom::Err::Incomplete(Needed::Unknown)) => panic!("incomplete"),
408+
Err(nom::Err::Incomplete(Needed::Size(s))) => panic!("need {} more bytes", s),
379409
}
380410
}
381411

src/lang/mod.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,22 +130,47 @@ impl<'a> From<&'a str> for Error {
130130
Error(String::from(e))
131131
}
132132
}
133-
impl From<nom::simple_errors::Err> for Error {
134-
fn from(e: nom::simple_errors::Err) -> Error {
135-
Error(String::from(e.description()))
133+
impl<I, E> From<nom::Err<I, E>> for Error {
134+
fn from(e: nom::Err<I, E>) -> Error {
135+
Error(String::from(e.into_error_kind().description()))
136+
}
137+
}
138+
impl<I, E> From<nom::Context<I, E>> for Error {
139+
fn from(e: nom::Context<I, E>) -> Error {
140+
Error(String::from(e.into_error_kind().description()))
136141
}
137142
}
138143
impl From<std::string::FromUtf8Error> for Error {
139144
fn from(e: std::string::FromUtf8Error) -> Error {
140-
Error(format!("err {}", e))
145+
Error(format!("string err {}", e))
141146
}
142147
}
143148
impl From<std::str::Utf8Error> for Error {
144149
fn from(e: std::str::Utf8Error) -> Error {
145-
Error(format!("err {}", e))
150+
Error(format!("string err {}", e))
151+
}
152+
}
153+
impl From<std::num::ParseIntError> for Error {
154+
fn from(e: std::num::ParseIntError) -> Error {
155+
Error(format!("int err {}", e))
146156
}
147157
}
148158

159+
/// Define this helper macro to replace the named! macro provided by nom
160+
/// to address https://github.com/Geal/nom/issues/790 with CompleteByteSlice
161+
macro_rules! named_complete {
162+
($name:ident<$t:ty>, $submac:ident!( $($args:tt)* )) => (
163+
fn $name( i: nom::types::CompleteByteSlice ) -> nom::IResult<nom::types::CompleteByteSlice, $t, u32> {
164+
$submac!(i, $($args)*)
165+
}
166+
);
167+
(pub $name:ident<$t:ty>, $submac:ident!( $($args:tt)* )) => (
168+
pub fn $name( i: nom::types::CompleteByteSlice ) -> nom::IResult<nom::types::CompleteByteSlice, $t, u32> {
169+
$submac!(i, $($args)*)
170+
}
171+
)
172+
}
173+
149174
mod ast;
150175
mod datapath;
151176
mod prog;

0 commit comments

Comments
 (0)