bind/compiler/
symbol_table.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
38// This struct contains bind library declaration data that's used for inserting symbol
39// table entries.
40struct SymbolTableDeclaration {
41    pub declaration: bind_library::Declaration,
42
43    // Key-value qualified identifiers that are namespaced to the highest dependency that
44    // defined the declaration.
45    pub qualified_k: CompoundIdentifier,
46    pub qualified_v: CompoundIdentifier,
47
48    // Key-value qualified identifiers that are namespaced to the library that defined the
49    // declaration.
50    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
112/// Find the namespace of a qualified identifier from the library's includes. Or, if the identifier
113/// is unqualified, return the local qualified identifier.
114fn 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        // A declaration of a qualified (i.e. non-local) key must be an extension.
121        if !declaration.extends {
122            return Err(CompilerError::MissingExtendsKeyword(declaration.identifier.clone()));
123        }
124
125        // Special case for deprecated symbols (currently in the fuchsia namespace), return the
126        // declaration as-is.
127        if namespace == make_identifier!["fuchsia"] {
128            return Ok(declaration.identifier.clone());
129        }
130
131        // Find the fully qualified name from the included libraries.
132        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    // It is not valid to extend an unqualified (i.e. local) key.
145    if declaration.extends {
146        return Err(CompilerError::InvalidExtendsKeyword(local_qualified.clone()));
147    }
148
149    // An unqualified/local key is scoped to the current library.
150    Ok(local_qualified.clone())
151}
152
153// Insert entries from |declaration_data| into |symbol_table|.
154fn 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    // Type-check the qualified name against the existing symbols, and check that extended
167    // keys are previously defined and that non-extended keys are not.
168    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    // Insert each value associated with the declaration into the symbol table, taking care
191    // to scope each identifier under the locally qualified identifier of the key. We don't
192    // need to type-check values here since the parser has already done that.
193    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
211/// Construct a map of every key and value defined by `libraries`. The identifiers in the symbol
212/// table will be fully qualified, i.e. they will contain their full namespace. A symbol is
213/// namespaced according to the name of the library it is defined in. If a library defines a value
214/// by extending a previously defined key, then that value will be namespaced to the current library
215/// and not the library of its key.
216pub 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    // Cache extended declarations and insert them into the symbol table after we resolve all
223    // library declarations.
224    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            // Construct a qualified identifier for this key that's namespaced to the current
236            // library, discarding any other qualifiers. This identifier is used to scope values
237            // defined under this key. We have separate entries for symbol table keys (k) and
238            // values (v) because the key might be aliased.
239            let local_qualified_id = name.nest(declaration.identifier.name.clone());
240
241            // Attempt to match the namespace of the key to an include of the current library, or if
242            // it is unqualified use the local qualified name. Also do a first pass at checking
243            // whether the extend keyword is used correctly. Once again keep separate entries for
244            // symbol table keys (k) and values (v) because the key might be aliased.
245            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")]
291/// Hard code these symbols during the migration from macros to bind rules. Eventually these
292/// will be defined in libraries and the compiler will emit strings for them in the bytecode.
293fn 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    // usb binding variables at 0x02XX
315    // these are used for both ZX_PROTOCOL_USB_INTERFACE and ZX_PROTOCOL_USB_FUNCTION
316    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    // Platform bus binding variables at 0x03XX
324    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    // ACPI binding variables at 0x04XX
331    keys.push(("BIND_ACPI_BUS_TYPE".to_string(), 0x0400));
332    keys.push(("BIND_ACPI_ID".to_string(), 0x0401));
333
334    // Intel HDA Codec binding variables at 0x05XX
335    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    // Serial binding variables at 0x06XX
343    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    // NAND binding variables at 0x07XX
348    keys.push(("BIND_NAND_CLASS".to_string(), 0x0700));
349
350    // SDIO binding variables at 0x09XX
351    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    // I2C binding variables at 0x0A0X
356    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    // GPIO binding variables at 0x0A1X
361    keys.push(("BIND_GPIO_PIN".to_string(), 0x0A10));
362    keys.push(("BIND_GPIO_CONTROLLER".to_string(), 0x0A11));
363
364    // POWER binding variables at 0x0A2X
365    keys.push(("BIND_POWER_DOMAIN".to_string(), 0x0A20));
366    keys.push(("BIND_POWER_DOMAIN_COMPOSITE".to_string(), 0x0A21));
367
368    // POWER binding variables at 0x0A3X
369    keys.push(("BIND_CLOCK_ID".to_string(), 0x0A30));
370
371    // SPI binding variables at 0x0A4X
372    keys.push(("BIND_SPI_BUS_ID".to_string(), 0x0A41));
373    keys.push(("BIND_SPI_CHIP_SELECT".to_string(), 0x0A42));
374
375    // PWM binding variables at 0x0A5X
376    keys.push(("BIND_PWM_ID".to_string(), 0x0A50));
377
378    // PWM binding variables at 0x0A6X
379    keys.push(("BIND_INIT_STEP".to_string(), 0x0A60));
380
381    // PWM binding variables at 0x0A7X
382    keys.push(("BIND_CODEC_INSTANCE".to_string(), 0x0A70));
383
384    // Power sensor binding variables at 0x0A9X
385    keys.push(("BIND_POWER_SENSOR_DOMAIN".to_string(), 0x0A90));
386
387    // Mailbox binding variables at 0x0AAX
388    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        // PCI binding variables at 0x01XX.
418        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        // USB binding variables at 0x02XX.
427        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        // Platform bus binding variables at 0x03XX.
435        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        // ACPI binding variables at 0x04XX.
442        0x0400 => Some("fuchsia.BIND_ACPI_BUS_TYPE".to_string()),
443        0x0401 => Some("fuchsia.BIND_ACPI_ID".to_string()),
444
445        // Intel HDA Codec binding variables at 0x05XX.
446        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        // Serial binding variables at 0x06XX.
454        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        // NAND binding variables at 0x07XX.
459        0x0700 => Some("fuchsia.BIND_NAND_CLASS".to_string()),
460
461        // SDIO binding variables at 0x09XX.
462        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        // I2C binding variables at 0x0A0X.
467        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        // GPIO binding variables at 0x0A1X.
474        0x0A10 => Some("fuchsia.BIND_GPIO_PIN".to_string()),
475        0x0A11 => Some("fuchsia.BIND_GPIO_CONTROLLER".to_string()),
476
477        // POWER binding variables at 0x0A2X.
478        0x0A20 => Some("fuchsia.BIND_POWER_DOMAIN".to_string()),
479        0x0A21 => Some("fuchsia.BIND_POWER_DOMAIN_COMPOSITE".to_string()),
480
481        // POWER (clock) binding variables at 0x0A3X.
482        0x0A30 => Some("fuchsia.BIND_CLOCK_ID".to_string()),
483
484        // SPI binding variables at 0x0A4X.
485        0x0A41 => Some("fuchsia.BIND_SPI_BUS_ID".to_string()),
486        0x0A42 => Some("fuchsia.BIND_SPI_CHIP_SELECT".to_string()),
487
488        // PWM binding variables at 0x0A5X.
489        0x0A50 => Some("fuchsia.BIND_PWM_ID".to_string()),
490
491        // Init step binding variables at 0x0A6X.
492        0x0A60 => Some("fuchsia.BIND_INIT_STEP".to_string()),
493
494        // Codec binding variables at 0x0A7X.
495        0x0A70 => Some("fuchsia.BIND_CODEC_INSTANCE".to_string()),
496
497        // Power sensor binding variables at 0x0A9X.
498        0x0A90 => Some("fuchsia.BIND_POWER_SENSOR_DOMAIN".to_string()),
499
500        // Mailbox binding variables at 0x0AAX.
501        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        // PCI binding variables at 0x01XX.
516        "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        // USB binding variables at 0x02XX.
525        "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        // Platform bus binding variables at 0x03XX
533        "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        // ACPI binding variables at 0x04XX
540        "fuchsia.BIND_ACPI_BUS_TYPE" => Some(0x0400),
541        "fuchsia.BIND_ACPI_ID" => Some(0x0401),
542
543        // Intel HDA Codec binding variables at 0x05XX
544        "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        // Serial binding variables at 0x06XX
552        "fuchsia.BIND_SERIAL_CLASS" => Some(0x0600),
553        "fuchsia.BIND_SERIAL_VID" => Some(0x0601),
554        "fuchsia.BIND_SERIAL_PID" => Some(0x0602),
555
556        // NAND binding variables at 0x07XX
557        "fuchsia.BIND_NAND_CLASS" => Some(0x0700),
558
559        // SDIO binding variables at 0x09XX
560        "fuchsia.BIND_SDIO_VID" => Some(0x0900),
561        "fuchsia.BIND_SDIO_PID" => Some(0x0901),
562        "fuchsia.BIND_SDIO_FUNCTION" => Some(0x0902),
563
564        // I2C binding variables at 0x0A0X
565        "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        // GPIO binding variables at 0x0A1X
572        "fuchsia.BIND_GPIO_PIN" => Some(0x0A10),
573        "fuchsia.BIND_GPIO_CONTROLLER" => Some(0x0A11),
574
575        // POWER binding variables at 0x0A2X
576        "fuchsia.BIND_POWER_DOMAIN" => Some(0x0A20),
577        "fuchsia.BIND_POWER_DOMAIN_COMPOSITE" => Some(0x0A21),
578
579        // POWER binding variables at 0x0A3X
580        "fuchsia.BIND_CLOCK_ID" => Some(0x0A30),
581
582        // SPI binding variables at 0x0A4X
583        "fuchsia.BIND_SPI_BUS_ID" => Some(0x0A41),
584        "fuchsia.BIND_SPI_CHIP_SELECT" => Some(0x0A42),
585
586        // PWM binding variables at 0x0A5X
587        "fuchsia.BIND_PWM_ID" => Some(0x0A50),
588
589        // Init step binding variables at 0x0A6X.
590        "fuchsia.BIND_INIT_STEP" => Some(0x0A60),
591
592        // Codec binding variables at 0x0A7X.
593        "fuchsia.BIND_CODEC_INSTANCE" => Some(0x0A70),
594
595        // Power sensor binding variables at 0x0A9X
596        "fuchsia.BIND_POWER_SENSOR_DOMAIN" => Some(0x0A90),
597
598        // Mailbox binding variables at 0x0AAX
599        "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            // The symbol table will be constructed with 'lib_b' aliased as 'opaque'.
858            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            // The same symbol declared in two libraries should not collide.
970            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            // A library referring to a previously declared symbol must use the "extend" keyword.
1007            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            // A library cannot declare an unqualified (and therefore locally namespaced) symbol
1039            // with the "extend" keyword.
1040            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            // A library cannot refer to a qualified identifier where the qualifier is not in its
1060            // list of includes.
1061            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}