1pub mod pass0;
4pub mod pass1;
5pub mod pass2;
6
7use crate::{
8 builder::{
9 pass0::build_pass_0 as pass0, pass1::build_pass_1 as pass1, pass2::build_pass_2 as pass2,
10 },
11 context::{CommonContext, Context},
12 parser::{parse_file, parse_str, ParseResult, Paths},
13};
14
15use failure::{bail, Error};
16use std::path::PathBuf;
17
18#[derive(Clone, PartialEq, Eq, Debug)]
19pub struct BuildResult {
20 pub code: Vec<u8>,
21 pub eeprom: Vec<u8>,
22
23 pub flash_size: u32,
24 pub eeprom_size: u32,
25 pub ram_size: u32,
26 pub ram_filling: u32,
27
28 pub messages: Vec<String>,
29}
30
31fn build_from_parsed(
32 parsed: ParseResult,
33 common_context: &CommonContext,
34) -> Result<BuildResult, Error> {
35 let passed_0 = pass0(parsed, common_context)?;
36
37 let passed_1 = pass1(passed_0, common_context)?;
38
39 let passed_2 = pass2(passed_1, common_context)?;
40
41 let device = common_context.get_device();
42
43 if passed_2.code.len() as u32 > device.flash_size * 2 {
44 bail!(
45 "Flash size overdue by {} bytes",
46 passed_2.code.len() as u32 - device.flash_size * 2
47 )
48 }
49
50 if passed_2.eeprom.len() as u32 > device.eeprom_size {
51 bail!(
52 "Eeprom size overdue by {} bytes",
53 passed_2.eeprom.len() as u32 - device.eeprom_size
54 )
55 }
56
57 if passed_2.ram_filling > device.ram_size {
58 bail!(
59 "RAM size overdue by {} bytes",
60 passed_2.ram_filling - device.ram_size
61 )
62 }
63
64 Ok(BuildResult {
65 code: passed_2.code,
66 eeprom: passed_2.eeprom,
67 flash_size: device.flash_size,
68 eeprom_size: device.eeprom_size,
69 ram_size: device.ram_size,
70 ram_filling: passed_2.ram_filling,
71 messages: passed_2.messages,
72 })
73}
74
75pub fn build_str(source: &str) -> Result<BuildResult, Error> {
76 let common_context = CommonContext::new();
77
78 let parsed = parse_str(source, &common_context)?;
79
80 build_from_parsed(parsed, &common_context)
81}
82
83pub fn build_file(path: PathBuf, paths: Paths) -> Result<BuildResult, Error> {
84 let common_context = CommonContext::new();
85
86 let parsed = parse_file(path, paths, &common_context)?;
87
88 build_from_parsed(parsed, &common_context)
89}
90
91#[cfg(test)]
92mod builder_tests {
93 use super::*;
94 use crate::utility::get_standard_includes;
95 use maplit::btreeset;
96 use std::path::PathBuf;
97
98 #[test]
99 fn check_empty() {
100 let built = build_str("").unwrap();
101
102 assert_eq!(
103 built,
104 BuildResult {
105 code: vec![],
106 eeprom: vec![],
107 flash_size: 4194304,
108 eeprom_size: 65536,
109 ram_size: 8388608,
110 ram_filling: 0,
111 messages: vec![],
112 }
113 );
114 }
115
116 #[test]
117 fn check_main_options() {
118 let asm_code = "
119 .cseg
120 .org 0x0
121 .equ end = 0x42
122 push r0
123m_begin:
124 mov r17, r0
125 subi r17, (-1)
126 brpl m0
127 rjmp m_begin
128
129m0: pop r1
130 ldi r30, low (data)
131 ldi r31, high(data)
132 lpm r16, Z+
133 rjmp m1
134data: .db 15, 26, \"Hello, World\", end
135data_w:
136 .dw 0xff44, end, 0xda4e
137m1:
138 ldi r18, data_w
139 ";
140
141 let built = build_str(asm_code).unwrap();
142
143 let code = vec![
144 0xf, 0x92, 0x10, 0x2d, 0x1f, 0x5f, 0xa, 0xf4, 0xfc, 0xcf, 0x1f, 0x90, 0xea, 0xe0, 0xf0,
145 0xe0, 0x5, 0x91, 0xb, 0xc0, 0xf, 0x1a, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57,
146 0x6f, 0x72, 0x6c, 0x64, 0x42, 0x0, 0x44, 0xff, 0x42, 0x0, 0x4e, 0xda, 0x22, 0xe1,
147 ];
148
149 let build_success_result = BuildResult {
150 code: code.clone(),
151 eeprom: vec![],
152 flash_size: 4194304,
153 eeprom_size: 65536,
154 ram_size: 8388608,
155 ram_filling: 0,
156 messages: vec![],
157 };
158
159 assert_eq!(built, build_success_result);
160
161 let build_success_result = BuildResult {
162 code: code.clone(),
163 eeprom: vec![],
164 flash_size: 2048,
165 eeprom_size: 256,
166 ram_size: 512,
167 ram_filling: 0,
168 messages: vec![
169 "info: This simple test displays basic assembler constructions. in line: 1"
170 .to_string(),
171 ],
172 };
173
174 let built = build_file(
175 PathBuf::from("tests/builder_simple.asm"),
176 btreeset! { PathBuf::from("includes") },
177 )
178 .unwrap();
179
180 assert_eq!(built, build_success_result);
181
182 let built = build_file(
183 PathBuf::from("tests/builder_simple.asm"),
184 btreeset! { get_standard_includes() },
185 )
186 .unwrap();
187
188 assert_eq!(built, build_success_result);
189 }
190}