1use crate::ast::parse;
2use either::Either;
3use getset::Getters;
4use parse::Rule;
5use pest::iterators::Pair;
6
7#[derive(Debug)]
8pub struct Program {
9 items: Vec<ProgramItem>,
10}
11
12impl Program {
13 pub fn items(self) -> Vec<ProgramItem> {
14 self.items
15 }
16}
17
18#[derive(Debug, Clone, Getters)]
19pub struct Span {
20 #[get = "pub"]
21 start: usize,
22 #[get = "pub"]
23 end: usize,
24}
25
26#[derive(Debug)]
27pub enum ProgramItem {
28 Comment(Comment),
29 Label(Label),
30 Instruction(Instruction),
31 Directive(Directive),
32}
33
34#[derive(Debug, Clone, Getters)]
35pub struct Comment {
36 #[get = "pub"]
37 content: String,
38 #[get = "pub"]
39 span: Span,
40}
41
42#[derive(Debug, Clone, Getters)]
43pub struct Label {
44 #[get = "pub"]
45 content: String,
46 #[get = "pub"]
47 span: Span,
48}
49
50#[derive(Debug, Copy, Clone)]
51pub enum RegisterType {
52 R0,
53 R1,
54 R2,
55 R3,
56 R4,
57 R5,
58 R6,
59 R7,
60}
61
62#[derive(Debug, Clone, Getters)]
63pub struct Register {
64 #[get = "pub"]
65 content: String,
66 #[get = "pub"]
67 span: Span,
68 #[get = "pub"]
69 register_type: RegisterType,
70}
71
72#[derive(Debug, Clone, Getters)]
73pub struct LabelReference {
74 #[get = "pub"]
75 content: String,
76 #[get = "pub"]
77 span: Span,
78}
79
80#[derive(Debug, Copy, Clone)]
81pub enum BrType {
82 N,
83 Z,
84 P,
85 Nz,
86 Zp,
87 Np,
88 Nzp,
89 None,
90}
91
92#[derive(Debug, Clone)]
93pub enum InstructionType {
94 Add(Register, Register, Either<Register, Immediate>),
96 And(Register, Register, Either<Register, Immediate>),
97 Not(Register, Register),
98 Ld(Register, LabelReference),
100 Ldi(Register, LabelReference),
101 Ldr(Register, Register, Immediate),
102 Lea(Register, LabelReference),
103 St(Register, LabelReference),
104 Sti(Register, LabelReference),
105 Str(Register, Register, Immediate),
106 Br(BrType, LabelReference),
108 Jmp(Register),
109 Jsr(LabelReference),
110 Jsrr(Register),
111 Nop,
113 Ret,
114 Halt,
115 Puts,
117 Getc,
118 Out,
119 In,
120 Trap(HexAddress),
122}
123
124#[derive(Debug, Clone, Getters)]
125pub struct Instruction {
126 #[get = "pub"]
127 instruction_type: InstructionType,
128 #[get = "pub"]
129 content: String,
130 #[get = "pub"]
131 span: Span,
132}
133
134#[derive(Debug, Clone, Getters)]
135pub struct StringLiteral {
136 #[get = "pub"]
137 content: String,
138 #[get = "pub"]
139 span: Span,
140}
141
142#[derive(Debug, Clone, Getters)]
143pub struct Immediate {
144 #[get = "pub"]
145 content: String,
146 #[get = "pub"]
147 span: Span,
148}
149
150#[derive(Debug, Clone, Getters)]
151pub struct HexAddress {
152 #[get = "pub"]
153 content: String,
154 #[get = "pub"]
155 span: Span,
156}
157
158#[derive(Debug, Clone)]
159pub enum DirectiveType {
160 ORIG(HexAddress),
161 END,
162 BLKW(Immediate),
163 FILL(Immediate),
164 STRINGZ(StringLiteral),
165}
166
167#[derive(Debug, Clone, Getters)]
168pub struct Directive {
169 #[get = "pub"]
170 directive_type: DirectiveType,
171 #[get = "pub"]
172 content: String,
173 #[get = "pub"]
174 span: Span,
175}
176
177pub fn parse_ast(pair: Pair<Rule>) -> Program {
178 if pair.as_rule() != Rule::Program {
179 unreachable!();
180 }
181 Program {
182 items: pair
183 .into_inner()
184 .into_iter()
185 .map_while(|p| parse_program_item(p))
186 .collect(),
187 }
188}
189
190fn parse_program_item(pair: Pair<Rule>) -> Option<ProgramItem> {
191 match pair.as_rule() {
192 Rule::Comment => Some(ProgramItem::Comment(parse_comment(pair))),
193 Rule::Label => Some(ProgramItem::Label(parse_label(pair))),
194 Rule::Instruction => Some(ProgramItem::Instruction(parse_instruction(pair))),
195 Rule::Directive => Some(ProgramItem::Directive(parse_directive(pair))),
196 Rule::EOI => None,
197 _ => {
198 unreachable!();
199 }
200 }
201}
202
203fn parse_comment(pair: Pair<Rule>) -> Comment {
204 Comment {
205 content: pair.as_str().to_string(),
206 span: Span::from(pair.as_span()),
207 }
208}
209
210fn parse_label(pair: Pair<Rule>) -> Label {
211 Label {
212 content: pair.as_str().to_owned(),
213 span: Span::from(pair.as_span()),
214 }
215}
216
217fn parse_instruction(pair: Pair<Rule>) -> Instruction {
218 assert_eq!(pair.as_rule(), Rule::Instruction);
219 let mut inner = pair.into_inner().into_iter();
220 let instruction = inner.next();
221 assert!(instruction.is_some());
222 let instruction = instruction.unwrap();
223 let mut instruction_line = instruction.clone().into_inner().into_iter();
224 let true_instruction = instruction_line.next();
225 assert!(true_instruction.is_some());
226 let true_instruction = true_instruction.unwrap();
227 Instruction {
228 instruction_type: match true_instruction.as_rule() {
229 Rule::AddInstruction => {
230 let register1 = instruction_line.next();
231 let register2 = instruction_line.next();
232 let register_or_immediate = instruction_line.next();
233 assert!(
234 register1.is_some() && register2.is_some() && register_or_immediate.is_some()
235 );
236 let register1 = register1.unwrap();
237 let register2 = register2.unwrap();
238 let register_or_immediate = register_or_immediate.unwrap();
239 InstructionType::Add(
240 parse_register(register1),
241 parse_register(register2),
242 parse_register_immediate(register_or_immediate),
243 )
244 }
245 Rule::AndInstruction => {
246 let register1 = instruction_line.next();
247 let register2 = instruction_line.next();
248 let register_or_immediate = instruction_line.next();
249 assert!(
250 register1.is_some() && register2.is_some() && register_or_immediate.is_some()
251 );
252 let register1 = register1.unwrap();
253 let register2 = register2.unwrap();
254 let register_or_immediate = register_or_immediate.unwrap();
255 InstructionType::And(
256 parse_register(register1),
257 parse_register(register2),
258 parse_register_immediate(register_or_immediate),
259 )
260 }
261 Rule::NotInstruction => {
262 let register1 = instruction_line.next();
263 let register2 = instruction_line.next();
264 assert!(register1.is_some() && register2.is_some());
265 let register1 = register1.unwrap();
266 let register2 = register2.unwrap();
267 InstructionType::Not(parse_register(register1), parse_register(register2))
268 }
269 Rule::LdInstruction => {
270 let register = instruction_line.next();
271 let label_reference = instruction_line.next();
272 assert!(register.is_some() && label_reference.is_some());
273 let register = register.unwrap();
274 let label_reference = label_reference.unwrap();
275 InstructionType::Ld(
276 parse_register(register),
277 parse_label_reference(label_reference),
278 )
279 }
280 Rule::LdiInstruction => {
281 let register = instruction_line.next();
282 let label_reference = instruction_line.next();
283 assert!(register.is_some() && label_reference.is_some());
284 let register = register.unwrap();
285 let label_reference = label_reference.unwrap();
286 InstructionType::Ldi(
287 parse_register(register),
288 parse_label_reference(label_reference),
289 )
290 }
291 Rule::LdrInstruction => {
292 let register1 = instruction_line.next();
293 let register2 = instruction_line.next();
294 let immediate = instruction_line.next();
295 assert!(register1.is_some() && register2.is_some() && immediate.is_some());
296 let register1 = register1.unwrap();
297 let register2 = register2.unwrap();
298 let immediate = immediate.unwrap();
299 InstructionType::Ldr(
300 parse_register(register1),
301 parse_register(register2),
302 parse_immediate(immediate),
303 )
304 }
305 Rule::LeaInstruction => {
306 let register = instruction_line.next();
307 let label_reference = instruction_line.next();
308 assert!(register.is_some() && label_reference.is_some());
309 let register = register.unwrap();
310 let label_reference = label_reference.unwrap();
311 InstructionType::Lea(
312 parse_register(register),
313 parse_label_reference(label_reference),
314 )
315 }
316 Rule::StInstruction => {
317 let register = instruction_line.next();
318 let label_reference = instruction_line.next();
319 assert!(register.is_some() && label_reference.is_some());
320 let register = register.unwrap();
321 let label_reference = label_reference.unwrap();
322 InstructionType::St(
323 parse_register(register),
324 parse_label_reference(label_reference),
325 )
326 }
327 Rule::StiInstruction => {
328 let register = instruction_line.next();
329 let label_reference = instruction_line.next();
330 assert!(register.is_some() && label_reference.is_some());
331 let register = register.unwrap();
332 let label_reference = label_reference.unwrap();
333 InstructionType::Sti(
334 parse_register(register),
335 parse_label_reference(label_reference),
336 )
337 }
338 Rule::StrInstruction => {
339 let register1 = instruction_line.next();
340 let register2 = instruction_line.next();
341 let immediate = instruction_line.next();
342 assert!(register1.is_some() && register2.is_some() && immediate.is_some());
343 let register1 = register1.unwrap();
344 let register2 = register2.unwrap();
345 let immediate = immediate.unwrap();
346 InstructionType::Str(
347 parse_register(register1),
348 parse_register(register2),
349 parse_immediate(immediate),
350 )
351 }
352 Rule::BrInstruction => {
353 let instruction_type = instruction;
354 assert_eq!(instruction_type.as_rule(), Rule::Br);
355 let instruction = instruction_type.as_str().split_whitespace().next();
356 assert!(instruction.is_some());
357 let instruction = instruction.unwrap().to_uppercase();
358 let instruction_tp = instruction.strip_prefix("BR");
359 assert!(instruction_tp.is_some());
360 let instruction_tp = instruction_tp.unwrap();
361
362 let br_tp = if instruction_tp.contains('N')
363 && instruction_tp.contains('Z')
364 && instruction_tp.contains('P')
365 {
366 BrType::Nzp
367 } else if instruction_tp.contains('N') && instruction_tp.contains('Z') {
368 BrType::Nz
369 } else if instruction_tp.contains('N') && instruction_tp.contains('P') {
370 BrType::Np
371 } else if instruction_tp.contains('Z') && instruction_tp.contains('P') {
372 BrType::Zp
373 } else if instruction_tp.contains('N') {
374 BrType::N
375 } else if instruction_tp.contains('P') {
376 BrType::P
377 } else if instruction_tp.contains('Z') {
378 BrType::Z
379 } else if instruction_tp.is_empty() {
380 BrType::None
381 } else {
382 unreachable!()
383 };
384
385 let label_reference = instruction_line.next();
386 assert!(label_reference.is_some());
387 let label_reference = label_reference.unwrap();
388
389 InstructionType::Br(br_tp, parse_label_reference(label_reference))
390 }
391 Rule::JmpInstruction => {
392 let register1 = instruction_line.next();
393 assert!(register1.is_some());
394 let register1 = register1.unwrap();
395 InstructionType::Jmp(parse_register(register1))
396 }
397 Rule::JsrInstruction => {
398 let label_ref = instruction_line.next();
399 assert!(label_ref.is_some());
400 let label_ref = label_ref.unwrap();
401 InstructionType::Jsr(parse_label_reference(label_ref))
402 }
403 Rule::JsrrInstruction => {
404 let register1 = instruction_line.next();
405 assert!(register1.is_some());
406 let register1 = register1.unwrap();
407 InstructionType::Jsrr(parse_register(register1))
408 }
409 Rule::NopInstruction => InstructionType::Nop,
410 Rule::RetInstruction => InstructionType::Ret,
411 Rule::HaltInstruction => InstructionType::Halt,
412 Rule::PutsInstruction => InstructionType::Puts,
413 Rule::GetcInstruction => InstructionType::Getc,
414 Rule::OutInstruction => InstructionType::Out,
415 Rule::InInstruction => InstructionType::In,
416 Rule::TrapInstruction => {
417 let hex_address = instruction_line.next();
418 assert!(hex_address.is_some());
419 let hex_address = hex_address.unwrap();
420 InstructionType::Trap(parse_hex_address(hex_address))
421 }
422 _ => {
423 unreachable!()
424 }
425 },
426 content: true_instruction.as_str().to_owned(),
427 span: Span::from(true_instruction.as_span()),
428 }
429}
430
431fn parse_directive(pair: Pair<Rule>) -> Directive {
432 assert_eq!(pair.as_rule(), Rule::Directive);
433 let mut inner = pair.into_inner().into_iter();
434 let directive_line = inner.next();
435 assert!(directive_line.is_some());
436 let mut directive_line = directive_line.unwrap().into_inner().into_iter();
437 let directive = directive_line.next();
438 assert!(directive.is_some());
439 let directive = directive.unwrap();
440 Directive {
441 directive_type: match directive.as_rule() {
442 Rule::StringzDirective => {
443 let string = directive_line.next();
444 assert!(string.is_some());
445 DirectiveType::STRINGZ(parse_string_literal(string.unwrap()))
446 }
447 Rule::FillDirective => {
448 let immediate = directive_line.next();
449 assert!(immediate.is_some());
450 DirectiveType::FILL(parse_immediate(immediate.unwrap()))
451 }
452 Rule::OrigDirective => {
453 let address = directive_line.next();
454 assert!(address.is_some());
455 DirectiveType::ORIG(parse_hex_address(address.unwrap()))
456 }
457 Rule::EndDirective => DirectiveType::END,
458 Rule::BlkwDirective => {
459 let immediate = directive_line.next();
460 assert!(immediate.is_some());
461 DirectiveType::BLKW(parse_immediate(immediate.unwrap()))
462 }
463 _ => {
464 unreachable!()
465 }
466 },
467 content: directive.as_span().as_str().to_owned(),
468 span: Span::from(directive.as_span()),
469 }
470}
471
472fn parse_string_literal(pair: Pair<Rule>) -> StringLiteral {
473 assert_eq!(pair.as_rule(), Rule::StringLiteral);
474 StringLiteral {
475 content: pair.as_str().to_owned(),
476 span: Span::from(pair.as_span()),
477 }
478}
479
480fn parse_immediate(pair: Pair<Rule>) -> Immediate {
481 assert_eq!(pair.as_rule(), Rule::Immediate);
482 Immediate {
483 content: pair.as_str().to_owned(),
484 span: Span::from(pair.as_span()),
485 }
486}
487
488fn parse_hex_address(pair: Pair<Rule>) -> HexAddress {
489 assert_eq!(pair.as_rule(), Rule::HexAddress);
490 HexAddress {
491 content: pair.as_str().to_owned(),
492 span: Span::from(pair.as_span()),
493 }
494}
495
496fn parse_register(pair: Pair<Rule>) -> Register {
497 assert_eq!(pair.as_rule(), Rule::Register);
498 Register {
499 content: pair.as_str().to_owned(),
500 span: Span::from(pair.as_span()),
501 register_type: match pair.as_str().to_uppercase().as_str() {
502 "R0" => RegisterType::R0,
503 "R1" => RegisterType::R1,
504 "R2" => RegisterType::R2,
505 "R3" => RegisterType::R3,
506 "R4" => RegisterType::R4,
507 "R5" => RegisterType::R5,
508 "R6" => RegisterType::R6,
509 "R7" => RegisterType::R7,
510 _ => {
511 unreachable!()
512 }
513 },
514 }
515}
516
517fn parse_register_immediate(pair: Pair<Rule>) -> Either<Register, Immediate> {
518 if pair.as_rule() == Rule::Register {
519 return Either::Left(parse_register(pair));
520 }
521 Either::Right(parse_immediate(pair))
522}
523
524fn parse_label_reference(pair: Pair<Rule>) -> LabelReference {
525 assert_eq!(pair.as_rule(), Rule::LabelReference);
526 LabelReference {
527 content: pair.as_str().to_owned(),
528 span: Span::from(pair.as_span()),
529 }
530}
531
532impl<'a> From<pest::Span<'a>> for Span {
533 fn from(value: pest::Span) -> Self {
534 Span {
535 start: value.start(),
536 end: value.end(),
537 }
538 }
539}