11use clap:: Parser ;
2- use std:: {
3- collections:: HashMap , fs, path:: PathBuf
4- } ;
2+ use std:: { collections:: HashMap , fmt, fs, path:: PathBuf } ;
53
64use rusty_man_computer:: value:: Value ;
75
@@ -38,11 +36,36 @@ enum Line {
3836}
3937
4038#[ derive( Debug ) ]
41- enum ParseError {
39+ enum ParseErrorType {
4240 InvalidOpcode ( String ) ,
4341 OperandOutOfRange ( i16 ) ,
4442}
4543
44+ impl fmt:: Display for ParseErrorType {
45+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
46+ match self {
47+ ParseErrorType :: InvalidOpcode ( opcode) => {
48+ write ! ( f, "Invalid opcode: {}" , opcode)
49+ }
50+ ParseErrorType :: OperandOutOfRange ( value) => {
51+ write ! ( f, "Operand out of range: {}" , value)
52+ }
53+ }
54+ }
55+ }
56+
57+ #[ derive( Debug ) ]
58+ struct ParseError {
59+ error : ParseErrorType ,
60+ line : usize ,
61+ }
62+
63+ impl fmt:: Display for ParseError {
64+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
65+ write ! ( f, "Parse error on line {}: {}" , self . line, self . error)
66+ }
67+ }
68+
4669fn parse_opcode ( string : & str ) -> Option < Opcode > {
4770 match string {
4871 "HLT" => Some ( Opcode :: HLT ) ,
@@ -64,8 +87,10 @@ fn parse_opcode(string: &str) -> Option<Opcode> {
6487fn parse_assembly ( program : & str ) -> Vec < Result < Line , ParseError > > {
6588 program
6689 . lines ( )
67- . map ( |line| {
90+ . enumerate ( )
91+ . map ( |( line_index, line) | {
6892 let line = line. trim ( ) ;
93+ let line_number = line_index + 1 ;
6994 if line. is_empty ( ) || line. starts_with ( "//" ) {
7095 return Ok ( Line :: Empty ) ;
7196 }
@@ -87,11 +112,21 @@ fn parse_assembly(program: &str) -> Vec<Result<Line, ParseError>> {
87112 let string = match parts. get ( 1 ) {
88113 Some ( string) => string,
89114 // This means there's only one part: there's nothing to label, so it's just an invalid opcode
90- None => return Err ( ParseError :: InvalidOpcode ( parts[ 0 ] . to_string ( ) ) ) ,
115+ None => {
116+ return Err ( ParseError {
117+ error : ParseErrorType :: InvalidOpcode ( parts[ 0 ] . to_string ( ) ) ,
118+ line : line_number,
119+ } ) ;
120+ }
91121 } ;
92122 match parse_opcode ( string) {
93123 Some ( opcode) => opcode,
94- None => return Err ( ParseError :: InvalidOpcode ( string. to_string ( ) ) ) ,
124+ None => {
125+ return Err ( ParseError {
126+ error : ParseErrorType :: InvalidOpcode ( string. to_string ( ) ) ,
127+ line : line_number,
128+ } ) ;
129+ }
95130 }
96131 }
97132 } ;
@@ -106,7 +141,10 @@ fn parse_assembly(program: &str) -> Vec<Result<Line, ParseError>> {
106141 Some ( string) => match string. parse :: < i16 > ( ) {
107142 Ok ( value) => Some ( Operand :: Value (
108143 // If the number doesn't fit within a Value, return an OperandOutOfRange error
109- Value :: new ( value) . map_err ( |_| ParseError :: OperandOutOfRange ( value) ) ?,
144+ Value :: new ( value) . map_err ( |_| ParseError {
145+ error : ParseErrorType :: OperandOutOfRange ( value) ,
146+ line : line_number,
147+ } ) ?,
110148 ) ) ,
111149 Err ( _) => Some ( Operand :: Label ( string. to_string ( ) ) ) ,
112150 } ,
@@ -222,17 +260,15 @@ fn main() -> Result<(), String> {
222260 match assembler_result {
223261 Err ( error) => match error {
224262 AssemblerError :: ParseError ( parse_error) => {
225- return Err ( format ! ( "Parse error: {:?}" , parse_error) ) ;
263+ return Err ( parse_error. to_string ( ) ) ;
226264 }
227265 AssemblerError :: MachineCodeError ( message) => {
228266 return Err ( message. to_string ( ) ) ;
229267 }
230268 } ,
231269 Ok ( machine_code) => {
232- let machine_code_bytes: Vec < u8 > = machine_code
233- . iter ( )
234- . flat_map ( |& i| i. to_be_bytes ( ) )
235- . collect ( ) ;
270+ let machine_code_bytes: Vec < u8 > =
271+ machine_code. iter ( ) . flat_map ( |& i| i. to_be_bytes ( ) ) . collect ( ) ;
236272 fs:: write ( args. output , machine_code_bytes)
237273 . map_err ( |e| format ! ( "Failed to write output file: {}" , e) )
238274 }
0 commit comments