Skip to content

Commit 560eb1c

Browse files
Include line numbers on assembler errors
1 parent 8646a5f commit 560eb1c

2 files changed

Lines changed: 50 additions & 13 deletions

File tree

demos/tests/invalid.lmc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ABC 1

src/rmc_assemble.rs

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use clap::Parser;
2-
use std::{
3-
collections::HashMap, fs, path::PathBuf
4-
};
2+
use std::{collections::HashMap, fmt, fs, path::PathBuf};
53

64
use 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+
4669
fn 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> {
6487
fn 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

Comments
 (0)