1use crate::compiler::{dependency_graph, CompilerError};
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 .into_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 from in libraries {
102 for to in &from.using {
103 graph.insert_edge(&from.name, &to.name)?;
104 }
105 }
106
107 graph.resolve()
108 })()
109 .map_err(CompilerError::DependencyError)
110}
111
112fn find_qualified_identifier(
115 declaration: &bind_library::Declaration,
116 using: &Vec<parser::common::Include>,
117 local_qualified: &CompoundIdentifier,
118) -> Result<CompoundIdentifier, CompilerError> {
119 if let Some(namespace) = declaration.identifier.parent() {
120 if !declaration.extends {
122 return Err(CompilerError::MissingExtendsKeyword(declaration.identifier.clone()));
123 }
124
125 if namespace == make_identifier!["fuchsia"] {
128 return Ok(declaration.identifier.clone());
129 }
130
131 let include = using
133 .iter()
134 .find(|include| {
135 namespace == include.name || Some(namespace.to_string()) == include.alias
136 })
137 .ok_or_else(|| {
138 CompilerError::UnresolvedQualification(declaration.identifier.clone())
139 })?;
140
141 return Ok(include.name.nest(declaration.identifier.name.clone()));
142 }
143
144 if declaration.extends {
146 return Err(CompilerError::InvalidExtendsKeyword(local_qualified.clone()));
147 }
148
149 Ok(local_qualified.clone())
151}
152
153fn insert_symbol_entries(
155 symbol_table: &mut SymbolTable,
156 declaration_data: SymbolTableDeclaration,
157) -> Result<(), CompilerError> {
158 let SymbolTableDeclaration {
159 declaration,
160 qualified_k,
161 qualified_v,
162 local_qualified_k,
163 local_qualified_v,
164 } = declaration_data;
165
166 match symbol_table.get(&qualified_k) {
169 Some(Symbol::Key(_, value_type)) => {
170 if !declaration.extends {
171 return Err(CompilerError::DuplicateIdentifier(qualified_k));
172 }
173 if declaration.value_type != *value_type {
174 return Err(CompilerError::TypeMismatch(qualified_k));
175 }
176 }
177 Some(Symbol::DeprecatedKey(_)) => (),
178 Some(_) => {
179 return Err(CompilerError::TypeMismatch(qualified_k));
180 }
181 None => {
182 if declaration.extends {
183 return Err(CompilerError::UndeclaredKey(qualified_k));
184 }
185 symbol_table
186 .insert(qualified_k, Symbol::Key(qualified_v.to_string(), declaration.value_type));
187 }
188 }
189
190 for value in &declaration.values {
194 let qualified_value_k = local_qualified_k.nest(value.identifier().to_string());
195 let qualified_value_v = local_qualified_v.nest(value.identifier().to_string());
196 if symbol_table.contains_key(&qualified_value_k) {
197 return Err(CompilerError::DuplicateIdentifier(qualified_value_k));
198 }
199
200 let value_symbol = match value {
201 bind_library::Value::Number(_, value) => Symbol::NumberValue(*value),
202 bind_library::Value::Str(_, value) => Symbol::StringValue(value.clone()),
203 bind_library::Value::Bool(_, value) => Symbol::BoolValue(*value),
204 bind_library::Value::Enum(_) => Symbol::EnumValue(qualified_value_v.to_string()),
205 };
206 symbol_table.insert(qualified_value_k, value_symbol);
207 }
208 Ok(())
209}
210
211pub fn construct_symbol_table(
217 libraries: impl Iterator<Item = impl Deref<Target = bind_library::Ast>>,
218 aliases: HashMap<CompoundIdentifier, String>,
219) -> Result<SymbolTable, CompilerError> {
220 let mut symbol_table: HashMap<CompoundIdentifier, Symbol> = get_deprecated_symbols();
221
222 let mut extended_declarations: Vec<SymbolTableDeclaration> = vec![];
225
226 for lib in libraries {
227 let bind_library::Ast { name, using, declarations } = &*lib;
228
229 let aliased_name = match aliases.get(name) {
230 Some(alias) => Some(make_identifier!(alias)),
231 None => None,
232 };
233
234 for declaration in declarations {
235 let local_qualified_id = name.nest(declaration.identifier.name.clone());
240
241 let qualified_id = find_qualified_identifier(declaration, using, &local_qualified_id)?;
246
247 if let Some(alias) = aliased_name.as_ref() {
248 let alias_local_qualified_id = alias.nest(declaration.identifier.name.clone());
249 let alias_qualified_id =
250 find_qualified_identifier(declaration, using, &alias_local_qualified_id)?;
251
252 let entry_data = SymbolTableDeclaration {
253 declaration: declaration.clone(),
254 qualified_k: alias_qualified_id,
255 qualified_v: qualified_id.clone(),
256 local_qualified_k: alias_local_qualified_id.clone(),
257 local_qualified_v: local_qualified_id.clone(),
258 };
259
260 if declaration.extends {
261 extended_declarations.push(entry_data);
262 } else {
263 insert_symbol_entries(&mut symbol_table, entry_data)?;
264 }
265 }
266
267 let entry_data = SymbolTableDeclaration {
268 declaration: declaration.clone(),
269 qualified_k: qualified_id.clone(),
270 qualified_v: qualified_id,
271 local_qualified_k: local_qualified_id.clone(),
272 local_qualified_v: local_qualified_id,
273 };
274
275 if declaration.extends {
276 extended_declarations.push(entry_data);
277 } else {
278 insert_symbol_entries(&mut symbol_table, entry_data)?;
279 }
280 }
281 }
282
283 for declaration in extended_declarations.into_iter() {
284 insert_symbol_entries(&mut symbol_table, declaration)?;
285 }
286
287 Ok(symbol_table)
288}
289
290#[allow(clippy::vec_init_then_push, reason = "mass allow for https://fxbug.dev/381896734")]
291fn deprecated_keys() -> Vec<(String, u32)> {
294 let mut keys = Vec::new();
295
296 keys.push(("BIND_PROTOCOL".to_string(), 0x0001));
297
298 keys.push(("BIND_AUTOBIND".to_string(), 0x0002));
299
300 keys.push(("BIND_COMPOSITE".to_string(), 0x0003));
301
302 keys.push(("BIND_FIDL_PROTOCOL".to_string(), 0x0004));
303
304 keys.push(("BIND_PLATFORM_DEV_VID".to_string(), 0x0300));
305 keys.push(("BIND_PCI_VID".to_string(), 0x0100));
306
307 keys.push(("BIND_PCI_DID".to_string(), 0x0101));
308 keys.push(("BIND_PCI_CLASS".to_string(), 0x0102));
309 keys.push(("BIND_PCI_SUBCLASS".to_string(), 0x0103));
310 keys.push(("BIND_PCI_INTERFACE".to_string(), 0x0104));
311 keys.push(("BIND_PCI_REVISION".to_string(), 0x0105));
312 keys.push(("BIND_PCI_TOPO".to_string(), 0x0107));
313
314 keys.push(("BIND_USB_VID".to_string(), 0x0200));
317 keys.push(("BIND_USB_PID".to_string(), 0x0201));
318 keys.push(("BIND_USB_CLASS".to_string(), 0x0202));
319 keys.push(("BIND_USB_SUBCLASS".to_string(), 0x0203));
320 keys.push(("BIND_USB_PROTOCOL".to_string(), 0x0204));
321 keys.push(("BIND_USB_INTERFACE_NUMBER".to_string(), 0x0205));
322
323 keys.push(("BIND_PLATFORM_DEV_VID".to_string(), 0x0300));
325 keys.push(("BIND_PLATFORM_DEV_PID".to_string(), 0x0301));
326 keys.push(("BIND_PLATFORM_DEV_DID".to_string(), 0x0302));
327 keys.push(("BIND_PLATFORM_DEV_INSTANCE_ID".to_string(), 0x0304));
328 keys.push(("BIND_PLATFORM_DEV_INTERRUPT_ID".to_string(), 0x0305));
329
330 keys.push(("BIND_ACPI_BUS_TYPE".to_string(), 0x0400));
332 keys.push(("BIND_ACPI_ID".to_string(), 0x0401));
333
334 keys.push(("BIND_IHDA_CODEC_VID".to_string(), 0x0500));
336 keys.push(("BIND_IHDA_CODEC_DID".to_string(), 0x0501));
337 keys.push(("BIND_IHDA_CODEC_MAJOR_REV".to_string(), 0x0502));
338 keys.push(("BIND_IHDA_CODEC_MINOR_REV".to_string(), 0x0503));
339 keys.push(("BIND_IHDA_CODEC_VENDOR_REV".to_string(), 0x0504));
340 keys.push(("BIND_IHDA_CODEC_VENDOR_STEP".to_string(), 0x0505));
341
342 keys.push(("BIND_SERIAL_CLASS".to_string(), 0x0600));
344 keys.push(("BIND_SERIAL_VID".to_string(), 0x0601));
345 keys.push(("BIND_SERIAL_PID".to_string(), 0x0602));
346
347 keys.push(("BIND_NAND_CLASS".to_string(), 0x0700));
349
350 keys.push(("BIND_SDIO_VID".to_string(), 0x0900));
352 keys.push(("BIND_SDIO_PID".to_string(), 0x0901));
353 keys.push(("BIND_SDIO_FUNCTION".to_string(), 0x0902));
354
355 keys.push(("BIND_I2C_CLASS".to_string(), 0x0A00));
357 keys.push(("BIND_I2C_BUS_ID".to_string(), 0x0A01));
358 keys.push(("BIND_I2C_ADDRESS".to_string(), 0x0A02));
359
360 keys.push(("BIND_GPIO_PIN".to_string(), 0x0A10));
362 keys.push(("BIND_GPIO_CONTROLLER".to_string(), 0x0A11));
363
364 keys.push(("BIND_POWER_DOMAIN".to_string(), 0x0A20));
366 keys.push(("BIND_POWER_DOMAIN_COMPOSITE".to_string(), 0x0A21));
367
368 keys.push(("BIND_CLOCK_ID".to_string(), 0x0A30));
370
371 keys.push(("BIND_SPI_BUS_ID".to_string(), 0x0A41));
373 keys.push(("BIND_SPI_CHIP_SELECT".to_string(), 0x0A42));
374
375 keys.push(("BIND_PWM_ID".to_string(), 0x0A50));
377
378 keys.push(("BIND_INIT_STEP".to_string(), 0x0A60));
380
381 keys.push(("BIND_CODEC_INSTANCE".to_string(), 0x0A70));
383
384 keys.push(("BIND_POWER_SENSOR_DOMAIN".to_string(), 0x0A90));
386
387 keys.push(("BIND_MAILBOX_ID".to_string(), 0x0AA0));
389
390 keys
391}
392
393fn get_deprecated_symbols() -> SymbolTable {
394 let mut symbol_table = HashMap::new();
395 for (key, value) in deprecated_keys() {
396 symbol_table.insert(make_identifier!("fuchsia", key), Symbol::DeprecatedKey(value));
397 }
398 symbol_table
399}
400
401pub fn get_deprecated_key_identifiers() -> HashMap<u32, String> {
402 let mut key_identifiers = HashMap::new();
403 for (key, value) in deprecated_keys() {
404 key_identifiers.insert(value, make_identifier!("fuchsia", key).to_string());
405 }
406 key_identifiers
407}
408
409pub fn get_deprecated_key_identifier(key: u32) -> Option<String> {
410 match key {
411 0x0000 => Some("fuchsia.BIND_FLAGS".to_string()),
412 0x0001 => Some("fuchsia.BIND_PROTOCOL".to_string()),
413 0x0002 => Some("fuchsia.BIND_AUTOBIND".to_string()),
414 0x0003 => Some("fuchsia.BIND_COMPOSITE".to_string()),
415 0x0004 => Some("fuchsia.BIND_FIDL_PROTOCOL".to_string()),
416
417 0x0100 => Some("fuchsia.BIND_PCI_VID".to_string()),
419 0x0101 => Some("fuchsia.BIND_PCI_DID".to_string()),
420 0x0102 => Some("fuchsia.BIND_PCI_CLASS".to_string()),
421 0x0103 => Some("fuchsia.BIND_PCI_SUBCLASS".to_string()),
422 0x0104 => Some("fuchsia.BIND_PCI_INTERFACE".to_string()),
423 0x0105 => Some("fuchsia.BIND_PCI_REVISION".to_string()),
424 0x0107 => Some("fuchsia.BIND_PCI_TOPO".to_string()),
425
426 0x0200 => Some("fuchsia.BIND_USB_VID".to_string()),
428 0x0201 => Some("fuchsia.BIND_USB_PID".to_string()),
429 0x0202 => Some("fuchsia.BIND_USB_CLASS".to_string()),
430 0x0203 => Some("fuchsia.BIND_USB_SUBCLASS".to_string()),
431 0x0204 => Some("fuchsia.BIND_USB_PROTOCOL".to_string()),
432 0x0205 => Some("fuchsia.BIND_USB_INTERFACE_NUMBER".to_string()),
433
434 0x0300 => Some("fuchsia.BIND_PLATFORM_DEV_VID".to_string()),
436 0x0301 => Some("fuchsia.BIND_PLATFORM_DEV_PID".to_string()),
437 0x0302 => Some("fuchsia.BIND_PLATFORM_DEV_DID".to_string()),
438 0x0304 => Some("fuchsia.BIND_PLATFORM_DEV_INSTANCE_ID".to_string()),
439 0x0305 => Some("fuchsia.BIND_PLATFORM_DEV_INTERRUPT_ID".to_string()),
440
441 0x0400 => Some("fuchsia.BIND_ACPI_BUS_TYPE".to_string()),
443 0x0401 => Some("fuchsia.BIND_ACPI_ID".to_string()),
444
445 0x0500 => Some("fuchsia.BIND_IHDA_CODEC_VID".to_string()),
447 0x0501 => Some("fuchsia.BIND_IHDA_CODEC_DID".to_string()),
448 0x0502 => Some("fuchsia.BIND_IHDA_CODEC_MAJOR_REV".to_string()),
449 0x0503 => Some("fuchsia.BIND_IHDA_CODEC_MINOR_REV".to_string()),
450 0x0504 => Some("fuchsia.BIND_IHDA_CODEC_VENDOR_REV".to_string()),
451 0x0505 => Some("fuchsia.BIND_IHDA_CODEC_VENDOR_STEP".to_string()),
452
453 0x0600 => Some("fuchsia.BIND_SERIAL_CLASS".to_string()),
455 0x0601 => Some("fuchsia.BIND_SERIAL_VID".to_string()),
456 0x0602 => Some("fuchsia.BIND_SERIAL_PID".to_string()),
457
458 0x0700 => Some("fuchsia.BIND_NAND_CLASS".to_string()),
460
461 0x0900 => Some("fuchsia.BIND_SDIO_VID".to_string()),
463 0x0901 => Some("fuchsia.BIND_SDIO_PID".to_string()),
464 0x0902 => Some("fuchsia.BIND_SDIO_FUNCTION".to_string()),
465
466 0x0A00 => Some("fuchsia.BIND_I2C_CLASS".to_string()),
468 0x0A01 => Some("fuchsia.BIND_I2C_BUS_ID".to_string()),
469 0x0A02 => Some("fuchsia.BIND_I2C_ADDRESS".to_string()),
470 0x0A03 => Some("fuchsia.BIND_I2C_VID".to_string()),
471 0x0A04 => Some("fuchsia.BIND_I2C_DID".to_string()),
472
473 0x0A10 => Some("fuchsia.BIND_GPIO_PIN".to_string()),
475 0x0A11 => Some("fuchsia.BIND_GPIO_CONTROLLER".to_string()),
476
477 0x0A20 => Some("fuchsia.BIND_POWER_DOMAIN".to_string()),
479 0x0A21 => Some("fuchsia.BIND_POWER_DOMAIN_COMPOSITE".to_string()),
480
481 0x0A30 => Some("fuchsia.BIND_CLOCK_ID".to_string()),
483
484 0x0A41 => Some("fuchsia.BIND_SPI_BUS_ID".to_string()),
486 0x0A42 => Some("fuchsia.BIND_SPI_CHIP_SELECT".to_string()),
487
488 0x0A50 => Some("fuchsia.BIND_PWM_ID".to_string()),
490
491 0x0A60 => Some("fuchsia.BIND_INIT_STEP".to_string()),
493
494 0x0A70 => Some("fuchsia.BIND_CODEC_INSTANCE".to_string()),
496
497 0x0A90 => Some("fuchsia.BIND_POWER_SENSOR_DOMAIN".to_string()),
499
500 0x0AA0 => Some("fuchsia.BIND_MAILBOX_ID".to_string()),
502
503 _ => None,
504 }
505}
506
507pub fn get_deprecated_key_value(key: &str) -> Option<u32> {
508 match key {
509 "fuchsia.BIND_FLAGS" => Some(0x0000),
510 "fuchsia.BIND_PROTOCOL" => Some(0x0001),
511 "fuchsia.BIND_AUTOBIND" => Some(0x0002),
512 "fuchsia.BIND_COMPOSITE" => Some(0x0003),
513 "fuchsia.BIND_FIDL_PROTOCOL" => Some(0x0004),
514
515 "fuchsia.BIND_PCI_VID" => Some(0x0100),
517 "fuchsia.BIND_PCI_DID" => Some(0x0101),
518 "fuchsia.BIND_PCI_CLASS" => Some(0x0102),
519 "fuchsia.BIND_PCI_SUBCLASS" => Some(0x0103),
520 "fuchsia.BIND_PCI_INTERFACE" => Some(0x0104),
521 "fuchsia.BIND_PCI_REVISION" => Some(0x0105),
522 "fuchsia.BIND_PCI_TOPO" => Some(0x0107),
523
524 "fuchsia.BIND_USB_VID" => Some(0x0200),
526 "fuchsia.BIND_USB_PID" => Some(0x0201),
527 "fuchsia.BIND_USB_CLASS" => Some(0x0202),
528 "fuchsia.BIND_USB_SUBCLASS" => Some(0x0203),
529 "fuchsia.BIND_USB_PROTOCOL" => Some(0x0204),
530 "fuchsia.BIND_USB_INTERFACE_NUMBER" => Some(0x0205),
531
532 "fuchsia.BIND_PLATFORM_DEV_VID" => Some(0x0300),
534 "fuchsia.BIND_PLATFORM_DEV_PID" => Some(0x0301),
535 "fuchsia.BIND_PLATFORM_DEV_DID" => Some(0x0302),
536 "fuchsia.BIND_PLATFORM_DEV_INSTANCE_ID" => Some(0x0304),
537 "fuchsia.BIND_PLATFORM_DEV_INTERRUPT_ID" => Some(0x0305),
538
539 "fuchsia.BIND_ACPI_BUS_TYPE" => Some(0x0400),
541 "fuchsia.BIND_ACPI_ID" => Some(0x0401),
542
543 "fuchsia.BIND_IHDA_CODEC_VID" => Some(0x0500),
545 "fuchsia.BIND_IHDA_CODEC_DID" => Some(0x0501),
546 "fuchsia.BIND_IHDA_CODEC_MAJOR_REV" => Some(0x0502),
547 "fuchsia.BIND_IHDA_CODEC_MINOR_REV" => Some(0x0503),
548 "fuchsia.BIND_IHDA_CODEC_VENDOR_REV" => Some(0x0504),
549 "fuchsia.BIND_IHDA_CODEC_VENDOR_STEP" => Some(0x0505),
550
551 "fuchsia.BIND_SERIAL_CLASS" => Some(0x0600),
553 "fuchsia.BIND_SERIAL_VID" => Some(0x0601),
554 "fuchsia.BIND_SERIAL_PID" => Some(0x0602),
555
556 "fuchsia.BIND_NAND_CLASS" => Some(0x0700),
558
559 "fuchsia.BIND_SDIO_VID" => Some(0x0900),
561 "fuchsia.BIND_SDIO_PID" => Some(0x0901),
562 "fuchsia.BIND_SDIO_FUNCTION" => Some(0x0902),
563
564 "fuchsia.BIND_I2C_CLASS" => Some(0x0A00),
566 "fuchsia.BIND_I2C_BUS_ID" => Some(0x0A01),
567 "fuchsia.BIND_I2C_ADDRESS" => Some(0x0A02),
568 "fuchsia.BIND_I2C_VID" => Some(0x0A03),
569 "fuchsia.BIND_I2C_DID" => Some(0x0A04),
570
571 "fuchsia.BIND_GPIO_PIN" => Some(0x0A10),
573 "fuchsia.BIND_GPIO_CONTROLLER" => Some(0x0A11),
574
575 "fuchsia.BIND_POWER_DOMAIN" => Some(0x0A20),
577 "fuchsia.BIND_POWER_DOMAIN_COMPOSITE" => Some(0x0A21),
578
579 "fuchsia.BIND_CLOCK_ID" => Some(0x0A30),
581
582 "fuchsia.BIND_SPI_BUS_ID" => Some(0x0A41),
584 "fuchsia.BIND_SPI_CHIP_SELECT" => Some(0x0A42),
585
586 "fuchsia.BIND_PWM_ID" => Some(0x0A50),
588
589 "fuchsia.BIND_INIT_STEP" => Some(0x0A60),
591
592 "fuchsia.BIND_CODEC_INSTANCE" => Some(0x0A70),
594
595 "fuchsia.BIND_POWER_SENSOR_DOMAIN" => Some(0x0A90),
597
598 "fuchsia.BIND_MAILBOX_ID" => Some(0x0AA0),
600
601 _ => None,
602 }
603}
604
605#[cfg(test)]
606mod test {
607 use super::*;
608 use crate::make_identifier;
609 use crate::parser::bind_library;
610 use crate::parser::common::Include;
611
612 mod symbol_table {
613 use super::*;
614
615 #[test]
616 fn simple_key_and_value() {
617 let libraries = vec![bind_library::Ast {
618 name: make_identifier!("test"),
619 using: vec![],
620 declarations: vec![bind_library::Declaration {
621 identifier: make_identifier!["symbol"],
622 value_type: bind_library::ValueType::Number,
623 extends: false,
624 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
625 }],
626 }];
627
628 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
629 assert_eq!(
630 st.get(&make_identifier!("test", "symbol")),
631 Some(&Symbol::Key("test.symbol".to_string(), bind_library::ValueType::Number))
632 );
633 assert_eq!(
634 st.get(&make_identifier!("test", "symbol", "x")),
635 Some(&Symbol::NumberValue(1))
636 );
637 }
638
639 #[test]
640 fn all_value_types() {
641 let libraries = vec![bind_library::Ast {
642 name: make_identifier!("hummingbird"),
643 using: vec![],
644 declarations: vec![
645 bind_library::Declaration {
646 identifier: make_identifier!["sunbeam"],
647 value_type: bind_library::ValueType::Number,
648 extends: false,
649 values: vec![(bind_library::Value::Number("shining".to_string(), 1))],
650 },
651 bind_library::Declaration {
652 identifier: make_identifier!["mountaingem"],
653 value_type: bind_library::ValueType::Bool,
654 extends: false,
655 values: vec![
656 (bind_library::Value::Bool("white-bellied".to_string(), false)),
657 ],
658 },
659 bind_library::Declaration {
660 identifier: make_identifier!["brilliant"],
661 value_type: bind_library::ValueType::Enum,
662 extends: false,
663 values: vec![(bind_library::Value::Enum("black-throated".to_string()))],
664 },
665 bind_library::Declaration {
666 identifier: make_identifier!["woodnymph"],
667 value_type: bind_library::ValueType::Str,
668 extends: false,
669 values: vec![
670 (bind_library::Value::Str(
671 "fork-tailed".to_string(),
672 "sabrewing".to_string(),
673 )),
674 ],
675 },
676 ],
677 }];
678
679 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
680 assert_eq!(
681 st.get(&make_identifier!("hummingbird", "sunbeam", "shining")),
682 Some(&Symbol::NumberValue(1))
683 );
684 assert_eq!(
685 st.get(&make_identifier!("hummingbird", "mountaingem", "white-bellied")),
686 Some(&Symbol::BoolValue(false))
687 );
688 assert_eq!(
689 st.get(&make_identifier!("hummingbird", "brilliant", "black-throated")),
690 Some(&Symbol::EnumValue("hummingbird.brilliant.black-throated".to_string()))
691 );
692 assert_eq!(
693 st.get(&make_identifier!("hummingbird", "woodnymph", "fork-tailed")),
694 Some(&Symbol::StringValue("sabrewing".to_string()))
695 );
696 }
697
698 #[test]
699 fn extension() {
700 let libraries = vec![
701 bind_library::Ast {
702 name: make_identifier!("lib_a"),
703 using: vec![],
704 declarations: vec![bind_library::Declaration {
705 identifier: make_identifier!["symbol"],
706 value_type: bind_library::ValueType::Number,
707 extends: false,
708 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
709 }],
710 },
711 bind_library::Ast {
712 name: make_identifier!("lib_b"),
713 using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
714 declarations: vec![bind_library::Declaration {
715 identifier: make_identifier!["lib_a", "symbol"],
716 value_type: bind_library::ValueType::Number,
717 extends: true,
718 values: vec![(bind_library::Value::Number("y".to_string(), 2))],
719 }],
720 },
721 ];
722
723 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
724 assert_eq!(
725 st.get(&make_identifier!("lib_a", "symbol")),
726 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
727 );
728 assert_eq!(
729 st.get(&make_identifier!("lib_a", "symbol", "x")),
730 Some(&Symbol::NumberValue(1))
731 );
732 assert_eq!(
733 st.get(&make_identifier!("lib_b", "symbol", "y")),
734 Some(&Symbol::NumberValue(2))
735 );
736 }
737
738 #[test]
739 fn extension_with_dependency_defined_after_library() {
740 let libraries = vec![
741 bind_library::Ast {
742 name: make_identifier!("lib_b"),
743 using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
744 declarations: vec![bind_library::Declaration {
745 identifier: make_identifier!["lib_a", "symbol"],
746 value_type: bind_library::ValueType::Number,
747 extends: true,
748 values: vec![(bind_library::Value::Number("y".to_string(), 2))],
749 }],
750 },
751 bind_library::Ast {
752 name: make_identifier!("lib_a"),
753 using: vec![],
754 declarations: vec![bind_library::Declaration {
755 identifier: make_identifier!["symbol"],
756 value_type: bind_library::ValueType::Number,
757 extends: false,
758 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
759 }],
760 },
761 ];
762
763 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
764 assert_eq!(
765 st.get(&make_identifier!("lib_a", "symbol")),
766 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
767 );
768 assert_eq!(
769 st.get(&make_identifier!("lib_a", "symbol", "x")),
770 Some(&Symbol::NumberValue(1))
771 );
772 assert_eq!(
773 st.get(&make_identifier!("lib_b", "symbol", "y")),
774 Some(&Symbol::NumberValue(2))
775 );
776 }
777
778 #[test]
779 fn aliased_extension() {
780 let libraries = vec![
781 bind_library::Ast {
782 name: make_identifier!("lib_a"),
783 using: vec![],
784 declarations: vec![bind_library::Declaration {
785 identifier: make_identifier!["symbol"],
786 value_type: bind_library::ValueType::Number,
787 extends: false,
788 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
789 }],
790 },
791 bind_library::Ast {
792 name: make_identifier!("lib_b"),
793 using: vec![Include {
794 name: make_identifier!("lib_a"),
795 alias: Some("alias".to_string()),
796 }],
797 declarations: vec![bind_library::Declaration {
798 identifier: make_identifier!["alias", "symbol"],
799 value_type: bind_library::ValueType::Number,
800 extends: true,
801 values: vec![(bind_library::Value::Number("y".to_string(), 2))],
802 }],
803 },
804 ];
805
806 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
807 assert_eq!(
808 st.get(&make_identifier!("lib_a", "symbol")),
809 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
810 );
811 assert_eq!(
812 st.get(&make_identifier!("lib_a", "symbol", "x")),
813 Some(&Symbol::NumberValue(1))
814 );
815 assert_eq!(
816 st.get(&make_identifier!("lib_b", "symbol", "y")),
817 Some(&Symbol::NumberValue(2))
818 );
819 }
820
821 #[test]
822 fn aliased_extension_with_library_alias() {
823 let libraries = vec![
824 bind_library::Ast {
825 name: make_identifier!("lib_a"),
826 using: vec![],
827 declarations: vec![bind_library::Declaration {
828 identifier: make_identifier!["symbol"],
829 value_type: bind_library::ValueType::Number,
830 extends: false,
831 values: vec![(bind_library::Value::Number("x".to_string(), 1))],
832 }],
833 },
834 bind_library::Ast {
835 name: make_identifier!("lib_b"),
836 using: vec![Include {
837 name: make_identifier!("lib_a"),
838 alias: Some("alias".to_string()),
839 }],
840 declarations: vec![
841 bind_library::Declaration {
842 identifier: make_identifier!["alias", "symbol"],
843 value_type: bind_library::ValueType::Number,
844 extends: true,
845 values: vec![(bind_library::Value::Number("y".to_string(), 2))],
846 },
847 bind_library::Declaration {
848 identifier: make_identifier!["enum_symbol"],
849 value_type: bind_library::ValueType::Enum,
850 extends: false,
851 values: vec![(bind_library::Value::Enum("the_val".to_string()))],
852 },
853 ],
854 },
855 ];
856
857 let st = construct_symbol_table(
859 libraries.iter(),
860 HashMap::from([(make_identifier!("lib_b"), "opaque".to_string())]),
861 )
862 .unwrap();
863
864 assert_eq!(
865 st.get(&make_identifier!("lib_a", "symbol")),
866 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
867 );
868 assert_eq!(
869 st.get(&make_identifier!("lib_a", "symbol", "x")),
870 Some(&Symbol::NumberValue(1))
871 );
872 assert_eq!(
873 st.get(&make_identifier!("opaque", "symbol", "y")),
874 Some(&Symbol::NumberValue(2))
875 );
876 assert_eq!(
877 st.get(&make_identifier!("lib_b", "symbol", "y")),
878 Some(&Symbol::NumberValue(2))
879 );
880 assert_eq!(
881 st.get(&make_identifier!("opaque", "enum_symbol")),
882 Some(&Symbol::Key("lib_b.enum_symbol".to_string(), bind_library::ValueType::Enum))
883 );
884 assert_eq!(
885 st.get(&make_identifier!("lib_b", "enum_symbol")),
886 Some(&Symbol::Key("lib_b.enum_symbol".to_string(), bind_library::ValueType::Enum))
887 );
888 assert_eq!(
889 st.get(&make_identifier!("opaque", "enum_symbol", "the_val")),
890 Some(&Symbol::EnumValue("lib_b.enum_symbol.the_val".to_string()))
891 );
892 assert_eq!(
893 st.get(&make_identifier!("lib_b", "enum_symbol", "the_val")),
894 Some(&Symbol::EnumValue("lib_b.enum_symbol.the_val".to_string()))
895 );
896 }
897
898 #[test]
899 fn deprecated_key_extension() {
900 let libraries = vec![bind_library::Ast {
901 name: make_identifier!("lib_a"),
902 using: vec![],
903 declarations: vec![bind_library::Declaration {
904 identifier: make_identifier!["fuchsia", "BIND_PCI_DID"],
905 value_type: bind_library::ValueType::Number,
906 extends: true,
907 values: vec![(bind_library::Value::Number("x".to_string(), 0x1234))],
908 }],
909 }];
910
911 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
912 assert_eq!(
913 st.get(&make_identifier!("lib_a", "BIND_PCI_DID", "x")),
914 Some(&Symbol::NumberValue(0x1234))
915 );
916 }
917
918 #[test]
919 fn duplicate_key() {
920 let libraries = vec![bind_library::Ast {
921 name: make_identifier!("test"),
922 using: vec![],
923 declarations: vec![
924 bind_library::Declaration {
925 identifier: make_identifier!["symbol"],
926 value_type: bind_library::ValueType::Number,
927 extends: false,
928 values: vec![],
929 },
930 bind_library::Declaration {
931 identifier: make_identifier!["symbol"],
932 value_type: bind_library::ValueType::Number,
933 extends: false,
934 values: vec![],
935 },
936 ],
937 }];
938
939 assert_eq!(
940 construct_symbol_table(libraries.iter(), HashMap::new()),
941 Err(CompilerError::DuplicateIdentifier(make_identifier!("test", "symbol")))
942 );
943 }
944
945 #[test]
946 fn duplicate_value() {
947 let libraries = vec![bind_library::Ast {
948 name: make_identifier!("test"),
949 using: vec![],
950 declarations: vec![bind_library::Declaration {
951 identifier: make_identifier!["symbol"],
952 value_type: bind_library::ValueType::Number,
953 extends: false,
954 values: vec![
955 bind_library::Value::Number("a".to_string(), 1),
956 bind_library::Value::Number("a".to_string(), 2),
957 ],
958 }],
959 }];
960
961 assert_eq!(
962 construct_symbol_table(libraries.iter(), HashMap::new()),
963 Err(CompilerError::DuplicateIdentifier(make_identifier!("test", "symbol", "a")))
964 );
965 }
966
967 #[test]
968 fn keys_are_qualified() {
969 let libraries = vec![
971 bind_library::Ast {
972 name: make_identifier!("lib_a"),
973 using: vec![],
974 declarations: vec![bind_library::Declaration {
975 identifier: make_identifier!["symbol"],
976 value_type: bind_library::ValueType::Number,
977 extends: false,
978 values: vec![],
979 }],
980 },
981 bind_library::Ast {
982 name: make_identifier!("lib_b"),
983 using: vec![],
984 declarations: vec![bind_library::Declaration {
985 identifier: make_identifier!["symbol"],
986 value_type: bind_library::ValueType::Number,
987 extends: false,
988 values: vec![],
989 }],
990 },
991 ];
992
993 let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
994 assert_eq!(
995 st.get(&make_identifier!("lib_a", "symbol")),
996 Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
997 );
998 assert_eq!(
999 st.get(&make_identifier!("lib_b", "symbol")),
1000 Some(&Symbol::Key("lib_b.symbol".to_string(), bind_library::ValueType::Number))
1001 );
1002 }
1003
1004 #[test]
1005 fn missing_extend_keyword() {
1006 let libraries = vec![
1008 bind_library::Ast {
1009 name: make_identifier!("lib_a"),
1010 using: vec![],
1011 declarations: vec![bind_library::Declaration {
1012 identifier: make_identifier!["symbol"],
1013 value_type: bind_library::ValueType::Number,
1014 extends: false,
1015 values: vec![],
1016 }],
1017 },
1018 bind_library::Ast {
1019 name: make_identifier!("lib_b"),
1020 using: vec![],
1021 declarations: vec![bind_library::Declaration {
1022 identifier: make_identifier!["lib_a", "symbol"],
1023 value_type: bind_library::ValueType::Number,
1024 extends: false,
1025 values: vec![],
1026 }],
1027 },
1028 ];
1029
1030 assert_eq!(
1031 construct_symbol_table(libraries.iter(), HashMap::new()),
1032 Err(CompilerError::MissingExtendsKeyword(make_identifier!("lib_a", "symbol")))
1033 );
1034 }
1035
1036 #[test]
1037 fn invalid_extend_keyword() {
1038 let libraries = vec![bind_library::Ast {
1041 name: make_identifier!("lib_a"),
1042 using: vec![],
1043 declarations: vec![bind_library::Declaration {
1044 identifier: make_identifier!["symbol"],
1045 value_type: bind_library::ValueType::Number,
1046 extends: true,
1047 values: vec![],
1048 }],
1049 }];
1050
1051 assert_eq!(
1052 construct_symbol_table(libraries.iter(), HashMap::new()),
1053 Err(CompilerError::InvalidExtendsKeyword(make_identifier!("lib_a", "symbol")))
1054 );
1055 }
1056
1057 #[test]
1058 fn unresolved_qualification() {
1059 let libraries = vec![bind_library::Ast {
1062 name: make_identifier!("lib_a"),
1063 using: vec![],
1064 declarations: vec![bind_library::Declaration {
1065 identifier: make_identifier!["lib_b", "symbol"],
1066 value_type: bind_library::ValueType::Number,
1067 extends: true,
1068 values: vec![],
1069 }],
1070 }];
1071
1072 assert_eq!(
1073 construct_symbol_table(libraries.iter(), HashMap::new()),
1074 Err(CompilerError::UnresolvedQualification(make_identifier!("lib_b", "symbol")))
1075 );
1076 }
1077
1078 #[test]
1079 fn undeclared_key() {
1080 let libraries = vec![
1081 bind_library::Ast {
1082 name: make_identifier!("lib_a"),
1083 using: vec![],
1084 declarations: vec![],
1085 },
1086 bind_library::Ast {
1087 name: make_identifier!("lib_b"),
1088 using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
1089 declarations: vec![bind_library::Declaration {
1090 identifier: make_identifier!["lib_a", "symbol"],
1091 value_type: bind_library::ValueType::Number,
1092 extends: true,
1093 values: vec![],
1094 }],
1095 },
1096 ];
1097
1098 assert_eq!(
1099 construct_symbol_table(libraries.iter(), HashMap::new()),
1100 Err(CompilerError::UndeclaredKey(make_identifier!("lib_a", "symbol")))
1101 );
1102 }
1103
1104 #[test]
1105 fn type_mismatch() {
1106 let libraries = vec![
1107 bind_library::Ast {
1108 name: make_identifier!("lib_a"),
1109 using: vec![],
1110 declarations: vec![bind_library::Declaration {
1111 identifier: make_identifier!["symbol"],
1112 value_type: bind_library::ValueType::Str,
1113 extends: false,
1114 values: vec![],
1115 }],
1116 },
1117 bind_library::Ast {
1118 name: make_identifier!("lib_b"),
1119 using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
1120 declarations: vec![bind_library::Declaration {
1121 identifier: make_identifier!["lib_a", "symbol"],
1122 value_type: bind_library::ValueType::Number,
1123 extends: true,
1124 values: vec![],
1125 }],
1126 },
1127 ];
1128
1129 assert_eq!(
1130 construct_symbol_table(libraries.iter(), HashMap::new()),
1131 Err(CompilerError::TypeMismatch(make_identifier!("lib_a", "symbol")))
1132 );
1133 }
1134 }
1135}