@@ -19,7 +19,7 @@ use nom::{
19
19
/// In this case, we want something tree-like
20
20
21
21
/// Starting from the most basic, we define some built-in functions that our lisp has
22
- #[ derive( Debug , PartialEq , Clone , Copy ) ]
22
+ #[ derive( Debug , Eq , PartialEq , Clone , Copy ) ]
23
23
pub enum BuiltIn {
24
24
Plus ,
25
25
Minus ,
@@ -32,7 +32,7 @@ pub enum BuiltIn {
32
32
/// We now wrap this type and a few other primitives into our Atom type.
33
33
/// Remember from before that Atoms form one half of our language.
34
34
35
- #[ derive( Debug , PartialEq , Clone ) ]
35
+ #[ derive( Debug , Eq , PartialEq , Clone ) ]
36
36
pub enum Atom {
37
37
Num ( i32 ) ,
38
38
Keyword ( String ) ,
@@ -50,7 +50,7 @@ pub enum Atom {
50
50
/// structure that we can deal with programmatically. Thus any valid expression
51
51
/// is also a valid data structure in Lisp itself.
52
52
53
- #[ derive( Debug , PartialEq , Clone ) ]
53
+ #[ derive( Debug , Eq , PartialEq , Clone ) ]
54
54
pub enum Expr {
55
55
Constant ( Atom ) ,
56
56
/// (func-name arg1 arg2)
@@ -65,7 +65,7 @@ pub enum Expr {
65
65
66
66
/// Continuing the trend of starting from the simplest piece and building up,
67
67
/// we start by creating a parser for the built-in operator functions.
68
- fn parse_builtin_op < ' a > ( i : & ' a str ) -> IResult < & ' a str , BuiltIn , VerboseError < & ' a str > > {
68
+ fn parse_builtin_op ( i : & str ) -> IResult < & str , BuiltIn , VerboseError < & str > > {
69
69
// one_of matches one of the characters we give it
70
70
let ( i, t) = one_of ( "+-*/=" ) ( i) ?;
71
71
@@ -84,7 +84,7 @@ fn parse_builtin_op<'a>(i: &'a str) -> IResult<&'a str, BuiltIn, VerboseError<&'
84
84
) )
85
85
}
86
86
87
- fn parse_builtin < ' a > ( i : & ' a str ) -> IResult < & ' a str , BuiltIn , VerboseError < & ' a str > > {
87
+ fn parse_builtin ( i : & str ) -> IResult < & str , BuiltIn , VerboseError < & str > > {
88
88
// alt gives us the result of first parser that succeeds, of the series of
89
89
// parsers we give it
90
90
alt ( (
@@ -96,7 +96,7 @@ fn parse_builtin<'a>(i: &'a str) -> IResult<&'a str, BuiltIn, VerboseError<&'a s
96
96
}
97
97
98
98
/// Our boolean values are also constant, so we can do it the same way
99
- fn parse_bool < ' a > ( i : & ' a str ) -> IResult < & ' a str , Atom , VerboseError < & ' a str > > {
99
+ fn parse_bool ( i : & str ) -> IResult < & str , Atom , VerboseError < & str > > {
100
100
alt ( (
101
101
map ( tag ( "#t" ) , |_| Atom :: Boolean ( true ) ) ,
102
102
map ( tag ( "#f" ) , |_| Atom :: Boolean ( false ) ) ,
@@ -109,7 +109,7 @@ fn parse_bool<'a>(i: &'a str) -> IResult<&'a str, Atom, VerboseError<&'a str>> {
109
109
///
110
110
/// Put plainly: `preceded(tag(":"), cut(alpha1))` means that once we see the `:`
111
111
/// character, we have to see one or more alphabetic chararcters or the input is invalid.
112
- fn parse_keyword < ' a > ( i : & ' a str ) -> IResult < & ' a str , Atom , VerboseError < & ' a str > > {
112
+ fn parse_keyword ( i : & str ) -> IResult < & str , Atom , VerboseError < & str > > {
113
113
map (
114
114
context ( "keyword" , preceded ( tag ( ":" ) , cut ( alpha1) ) ) ,
115
115
|sym_str : & str | Atom :: Keyword ( sym_str. to_string ( ) ) ,
@@ -118,20 +118,20 @@ fn parse_keyword<'a>(i: &'a str) -> IResult<&'a str, Atom, VerboseError<&'a str>
118
118
119
119
/// Next up is number parsing. We're keeping it simple here by accepting any number (> 1)
120
120
/// of digits but ending the program if it doesn't fit into an i32.
121
- fn parse_num < ' a > ( i : & ' a str ) -> IResult < & ' a str , Atom , VerboseError < & ' a str > > {
121
+ fn parse_num ( i : & str ) -> IResult < & str , Atom , VerboseError < & str > > {
122
122
alt ( (
123
123
map_res ( digit1, |digit_str : & str | {
124
124
digit_str. parse :: < i32 > ( ) . map ( Atom :: Num )
125
125
} ) ,
126
126
map ( preceded ( tag ( "-" ) , digit1) , |digit_str : & str | {
127
- Atom :: Num ( -1 * digit_str. parse :: < i32 > ( ) . unwrap ( ) )
127
+ Atom :: Num ( -digit_str. parse :: < i32 > ( ) . unwrap ( ) )
128
128
} ) ,
129
129
) ) ( i)
130
130
}
131
131
132
132
/// Now we take all these simple parsers and connect them.
133
133
/// We can now parse half of our language!
134
- fn parse_atom < ' a > ( i : & ' a str ) -> IResult < & ' a str , Atom , VerboseError < & ' a str > > {
134
+ fn parse_atom ( i : & str ) -> IResult < & str , Atom , VerboseError < & str > > {
135
135
alt ( (
136
136
parse_num,
137
137
parse_bool,
@@ -141,8 +141,8 @@ fn parse_atom<'a>(i: &'a str) -> IResult<&'a str, Atom, VerboseError<&'a str>> {
141
141
}
142
142
143
143
/// We then add the Expr layer on top
144
- fn parse_constant < ' a > ( i : & ' a str ) -> IResult < & ' a str , Expr , VerboseError < & ' a str > > {
145
- map ( parse_atom, |atom| Expr :: Constant ( atom ) ) ( i)
144
+ fn parse_constant ( i : & str ) -> IResult < & str , Expr , VerboseError < & str > > {
145
+ map ( parse_atom, Expr :: Constant ) ( i)
146
146
}
147
147
148
148
/// Before continuing, we need a helper function to parse lists.
@@ -172,7 +172,7 @@ where
172
172
///
173
173
/// `tuple` is used to sequence parsers together, so we can translate this directly
174
174
/// and then map over it to transform the output into an `Expr::Application`
175
- fn parse_application < ' a > ( i : & ' a str ) -> IResult < & ' a str , Expr , VerboseError < & ' a str > > {
175
+ fn parse_application ( i : & str ) -> IResult < & str , Expr , VerboseError < & str > > {
176
176
let application_inner = map ( tuple ( ( parse_expr, many0 ( parse_expr) ) ) , |( head, tail) | {
177
177
Expr :: Application ( Box :: new ( head) , tail)
178
178
} ) ;
@@ -186,7 +186,7 @@ fn parse_application<'a>(i: &'a str) -> IResult<&'a str, Expr, VerboseError<&'a
186
186
///
187
187
/// In fact, we define our parser as if `Expr::If` was defined with an Option in it,
188
188
/// we have the `opt` combinator which fits very nicely here.
189
- fn parse_if < ' a > ( i : & ' a str ) -> IResult < & ' a str , Expr , VerboseError < & ' a str > > {
189
+ fn parse_if ( i : & str ) -> IResult < & str , Expr , VerboseError < & str > > {
190
190
let if_inner = context (
191
191
"if expression" ,
192
192
map (
@@ -218,19 +218,19 @@ fn parse_if<'a>(i: &'a str) -> IResult<&'a str, Expr, VerboseError<&'a str>> {
218
218
/// This example doesn't have the symbol atom, but by adding variables and changing
219
219
/// the definition of quote to not always be around an S-expression, we'd get them
220
220
/// naturally.
221
- fn parse_quote < ' a > ( i : & ' a str ) -> IResult < & ' a str , Expr , VerboseError < & ' a str > > {
221
+ fn parse_quote ( i : & str ) -> IResult < & str , Expr , VerboseError < & str > > {
222
222
// this should look very straight-forward after all we've done:
223
223
// we find the `'` (quote) character, use cut to say that we're unambiguously
224
224
// looking for an s-expression of 0 or more expressions, and then parse them
225
225
map (
226
226
context ( "quote" , preceded ( tag ( "'" ) , cut ( s_exp ( many0 ( parse_expr) ) ) ) ) ,
227
- |exprs| Expr :: Quote ( exprs ) ,
227
+ Expr :: Quote ,
228
228
) ( i)
229
229
}
230
230
231
231
/// We tie them all together again, making a top-level expression parser!
232
232
233
- fn parse_expr < ' a > ( i : & ' a str ) -> IResult < & ' a str , Expr , VerboseError < & ' a str > > {
233
+ fn parse_expr ( i : & str ) -> IResult < & str , Expr , VerboseError < & str > > {
234
234
preceded (
235
235
multispace0,
236
236
alt ( ( parse_constant, parse_application, parse_if, parse_quote) ) ,
@@ -291,7 +291,7 @@ fn eval_expression(e: Expr) -> Option<Expr> {
291
291
let reduced_head = eval_expression ( * head) ?;
292
292
let reduced_tail = tail
293
293
. into_iter ( )
294
- . map ( |expr| eval_expression ( expr ) )
294
+ . map ( eval_expression)
295
295
. collect :: < Option < Vec < Expr > > > ( ) ?;
296
296
if let Expr :: Constant ( Atom :: BuiltIn ( bi) ) = reduced_head {
297
297
Some ( Expr :: Constant ( match bi {
@@ -361,7 +361,7 @@ fn eval_expression(e: Expr) -> Option<Expr> {
361
361
fn eval_from_str ( src : & str ) -> Result < Expr , String > {
362
362
parse_expr ( src)
363
363
. map_err ( |e : nom:: Err < VerboseError < & str > > | format ! ( "{:#?}" , e) )
364
- . and_then ( |( _, exp) | eval_expression ( exp) . ok_or ( "Eval failed" . to_string ( ) ) )
364
+ . and_then ( |( _, exp) | eval_expression ( exp) . ok_or_else ( || "Eval failed" . to_string ( ) ) )
365
365
}
366
366
367
367
fn main ( ) {
0 commit comments