1use crate::compiler::{CompilerError, dependency_graph};
6use crate::parser::common::{CompoundIdentifier, Include};
7use crate::parser::{self, bind_library};
8use crate::{linter, make_identifier};
9use std::collections::HashMap;
10use std::fmt;
11use std::ops::Deref;
12
13pub type SymbolTable = HashMap<CompoundIdentifier, Symbol>;
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)]
16pub enum Symbol {
17 DeprecatedKey(u32),
18 Key(String, bind_library::ValueType),
19 NumberValue(u64),
20 StringValue(String),
21 BoolValue(bool),
22 EnumValue(String),
23}
24
25impl fmt::Display for Symbol {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 match self {
28 Symbol::DeprecatedKey(key) => write!(f, "DeprecatedKey({})", key),
29 Symbol::Key(key, _) => write!(f, "Key({})", key),
30 Symbol::NumberValue(value) => write!(f, "{}", value),
31 Symbol::StringValue(value) => write!(f, "\"{}\"", value),
32 Symbol::BoolValue(value) => write!(f, "{}", value),
33 Symbol::EnumValue(value) => write!(f, "Enum({})", value),
34 }
35 }
36}
37
38struct SymbolTableDeclaration {
41 pub declaration: bind_library::Declaration,
42
43 pub qualified_k: CompoundIdentifier,
46 pub qualified_v: CompoundIdentifier,
47
48 pub local_qualified_k: CompoundIdentifier,
51 pub local_qualified_v: CompoundIdentifier,
52}
53
54pub fn get_symbol_table_from_libraries<'a>(
55 using: &Vec<Include>,
56 libraries: &[String],
57 lint: bool,
58) -> Result<SymbolTable, CompilerError> {
59 let library_asts: Vec<bind_library::Ast> = libraries
60 .iter()
61 .map(|lib| {
62 let ast = bind_library::Ast::try_from(lib.as_str())
63 .map_err(CompilerError::BindParserError)?;
64 if lint {
65 linter::lint_library(&ast).map_err(CompilerError::LinterError)?;
66 }
67 Ok(ast)
68 })
69 .collect::<Result<_, CompilerError>>()?;
70
71 let dependencies = resolve_dependencies(using, library_asts.iter())?;
72 let aliases = get_aliases(using);
73 construct_symbol_table(dependencies.into_iter(), aliases)
74}
75
76fn get_aliases(using: &Vec<Include>) -> HashMap<CompoundIdentifier, String> {
77 return using
78 .iter()
79 .filter_map(|using| match &using.alias {
80 Some(alias) => Some((using.name.clone(), alias.clone())),
81 None => None,
82 })
83 .collect::<HashMap<_, _>>();
84}
85
86pub fn resolve_dependencies<'a>(
87 using: &Vec<Include>,
88 libraries: impl Iterator<Item = &'a bind_library::Ast> + Clone,
89) -> Result<Vec<&'a bind_library::Ast>, CompilerError> {
90 (|| {
91 let mut graph = dependency_graph::DependencyGraph::new();
92
93 for library in libraries.clone() {
94 graph.insert_node(library.name.clone(), library);
95 }
96
97 for Include { name, .. } in using {
98 graph.insert_edge_from_root(name)?;
99 }
100
101 for library in libraries.clone() {
102 graph.insert_edge_from_root(&library.name)?;
103 }
104
105 for from in libraries {
106 for to in &from.using {
107 graph.insert_edge(&from.name, &to.name)?;
108 }
109 }
110
111 graph.resolve()
112 })()
113 .map_err(CompilerError::DependencyError)
114}
115
116fn find_qualified_identifier(
119 declaration: &bind_library::Declaration,
120 using: &Vec<parser::common::Include>,
121 library_names: &std::collections::HashSet<CompoundIdentifier>,
122 local_qualified: &CompoundIdentifier,
123) -> Result<CompoundIdentifier, CompilerError> {
124 if let Some(namespace) = declaration.identifier.parent() {
125 if !declaration.extends {
127 return Err(CompilerError::MissingExtendsKeyword(declaration.identifier.clone()));
128 }
129
130 if namespace == make_identifier!["fuchsia"] {
133 return Ok(declaration.identifier.clone());
134 }
135
136 let include = using.iter().find(|include| {
138 namespace == include.name || Some(namespace.to_string()) == include.alias
139 });
140
141 if let Some(include) = include {
142 return Ok(include.name.nest(declaration.identifier.name.clone()));
143 }
144
145 if library_names.contains(&namespace) {
147 return Ok(namespace.nest(declaration.identifier.name.clone()));
148 }
149
150 return Err(CompilerError::UnresolvedQualification(declaration.identifier.clone()));
151 }
152
153 if declaration.extends {
155 return Err(CompilerError::InvalidExtendsKeyword(local_qualified.clone()));
156 }
157
158 Ok(local_qualified.clone())
160}
161
162fn insert_symbol_entries(
164 symbol_table: &mut SymbolTable,
165 declaration_data: SymbolTableDeclaration,
166) -> Result<(), CompilerError> {
167 let SymbolTableDeclaration {
168 declaration,
169 qualified_k,
170 qualified_v,
171 local_qualified_k,
172 local_qualified_v,
173 } = declaration_data;
174
175 match symbol_table.get(&qualified_k) {
178 Some(Symbol::Key(_, value_type)) => {
179 if !declaration.extends {
180 return Err(CompilerError::DuplicateIdentifier(qualified_k));
181 }
182 if declaration.value_type != *value_type {
183 return Err(CompilerError::TypeMismatch(qualified_k));
184 }
185 }
186 Some(Symbol::DeprecatedKey(_)) => (),
187 Some(_) => {
188 return Err(CompilerError::TypeMismatch(qualified_k));
189 }
190 None => {
191 if declaration.extends {
192 return Err(CompilerError::UndeclaredKey(qualified_k));
193 }
194 symbol_table
195 .insert(qualified_k, Symbol::Key(qualified_v.to_string(), declaration.value_type));
196 }
197 }
198
199 for value in &declaration.values {
203 let qualified_value_k = local_qualified_k.nest(value.identifier().to_string());
204 let qualified_value_v = local_qualified_v.nest(value.identifier().to_string());
205 if symbol_table.contains_key(&qualified_value_k) {
206 return Err(CompilerError::DuplicateIdentifier(qualified_value_k));
207 }
208
209 let value_symbol = match value {
210 bind_library::Value::Number(_, value) => Symbol::NumberValue(*value),
211 bind_library::Value::Str(_, value) => Symbol::StringValue(value.clone()),
212 bind_library::Value::Bool(_, value) => Symbol::BoolValue(*value),
213 bind_library::Value::Enum(_) => Symbol::EnumValue(qualified_value_v.to_string()),
214 };
215 symbol_table.insert(qualified_value_k, value_symbol);
216 }
217 Ok(())
218}
219
220pub fn construct_symbol_table(
226 libraries: impl Iterator<Item = impl Deref<Target = bind_library::Ast>>,
227 aliases: HashMap<CompoundIdentifier, String>,
228) -> Result<SymbolTable, CompilerError> {
229 let mut symbol_table: HashMap<CompoundIdentifier, Symbol> = get_deprecated_symbols();
230
231 let libs = libraries.collect::<Vec<_>>();
232 let library_names =
233 libs.iter().map(|lib| lib.name.clone()).collect::<std::collections::HashSet<_>>();
234
235 let mut extended_declarations: Vec<SymbolTableDeclaration> = vec![];
238
239 for lib in libs {
240 let bind_library::Ast { name, using, declarations } = &*lib;
241
242 let aliased_name = match aliases.get(name) {
243 Some(alias) => Some(make_identifier!(alias)),
244 None => None,
245 };
246
247 for declaration in declarations {
248 let local_qualified_id = name.nest(declaration.identifier.name.clone());
253
254 let qualified_id =
259 find_qualified_identifier(declaration, using, &library_names, &local_qualified_id)?;
260
261 if let Some(alias) = aliased_name.as_ref() {
262 let alias_local_qualified_id = alias.nest(declaration.identifier.name.clone());
263 let alias_qualified_id = find_qualified_identifier(
264 declaration,
265 using,
266 &library_names,
267 &alias_local_qualified_id,
268 )?;
269
270 let entry_data = SymbolTableDeclaration {
271 declaration: declaration.clone(),
272 qualified_k: alias_qualified_id,
273 qualified_v: qualified_id.clone(),
274 local_qualified_k: alias_local_qualified_id,
275 local_qualified_v: local_qualified_id.clone(),
276 };
277
278 if declaration.extends {
279 extended_declarations.push(entry_data);
280 } else {
281 insert_symbol_entries(&mut symbol_table, entry_data)?;
282 }
283 }
284
285 let entry_data = SymbolTableDeclaration {
286 declaration: declaration.clone(),
287 qualified_k: qualified_id.clone(),
288 qualified_v: qualified_id,
289 local_qualified_k: local_qualified_id.clone(),
290 local_qualified_v: local_qualified_id,
291 };
292
293 if declaration.extends {
294 extended_declarations.push(entry_data);
295 } else {
296 insert_symbol_entries(&mut symbol_table, entry_data)?;
297 }
298 }
299 }
300
301 for declaration in extended_declarations.into_iter() {
302 insert_symbol_entries(&mut symbol_table, declaration)?;
303 }
304
305 Ok(symbol_table)
306}
307
308#[allow(clippy::vec_init_then_push, reason = "mass allow for https://fxbug.dev/381896734")]
309fn deprecated_keys() -> Vec<(String, u32)> {
312 let mut keys = Vec::new();
313
314 keys.push(("BIND_PROTOCOL".to_string(), 0x0001));
315
316 keys.push(("BIND_AUTOBIND".to_string(), 0x0002));
317
318 keys.push(("BIND_COMPOSITE".to_string(), 0x0003));
319
320 keys.push(("BIND_PLATFORM_DEV_VID".to_string(), 0x0300));
321 keys.push(("BIND_PCI_VID".to_string(), 0x0100));
322
323 keys.push(("BIND_PCI_DID".to_string(), 0x0101));
324 keys.push(("BIND_PCI_CLASS".to_string(), 0x0102));
325 keys.push(("BIND_PCI_SUBCLASS".to_string(), 0x0103));
326 keys.push(("BIND_PCI_INTERFACE".to_string(), 0x0104));
327 keys.push(("BIND_PCI_REVISION".to_string(), 0x0105));
328 keys.push(("BIND_PCI_TOPO".to_string(), 0x0107));
329
330 keys.push(("BIND_USB_VID".to_string(), 0x0200));
333 keys.push(("BIND_USB_PID".to_string(), 0x0201));
334 keys.push(("BIND_USB_CLASS".to_string(), 0x0202));
335 keys.push(("BIND_USB_SUBCLASS".to_string(), 0x0203));
336 keys.push(("BIND_USB_PROTOCOL".to_string(), 0x0204));
337 keys.push(("BIND_USB_INTERFACE_NUMBER".to_string(), 0x0205));
338
339 keys.push(("BIND_PLATFORM_DEV_VID".to_string(), 0x0300));
341 keys.push(("BIND_PLATFORM_DEV_PID".to_string(), 0x0301));
342 keys.push(("BIND_PLATFORM_DEV_DID".to_string(), 0x0302));
343 keys.push(("BIND_PLATFORM_DEV_INSTANCE_ID".to_string(), 0x0304));
344 keys.push(("BIND_PLATFORM_DEV_INTERRUPT_ID".to_string(), 0x0305));
345
346 keys.push(("BIND_ACPI_BUS_TYPE".to_string(), 0x0400));
348 keys.push(("BIND_ACPI_ID".to_string(), 0x0401));
349
350 keys.push(("BIND_IHDA_CODEC_VID".to_string(), 0x0500));
352 keys.push(("BIND_IHDA_CODEC_DID".to_string(), 0x0501));
353
354 keys.push(("BIND_SERIAL_CLASS".to_string(), 0x0600));
356
357 keys.push(("BIND_NAND_CLASS".to_string(), 0x0700));
359
360 keys.push(("BIND_SDIO_VID".to_string(), 0x0900));
362 keys.push(("BIND_SDIO_PID".to_string(), 0x0901));
363 keys.push(("BIND_SDIO_FUNCTION".to_string(), 0x0902));
364
365 keys.push(("BIND_INIT_STEP".to_string(), 0x0A60));
367
368 keys
369}
370
371fn get_deprecated_symbols() -> SymbolTable {
372 let mut symbol_table = HashMap::new();
373 for (key, value) in deprecated_keys() {
374 symbol_table.insert(make_identifier!("fuchsia", key), Symbol::DeprecatedKey(value));
375 }
376 symbol_table
377}
378
379pub fn get_deprecated_key_identifiers() -> HashMap<u32, String> {
380 let mut key_identifiers = HashMap::new();
381 for (key, value) in deprecated_keys() {
382 key_identifiers.insert(value, make_identifier!("fuchsia", key).to_string());
383 }
384 key_identifiers
385}
386
387pub fn get_deprecated_key_identifier(key: u32) -> Option<String> {
388 match key {
389 0x0001 => Some("fuchsia.BIND_PROTOCOL".to_string()),
390 0x0002 => Some("fuchsia.BIND_AUTOBIND".to_string()),
391 0x0003 => Some("fuchsia.BIND_COMPOSITE".to_string()),
392
393 0x0100 => Some("fuchsia.BIND_PCI_VID".to_string()),
395 0x0101 => Some("fuchsia.BIND_PCI_DID".to_string()),
396 0x0102 => Some("fuchsia.BIND_PCI_CLASS".to_string()),
397 0x0103 => Some("fuchsia.BIND_PCI_SUBCLASS".to_string()),
398 0x0104 => Some("fuchsia.BIND_PCI_INTERFACE".to_string()),
399 0x0105 => Some("fuchsia.BIND_PCI_REVISION".to_string()),
400 0x0107 => Some("fuchsia.BIND_PCI_TOPO".to_string()),
401
402 0x0200 => Some("fuchsia.BIND_USB_VID".to_string()),
404 0x0201 => Some("fuchsia.BIND_USB_PID".to_string()),
405 0x0202 => Some("fuchsia.BIND_USB_CLASS".to_string()),
406 0x0203 => Some("fuchsia.BIND_USB_SUBCLASS".to_string()),
407 0x0204 => Some("fuchsia.BIND_USB_PROTOCOL".to_string()),
408 0x0205 => Some("fuchsia.BIND_USB_INTERFACE_NUMBER".to_string()),
409
410 0x0300 => Some("fuchsia.BIND_PLATFORM_DEV_VID".to_string()),
412 0x0301 => Some("fuchsia.BIND_PLATFORM_DEV_PID".to_string()),
413 0x0302 => Some("fuchsia.BIND_PLATFORM_DEV_DID".to_string()),
414 0x0304 => Some("fuchsia.BIND_PLATFORM_DEV_INSTANCE_ID".to_string()),
415 0x0305 => Some("fuchsia.BIND_PLATFORM_DEV_INTERRUPT_ID".to_string()),
416
417 0x0400 => Some("fuchsia.BIND_ACPI_BUS_TYPE".to_string()),
419 0x0401 => Some("fuchsia.BIND_ACPI_ID".to_string()),
420
421 0x0500 => Some("fuchsia.BIND_IHDA_CODEC_VID".to_string()),
423 0x0501 => Some("fuchsia.BIND_IHDA_CODEC_DID".to_string()),
424
425 0x0600 => Some("fuchsia.BIND_SERIAL_CLASS".to_string()),
427
428 0x0700 => Some("fuchsia.BIND_NAND_CLASS".to_string()),
430
431 0x0900 => Some("fuchsia.BIND_SDIO_VID".to_string()),
433 0x0901 => Some("fuchsia.BIND_SDIO_PID".to_string()),
434 0x0902 => Some("fuchsia.BIND_SDIO_FUNCTION".to_string()),
435
436 0x0A60 => Some("fuchsia.BIND_INIT_STEP".to_string()),
438
439 _ => None,
440 }
441}
442
443pub fn get_deprecated_key_value(key: &str) -> Option<u32> {
444 match key {
445 "fuchsia.BIND_PROTOCOL" => Some(0x0001),
446 "fuchsia.BIND_AUTOBIND" => Some(0x0002),
447 "fuchsia.BIND_COMPOSITE" => Some(0x0003),
448
449 "fuchsia.BIND_PCI_VID" => Some(0x0100),
451 "fuchsia.BIND_PCI_DID" => Some(0x0101),
452 "fuchsia.BIND_PCI_CLASS" => Some(0x0102),
453 "fuchsia.BIND_PCI_SUBCLASS" => Some(0x0103),
454 "fuchsia.BIND_PCI_INTERFACE" => Some(0x0104),
455 "fuchsia.BIND_PCI_REVISION" => Some(0x0105),
456 "fuchsia.BIND_PCI_TOPO" => Some(0x0107),
457
458 "fuchsia.BIND_USB_VID" => Some(0x0200),
460 "fuchsia.BIND_USB_PID" => Some(0x0201),
461 "fuchsia.BIND_USB_CLASS" => Some(0x0202),
462 "fuchsia.BIND_USB_SUBCLASS" => Some(0x0203),
463 "fuchsia.BIND_USB_PROTOCOL" => Some(0x0204),
464 "fuchsia.BIND_USB_INTERFACE_NUMBER" => Some(0x0205),
465
466 "fuchsia.BIND_PLATFORM_DEV_VID" => Some(0x0300),
468 "fuchsia.BIND_PLATFORM_DEV_PID" => Some(0x0301),
469 "fuchsia.BIND_PLATFORM_DEV_DID" => Some(0x0302),
470 "fuchsia.BIND_PLATFORM_DEV_INSTANCE_ID" => Some(0x0304),
471 "fuchsia.BIND_PLATFORM_DEV_INTERRUPT_ID" => Some(0x0305),
472
473 "fuchsia.BIND_ACPI_BUS_TYPE" => Some(0x0400),
475 "fuchsia.BIND_ACPI_ID" => Some(0x0401),
476
477 "fuchsia.BIND_IHDA_CODEC_VID" => Some(0x0500),
479 "fuchsia.BIND_IHDA_CODEC_DID" => Some(0x0501),
480
481 "fuchsia.BIND_SERIAL_CLASS" => Some(0x0600),
483
484 "fuchsia.BIND_NAND_CLASS" => Some(0x0700),
486
487 "fuchsia.BIND_SDIO_VID" => Some(0x0900),
489 "fuchsia.BIND_SDIO_PID" => Some(0x0901),
490 "fuchsia.BIND_SDIO_FUNCTION" => Some(0x0902),
491
492 "fuchsia.BIND_INIT_STEP" => Some(0x0A60),
494
495 _ => None,
496 }
497}
498
499#[cfg(test)]
500mod test {
501 use super::*;
502 use crate::make_identifier;
503 use crate::parser::bind_library;
504 use crate::parser::common::Include;
505
506 mod symbol_table {
507 use super::*;
508
509 #[test]
510 fn simple_key_and_value() {
511 let libraries = vec![bind_library::Ast {
512 name: make_identifier!("test"),
513 using: vec![],
514 declarations: vec![bind_library::Declaration {
515 identifier: make_identifier!["symbol"],
516 value_type: bind_library::ValueType::Number,
517 extends: false,
518 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
519 }],
520 }];
521
522 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
523 assert_eq!(
524 st.get(&make_identifier!("test", "symbol")),
525 Some(&Symbol::Key("test.symbol".to_string(), bind_library::ValueType::Number))
526 );
527 assert_eq!(
528 st.get(&make_identifier!("test", "symbol", "x")),
529 Some(&Symbol::NumberValue(1))
530 );
531 }
532
533 #[test]
534 fn all_value_types() {
535 let libraries = vec![bind_library::Ast {
536 name: make_identifier!("hummingbird"),
537 using: vec![],
538 declarations: vec![
539 bind_library::Declaration {
540 identifier: make_identifier!["sunbeam"],
541 value_type: bind_library::ValueType::Number,
542 extends: false,
543 values: vec![(bind_library::Value::Number("shining".to_string(), 1))],
544 },
545 bind_library::Declaration {
546 identifier: make_identifier!["mountaingem"],
547 value_type: bind_library::ValueType::Bool,
548 extends: false,
549 values: vec![
550 (bind_library::Value::Bool("white-bellied".to_string(), false)),
551 ],
552 },
553 bind_library::Declaration {
554 identifier: make_identifier!["brilliant"],
555 value_type: bind_library::ValueType::Enum,
556 extends: false,
557 values: vec![(bind_library::Value::Enum("black-throated".to_string()))],
558 },
559 bind_library::Declaration {
560 identifier: make_identifier!["woodnymph"],
561 value_type: bind_library::ValueType::Str,
562 extends: false,
563 values: vec![
564 (bind_library::Value::Str(
565 "fork-tailed".to_string(),
566 "sabrewing".to_string(),
567 )),
568 ],
569 },
570 ],
571 }];
572
573 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
574 assert_eq!(
575 st.get(&make_identifier!("hummingbird", "sunbeam", "shining")),
576 Some(&Symbol::NumberValue(1))
577 );
578 assert_eq!(
579 st.get(&make_identifier!("hummingbird", "mountaingem", "white-bellied")),
580 Some(&Symbol::BoolValue(false))
581 );
582 assert_eq!(
583 st.get(&make_identifier!("hummingbird", "brilliant", "black-throated")),
584 Some(&Symbol::EnumValue("hummingbird.brilliant.black-throated".to_string()))
585 );
586 assert_eq!(
587 st.get(&make_identifier!("hummingbird", "woodnymph", "fork-tailed")),
588 Some(&Symbol::StringValue("sabrewing".to_string()))
589 );
590 }
591
592 #[test]
593 fn extension() {
594 let libraries = vec![
595 bind_library::Ast {
596 name: make_identifier!("lib_a"),
597 using: vec![],
598 declarations: vec![bind_library::Declaration {
599 identifier: make_identifier!["symbol"],
600 value_type: bind_library::ValueType::Number,
601 extends: false,
602 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
603 }],
604 },
605 bind_library::Ast {
606 name: make_identifier!("lib_b"),
607 using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
608 declarations: vec![bind_library::Declaration {
609 identifier: make_identifier!["lib_a", "symbol"],
610 value_type: bind_library::ValueType::Number,
611 extends: true,
612 values: vec![(bind_library::Value::Number("y".to_string(), 2))],
613 }],
614 },
615 ];
616
617 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
618 assert_eq!(
619 st.get(&make_identifier!("lib_a", "symbol")),
620 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
621 );
622 assert_eq!(
623 st.get(&make_identifier!("lib_a", "symbol", "x")),
624 Some(&Symbol::NumberValue(1))
625 );
626 assert_eq!(
627 st.get(&make_identifier!("lib_b", "symbol", "y")),
628 Some(&Symbol::NumberValue(2))
629 );
630 }
631
632 #[test]
633 fn extension_with_dependency_defined_after_library() {
634 let libraries = vec![
635 bind_library::Ast {
636 name: make_identifier!("lib_b"),
637 using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
638 declarations: vec![bind_library::Declaration {
639 identifier: make_identifier!["lib_a", "symbol"],
640 value_type: bind_library::ValueType::Number,
641 extends: true,
642 values: vec![(bind_library::Value::Number("y".to_string(), 2))],
643 }],
644 },
645 bind_library::Ast {
646 name: make_identifier!("lib_a"),
647 using: vec![],
648 declarations: vec![bind_library::Declaration {
649 identifier: make_identifier!["symbol"],
650 value_type: bind_library::ValueType::Number,
651 extends: false,
652 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
653 }],
654 },
655 ];
656
657 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
658 assert_eq!(
659 st.get(&make_identifier!("lib_a", "symbol")),
660 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
661 );
662 assert_eq!(
663 st.get(&make_identifier!("lib_a", "symbol", "x")),
664 Some(&Symbol::NumberValue(1))
665 );
666 assert_eq!(
667 st.get(&make_identifier!("lib_b", "symbol", "y")),
668 Some(&Symbol::NumberValue(2))
669 );
670 }
671
672 #[test]
673 fn aliased_extension() {
674 let libraries = vec![
675 bind_library::Ast {
676 name: make_identifier!("lib_a"),
677 using: vec![],
678 declarations: vec![bind_library::Declaration {
679 identifier: make_identifier!["symbol"],
680 value_type: bind_library::ValueType::Number,
681 extends: false,
682 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
683 }],
684 },
685 bind_library::Ast {
686 name: make_identifier!("lib_b"),
687 using: vec![Include {
688 name: make_identifier!("lib_a"),
689 alias: Some("alias".to_string()),
690 }],
691 declarations: vec![bind_library::Declaration {
692 identifier: make_identifier!["alias", "symbol"],
693 value_type: bind_library::ValueType::Number,
694 extends: true,
695 values: vec![(bind_library::Value::Number("y".to_string(), 2))],
696 }],
697 },
698 ];
699
700 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
701 assert_eq!(
702 st.get(&make_identifier!("lib_a", "symbol")),
703 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
704 );
705 assert_eq!(
706 st.get(&make_identifier!("lib_a", "symbol", "x")),
707 Some(&Symbol::NumberValue(1))
708 );
709 assert_eq!(
710 st.get(&make_identifier!("lib_b", "symbol", "y")),
711 Some(&Symbol::NumberValue(2))
712 );
713 }
714
715 #[test]
716 fn aliased_extension_with_library_alias() {
717 let libraries = vec![
718 bind_library::Ast {
719 name: make_identifier!("lib_a"),
720 using: vec![],
721 declarations: vec![bind_library::Declaration {
722 identifier: make_identifier!["symbol"],
723 value_type: bind_library::ValueType::Number,
724 extends: false,
725 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
726 }],
727 },
728 bind_library::Ast {
729 name: make_identifier!("lib_b"),
730 using: vec![Include {
731 name: make_identifier!("lib_a"),
732 alias: Some("alias".to_string()),
733 }],
734 declarations: vec![
735 bind_library::Declaration {
736 identifier: make_identifier!["alias", "symbol"],
737 value_type: bind_library::ValueType::Number,
738 extends: true,
739 values: vec![(bind_library::Value::Number("y".to_string(), 2))],
740 },
741 bind_library::Declaration {
742 identifier: make_identifier!["enum_symbol"],
743 value_type: bind_library::ValueType::Enum,
744 extends: false,
745 values: vec![(bind_library::Value::Enum("the_val".to_string()))],
746 },
747 ],
748 },
749 ];
750
751 let st = construct_symbol_table(
753 libraries.iter(),
754 HashMap::from([(make_identifier!("lib_b"), "opaque".to_string())]),
755 )
756 .unwrap();
757
758 assert_eq!(
759 st.get(&make_identifier!("lib_a", "symbol")),
760 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
761 );
762 assert_eq!(
763 st.get(&make_identifier!("lib_a", "symbol", "x")),
764 Some(&Symbol::NumberValue(1))
765 );
766 assert_eq!(
767 st.get(&make_identifier!("opaque", "symbol", "y")),
768 Some(&Symbol::NumberValue(2))
769 );
770 assert_eq!(
771 st.get(&make_identifier!("lib_b", "symbol", "y")),
772 Some(&Symbol::NumberValue(2))
773 );
774 assert_eq!(
775 st.get(&make_identifier!("opaque", "enum_symbol")),
776 Some(&Symbol::Key("lib_b.enum_symbol".to_string(), bind_library::ValueType::Enum))
777 );
778 assert_eq!(
779 st.get(&make_identifier!("lib_b", "enum_symbol")),
780 Some(&Symbol::Key("lib_b.enum_symbol".to_string(), bind_library::ValueType::Enum))
781 );
782 assert_eq!(
783 st.get(&make_identifier!("opaque", "enum_symbol", "the_val")),
784 Some(&Symbol::EnumValue("lib_b.enum_symbol.the_val".to_string()))
785 );
786 assert_eq!(
787 st.get(&make_identifier!("lib_b", "enum_symbol", "the_val")),
788 Some(&Symbol::EnumValue("lib_b.enum_symbol.the_val".to_string()))
789 );
790 }
791
792 #[test]
793 fn deprecated_key_extension() {
794 let libraries = vec![bind_library::Ast {
795 name: make_identifier!("lib_a"),
796 using: vec![],
797 declarations: vec![bind_library::Declaration {
798 identifier: make_identifier!["fuchsia", "BIND_PCI_DID"],
799 value_type: bind_library::ValueType::Number,
800 extends: true,
801 values: vec![(bind_library::Value::Number("x".to_string(), 0x1234))],
802 }],
803 }];
804
805 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
806 assert_eq!(
807 st.get(&make_identifier!("lib_a", "BIND_PCI_DID", "x")),
808 Some(&Symbol::NumberValue(0x1234))
809 );
810 }
811
812 #[test]
813 fn duplicate_key() {
814 let libraries = vec![bind_library::Ast {
815 name: make_identifier!("test"),
816 using: vec![],
817 declarations: vec![
818 bind_library::Declaration {
819 identifier: make_identifier!["symbol"],
820 value_type: bind_library::ValueType::Number,
821 extends: false,
822 values: vec![],
823 },
824 bind_library::Declaration {
825 identifier: make_identifier!["symbol"],
826 value_type: bind_library::ValueType::Number,
827 extends: false,
828 values: vec![],
829 },
830 ],
831 }];
832
833 assert_eq!(
834 construct_symbol_table(libraries.iter(), HashMap::new()),
835 Err(CompilerError::DuplicateIdentifier(make_identifier!("test", "symbol")))
836 );
837 }
838
839 #[test]
840 fn duplicate_value() {
841 let libraries = vec![bind_library::Ast {
842 name: make_identifier!("test"),
843 using: vec![],
844 declarations: vec![bind_library::Declaration {
845 identifier: make_identifier!["symbol"],
846 value_type: bind_library::ValueType::Number,
847 extends: false,
848 values: vec![
849 bind_library::Value::Number("a".to_string(), 1),
850 bind_library::Value::Number("a".to_string(), 2),
851 ],
852 }],
853 }];
854
855 assert_eq!(
856 construct_symbol_table(libraries.iter(), HashMap::new()),
857 Err(CompilerError::DuplicateIdentifier(make_identifier!("test", "symbol", "a")))
858 );
859 }
860
861 #[test]
862 fn keys_are_qualified() {
863 let libraries = vec![
865 bind_library::Ast {
866 name: make_identifier!("lib_a"),
867 using: vec![],
868 declarations: vec![bind_library::Declaration {
869 identifier: make_identifier!["symbol"],
870 value_type: bind_library::ValueType::Number,
871 extends: false,
872 values: vec![],
873 }],
874 },
875 bind_library::Ast {
876 name: make_identifier!("lib_b"),
877 using: vec![],
878 declarations: vec![bind_library::Declaration {
879 identifier: make_identifier!["symbol"],
880 value_type: bind_library::ValueType::Number,
881 extends: false,
882 values: vec![],
883 }],
884 },
885 ];
886
887 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
888 assert_eq!(
889 st.get(&make_identifier!("lib_a", "symbol")),
890 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
891 );
892 assert_eq!(
893 st.get(&make_identifier!("lib_b", "symbol")),
894 Some(&Symbol::Key("lib_b.symbol".to_string(), bind_library::ValueType::Number))
895 );
896 }
897
898 #[test]
899 fn missing_extend_keyword() {
900 let libraries = vec![
902 bind_library::Ast {
903 name: make_identifier!("lib_a"),
904 using: vec![],
905 declarations: vec![bind_library::Declaration {
906 identifier: make_identifier!["symbol"],
907 value_type: bind_library::ValueType::Number,
908 extends: false,
909 values: vec![],
910 }],
911 },
912 bind_library::Ast {
913 name: make_identifier!("lib_b"),
914 using: vec![],
915 declarations: vec![bind_library::Declaration {
916 identifier: make_identifier!["lib_a", "symbol"],
917 value_type: bind_library::ValueType::Number,
918 extends: false,
919 values: vec![],
920 }],
921 },
922 ];
923
924 assert_eq!(
925 construct_symbol_table(libraries.iter(), HashMap::new()),
926 Err(CompilerError::MissingExtendsKeyword(make_identifier!("lib_a", "symbol")))
927 );
928 }
929
930 #[test]
931 fn invalid_extend_keyword() {
932 let libraries = vec![bind_library::Ast {
935 name: make_identifier!("lib_a"),
936 using: vec![],
937 declarations: vec![bind_library::Declaration {
938 identifier: make_identifier!["symbol"],
939 value_type: bind_library::ValueType::Number,
940 extends: true,
941 values: vec![],
942 }],
943 }];
944
945 assert_eq!(
946 construct_symbol_table(libraries.iter(), HashMap::new()),
947 Err(CompilerError::InvalidExtendsKeyword(make_identifier!("lib_a", "symbol")))
948 );
949 }
950
951 #[test]
952 fn unresolved_qualification() {
953 let libraries = vec![bind_library::Ast {
956 name: make_identifier!("lib_a"),
957 using: vec![],
958 declarations: vec![bind_library::Declaration {
959 identifier: make_identifier!["lib_b", "symbol"],
960 value_type: bind_library::ValueType::Number,
961 extends: true,
962 values: vec![],
963 }],
964 }];
965
966 assert_eq!(
967 construct_symbol_table(libraries.iter(), HashMap::new()),
968 Err(CompilerError::UnresolvedQualification(make_identifier!("lib_b", "symbol")))
969 );
970 }
971
972 #[test]
973 fn undeclared_key() {
974 let libraries = vec![
975 bind_library::Ast {
976 name: make_identifier!("lib_a"),
977 using: vec![],
978 declarations: vec![],
979 },
980 bind_library::Ast {
981 name: make_identifier!("lib_b"),
982 using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
983 declarations: vec![bind_library::Declaration {
984 identifier: make_identifier!["lib_a", "symbol"],
985 value_type: bind_library::ValueType::Number,
986 extends: true,
987 values: vec![],
988 }],
989 },
990 ];
991
992 assert_eq!(
993 construct_symbol_table(libraries.iter(), HashMap::new()),
994 Err(CompilerError::UndeclaredKey(make_identifier!("lib_a", "symbol")))
995 );
996 }
997
998 #[test]
999 fn type_mismatch() {
1000 let libraries = vec![
1001 bind_library::Ast {
1002 name: make_identifier!("lib_a"),
1003 using: vec![],
1004 declarations: vec![bind_library::Declaration {
1005 identifier: make_identifier!["symbol"],
1006 value_type: bind_library::ValueType::Str,
1007 extends: false,
1008 values: vec![],
1009 }],
1010 },
1011 bind_library::Ast {
1012 name: make_identifier!("lib_b"),
1013 using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
1014 declarations: vec![bind_library::Declaration {
1015 identifier: make_identifier!["lib_a", "symbol"],
1016 value_type: bind_library::ValueType::Number,
1017 extends: true,
1018 values: vec![],
1019 }],
1020 },
1021 ];
1022
1023 assert_eq!(
1024 construct_symbol_table(libraries.iter(), HashMap::new()),
1025 Err(CompilerError::TypeMismatch(make_identifier!("lib_a", "symbol")))
1026 );
1027 }
1028 }
1029}