1#![doc(hidden)]
18
19pub mod symtable;
20
21use diags::Diags;
22use diags::SourceSpan;
23use parse_int::parse;
24
25#[derive(Clone, Debug)]
30pub struct ObjProps {
31 pub file: String,
32 pub name: String,
33 pub file_exclude: String,
34 pub section_exclude: String,
35 pub src_loc: SourceSpan,
37}
38
39#[derive(Clone, Debug)]
43pub struct ObjsecInfo {
44 pub file: String,
46 pub name: String,
48 pub file_offset: u64,
49 pub size: u64,
50 pub align: u64,
52 pub vma: u64,
54 pub lma: u64,
56 pub src_loc: SourceSpan,
57}
58
59#[derive(Clone, Debug)]
64pub struct RegionProps {
65 pub addr: u64,
66 pub size: u64,
67 pub name: String,
69 pub default_pad_byte: u8,
70 pub src_loc: SourceSpan,
72}
73
74impl RegionProps {
75 pub fn intersect(&self, other: &RegionProps) -> Option<RegionProps> {
78 let addr = self.addr.max(other.addr);
79 let end = (self.addr + self.size).min(other.addr + other.size);
81 if end <= addr {
82 return None;
83 }
84 Some(RegionProps {
85 addr,
86 size: end - addr,
87 name: format!("{} & {}", self.name, other.name),
88 default_pad_byte: other.default_pad_byte,
89 src_loc: other.src_loc.clone(),
90 })
91 }
92}
93
94#[derive(Clone, Debug)]
99pub struct EffectiveRegion {
100 pub effective_region: RegionProps,
102 pub region_stack: Vec<RegionProps>,
104}
105
106impl EffectiveRegion {
107 pub fn contains_addr(&self, addr: u64) -> bool {
111 let b = &self.effective_region;
112 addr >= b.addr && addr < b.addr + b.size
113 }
114
115 pub fn check_section_fits(
119 &self,
120 sec_name: &str,
121 sec_size: u64,
122 use_src_loc: SourceSpan,
123 diags: &mut Diags,
124 ) -> bool {
125 let b = &self.effective_region;
126 if sec_size <= b.size {
127 return true;
128 }
129 let excess = sec_size - b.size;
130 let msg = format!(
131 "Section '{}' size {} bytes exceeds region '{}' effective size {} by {} bytes.",
132 sec_name, sec_size, b.name, b.size, excess
133 );
134 let secondaries: Vec<(SourceSpan, String)> = if !self.region_stack.is_empty() {
135 self.region_stack
136 .iter()
137 .map(|c| {
138 (
139 c.src_loc.clone(),
140 format!("region '{}': addr={:#X}, size={}", c.name, c.addr, c.size),
141 )
142 })
143 .collect()
144 } else {
145 vec![(
146 b.src_loc.clone(),
147 format!("region '{}': addr={:#X}, size={}", b.name, b.addr, b.size),
148 )]
149 };
150 diags.err_with_locs("ERR_186", &msg, use_src_loc, &secondaries);
151 false
152 }
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub enum IRKind {
157 Addr,
158 Add,
159 Align,
160 Assert,
161 BitAnd,
162 BitOr,
163 Const,
164 Divide,
165 DoubleEq,
166 Eq,
167 ConstDeclare,
170 IfBegin,
173 ElseBegin,
176 IfEnd,
179 BareAssign,
182 ExtensionCall,
186 GEq,
187 Gt,
188 I64,
189 AddrOffset,
190 Label,
191 LeftShift,
192 LEq,
193 Lt,
194 LogicalAnd,
195 LogicalOr,
196 Modulo,
197 Multiply,
198 NEq,
199 BuiltinOutputAddr,
200 BuiltinOutputSize,
201 BuiltinVersionMajor,
202 BuiltinVersionMinor,
203 BuiltinVersionPatch,
204 BuiltinVersionString,
205 SetSecOffset,
206 SetAddrOffset,
207 SetAddr,
208 SetFileOffset,
209 Print,
210 Trace,
211 RightShift,
212 SecOffset,
213 FileOffset,
214 SectionEnd,
215 SectionStart,
216 ObjAlign,
217 ObjLma,
218 ObjVma,
219 Sizeof,
220 SizeofExt,
221 Subtract,
222 ToI64,
223 ToU64,
224 U64,
225 Wr(u8, bool),
227 Wrf,
228 Wrobj,
229 Wrs,
230 Output,
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq)]
238pub enum DataType {
239 U64,
240 I64,
241 Integer, QuotedString,
243 Identifier,
245 DeferredRef,
248 Extension,
251 Unknown,
254}
255
256#[derive(Debug, Clone, PartialEq)]
257pub enum ParameterValue {
258 U64(u64),
259 I64(i64),
260 Integer(i64), QuotedString(String),
262 Identifier(String),
264 DeferredRef(String),
267 Extension,
269 Unknown,
272}
273
274impl ParameterValue {
275 pub fn is_numeric(&self) -> bool {
277 matches!(
278 self,
279 ParameterValue::U64(_) | ParameterValue::I64(_) | ParameterValue::Integer(_)
280 )
281 }
282
283 pub fn data_type(&self) -> DataType {
284 match self {
285 ParameterValue::U64(_) => DataType::U64,
286 ParameterValue::I64(_) => DataType::I64,
287 ParameterValue::Integer(_) => DataType::Integer,
288 ParameterValue::QuotedString(_) => DataType::QuotedString,
289 ParameterValue::Identifier(_) => DataType::Identifier,
290 ParameterValue::DeferredRef(_) => DataType::DeferredRef,
291 ParameterValue::Extension => DataType::Extension,
292 ParameterValue::Unknown => DataType::Unknown,
293 }
294 }
295
296 pub fn to_bool(&self) -> Option<bool> {
297 match self {
298 ParameterValue::I64(v) | ParameterValue::Integer(v) => Some((*v as u64) != 0),
299 ParameterValue::U64(v) => Some(*v != 0),
300 _ => None,
301 }
302 }
303
304 pub fn to_u64(&self) -> u64 {
305 match self {
306 ParameterValue::I64(v) | ParameterValue::Integer(v) => *v as u64,
307 ParameterValue::U64(v) => *v,
308 _ => {
309 panic!("Internal error: Invalid type conversion from {:?} to u64", self);
310 }
311 }
312 }
313
314 pub fn to_u64_mut(&mut self) -> &mut u64 {
315 match self {
316 ParameterValue::U64(v) => v,
317 _ => {
318 panic!("Internal error: Invalid type conversion from {:?} to &mut u64", self);
319 }
320 }
321 }
322
323 pub fn to_i64(&self) -> i64 {
324 match self {
325 ParameterValue::I64(v) | ParameterValue::Integer(v) => *v,
326 _ => {
327 panic!("Internal error: Invalid type conversion from {:?} to i64", self);
328 }
329 }
330 }
331
332 pub fn to_i64_mut(&mut self) -> &mut i64 {
333 match self {
334 ParameterValue::I64(v) | ParameterValue::Integer(v) => v,
335 _ => {
336 panic!("Internal error: Invalid type conversion from {:?} to &mut i64", self);
337 }
338 }
339 }
340
341 pub fn to_str(&self) -> &str {
342 match self {
343 ParameterValue::QuotedString(s) => s,
344 _ => {
345 panic!("Internal error: Invalid type conversion from {:?} to str", self);
346 }
347 }
348 }
349
350 pub fn identifier_to_str(&self) -> &str {
351 match self {
352 ParameterValue::Identifier(s) | ParameterValue::DeferredRef(s) => s,
353 _ => {
354 panic!("Internal error: Invalid type conversion from {:?} to identifier", self);
355 }
356 }
357 }
358}
359
360pub fn strip_kmg(s: &str) -> (&str, u64) {
363 match s.as_bytes().last() {
364 Some(b'K') => (&s[..s.len() - 1], 1024),
365 Some(b'M') => (&s[..s.len() - 1], 1024 * 1024),
366 Some(b'G') => (&s[..s.len() - 1], 1024 * 1024 * 1024),
367 _ => (s, 1),
368 }
369}
370
371#[derive(Debug)]
372pub struct IROperand {
373 pub ir_lid: Option<usize>,
377 pub src_loc: SourceSpan,
380 pub is_immediate: bool,
385 pub val: ParameterValue,
389 pub param_name: Option<String>,
392}
393
394impl IROperand {
395 pub fn new(
396 ir_lid: Option<usize>,
397 sval: &str,
398 src_loc: &SourceSpan,
399 data_type: DataType,
400 is_immediate: bool,
401 diags: &mut Diags,
402 ) -> Option<IROperand> {
403 if let Some(val) = IROperand::convert_type(sval, data_type, src_loc, is_immediate, diags) {
404 return Some(IROperand {
405 ir_lid,
406 src_loc: src_loc.clone(),
407 is_immediate,
408 val,
409 param_name: None,
410 });
411 }
412
413 None
414 }
415
416 pub fn is_output_of(&self) -> Option<usize> {
417 self.ir_lid
418 }
419
420 fn convert_type(
422 sval: &str,
423 data_type: DataType,
424 src_loc: &SourceSpan,
425 is_immediate: bool,
426 diags: &mut Diags,
427 ) -> Option<ParameterValue> {
428 match data_type {
429 DataType::QuotedString => {
430 if !is_immediate {
431 return Some(ParameterValue::QuotedString(String::new()));
435 }
436 return Some(ParameterValue::QuotedString(
440 sval.strip_prefix('\"')
441 .unwrap()
442 .strip_suffix('\"')
443 .unwrap()
444 .replace("\\\"", "\"")
445 .replace("\\n", "\n")
446 .replace("\\0", "\0")
447 .replace("\\t", "\t"),
448 ));
449 }
450 DataType::Extension => {
451 return Some(ParameterValue::Extension);
452 }
453 DataType::U64 => {
454 if is_immediate {
455 let sval_no_u = sval.strip_suffix('u').unwrap_or(sval);
456 let (sval_base, mult) = strip_kmg(sval_no_u);
457 match parse::<u64>(sval_base).ok().and_then(|v| v.checked_mul(mult)) {
458 Some(v) => return Some(ParameterValue::U64(v)),
459 None => {
460 let m = format!("Malformed integer operand {}", sval);
461 diags.err1("ERR_198", &m, src_loc.clone());
462 }
463 }
464 } else {
465 return Some(ParameterValue::U64(0));
467 }
468 }
469
470 DataType::I64 => {
471 if is_immediate {
472 let sval_no_i = sval.strip_suffix('i').unwrap_or(sval);
473 let (sval_base, mult) = strip_kmg(sval_no_i);
474 match parse::<i64>(sval_base).ok().and_then(|v| v.checked_mul(mult as i64)) {
475 Some(v) => return Some(ParameterValue::I64(v)),
476 None => {
477 let m = format!("Malformed integer operand {}", sval);
478 diags.err1("ERR_200", &m, src_loc.clone());
479 }
480 }
481 } else {
482 return Some(ParameterValue::I64(0));
484 }
485 }
486
487 DataType::Integer => {
488 if is_immediate {
489 let (sval_base, mult) = strip_kmg(sval);
491 match parse::<i64>(sval_base).ok().and_then(|v| v.checked_mul(mult as i64)) {
492 Some(v) => return Some(ParameterValue::Integer(v)),
493 None => {
494 let m = format!("Malformed integer operand {}", sval);
495 diags.err1("ERR_201", &m, src_loc.clone());
496 }
497 }
498 } else {
499 return Some(ParameterValue::Integer(0));
501 }
502 }
503
504 DataType::Identifier => {
505 return Some(ParameterValue::Identifier(sval.to_string()));
506 }
507 DataType::DeferredRef => {
508 return Some(ParameterValue::DeferredRef(sval.to_string()));
509 }
510 DataType::Unknown => {
511 let m = format!("Conversion failed for unknown type {}.", sval);
512 diags.err1("ERR_199", &m, src_loc.clone());
513 return Some(ParameterValue::Unknown);
514 }
515 };
516 None
517 }
518
519 pub fn clone_val(&self) -> ParameterValue {
520 self.val.clone()
521 }
522}
523
524#[derive(Debug, Clone)]
525pub struct IR {
526 pub kind: IRKind,
527 pub operands: Vec<usize>,
528 pub src_loc: SourceSpan,
529}
530
531pub struct ConstBuiltins {
537 pub firmion_version_string: &'static str,
538 pub firmion_version_major: u64,
539 pub firmion_version_minor: u64,
540 pub firmion_version_patch: u64,
541}
542
543impl ConstBuiltins {
544 pub fn init() {
547 }
549
550 pub fn from_version_str(version: &'static str) -> Self {
551 let mut parts = version.splitn(3, '.');
552 ConstBuiltins {
553 firmion_version_string: version,
554 firmion_version_major: parts.next().and_then(|s| s.parse().ok()).unwrap_or(0),
555 firmion_version_minor: parts.next().and_then(|s| s.parse().ok()).unwrap_or(0),
556 firmion_version_patch: parts.next().and_then(|s| s.parse().ok()).unwrap_or(0),
557 }
558 }
559
560 pub fn get() -> Self {
561 Self::from_version_str(env!("CARGO_PKG_VERSION"))
562 }
563}
564
565#[cfg(test)]
566mod tests {
567 use super::ConstBuiltins;
568
569 #[test]
570 fn parse_version_string_valid() {
571 let b = ConstBuiltins::from_version_str("4.5.6");
572 assert_eq!(b.firmion_version_string, "4.5.6");
573 assert_eq!(b.firmion_version_major, 4);
574 assert_eq!(b.firmion_version_minor, 5);
575 assert_eq!(b.firmion_version_patch, 6);
576 }
577
578 #[test]
579 fn parse_version_string_malformed_minor() {
580 let b = ConstBuiltins::from_version_str("10.x");
581 assert_eq!(b.firmion_version_string, "10.x");
582 assert_eq!(b.firmion_version_major, 10);
583 assert_eq!(b.firmion_version_minor, 0);
584 assert_eq!(b.firmion_version_patch, 0);
585 }
586
587 #[test]
588 fn parse_version_string_partial_only() {
589 let b = ConstBuiltins::from_version_str("7");
590 assert_eq!(b.firmion_version_string, "7");
591 assert_eq!(b.firmion_version_major, 7);
592 assert_eq!(b.firmion_version_minor, 0);
593 assert_eq!(b.firmion_version_patch, 0);
594 }
595
596 #[test]
597 fn parse_version_string_nonnumeric() {
598 let b = ConstBuiltins::from_version_str("foo.bar.baz");
599 assert_eq!(b.firmion_version_string, "foo.bar.baz");
600 assert_eq!(b.firmion_version_major, 0);
601 assert_eq!(b.firmion_version_minor, 0);
602 assert_eq!(b.firmion_version_patch, 0);
603 }
604}