1
1
use std:: { error, fmt, str:: FromStr } ;
2
2
3
3
use itertools:: Itertools ;
4
- use pest:: {
5
- error:: { Error as PestError , ErrorVariant , LineColLocation } ,
6
- iterators:: { Pair , Pairs } ,
7
- } ;
4
+ use pest:: iterators:: { Pair , Pairs } ;
8
5
9
6
use crate :: load_file:: { AddressMode , Core , Field , Instruction , Modifier , Opcode , Value } ;
10
7
11
8
mod grammar;
12
9
13
- #[ derive( Debug ) ]
10
+ #[ derive( Debug , PartialEq ) ]
14
11
pub struct Error {
15
12
details : String ,
16
13
}
@@ -31,41 +28,39 @@ impl Error {
31
28
}
32
29
}
33
30
34
- impl From < PestError < grammar:: Rule > > for Error {
35
- fn from ( pest_error : PestError < grammar:: Rule > ) -> Error {
31
+ pub trait IntoError : fmt:: Display { }
32
+
33
+ impl < T : pest:: RuleType > IntoError for pest:: error:: Error < T > { }
34
+ impl IntoError for String { }
35
+ impl IntoError for & str { }
36
+
37
+ impl < T : IntoError > From < T > for Error {
38
+ fn from ( displayable_error : T ) -> Self {
36
39
Error {
37
- details : format ! (
38
- "Parse error: {} {}" ,
39
- match pest_error. variant {
40
- ErrorVariant :: ParsingError {
41
- positives,
42
- negatives,
43
- } => format!( "expected one of {:?}, none of {:?}" , positives, negatives) ,
44
- ErrorVariant :: CustomError { message } => message,
45
- } ,
46
- match pest_error. line_col {
47
- LineColLocation :: Pos ( ( line, col) ) => format!( "at line {} column {}" , line, col) ,
48
- LineColLocation :: Span ( ( start_line, start_col) , ( end_line, end_col) ) => format!(
49
- "from line {} column {} to line {} column {}" ,
50
- start_line, start_col, end_line, end_col
51
- ) ,
52
- }
53
- ) ,
40
+ details : format ! ( "{}" , displayable_error) ,
54
41
}
55
42
}
56
43
}
57
44
58
- impl From < String > for Error {
59
- fn from ( details : String ) -> Error {
60
- Error { details }
45
+ #[ derive( Debug ) ]
46
+ pub struct ParsedCore {
47
+ pub result : Core ,
48
+ pub warnings : Vec < Error > ,
49
+ }
50
+
51
+ impl fmt:: Display for ParsedCore {
52
+ fn fmt ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
53
+ write ! ( formatter, "{}" , self . result)
61
54
}
62
55
}
63
56
64
- pub fn parse ( file_contents : & str ) -> Result < Core , Error > {
57
+ pub fn parse ( file_contents : & str ) -> Result < ParsedCore , Error > {
65
58
if file_contents. is_empty ( ) {
66
59
return Err ( Error :: no_input ( ) ) ;
67
60
}
68
61
62
+ let mut warnings = Vec :: new ( ) ;
63
+
69
64
let mut core = Core :: default ( ) ;
70
65
71
66
let parse_result = grammar:: parse ( grammar:: Rule :: File , file_contents) ?
@@ -83,7 +78,9 @@ pub fn parse(file_contents: &str) -> Result<Core, Error> {
83
78
. map ( |pair| pair. as_str ( ) . to_owned ( ) ) ;
84
79
85
80
for label in label_pairs {
86
- core. add_label ( i, label. to_string ( ) ) ?;
81
+ if let Err ( failed_add) = core. add_label ( i, label. to_string ( ) ) {
82
+ warnings. push ( failed_add. into ( ) )
83
+ }
87
84
}
88
85
89
86
if line_pair. peek ( ) . is_some ( ) {
@@ -92,7 +89,10 @@ pub fn parse(file_contents: &str) -> Result<Core, Error> {
92
89
}
93
90
}
94
91
95
- Ok ( core)
92
+ Ok ( ParsedCore {
93
+ result : core,
94
+ warnings,
95
+ } )
96
96
}
97
97
98
98
fn parse_instruction ( mut instruction_pairs : Pairs < grammar:: Rule > ) -> Instruction {
@@ -188,10 +188,10 @@ mod tests {
188
188
189
189
#[ test]
190
190
fn parse_empty ( ) {
191
- let result = parse ( "" ) ;
192
- assert ! ( result . is_err( ) ) ;
191
+ let parsed = parse ( "" ) ;
192
+ assert ! ( parsed . is_err( ) ) ;
193
193
194
- assert_eq ! ( result . unwrap_err( ) . details, "No input found" ) ;
194
+ assert_eq ! ( parsed . unwrap_err( ) . details, "No input found" ) ;
195
195
}
196
196
197
197
#[ test]
@@ -201,7 +201,14 @@ mod tests {
201
201
label1 dat 0,0
202
202
" ;
203
203
204
- parse ( simple_input) . expect_err ( "Should fail for duplicate label" ) ;
204
+ let parsed = parse ( simple_input) . expect ( "Failed to parse" ) ;
205
+
206
+ assert_eq ! (
207
+ parsed. warnings,
208
+ vec![ Error :: from( "Label 'label1' already exists" ) ]
209
+ ) ;
210
+
211
+ assert_eq ! ( parsed. result. label_address( "label1" ) , Some ( 1 ) ) ;
205
212
}
206
213
207
214
#[ test]
@@ -249,8 +256,10 @@ mod tests {
249
256
. expect ( "Should resolve a core with no labels" ) ;
250
257
251
258
let mut parsed = parse ( simple_input) . expect ( "Should parse simple file" ) ;
252
- parsed. resolve ( ) . expect ( "Parsed file should resolve" ) ;
259
+ parsed. result . resolve ( ) . expect ( "Parsed file should resolve" ) ;
260
+
261
+ assert ! ( parsed. warnings. is_empty( ) ) ;
253
262
254
- assert_eq ! ( parsed, expected_core) ;
263
+ assert_eq ! ( parsed. result , expected_core) ;
255
264
}
256
265
}
0 commit comments