nand7400/assembler/
mod.rs1pub mod config;
2pub mod errors;
3pub mod parser;
4pub mod position;
5
6mod tests;
7
8use std::collections::HashMap;
9
10use crate::assembler::config::OpcodeArg;
11
12use self::parser::{
13 ast::{Argument, ArgumentKind, Ast, InstructionKind, Keyword, Label},
14 Parser,
15};
16use config::AssemblerConfig;
17use errors::AssemblerError;
18use num_traits::{FromPrimitive, Num, ToBytes, ToPrimitive};
19
20pub struct Assembler {
22 config: AssemblerConfig,
24}
25
26impl Assembler {
28 pub fn new(config: AssemblerConfig) -> Self {
30 Self { config }
31 }
32
33 pub fn set_config(&mut self, config: AssemblerConfig) {
35 self.config = config;
36 }
37
38 pub fn assemble(&mut self, source: &str) -> Result<Vec<u8>, AssemblerError> {
40 Ok(self.assemble_with_ast(source)?.0)
41 }
42
43 pub fn assemble_with_ast(&mut self, source: &str) -> Result<(Vec<u8>, Ast), AssemblerError> {
45 let ast = Parser::new(source)?.parse()?; let mut next_mem_location = 0; let mut binary = vec![]; for instruction in &ast.instructions {
50 match &instruction.kind {
51 InstructionKind::Label(_) => continue,
53
54 InstructionKind::Keyword { keyword, arguments } => match keyword {
56 Keyword::Org => {
58 if arguments.len() != 1 {
60 return Err(AssemblerError::WrongNumArgs {
61 mnemonic: keyword.to_string(),
62 expected: 1,
63 given: arguments.len() as u16,
64 mnemonic_span: instruction.token_span,
65 args_span: arguments
66 .iter()
67 .map(|arg| arg.span)
68 .fold(instruction.token_span, |acc, span| acc.join(&span)),
69 });
70 }
71
72 let arg = &arguments[0]; next_mem_location = decode_arg_u16(&ast.symbols, arg)? as usize;
76 }
77
78 Keyword::Byte => {
80 let mut bytes = vec![];
81
82 for arg in arguments {
83 bytes.extend(decode_arg_bytes(&ast.symbols, arg)?);
84 }
85
86 for (i, byte) in bytes.iter().enumerate() {
87 binary.insert(next_mem_location + i, *byte);
88 }
89
90 next_mem_location += bytes.len();
91 }
92 },
93
94 InstructionKind::Opcode {
95 mnemonic,
96 arguments,
97 } => {
98 let opcode = self.config.get_opcode(mnemonic).ok_or_else(|| {
100 AssemblerError::OpcodeDNE {
101 mnemonic: mnemonic.clone(),
102 span: instruction.token_span,
103 }
104 })?;
105
106 if opcode.args.len() != instruction.args_len_bytes() {
108 return Err(AssemblerError::WrongNumArgs {
109 mnemonic: mnemonic.clone(),
110 expected: opcode.args.len() as u16,
111 given: arguments.len() as u16,
112 mnemonic_span: instruction.token_span,
113 args_span: arguments
114 .iter()
115 .map(|arg| arg.span)
116 .fold(instruction.token_span, |acc, span| acc.join(&span)),
117 });
118 }
119
120 let mut bytes = vec![opcode.binary];
122
123 for (arg, arg_type) in arguments.iter().zip(opcode.args.iter()) {
124 let given_arg_type = OpcodeArg::from(arg);
125
126 if given_arg_type != *arg_type {
128 return Err(AssemblerError::WrongArgType {
129 mnemonic: mnemonic.clone(),
130 expected: *arg_type,
131 given: given_arg_type,
132 mnemonic_span: instruction.token_span,
133 arg_span: arg.span,
134 });
135 }
136
137 bytes.extend(decode_arg_bytes(&ast.symbols, arg)?);
139 }
140
141 for (i, byte) in bytes.iter().enumerate() {
143 binary.insert(next_mem_location + i, *byte);
144 }
145
146 next_mem_location += bytes.len();
148 }
149 }
150
151 if next_mem_location > binary.len() {
153 binary.resize(next_mem_location, 0);
154 }
155 }
156
157 Ok((binary, ast))
158 }
159}
160
161pub fn decode_arg_bytes<T>(
164 symbol_table: &HashMap<Label, u16>,
165 arg: &Argument<T>,
166) -> Result<Vec<u8>, AssemblerError>
167where
168 T: Num + ToBytes + ToPrimitive + Clone,
169{
170 match &arg.kind {
171 ArgumentKind::ImmediateNumber(num) | ArgumentKind::IndirectNumber(num) => {
172 let mut bytes = num.to_le_bytes().as_ref().to_vec();
173
174 while bytes.last() == Some(&0) && bytes.len() > 1 {
176 bytes.pop();
177 }
178
179 Ok(bytes)
180 }
181
182 ArgumentKind::Label(label) => Ok(symbol_table
183 .get(label)
184 .ok_or_else(|| AssemblerError::LabelDNE {
185 mnemonic: label.clone(),
186 span: arg.span,
187 })?
188 .to_le_bytes()
189 .to_vec()),
190 }
191}
192
193pub fn decode_arg_u16<T>(
195 symbol_table: &HashMap<Label, u16>,
196 arg: &Argument<T>,
197) -> Result<u16, AssemblerError>
198where
199 T: Num + ToBytes + ToPrimitive + Clone + FromPrimitive,
200{
201 match &arg.kind {
202 ArgumentKind::ImmediateNumber(num) | ArgumentKind::IndirectNumber(num) => {
203 Ok(num.to_u16().expect("Need to catch this error!"))
204 }
205
206 ArgumentKind::Label(label) => {
207 Ok(*symbol_table
208 .get(label)
209 .ok_or_else(|| AssemblerError::LabelDNE {
210 mnemonic: label.clone(),
211 span: arg.span,
212 })?)
213 }
214 }
215}