1use strum_macros::{Display, EnumString};
4
5use crate::{
6 device::{Device, DEVICES},
7 expr::Expr,
8 parser::{
9 parse_file_internal, CodePoint, DataDefine, Item, NextItem, ParseContext, Segment,
10 SegmentType,
11 },
12};
13
14use crate::context::Context;
15use failure::{bail, Error};
16use std::path::PathBuf;
17
18#[derive(Clone, PartialEq, Eq, Debug, EnumString, Display)]
19#[strum(serialize_all = "lowercase")]
20pub enum Directive {
21 Byte,
23 CSeg,
25 CSegSize,
27 Db,
29 Def,
31 Device,
33 DSeg,
35 Dw,
37 EndM,
39 EndMacro,
40 Equ,
42 ESeg,
44 Exit,
46 Include,
48 IncludePath,
50 List,
52 ListMac,
54 Macro,
56 NoList,
58 Org,
60 Set,
62 Define,
64 Else,
66 ElIf,
67 Endif,
69 Error,
71 If,
73 IfDef,
74 IfNDef,
75 Message,
77 Dd,
79 Dq,
81 Undef,
83 Warning,
85 Overlap,
87 NoOverlap,
88 Pragma,
90
91 #[strum(disabled)]
93 Custom(String),
94}
95
96impl Directive {
97 pub fn parse(
98 &self,
99 opts: &DirectiveOps,
100 context: &ParseContext,
101 point: CodePoint,
102 ) -> Result<NextItem, Error> {
103 let mut next_item = NextItem::NewLine;
104
105 let ParseContext {
106 current_path,
107 include_paths,
108 common_context,
109 segments,
110 macros,
111 messages,
112 } = context;
113
114 match self {
115 Directive::Db | Directive::Dw | Directive::Dd | Directive::Dq => {
116 if let DirectiveOps::OpList(args) = opts {
117 let item_type = match self {
118 Directive::Db => DataDefine::Db,
119 Directive::Dw => DataDefine::Dw,
120 Directive::Dd => DataDefine::Dd,
121 Directive::Dq => DataDefine::Dq,
122 _ => bail!("unknown argument for define data, {}", point),
123 };
124 context.push_to_last((point, Item::Data(item_type, args.clone())));
125 } else {
126 bail!("Not allowed type of arguments for .db, {}", point);
127 }
128 }
129 Directive::Set | Directive::Def => {
130 if let DirectiveOps::Assign(Expr::Ident(name), expr) = opts {
131 match self {
132 Directive::Set => {
133 context.push_to_last((point, Item::Set(name.clone(), expr.clone())))
134 }
135 Directive::Def => {
136 context.push_to_last((point, Item::Def(name.clone(), expr.clone())))
137 }
138 _ => bail!("unknown argument for {} data, {}", self, point),
139 };
140 } else {
141 bail!("Not allowed type of arguments for .{}, {}", self, point);
142 }
143 }
144 Directive::Undef => {
145 if let DirectiveOps::OpList(values) = opts {
146 if let Operand::E(Expr::Ident(name)) = &values[0] {
147 context.push_to_last((point, Item::Undef(name.clone())))
148 } else {
149 bail!("Not allowed type of arguments for .{}, {}", self, point);
150 }
151 } else {
152 bail!("Not allowed type of arguments for .{}, {}", self, point);
153 }
154 }
155 Directive::Pragma => {
156 if let DirectiveOps::OpList(args) = opts {
157 context.push_to_last((point, Item::Pragma(args.clone())));
158 } else {
159 bail!("Not allowed type of arguments for .{}, {}", self, point);
160 }
161 }
162 Directive::Byte => {
163 if let DirectiveOps::OpList(args) = opts {
164 if args.len() > 1 {
165 bail!("Too many arguments for {}", self);
166 }
167 if let Operand::E(expr) = &args[0] {
168 if let Expr::Const(n) = expr {
169 context.push_to_last((point, Item::ReserveData(*n)));
170 }
171 }
172 } else {
173 bail!("Not allowed type of arguments for .byte, {}", point);
174 }
175 }
176 Directive::Equ => {
177 if let DirectiveOps::Assign(name, value) = opts {
178 if let Expr::Ident(name) = name {
179 context.common_context.set_equ(name.clone(), value.clone());
180 }
181 } else {
182 bail!("wrong format for .equ, expected: {} in {}", opts, point,);
183 }
184 }
185 Directive::Org => {
186 if let DirectiveOps::OpList(values) = opts {
187 if let Operand::E(Expr::Const(value)) = &values[0] {
188 if !context.last_segment().unwrap().borrow().is_empty() {
189 let current_type = context.last_segment().unwrap().borrow().t;
190 context.add_segment(Segment::new(current_type));
191 }
192 context.last_segment().unwrap().borrow_mut().address = *value as u32;
193 }
194 } else {
195 bail!("wrong format for .org, expected: {} in {}", opts, point,);
196 }
197 }
198 Directive::CSeg | Directive::DSeg | Directive::ESeg => {
199 let new_type = match self {
200 Directive::CSeg => SegmentType::Code,
201 Directive::DSeg => SegmentType::Data,
202 Directive::ESeg => SegmentType::Eeprom,
203 _ => SegmentType::Code,
204 };
205
206 if !context.last_segment().unwrap().borrow().is_empty() {
207 context.add_segment(Segment::new(new_type));
208 } else {
209 context.last_segment().unwrap().borrow_mut().t = new_type;
210 }
211 }
212 Directive::Device => {
213 if let DirectiveOps::OpList(values) = opts {
214 if let Operand::E(Expr::Ident(value)) = &values[0] {
215 if let Some(device) = DEVICES.get(value.as_str()) {
216 if let Some(old_device) = context
217 .common_context
218 .device
219 .as_ref()
220 .clone()
221 .borrow()
222 .as_ref()
223 {
224 if old_device == &Device::new(0) {
225 context.common_context.device.replace(Some(device.clone()));
226 } else {
227 bail!(
228 "device redefinition in {}, old: {:?} -> new: {:?}",
229 point,
230 old_device,
231 device,
232 )
233 }
234 } else {
235 context.common_context.device.replace(Some(device.clone()));
236 }
237 } else {
238 bail!("unknown device {} in {}", value, point,)
239 }
240 }
241 } else {
242 bail!("wrong format for .device, expected: {} in {}", opts, point,);
243 }
244 }
245 Directive::Include => {
246 if let DirectiveOps::OpList(values) = &opts {
247 if let Operand::S(include) = &values[0] {
248 let context = ParseContext {
249 current_path: PathBuf::from(include),
250 include_paths: include_paths.clone(),
251 common_context: common_context.clone(),
252 segments: segments.clone(),
253 macros: macros.clone(),
254 messages: messages.clone(),
255 };
256 parse_file_internal(&context)?;
257 } else {
258 bail!("wrong format for .include, expected: {} in {}", opts, point,);
259 }
260 } else {
261 bail!("wrong format for .include, expected: {} in {}", opts, point,);
262 }
263 }
264 Directive::IncludePath => {
265 if let DirectiveOps::OpList(values) = &opts {
266 if let Operand::S(include) = &values[0] {
267 let path = PathBuf::from(include);
268 let path = if path.is_relative() {
269 let mut current_path = current_path.parent().unwrap().to_path_buf();
270 current_path.push(path);
271 current_path
272 } else {
273 path
274 };
275 if !include_paths.borrow_mut().contains(&path) {
276 include_paths.borrow_mut().insert(path);
277 }
278 } else {
279 bail!(
280 "wrong format for .includepath, expected: {} in {}",
281 opts,
282 point,
283 );
284 }
285 } else {
286 bail!(
287 "wrong format for .includepath, expected: {} in {}",
288 opts,
289 point,
290 );
291 }
292 }
293 Directive::If | Directive::ElIf => {
294 if let DirectiveOps::OpList(values) = &opts {
295 if let Operand::E(expr) = &values[0] {
296 let value = expr.run(&context.common_context)?;
297 if value == 0 {
298 next_item = NextItem::EndIf;
299 }
300 } else {
301 bail!(
302 "wrong format for .{}, expected: {} in {}",
303 self,
304 opts,
305 point,
306 );
307 }
308 } else {
309 bail!(
310 "wrong format for .{}, expected: {} in {}",
311 self,
312 opts,
313 point,
314 );
315 }
316 }
317 Directive::IfNDef | Directive::IfDef => {
318 if let DirectiveOps::OpList(values) = &opts {
319 if let Operand::E(Expr::Ident(name)) = &values[0] {
320 if context.common_context.defines.borrow().contains_key(name) {
321 if self == &Directive::IfNDef {
322 next_item = NextItem::EndIf;
323 };
324 } else {
325 if self == &Directive::IfDef {
326 next_item = NextItem::EndIf;
327 }
328 }
329 } else {
330 bail!(
331 "wrong format for .{}, expected: {} in {}",
332 self,
333 opts,
334 point,
335 );
336 }
337 } else {
338 bail!(
339 "wrong format for .{}, expected: {} in {}",
340 self,
341 opts,
342 point,
343 );
344 }
345 }
346 Directive::Define => {
347 if let DirectiveOps::OpList(values) = &opts {
348 if let Operand::E(Expr::Ident(name)) = &values[0] {
349 context
350 .common_context
351 .set_define(name.clone(), Expr::Const(0));
352 } else {
353 bail!("wrong format for .define, expected: {} in {}", opts, point,);
354 }
355 } else {
356 bail!("wrong format for .define, expected: {} in {}", opts, point,);
357 }
358 }
359 Directive::Else => {
360 next_item = NextItem::EndIf;
361 }
362 Directive::Endif => {}
363 Directive::Exit => {
364 next_item = NextItem::EndFile;
365 }
366 Directive::Macro => {
367 if let DirectiveOps::OpList(values) = &opts {
368 if let Operand::E(Expr::Ident(name)) = &values[0] {
369 context.macros.name.replace(name.clone());
370 next_item = NextItem::EndMacro;
371 } else {
372 bail!("wrong format for .macro, expected: {} in {}", opts, point,);
373 }
374 } else {
375 bail!("wrong format for .macro, expected: {} in {}", opts, point,);
376 }
377 }
378 Directive::CSegSize => {}
380 Directive::Message | Directive::Warning | Directive::Error => {
381 if let DirectiveOps::OpList(values) = &opts {
382 if let Operand::S(message) = &values[0] {
383 let message_type = match self {
384 Directive::Message => "info",
385 Directive::Warning => "warning",
386 Directive::Error => "error",
387 _ => bail!("wrong option for message in {}", point),
388 };
389 context
390 .messages
391 .borrow_mut()
392 .push(format!("{}: {} in {}", message_type, message, point));
393 if self == &Directive::Error {
394 bail!("failed by error: {} in {}", message, point);
395 }
396 } else {
397 bail!(
398 "wrong format for .{}, expected: {} in {}",
399 self,
400 opts,
401 point,
402 );
403 }
404 } else {
405 bail!(
406 "wrong format for .{}, expected: {} in {}",
407 self,
408 opts,
409 point,
410 );
411 }
412 }
413 Directive::Custom(name) => bail!("unsupported custom directive {}, {}", name, point),
414 _ => bail!(
415 "Unsupported directive {} in {} segment, {}",
416 self,
417 context.last_segment().unwrap().borrow().t,
418 point,
419 ),
420 }
421
422 Ok(next_item)
423 }
424}
425
426#[derive(Clone, PartialEq, Eq, Debug)]
427pub enum Operand {
428 E(Expr),
429 S(String),
430}
431
432impl Operand {
433 pub fn len(&self) -> usize {
434 match self {
435 Operand::E(_) => 1,
436 Operand::S(s) => s.len(),
437 }
438 }
439
440 pub fn get_bytes(&self, e_p: &dyn Context) -> Result<Vec<u8>, Error> {
441 match self {
442 Operand::E(expr) => Ok(vec![expr.get_byte(e_p)?]),
443 Operand::S(s) => Ok(s.as_bytes().to_vec()),
444 }
445 }
446
447 pub fn get_words(&self, e_p: &dyn Context) -> Result<Vec<u8>, Error> {
448 match self {
449 Operand::E(expr) => Ok(expr.get_words(e_p)?.to_vec()),
450 Operand::S(_) => bail!("not allowed to convert string as 2 bytes array"),
451 }
452 }
453
454 pub fn get_double_words(&self, e_p: &dyn Context) -> Result<Vec<u8>, Error> {
455 match self {
456 Operand::E(expr) => Ok(expr.get_double_words(e_p)?.to_vec()),
457 Operand::S(_) => bail!("not allowed to convert string as 2 bytes array"),
458 }
459 }
460
461 pub fn get_quad_words(&self, e_p: &dyn Context) -> Result<Vec<u8>, Error> {
462 match self {
463 Operand::E(expr) => Ok(expr.get_quad_words(e_p)?.to_vec()),
464 Operand::S(_) => bail!("not allowed to convert string as 2 bytes array"),
465 }
466 }
467}
468
469#[derive(Clone, PartialEq, Eq, Debug, Display)]
470pub enum DirectiveOps {
471 OpList(Vec<Operand>),
472 Assign(Expr, Expr),
473}
474
475pub trait GetData {
476 fn actual_len(&self) -> usize;
477 fn get_bytes(&self, constants: &dyn Context) -> Result<Vec<u8>, Error>;
478 fn get_words(&self, constants: &dyn Context) -> Result<Vec<u8>, Error>;
479 fn get_double_words(&self, constants: &dyn Context) -> Result<Vec<u8>, Error>;
480 fn get_quad_words(&self, constants: &dyn Context) -> Result<Vec<u8>, Error>;
481}
482
483impl GetData for Vec<Operand> {
484 fn actual_len(&self) -> usize {
485 self.iter().fold(0, |acc, op| acc + op.len())
486 }
487
488 fn get_bytes(&self, constants: &dyn Context) -> Result<Vec<u8>, Error> {
489 let mut bytes = vec![];
490 for item in self {
491 bytes.extend(item.get_bytes(constants)?);
492 }
493
494 Ok(bytes)
495 }
496 fn get_words(&self, constants: &dyn Context) -> Result<Vec<u8>, Error> {
497 let mut bytes = vec![];
498 for item in self {
499 bytes.extend(item.get_words(constants)?);
500 }
501
502 Ok(bytes)
503 }
504 fn get_double_words(&self, constants: &dyn Context) -> Result<Vec<u8>, Error> {
505 let mut bytes = vec![];
506 for item in self {
507 bytes.extend(item.get_double_words(constants)?);
508 }
509
510 Ok(bytes)
511 }
512 fn get_quad_words(&self, constants: &dyn Context) -> Result<Vec<u8>, Error> {
513 let mut bytes = vec![];
514 for item in self {
515 bytes.extend(item.get_quad_words(constants)?);
516 }
517
518 Ok(bytes)
519 }
520}
521
522#[cfg(test)]
523mod parser_tests {
524 use super::*;
525
526 use crate::{
527 device::DEVICES,
528 directive::Operand,
529 document::{document, Document},
530 expr::{BinaryExpr, BinaryOperator},
531 instruction::{
532 operation::Operation,
533 register::{Reg16, Reg8},
534 IndexOps, InstructionOps,
535 },
536 parser::{parse_file, parse_str, ParseResult},
537 };
538
539 use crate::context::CommonContext;
540 use maplit::{btreeset, hashmap};
541 use std::path::PathBuf;
542
543 #[test]
544 fn directive_test() {
545 assert_eq!(document::directive(".equ"), Ok(Directive::Equ));
546
547 assert_eq!(document::directive(".dseg"), Ok(Directive::DSeg));
548 }
549
550 #[test]
551 fn directive_op_test() {
552 assert_eq!(
553 document::directive_op("a"),
554 Ok(Operand::E(Expr::Ident("a".to_string())))
555 );
556
557 assert_eq!(
558 document::directive_op("\"bla bla bla\""),
559 Ok(Operand::S("bla bla bla".to_string()))
560 );
561 }
562
563 #[test]
564 fn directive_ops_test() {
565 assert_eq!(
566 document::directive_ops(""),
567 Ok(DirectiveOps::OpList(vec![]))
568 );
569
570 assert_eq!(
571 document::directive_ops("a\t, b,c ,\td"),
572 Ok(DirectiveOps::OpList(vec![
573 Operand::E(Expr::Ident("a".to_string())),
574 Operand::E(Expr::Ident("b".to_string())),
575 Operand::E(Expr::Ident("c".to_string())),
576 Operand::E(Expr::Ident("d".to_string()))
577 ]))
578 );
579
580 assert_eq!(
581 document::directive_ops("a,b,c,d"),
582 Ok(DirectiveOps::OpList(vec![
583 Operand::E(Expr::Ident("a".to_string())),
584 Operand::E(Expr::Ident("b".to_string())),
585 Operand::E(Expr::Ident("c".to_string())),
586 Operand::E(Expr::Ident("d".to_string()))
587 ]))
588 );
589
590 assert_eq!(
591 document::directive_ops("a b c d"),
592 Ok(DirectiveOps::OpList(vec![
593 Operand::E(Expr::Ident("a".to_string())),
594 Operand::E(Expr::Ident("b".to_string())),
595 Operand::E(Expr::Ident("c".to_string())),
596 Operand::E(Expr::Ident("d".to_string()))
597 ]))
598 );
599
600 assert_eq!(
601 document::directive_ops("t = 44"),
602 Ok(DirectiveOps::Assign(
603 Expr::Ident("t".to_string()),
604 Expr::Const(44)
605 ))
606 );
607 }
608
609 #[test]
610 fn directive_line_test() {
611 assert_eq!(
612 document::directive_line(".dseg"),
613 Ok(Document::DirectiveLine(
614 Box::new(None),
615 Directive::DSeg,
616 DirectiveOps::OpList(vec![])
617 ))
618 );
619
620 assert_eq!(
621 document::directive_line(".equ Last = 8"),
622 Ok(Document::DirectiveLine(
623 Box::new(None),
624 Directive::Equ,
625 DirectiveOps::Assign(Expr::Ident("Last".to_string()), Expr::Const(8))
626 ))
627 );
628
629 assert_eq!(
630 document::directive_line("#define MIDDLE"),
631 Ok(Document::DirectiveLine(
632 Box::new(None),
633 Directive::Define,
634 DirectiveOps::OpList(vec![Operand::E(Expr::Ident("MIDDLE".to_string()))])
635 ))
636 );
637 }
638
639 #[test]
640 fn check_org() {
641 let common_context = CommonContext::new();
642 let parse_result = parse_str("good_point:\n.org 0x2\ngood_point2:", &common_context);
643 assert_eq!(
644 parse_result.unwrap(),
645 ParseResult {
646 segments: vec![
647 Segment {
648 items: vec![(
649 CodePoint {
650 line_num: 1,
651 num: 1
652 },
653 Item::Label("good_point".to_string())
654 )],
655 t: SegmentType::Code,
656 address: 0
657 },
658 Segment {
659 items: vec![(
660 CodePoint {
661 line_num: 3,
662 num: 1
663 },
664 Item::Label("good_point2".to_string())
665 )],
666 t: SegmentType::Code,
667 address: 0x2
668 }
669 ],
670 macroses: hashmap! {},
671 messages: vec![],
672 }
673 );
674 }
675
676 #[test]
677 fn check_segments() {
678 let common_context = CommonContext::new();
679 let parse_result = parse_str("good_point:\n.cseg\ngood_point2:", &common_context);
680 assert_eq!(
681 parse_result.unwrap(),
682 ParseResult {
683 segments: vec![
684 Segment {
685 items: vec![(
686 CodePoint {
687 line_num: 1,
688 num: 1
689 },
690 Item::Label("good_point".to_string())
691 )],
692 t: SegmentType::Code,
693 address: 0
694 },
695 Segment {
696 items: vec![(
697 CodePoint {
698 line_num: 3,
699 num: 1
700 },
701 Item::Label("good_point2".to_string())
702 )],
703 t: SegmentType::Code,
704 address: 0
705 }
706 ],
707 macroses: hashmap! {},
708 messages: vec![],
709 }
710 );
711
712 let common_context = CommonContext::new();
713 let parse_result = parse_str(
714 "good_point:\n.cseg\n.org 0x20\ngood_point2:",
715 &common_context,
716 );
717 assert_eq!(
718 parse_result.unwrap(),
719 ParseResult {
720 segments: vec![
721 Segment {
722 items: vec![(
723 CodePoint {
724 line_num: 1,
725 num: 1
726 },
727 Item::Label("good_point".to_string())
728 )],
729 t: SegmentType::Code,
730 address: 0
731 },
732 Segment {
733 items: vec![(
734 CodePoint {
735 line_num: 4,
736 num: 1
737 },
738 Item::Label("good_point2".to_string())
739 )],
740 t: SegmentType::Code,
741 address: 0x20
742 }
743 ],
744 macroses: hashmap! {},
745 messages: vec![],
746 }
747 );
748
749 let common_context = CommonContext::new();
750 let parse_result = parse_str(
751 "good_point:\n.dseg\ngood_point2:\n.cseg\ngood_point3:",
752 &common_context,
753 );
754 assert_eq!(
755 parse_result.unwrap(),
756 ParseResult {
757 segments: vec![
758 Segment {
759 items: vec![(
760 CodePoint {
761 line_num: 1,
762 num: 1
763 },
764 Item::Label("good_point".to_string())
765 )],
766 t: SegmentType::Code,
767 address: 0
768 },
769 Segment {
770 items: vec![(
771 CodePoint {
772 line_num: 3,
773 num: 1
774 },
775 Item::Label("good_point2".to_string())
776 )],
777 t: SegmentType::Data,
778 address: 0
779 },
780 Segment {
781 items: vec![(
782 CodePoint {
783 line_num: 5,
784 num: 1
785 },
786 Item::Label("good_point3".to_string())
787 )],
788 t: SegmentType::Code,
789 address: 0
790 },
791 ],
792 macroses: hashmap! {},
793 messages: vec![],
794 }
795 );
796 }
797
798 #[test]
799 fn check_db_dw_dd_dq() {
800 let common_context = CommonContext::new();
801 let parse_result = parse_str(
802 "ldi r16, data\ndata:\n.db 15, 26, \"Hello, World\", end",
803 &common_context,
804 );
805 assert_eq!(
806 parse_result.unwrap(),
807 ParseResult {
808 segments: vec![Segment {
809 items: vec![
810 (
811 CodePoint {
812 line_num: 1,
813 num: 2
814 },
815 Item::Instruction(
816 Operation::Ldi,
817 vec![
818 InstructionOps::R8(Reg8::R16),
819 InstructionOps::E(Expr::Ident("data".to_string()))
820 ]
821 )
822 ),
823 (
824 CodePoint {
825 line_num: 2,
826 num: 1
827 },
828 Item::Label("data".to_string())
829 ),
830 (
831 CodePoint {
832 line_num: 3,
833 num: 2
834 },
835 Item::Data(
836 DataDefine::Db,
837 vec![
838 Operand::E(Expr::Const(15)),
839 Operand::E(Expr::Const(26)),
840 Operand::S("Hello, World".to_string()),
841 Operand::E(Expr::Ident("end".to_string())),
842 ]
843 )
844 )
845 ],
846 t: SegmentType::Code,
847 address: 0
848 }],
849 macroses: hashmap! {},
850 messages: vec![],
851 }
852 );
853
854 let common_context = CommonContext::new();
855 let parse_result = parse_str(
856 "ldi r18, data_w\ndata_w:\n.dw 0xff44, end, 0xda4e",
857 &common_context,
858 );
859 assert_eq!(
860 parse_result.unwrap(),
861 ParseResult {
862 segments: vec![Segment {
863 items: vec![
864 (
865 CodePoint {
866 line_num: 1,
867 num: 2
868 },
869 Item::Instruction(
870 Operation::Ldi,
871 vec![
872 InstructionOps::R8(Reg8::R18),
873 InstructionOps::E(Expr::Ident("data_w".to_string()))
874 ]
875 )
876 ),
877 (
878 CodePoint {
879 line_num: 2,
880 num: 1
881 },
882 Item::Label("data_w".to_string())
883 ),
884 (
885 CodePoint {
886 line_num: 3,
887 num: 2
888 },
889 Item::Data(
890 DataDefine::Dw,
891 vec![
892 Operand::E(Expr::Const(0xff44)),
893 Operand::E(Expr::Ident("end".to_string())),
894 Operand::E(Expr::Const(0xda4e))
895 ]
896 )
897 )
898 ],
899 t: SegmentType::Code,
900 address: 0
901 }],
902 macroses: hashmap! {},
903 messages: vec![],
904 }
905 );
906
907 let common_context = CommonContext::new();
908 let parse_result = parse_str(
909 "ldi r18, data_w\ndata_w:\n.dw 0xff44, end, 0xda4e",
910 &common_context,
911 );
912 assert_eq!(
913 parse_result.unwrap(),
914 ParseResult {
915 segments: vec![Segment {
916 items: vec![
917 (
918 CodePoint {
919 line_num: 1,
920 num: 2
921 },
922 Item::Instruction(
923 Operation::Ldi,
924 vec![
925 InstructionOps::R8(Reg8::R18),
926 InstructionOps::E(Expr::Ident("data_w".to_string()))
927 ]
928 )
929 ),
930 (
931 CodePoint {
932 line_num: 2,
933 num: 1
934 },
935 Item::Label("data_w".to_string())
936 ),
937 (
938 CodePoint {
939 line_num: 3,
940 num: 2
941 },
942 Item::Data(
943 DataDefine::Dw,
944 vec![
945 Operand::E(Expr::Const(0xff44)),
946 Operand::E(Expr::Ident("end".to_string())),
947 Operand::E(Expr::Const(0xda4e))
948 ]
949 )
950 )
951 ],
952 t: SegmentType::Code,
953 address: 0
954 }],
955 macroses: hashmap! {},
956 messages: vec![],
957 }
958 );
959
960 let common_context = CommonContext::new();
961 let parse_result = parse_str(
962 "ldi r18, data_w\ndata_w:\n.dd 0xff44, end, 0xda4e",
963 &common_context,
964 );
965 assert_eq!(
966 parse_result.unwrap(),
967 ParseResult {
968 segments: vec![Segment {
969 items: vec![
970 (
971 CodePoint {
972 line_num: 1,
973 num: 2
974 },
975 Item::Instruction(
976 Operation::Ldi,
977 vec![
978 InstructionOps::R8(Reg8::R18),
979 InstructionOps::E(Expr::Ident("data_w".to_string()))
980 ]
981 )
982 ),
983 (
984 CodePoint {
985 line_num: 2,
986 num: 1
987 },
988 Item::Label("data_w".to_string())
989 ),
990 (
991 CodePoint {
992 line_num: 3,
993 num: 2
994 },
995 Item::Data(
996 DataDefine::Dd,
997 vec![
998 Operand::E(Expr::Const(0xff44)),
999 Operand::E(Expr::Ident("end".to_string())),
1000 Operand::E(Expr::Const(0xda4e))
1001 ]
1002 )
1003 )
1004 ],
1005 t: SegmentType::Code,
1006 address: 0
1007 }],
1008 macroses: hashmap! {},
1009 messages: vec![],
1010 }
1011 );
1012
1013 let common_context = CommonContext::new();
1014 let parse_result = parse_str(
1015 "ldi r18, data_w\ndata_w:\n.dq 0xff44, end, 0xda4e",
1016 &common_context,
1017 );
1018 assert_eq!(
1019 parse_result.unwrap(),
1020 ParseResult {
1021 segments: vec![Segment {
1022 items: vec![
1023 (
1024 CodePoint {
1025 line_num: 1,
1026 num: 2
1027 },
1028 Item::Instruction(
1029 Operation::Ldi,
1030 vec![
1031 InstructionOps::R8(Reg8::R18),
1032 InstructionOps::E(Expr::Ident("data_w".to_string()))
1033 ]
1034 )
1035 ),
1036 (
1037 CodePoint {
1038 line_num: 2,
1039 num: 1
1040 },
1041 Item::Label("data_w".to_string())
1042 ),
1043 (
1044 CodePoint {
1045 line_num: 3,
1046 num: 2
1047 },
1048 Item::Data(
1049 DataDefine::Dq,
1050 vec![
1051 Operand::E(Expr::Const(0xff44)),
1052 Operand::E(Expr::Ident("end".to_string())),
1053 Operand::E(Expr::Const(0xda4e))
1054 ]
1055 )
1056 )
1057 ],
1058 t: SegmentType::Code,
1059 address: 0
1060 }],
1061 macroses: hashmap! {},
1062 messages: vec![],
1063 }
1064 );
1065 }
1066
1067 #[test]
1068 fn check_directive_equ() {
1069 let common_context = CommonContext::new();
1070 let parse_result = parse_str(
1071 ".equ REG0 = 0x44\n.equ REG1 = 0x45\n.equ REG2 = 0x46",
1072 &common_context,
1073 );
1074 assert!(parse_result.is_ok());
1075
1076 assert_eq!(
1077 common_context.equs.borrow().clone(),
1078 hashmap! {
1079 "reg0".to_string() => Expr::Const(0x44),
1080 "reg1".to_string() => Expr::Const(0x45),
1081 "reg2".to_string() => Expr::Const(0x46),
1082 }
1083 );
1084 }
1085
1086 #[test]
1087 fn check_directive_set() {
1088 let common_context = CommonContext::new();
1089 let parse_result = parse_str(".set t = 4\n.set t = t + 1", &common_context);
1090 assert_eq!(
1091 parse_result.unwrap(),
1092 ParseResult {
1093 segments: vec![Segment {
1094 items: vec![
1095 (
1096 CodePoint {
1097 line_num: 1,
1098 num: 2
1099 },
1100 Item::Set("t".to_string(), Expr::Const(4))
1101 ),
1102 (
1103 CodePoint {
1104 line_num: 2,
1105 num: 2
1106 },
1107 Item::Set(
1108 "t".to_string(),
1109 Expr::Binary(Box::new(BinaryExpr {
1110 left: Expr::Ident("t".to_string()),
1111 operator: BinaryOperator::Add,
1112 right: Expr::Const(1)
1113 }))
1114 )
1115 )
1116 ],
1117 t: SegmentType::Code,
1118 address: 0,
1119 }],
1120 macroses: hashmap! {},
1121 messages: vec![],
1122 }
1123 );
1124 }
1125
1126 #[test]
1127 fn check_directive_byte() {
1128 let common_context = CommonContext::new();
1129 let parse_result = parse_str(".dseg\ndata: .byte 1\ncounter: .byte 2", &common_context);
1130 assert_eq!(
1131 parse_result.unwrap(),
1132 ParseResult {
1133 segments: vec![Segment {
1134 items: vec![
1135 (
1136 CodePoint {
1137 line_num: 2,
1138 num: 1
1139 },
1140 Item::Label("data".to_string())
1141 ),
1142 (
1143 CodePoint {
1144 line_num: 2,
1145 num: 2
1146 },
1147 Item::ReserveData(1)
1148 ),
1149 (
1150 CodePoint {
1151 line_num: 3,
1152 num: 1
1153 },
1154 Item::Label("counter".to_string())
1155 ),
1156 (
1157 CodePoint {
1158 line_num: 3,
1159 num: 2
1160 },
1161 Item::ReserveData(2),
1162 ),
1163 ],
1164 t: SegmentType::Data,
1165 address: 0,
1166 }],
1167 macroses: hashmap! {},
1168 messages: vec![],
1169 }
1170 );
1171 }
1172
1173 #[test]
1174 fn check_directive_device() {
1175 let common_context = CommonContext::new();
1176 let parse_result = parse_str(".device ATmega48\nldd r25, Z+2", &common_context);
1177 assert_eq!(
1178 parse_result.unwrap(),
1179 ParseResult {
1180 segments: vec![Segment {
1181 items: vec![(
1182 CodePoint {
1183 line_num: 2,
1184 num: 2
1185 },
1186 Item::Instruction(
1187 Operation::Ldd,
1188 vec![
1189 InstructionOps::R8(Reg8::R25),
1190 InstructionOps::Index(IndexOps::PostIncrementE(
1191 Reg16::Z,
1192 Expr::Const(2)
1193 ))
1194 ]
1195 )
1196 ),],
1197 t: SegmentType::Code,
1198 address: 0
1199 }],
1200 macroses: hashmap! {},
1201 messages: vec![],
1202 }
1203 );
1204
1205 assert_eq!(
1206 common_context.get_device(),
1207 DEVICES.get("ATmega48").unwrap().clone()
1208 );
1209
1210 let common_context = CommonContext::new();
1211 let parse_result = parse_str(".device ATmega96\nldd r25, Z+2", &common_context);
1212 assert!(parse_result.is_err());
1213 }
1214
1215 #[test]
1216 fn check_directive_include() {
1217 let common_context = CommonContext::new();
1218 let parse_result = parse_file(
1219 PathBuf::from("tests/include_test.asm"),
1220 btreeset! {},
1221 &common_context,
1222 );
1223
1224 assert_eq!(
1225 parse_result.unwrap(),
1226 ParseResult {
1227 segments: vec![Segment {
1228 items: vec![(
1229 CodePoint {
1230 line_num: 3,
1231 num: 2
1232 },
1233 Item::Instruction(
1234 Operation::In,
1235 vec![
1236 InstructionOps::R8(Reg8::R0),
1237 InstructionOps::E(Expr::Ident("SREG".to_string()))
1238 ]
1239 )
1240 ),],
1241 t: SegmentType::Code,
1242 address: 0
1243 }],
1244 macroses: hashmap! {},
1245 messages: vec![],
1246 }
1247 );
1248
1249 assert_eq!(
1250 common_context.equs.borrow().clone(),
1251 hashmap! {
1252 "sreg".to_string() => Expr::Const(0x3f),
1253 }
1254 );
1255
1256 assert_eq!(
1257 common_context.get_device(),
1258 DEVICES.get("ATmega48").unwrap().clone()
1259 );
1260 }
1261
1262 #[test]
1263 fn check_directive_include_path() {
1264 let common_context = CommonContext::new();
1265 let parse_result = parse_file(
1266 PathBuf::from("tests/include_path_test.asm"),
1267 btreeset! {},
1268 &common_context,
1269 );
1270
1271 assert_eq!(
1272 parse_result.unwrap(),
1273 ParseResult {
1274 segments: vec![Segment {
1275 items: vec![(
1276 CodePoint {
1277 line_num: 4,
1278 num: 2
1279 },
1280 Item::Instruction(
1281 Operation::In,
1282 vec![
1283 InstructionOps::R8(Reg8::R0),
1284 InstructionOps::E(Expr::Ident("SREG".to_string()))
1285 ]
1286 )
1287 ),],
1288 t: SegmentType::Code,
1289 address: 0
1290 }],
1291 macroses: hashmap! {},
1292 messages: vec![],
1293 }
1294 );
1295
1296 assert_eq!(
1297 common_context.equs.borrow().clone(),
1298 hashmap! {
1299 "sreg".to_string() => Expr::Const(0x3f),
1300 }
1301 );
1302
1303 assert_eq!(
1304 common_context.get_device(),
1305 DEVICES.get("ATmega88").unwrap().clone()
1306 );
1307 }
1308
1309 #[test]
1310 fn check_directive_if_ifdef_ifndef_elif_else_define() {
1311 let common_context = CommonContext::new();
1312 let parse_result = parse_str(".define T\n.ifndef T\n.endif", &common_context);
1313 assert!(parse_result.is_ok());
1314
1315 assert_eq!(
1316 common_context.defines.borrow().clone(),
1317 hashmap! { "T".to_string() => Expr::Const(0) }
1318 );
1319
1320 let common_context = CommonContext::new();
1321 let parse_result = parse_str("\n.ifndef T\n.endif", &common_context);
1322 assert!(parse_result.is_ok());
1323
1324 let common_context = CommonContext::new();
1325 let parse_result = parse_str(".ifdef T\n.endif", &common_context);
1326 assert!(parse_result.is_ok());
1327
1328 let common_context = CommonContext::new();
1329 let parse_result = parse_str(".define T\n.ifdef T\n.endif", &common_context);
1330 assert!(parse_result.is_ok());
1331
1332 assert_eq!(
1333 common_context.defines.borrow().clone(),
1334 hashmap! { "T".to_string() => Expr::Const(0) }
1335 );
1336
1337 let common_context = CommonContext::new();
1338 let parse_result = parse_str(
1339 "\n.ifndef T\n.ifdef T\n.define T\n.endif\n.define X\n.endif",
1340 &common_context,
1341 );
1342 assert!(parse_result.is_ok());
1343
1344 assert_eq!(
1345 common_context.defines.borrow().clone(),
1346 hashmap! { "X".to_string() => Expr::Const(0) }
1347 );
1348
1349 let common_context = CommonContext::new();
1350 let parse_result = parse_str(
1351 ".ifdef T\n.define X\n.else\n.define Y\n.endif\n.define Z",
1352 &common_context,
1353 );
1354 assert!(parse_result.is_ok());
1355
1356 assert_eq!(
1357 common_context.defines.borrow().clone(),
1358 hashmap! { "Y".to_string() => Expr::Const(0), "Z".to_string() => Expr::Const(0) }
1359 );
1360
1361 let common_context = CommonContext::new();
1362 let parse_result = parse_str(
1363 ".ifndef T\n.define X\n.else\n.define Y\n.endif\n.define Z",
1364 &common_context,
1365 );
1366 assert!(parse_result.is_ok());
1367
1368 assert_eq!(
1369 common_context.defines.borrow().clone(),
1370 hashmap! { "X".to_string() => Expr::Const(0), "Z".to_string() => Expr::Const(0) }
1371 );
1372
1373 let common_context = CommonContext::new();
1374 let parse_result = parse_str(
1375 ".ifndef T\n.define X\n.else\n.endif\n.define Z",
1376 &common_context,
1377 );
1378 assert!(parse_result.is_ok());
1379
1380 assert_eq!(
1381 common_context.defines.borrow().clone(),
1382 hashmap! { "X".to_string() => Expr::Const(0), "Z".to_string() => Expr::Const(0) }
1383 );
1384
1385 let common_context = CommonContext::new();
1386 let parse_result = parse_str(
1387 ".if 4 > 5\n.define X\n.else\n.define Y\n.endif\n.define Z",
1388 &common_context,
1389 );
1390 assert!(parse_result.is_ok());
1391
1392 assert_eq!(
1393 common_context.defines.borrow().clone(),
1394 hashmap! { "Y".to_string() => Expr::Const(0), "Z".to_string() => Expr::Const(0) }
1395 );
1396
1397 let common_context = CommonContext::new();
1398 let parse_result = parse_str(
1399 "\
1400 .if 4 > 5
1401 .define X
1402 .elif 2 > 1
1403 .define Y
1404 .else
1405 .define T
1406 .endif
1407 .define Z",
1408 &common_context,
1409 );
1410 assert!(parse_result.is_ok());
1411
1412 assert_eq!(
1413 common_context.defines.borrow().clone(),
1414 hashmap! { "Y".to_string() => Expr::Const(0), "Z".to_string() => Expr::Const(0) },
1415 );
1416 }
1417
1418 #[test]
1419 fn check_directive_exit() {
1420 let common_context = CommonContext::new();
1421 let parse_result = parse_str(".define Y\n.exit\n.define X", &common_context);
1422 assert!(parse_result.is_ok());
1423
1424 assert_eq!(
1425 common_context.defines.borrow().clone(),
1426 hashmap! { "Y".to_string() => Expr::Const(0) },
1427 );
1428 }
1429
1430 #[test]
1431 fn check_directive_macro() {
1432 let common_context = CommonContext::new();
1433 let parse_result = parse_str(
1434 "
1435.macro test
1436 ; bla bla bla
1437 mov r0, @1
1438 mov r2, @0
1439.if @2 > 0x40
1440 lds r16, @2
1441.endif
1442.endm
1443.macro test2
1444.endmacro
1445
1446 ",
1447 &common_context,
1448 );
1449 assert_eq!(
1450 parse_result.unwrap(),
1451 ParseResult {
1452 segments: vec![],
1453 macroses: hashmap! {
1454 "test".to_string() => vec! [
1455 (CodePoint{ line_num: 2, num: 3}, " ; bla bla bla".to_string()),
1456 (CodePoint{ line_num: 3, num: 3}, " mov r0, @1".to_string()),
1457 (CodePoint{ line_num: 4, num: 3}, " mov r2, @0".to_string()),
1458 (CodePoint{ line_num: 5, num: 3}, ".if @2 > 0x40".to_string()),
1459 (CodePoint{ line_num: 6, num: 3}, " lds r16, @2".to_string()),
1460 (CodePoint{ line_num: 7, num: 3}, ".endif".to_string()),
1461 ],
1462 "test2".to_string() => vec![]
1463 },
1464 messages: vec![],
1465 }
1466 );
1467 }
1468
1469 #[test]
1470 fn check_directive_pragma() {
1471 let common_context = CommonContext::new();
1472 let parse_result = parse_str(
1473 "
1474.pragma option use core v1
1475 ",
1476 &common_context,
1477 );
1478 assert_eq!(
1479 parse_result.unwrap(),
1480 ParseResult {
1481 segments: vec![Segment {
1482 items: vec![(
1483 CodePoint {
1484 line_num: 2,
1485 num: 2
1486 },
1487 Item::Pragma(vec![
1488 Operand::E(Expr::Ident("option".to_string())),
1489 Operand::E(Expr::Ident("use".to_string())),
1490 Operand::E(Expr::Ident("core".to_string())),
1491 Operand::E(Expr::Ident("v1".to_string())),
1492 ])
1493 )],
1494 t: SegmentType::Code,
1495 address: 0
1496 }],
1497 macroses: hashmap! {},
1498 messages: vec![],
1499 }
1500 );
1501 }
1502
1503 #[test]
1504 fn check_directive_cseg_size() {
1505 let common_context = CommonContext::new();
1506 let parse_result = parse_str(
1507 "
1508.csegsize 11
1509 ",
1510 &common_context,
1511 );
1512 assert!(parse_result.is_ok());
1513 }
1514
1515 #[test]
1516 fn check_directive_message_warning_error() {
1517 let common_context = CommonContext::new();
1518 let parse_result = parse_str(
1519 "
1520.message \"test\"
1521.warning \"test 2\"
1522 ",
1523 &common_context,
1524 );
1525 assert_eq!(
1526 parse_result.unwrap(),
1527 ParseResult {
1528 segments: vec![],
1529 macroses: hashmap! {},
1530 messages: vec![
1531 "info: test in line: 2".to_string(),
1532 "warning: test 2 in line: 3".to_string(),
1533 ],
1534 }
1535 );
1536
1537 let common_context = CommonContext::new();
1538 let parse_result = parse_str(
1539 "
1540.error \"Fail Fail Fail\"
1541 ",
1542 &common_context,
1543 );
1544 assert_eq!(parse_result.is_err(), true,);
1545 }
1546}