@@ -28,6 +28,8 @@ pub struct PositionInfo {
2828 pub path : Option < String > ,
2929 /// Location of this error
3030 pub position : Position ,
31+ /// Character index in the source file where this position starts
32+ pub start : usize ,
3133 /// Length of the token
3234 pub len : usize ,
3335 /// Additional information
@@ -36,10 +38,11 @@ pub struct PositionInfo {
3638
3739impl PositionInfo {
3840 /// Create a new error from scratch
39- pub fn new ( meta : & impl Metadata , position : Position , len : usize ) -> Self {
41+ pub fn new ( meta : & impl Metadata , position : Position , start : usize , len : usize ) -> Self {
4042 let info = PositionInfo {
4143 position,
4244 path : meta. get_path ( ) ,
45+ start,
4346 len,
4447 data : None
4548 } ;
@@ -51,17 +54,19 @@ impl PositionInfo {
5154 let info = PositionInfo {
5255 path : meta. get_path ( ) ,
5356 position : Position :: EOF ,
57+ start : 0 ,
5458 len : 0 ,
5559 data : None
5660 } ;
5761 info. updated_pos ( meta)
5862 }
5963
6064 /// Create a new error at given position
61- pub fn at_pos ( path : Option < String > , ( row, col) : ( usize , usize ) , len : usize ) -> Self {
65+ pub fn at_pos ( path : Option < String > , ( row, col) : ( usize , usize ) , start : usize , len : usize ) -> Self {
6266 PositionInfo {
6367 path,
6468 position : Position :: Pos ( row, col) ,
69+ start,
6570 len,
6671 data : None
6772 }
@@ -94,7 +99,7 @@ impl PositionInfo {
9499 /// and error once you finished parsing the entire expression
95100 pub fn from_token ( meta : & impl Metadata , token_opt : Option < Token > ) -> Self {
96101 match token_opt {
97- Some ( token) => PositionInfo :: at_pos ( meta. get_path ( ) , token. pos , token. word . chars ( ) . count ( ) ) ,
102+ Some ( token) => PositionInfo :: at_pos ( meta. get_path ( ) , token. pos , token. start , token . word . chars ( ) . count ( ) ) ,
98103 None => PositionInfo :: at_eof ( meta)
99104 }
100105 }
@@ -106,15 +111,29 @@ impl PositionInfo {
106111 pub fn from_between_tokens ( meta : & impl Metadata , begin : Option < Token > , end : Option < Token > ) -> Self {
107112 if let Some ( begin) = begin {
108113 let ( row, col) = begin. pos ;
109- let end = end. map_or ( usize:: max_value ( ) , |tok| tok. start ) ;
110- let len = end - begin. start ;
111- PositionInfo :: at_pos ( meta. get_path ( ) , ( row, col) , len)
112- }
113- else {
114+ let end_pos = end. map_or ( usize:: max_value ( ) , |tok| tok. start ) ;
115+ let len = end_pos - begin. start ;
116+ PositionInfo :: at_pos ( meta. get_path ( ) , ( row, col) , begin. start , len)
117+ } else {
114118 PositionInfo :: from_metadata ( meta)
115119 }
116120 }
117121
122+ /// Create an error at position between two PositionInfo objects
123+ ///
124+ /// This function is used to create an error between two positions
125+ /// which can be used to express an error in a specific range
126+ pub fn from_between_positions ( meta : & impl Metadata , begin : PositionInfo , end : PositionInfo ) -> Self {
127+ let start_index = begin. start ;
128+ let end_index = end. start + end. len ;
129+ let len = end_index - start_index;
130+ if let Position :: Pos ( row, col) = begin. position {
131+ PositionInfo :: at_pos ( meta. get_path ( ) , ( row, col) , start_index, len)
132+ } else {
133+ PositionInfo :: at_eof ( meta)
134+ }
135+ }
136+
118137 /// Attach additional data in form of a string
119138 pub fn data < T : AsRef < str > > ( mut self , data : T ) -> Self {
120139 self . data = Some ( data. as_ref ( ) . to_string ( ) ) ;
@@ -177,7 +196,7 @@ mod test {
177196
178197 #[ test]
179198 fn test_position_info ( ) {
180- let pos = PositionInfo :: at_pos ( Some ( "test" . to_string ( ) ) , ( 1 , 1 ) , 1 ) ;
199+ let pos = PositionInfo :: at_pos ( Some ( "test" . to_string ( ) ) , ( 1 , 1 ) , 0 , 1 ) ;
181200 assert_eq ! ( pos. get_path( ) , "test" ) ;
182201 assert_eq ! ( pos. get_pos_by_code( "test" ) , ( 1 , 1 ) ) ;
183202 }
@@ -191,4 +210,15 @@ mod test {
191210 let pos = PositionInfo :: from_between_tokens ( & mut meta, Some ( begin. clone ( ) ) , Some ( end. clone ( ) ) ) ;
192211 assert_eq ! ( pos. len, end. start - begin. start) ;
193212 }
213+
214+ #[ test]
215+ fn test_position_info_between_positions ( ) {
216+ let begin = PositionInfo :: at_pos ( Some ( "test" . to_string ( ) ) , ( 1 , 1 ) , 0 , 5 ) ;
217+ let end = PositionInfo :: at_pos ( Some ( "test" . to_string ( ) ) , ( 1 , 10 ) , 9 , 3 ) ;
218+ let mut meta = DefaultMetadata :: new ( vec ! [ ] , None , Some ( "begin to end" . to_string ( ) ) ) ;
219+ let pos = PositionInfo :: from_between_positions ( & mut meta, begin. clone ( ) , end. clone ( ) ) ;
220+ assert_eq ! ( pos. start, 0 ) ;
221+ assert_eq ! ( pos. len, 12 ) ;
222+ assert_eq ! ( pos. get_pos_by_code( "begin to end" ) , ( 1 , 1 ) ) ;
223+ }
194224}
0 commit comments