@@ -2,22 +2,24 @@ use std::str::FromStr;
2
2
3
3
use winnow:: ascii:: digit1;
4
4
use winnow:: ascii:: space0;
5
+ use winnow:: combinator:: cut_err;
5
6
use winnow:: combinator:: dispatch;
6
- use winnow:: combinator:: eof;
7
7
use winnow:: combinator:: fail;
8
8
use winnow:: combinator:: opt;
9
9
use winnow:: combinator:: repeat;
10
10
use winnow:: combinator:: seq;
11
11
use winnow:: error:: ContextError ;
12
+ use winnow:: error:: ParseError ;
13
+ use winnow:: error:: StrContext ;
14
+ use winnow:: error:: StrContextValue ;
12
15
use winnow:: prelude:: * ;
13
16
use winnow:: token:: any;
14
17
use winnow:: token:: take_while;
15
18
16
19
use crate :: path:: Expression ;
17
20
18
- pub ( crate ) fn from_str ( mut input : & str ) -> Result < Expression , ContextError > {
19
- let input = & mut input;
20
- path ( input) . map_err ( |e| e. into_inner ( ) . unwrap ( ) )
21
+ pub ( crate ) fn from_str ( input : & str ) -> Result < Expression , ParseError < & str , ContextError > > {
22
+ path. parse ( input)
21
23
}
22
24
23
25
fn path ( i : & mut & str ) -> PResult < Expression > {
@@ -31,7 +33,6 @@ fn path(i: &mut &str) -> PResult<Expression> {
31
33
} ,
32
34
)
33
35
. parse_next ( i) ?;
34
- eof. parse_next ( i) ?;
35
36
Ok ( expr)
36
37
}
37
38
@@ -41,9 +42,21 @@ fn ident(i: &mut &str) -> PResult<Expression> {
41
42
42
43
fn postfix ( i : & mut & str ) -> PResult < Child > {
43
44
dispatch ! { any;
44
- '[' => seq!( integer. map( Child :: Index ) , _: ']' ) . map( |( i, ) | i) ,
45
- '.' => raw_ident. map( Child :: Key ) ,
46
- _ => fail,
45
+ '[' => cut_err(
46
+ seq!(
47
+ integer. map( Child :: Index ) ,
48
+ _: ']' . context( StrContext :: Expected ( StrContextValue :: CharLiteral ( ']' ) ) ) ,
49
+ )
50
+ . map( |( i, ) | i)
51
+ . context( StrContext :: Label ( "subscript" ) )
52
+ ) ,
53
+ '.' => cut_err( raw_ident. map( Child :: Key ) ) ,
54
+ _ => cut_err(
55
+ fail
56
+ . context( StrContext :: Label ( "postfix" ) )
57
+ . context( StrContext :: Expected ( StrContextValue :: CharLiteral ( '[' ) ) )
58
+ . context( StrContext :: Expected ( StrContextValue :: CharLiteral ( '.' ) ) )
59
+ ) ,
47
60
}
48
61
. parse_next ( i)
49
62
}
@@ -56,6 +69,12 @@ enum Child {
56
69
fn raw_ident ( i : & mut & str ) -> PResult < String > {
57
70
take_while ( 1 .., ( 'a' ..='z' , 'A' ..='Z' , '0' ..='9' , '_' , '-' ) )
58
71
. map ( ToString :: to_string)
72
+ . context ( StrContext :: Label ( "identifier" ) )
73
+ . context ( StrContext :: Expected ( StrContextValue :: Description (
74
+ "ASCII alphanumeric" ,
75
+ ) ) )
76
+ . context ( StrContext :: Expected ( StrContextValue :: CharLiteral ( '_' ) ) )
77
+ . context ( StrContext :: Expected ( StrContextValue :: CharLiteral ( '-' ) ) )
59
78
. parse_next ( i)
60
79
}
61
80
@@ -65,12 +84,17 @@ fn integer(i: &mut &str) -> PResult<isize> {
65
84
( opt( '-' ) , digit1) . take( ) . try_map( FromStr :: from_str) ,
66
85
_: space0
67
86
)
87
+ . context ( StrContext :: Expected ( StrContextValue :: Description (
88
+ "integer" ,
89
+ ) ) )
68
90
. map ( |( i, ) | i)
69
91
. parse_next ( i)
70
92
}
71
93
72
94
#[ cfg( test) ]
73
95
mod test {
96
+ use snapbox:: { assert_data_eq, str} ;
97
+
74
98
use super :: Expression :: * ;
75
99
use super :: * ;
76
100
@@ -117,4 +141,74 @@ mod test {
117
141
118
142
assert_eq ! ( parsed, expected) ;
119
143
}
144
+
145
+ #[ test]
146
+ fn test_invalid_identifier ( ) {
147
+ let err = from_str ( "!" ) . unwrap_err ( ) ;
148
+ assert_data_eq ! (
149
+ err. to_string( ) ,
150
+ str ![ [ r#"
151
+ !
152
+ ^
153
+ invalid identifier
154
+ expected ASCII alphanumeric, `_`, `-`
155
+ "# ] ]
156
+ ) ;
157
+ }
158
+
159
+ #[ test]
160
+ fn test_invalid_child ( ) {
161
+ let err = from_str ( "a.." ) . unwrap_err ( ) ;
162
+ assert_data_eq ! (
163
+ err. to_string( ) ,
164
+ str ![ [ r#"
165
+ a..
166
+ ^
167
+ invalid identifier
168
+ expected ASCII alphanumeric, `_`, `-`
169
+ "# ] ]
170
+ ) ;
171
+ }
172
+
173
+ #[ test]
174
+ fn test_invalid_subscript ( ) {
175
+ let err = from_str ( "a[b]" ) . unwrap_err ( ) ;
176
+ assert_data_eq ! (
177
+ err. to_string( ) ,
178
+ str ![ [ r#"
179
+ a[b]
180
+ ^
181
+ invalid subscript
182
+ expected integer
183
+ "# ] ]
184
+ ) ;
185
+ }
186
+
187
+ #[ test]
188
+ fn test_incomplete_subscript ( ) {
189
+ let err = from_str ( "a[0" ) . unwrap_err ( ) ;
190
+ assert_data_eq ! (
191
+ err. to_string( ) ,
192
+ str ![ [ r#"
193
+ a[0
194
+ ^
195
+ invalid subscript
196
+ expected `]`
197
+ "# ] ]
198
+ ) ;
199
+ }
200
+
201
+ #[ test]
202
+ fn test_invalid_postfix ( ) {
203
+ let err = from_str ( "a!b" ) . unwrap_err ( ) ;
204
+ assert_data_eq ! (
205
+ err. to_string( ) ,
206
+ str ![ [ r#"
207
+ a!b
208
+ ^
209
+ invalid postfix
210
+ expected `[`, `.`
211
+ "# ] ]
212
+ ) ;
213
+ }
120
214
}
0 commit comments