Skip to main content

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::{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
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        .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
116/// Find the namespace of a qualified identifier from the library's includes. Or, if the identifier
117/// is unqualified, return the local qualified identifier.
118fn 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        // A declaration of a qualified (i.e. non-local) key must be an extension.
126        if !declaration.extends {
127            return Err(CompilerError::MissingExtendsKeyword(declaration.identifier.clone()));
128        }
129
130        // Special case for deprecated symbols (currently in the fuchsia namespace), return the
131        // declaration as-is.
132        if namespace == make_identifier!["fuchsia"] {
133            return Ok(declaration.identifier.clone());
134        }
135
136        // Find the fully qualified name from the included libraries.
137        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        // Check if the namespace exists in the compiled library names
146        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    // It is not valid to extend an unqualified (i.e. local) key.
154    if declaration.extends {
155        return Err(CompilerError::InvalidExtendsKeyword(local_qualified.clone()));
156    }
157
158    // An unqualified/local key is scoped to the current library.
159    Ok(local_qualified.clone())
160}
161
162// Insert entries from |declaration_data| into |symbol_table|.
163fn 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    // Type-check the qualified name against the existing symbols, and check that extended
176    // keys are previously defined and that non-extended keys are not.
177    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    // Insert each value associated with the declaration into the symbol table, taking care
200    // to scope each identifier under the locally qualified identifier of the key. We don't
201    // need to type-check values here since the parser has already done that.
202    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
220/// Construct a map of every key and value defined by `libraries`. The identifiers in the symbol
221/// table will be fully qualified, i.e. they will contain their full namespace. A symbol is
222/// namespaced according to the name of the library it is defined in. If a library defines a value
223/// by extending a previously defined key, then that value will be namespaced to the current library
224/// and not the library of its key.
225pub 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    // Cache extended declarations and insert them into the symbol table after we resolve all
236    // library declarations.
237    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            // Construct a qualified identifier for this key that's namespaced to the current
249            // library, discarding any other qualifiers. This identifier is used to scope values
250            // defined under this key. We have separate entries for symbol table keys (k) and
251            // values (v) because the key might be aliased.
252            let local_qualified_id = name.nest(declaration.identifier.name.clone());
253
254            // Attempt to match the namespace of the key to an include of the current library, or if
255            // it is unqualified use the local qualified name. Also do a first pass at checking
256            // whether the extend keyword is used correctly. Once again keep separate entries for
257            // symbol table keys (k) and values (v) because the key might be aliased.
258            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.clone(),
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")]
309/// Hard code these symbols during the migration from macros to bind rules. Eventually these
310/// will be defined in libraries and the compiler will emit strings for them in the bytecode.
311fn 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_FIDL_PROTOCOL".to_string(), 0x0004));
321
322    keys.push(("BIND_PLATFORM_DEV_VID".to_string(), 0x0300));
323    keys.push(("BIND_PCI_VID".to_string(), 0x0100));
324
325    keys.push(("BIND_PCI_DID".to_string(), 0x0101));
326    keys.push(("BIND_PCI_CLASS".to_string(), 0x0102));
327    keys.push(("BIND_PCI_SUBCLASS".to_string(), 0x0103));
328    keys.push(("BIND_PCI_INTERFACE".to_string(), 0x0104));
329    keys.push(("BIND_PCI_REVISION".to_string(), 0x0105));
330    keys.push(("BIND_PCI_TOPO".to_string(), 0x0107));
331
332    // usb binding variables at 0x02XX
333    // these are used for both ZX_PROTOCOL_USB_INTERFACE and ZX_PROTOCOL_USB_FUNCTION
334    keys.push(("BIND_USB_VID".to_string(), 0x0200));
335    keys.push(("BIND_USB_PID".to_string(), 0x0201));
336    keys.push(("BIND_USB_CLASS".to_string(), 0x0202));
337    keys.push(("BIND_USB_SUBCLASS".to_string(), 0x0203));
338    keys.push(("BIND_USB_PROTOCOL".to_string(), 0x0204));
339    keys.push(("BIND_USB_INTERFACE_NUMBER".to_string(), 0x0205));
340
341    // Platform bus binding variables at 0x03XX
342    keys.push(("BIND_PLATFORM_DEV_VID".to_string(), 0x0300));
343    keys.push(("BIND_PLATFORM_DEV_PID".to_string(), 0x0301));
344    keys.push(("BIND_PLATFORM_DEV_DID".to_string(), 0x0302));
345    keys.push(("BIND_PLATFORM_DEV_INSTANCE_ID".to_string(), 0x0304));
346    keys.push(("BIND_PLATFORM_DEV_INTERRUPT_ID".to_string(), 0x0305));
347
348    // ACPI binding variables at 0x04XX
349    keys.push(("BIND_ACPI_BUS_TYPE".to_string(), 0x0400));
350    keys.push(("BIND_ACPI_ID".to_string(), 0x0401));
351
352    // Intel HDA Codec binding variables at 0x05XX
353    keys.push(("BIND_IHDA_CODEC_VID".to_string(), 0x0500));
354    keys.push(("BIND_IHDA_CODEC_DID".to_string(), 0x0501));
355    keys.push(("BIND_IHDA_CODEC_MAJOR_REV".to_string(), 0x0502));
356    keys.push(("BIND_IHDA_CODEC_MINOR_REV".to_string(), 0x0503));
357    keys.push(("BIND_IHDA_CODEC_VENDOR_REV".to_string(), 0x0504));
358    keys.push(("BIND_IHDA_CODEC_VENDOR_STEP".to_string(), 0x0505));
359
360    // Serial binding variables at 0x06XX
361    keys.push(("BIND_SERIAL_CLASS".to_string(), 0x0600));
362    keys.push(("BIND_SERIAL_VID".to_string(), 0x0601));
363    keys.push(("BIND_SERIAL_PID".to_string(), 0x0602));
364
365    // NAND binding variables at 0x07XX
366    keys.push(("BIND_NAND_CLASS".to_string(), 0x0700));
367
368    // SDIO binding variables at 0x09XX
369    keys.push(("BIND_SDIO_VID".to_string(), 0x0900));
370    keys.push(("BIND_SDIO_PID".to_string(), 0x0901));
371    keys.push(("BIND_SDIO_FUNCTION".to_string(), 0x0902));
372
373    // I2C binding variables at 0x0A0X
374    keys.push(("BIND_I2C_CLASS".to_string(), 0x0A00));
375    keys.push(("BIND_I2C_BUS_ID".to_string(), 0x0A01));
376    keys.push(("BIND_I2C_ADDRESS".to_string(), 0x0A02));
377
378    // GPIO binding variables at 0x0A1X
379    keys.push(("BIND_GPIO_PIN".to_string(), 0x0A10));
380    keys.push(("BIND_GPIO_CONTROLLER".to_string(), 0x0A11));
381
382    // POWER binding variables at 0x0A2X
383    keys.push(("BIND_POWER_DOMAIN".to_string(), 0x0A20));
384    keys.push(("BIND_POWER_DOMAIN_COMPOSITE".to_string(), 0x0A21));
385
386    // POWER binding variables at 0x0A3X
387    keys.push(("BIND_CLOCK_ID".to_string(), 0x0A30));
388
389    // SPI binding variables at 0x0A4X
390    keys.push(("BIND_SPI_BUS_ID".to_string(), 0x0A41));
391    keys.push(("BIND_SPI_CHIP_SELECT".to_string(), 0x0A42));
392
393    // PWM binding variables at 0x0A5X
394    keys.push(("BIND_PWM_ID".to_string(), 0x0A50));
395
396    // PWM binding variables at 0x0A6X
397    keys.push(("BIND_INIT_STEP".to_string(), 0x0A60));
398
399    // PWM binding variables at 0x0A7X
400    keys.push(("BIND_CODEC_INSTANCE".to_string(), 0x0A70));
401
402    // Power sensor binding variables at 0x0A9X
403    keys.push(("BIND_POWER_SENSOR_DOMAIN".to_string(), 0x0A90));
404
405    // Mailbox binding variables at 0x0AAX
406    keys.push(("BIND_MAILBOX_ID".to_string(), 0x0AA0));
407
408    keys
409}
410
411fn get_deprecated_symbols() -> SymbolTable {
412    let mut symbol_table = HashMap::new();
413    for (key, value) in deprecated_keys() {
414        symbol_table.insert(make_identifier!("fuchsia", key), Symbol::DeprecatedKey(value));
415    }
416    symbol_table
417}
418
419pub fn get_deprecated_key_identifiers() -> HashMap<u32, String> {
420    let mut key_identifiers = HashMap::new();
421    for (key, value) in deprecated_keys() {
422        key_identifiers.insert(value, make_identifier!("fuchsia", key).to_string());
423    }
424    key_identifiers
425}
426
427pub fn get_deprecated_key_identifier(key: u32) -> Option<String> {
428    match key {
429        0x0000 => Some("fuchsia.BIND_FLAGS".to_string()),
430        0x0001 => Some("fuchsia.BIND_PROTOCOL".to_string()),
431        0x0002 => Some("fuchsia.BIND_AUTOBIND".to_string()),
432        0x0003 => Some("fuchsia.BIND_COMPOSITE".to_string()),
433        0x0004 => Some("fuchsia.BIND_FIDL_PROTOCOL".to_string()),
434
435        // PCI binding variables at 0x01XX.
436        0x0100 => Some("fuchsia.BIND_PCI_VID".to_string()),
437        0x0101 => Some("fuchsia.BIND_PCI_DID".to_string()),
438        0x0102 => Some("fuchsia.BIND_PCI_CLASS".to_string()),
439        0x0103 => Some("fuchsia.BIND_PCI_SUBCLASS".to_string()),
440        0x0104 => Some("fuchsia.BIND_PCI_INTERFACE".to_string()),
441        0x0105 => Some("fuchsia.BIND_PCI_REVISION".to_string()),
442        0x0107 => Some("fuchsia.BIND_PCI_TOPO".to_string()),
443
444        // USB binding variables at 0x02XX.
445        0x0200 => Some("fuchsia.BIND_USB_VID".to_string()),
446        0x0201 => Some("fuchsia.BIND_USB_PID".to_string()),
447        0x0202 => Some("fuchsia.BIND_USB_CLASS".to_string()),
448        0x0203 => Some("fuchsia.BIND_USB_SUBCLASS".to_string()),
449        0x0204 => Some("fuchsia.BIND_USB_PROTOCOL".to_string()),
450        0x0205 => Some("fuchsia.BIND_USB_INTERFACE_NUMBER".to_string()),
451
452        // Platform bus binding variables at 0x03XX.
453        0x0300 => Some("fuchsia.BIND_PLATFORM_DEV_VID".to_string()),
454        0x0301 => Some("fuchsia.BIND_PLATFORM_DEV_PID".to_string()),
455        0x0302 => Some("fuchsia.BIND_PLATFORM_DEV_DID".to_string()),
456        0x0304 => Some("fuchsia.BIND_PLATFORM_DEV_INSTANCE_ID".to_string()),
457        0x0305 => Some("fuchsia.BIND_PLATFORM_DEV_INTERRUPT_ID".to_string()),
458
459        // ACPI binding variables at 0x04XX.
460        0x0400 => Some("fuchsia.BIND_ACPI_BUS_TYPE".to_string()),
461        0x0401 => Some("fuchsia.BIND_ACPI_ID".to_string()),
462
463        // Intel HDA Codec binding variables at 0x05XX.
464        0x0500 => Some("fuchsia.BIND_IHDA_CODEC_VID".to_string()),
465        0x0501 => Some("fuchsia.BIND_IHDA_CODEC_DID".to_string()),
466        0x0502 => Some("fuchsia.BIND_IHDA_CODEC_MAJOR_REV".to_string()),
467        0x0503 => Some("fuchsia.BIND_IHDA_CODEC_MINOR_REV".to_string()),
468        0x0504 => Some("fuchsia.BIND_IHDA_CODEC_VENDOR_REV".to_string()),
469        0x0505 => Some("fuchsia.BIND_IHDA_CODEC_VENDOR_STEP".to_string()),
470
471        // Serial binding variables at 0x06XX.
472        0x0600 => Some("fuchsia.BIND_SERIAL_CLASS".to_string()),
473        0x0601 => Some("fuchsia.BIND_SERIAL_VID".to_string()),
474        0x0602 => Some("fuchsia.BIND_SERIAL_PID".to_string()),
475
476        // NAND binding variables at 0x07XX.
477        0x0700 => Some("fuchsia.BIND_NAND_CLASS".to_string()),
478
479        // SDIO binding variables at 0x09XX.
480        0x0900 => Some("fuchsia.BIND_SDIO_VID".to_string()),
481        0x0901 => Some("fuchsia.BIND_SDIO_PID".to_string()),
482        0x0902 => Some("fuchsia.BIND_SDIO_FUNCTION".to_string()),
483
484        // I2C binding variables at 0x0A0X.
485        0x0A00 => Some("fuchsia.BIND_I2C_CLASS".to_string()),
486        0x0A01 => Some("fuchsia.BIND_I2C_BUS_ID".to_string()),
487        0x0A02 => Some("fuchsia.BIND_I2C_ADDRESS".to_string()),
488        0x0A03 => Some("fuchsia.BIND_I2C_VID".to_string()),
489        0x0A04 => Some("fuchsia.BIND_I2C_DID".to_string()),
490
491        // GPIO binding variables at 0x0A1X.
492        0x0A10 => Some("fuchsia.BIND_GPIO_PIN".to_string()),
493        0x0A11 => Some("fuchsia.BIND_GPIO_CONTROLLER".to_string()),
494
495        // POWER binding variables at 0x0A2X.
496        0x0A20 => Some("fuchsia.BIND_POWER_DOMAIN".to_string()),
497        0x0A21 => Some("fuchsia.BIND_POWER_DOMAIN_COMPOSITE".to_string()),
498
499        // POWER (clock) binding variables at 0x0A3X.
500        0x0A30 => Some("fuchsia.BIND_CLOCK_ID".to_string()),
501
502        // SPI binding variables at 0x0A4X.
503        0x0A41 => Some("fuchsia.BIND_SPI_BUS_ID".to_string()),
504        0x0A42 => Some("fuchsia.BIND_SPI_CHIP_SELECT".to_string()),
505
506        // PWM binding variables at 0x0A5X.
507        0x0A50 => Some("fuchsia.BIND_PWM_ID".to_string()),
508
509        // Init step binding variables at 0x0A6X.
510        0x0A60 => Some("fuchsia.BIND_INIT_STEP".to_string()),
511
512        // Codec binding variables at 0x0A7X.
513        0x0A70 => Some("fuchsia.BIND_CODEC_INSTANCE".to_string()),
514
515        // Power sensor binding variables at 0x0A9X.
516        0x0A90 => Some("fuchsia.BIND_POWER_SENSOR_DOMAIN".to_string()),
517
518        // Mailbox binding variables at 0x0AAX.
519        0x0AA0 => Some("fuchsia.BIND_MAILBOX_ID".to_string()),
520
521        _ => None,
522    }
523}
524
525pub fn get_deprecated_key_value(key: &str) -> Option<u32> {
526    match key {
527        "fuchsia.BIND_FLAGS" => Some(0x0000),
528        "fuchsia.BIND_PROTOCOL" => Some(0x0001),
529        "fuchsia.BIND_AUTOBIND" => Some(0x0002),
530        "fuchsia.BIND_COMPOSITE" => Some(0x0003),
531        "fuchsia.BIND_FIDL_PROTOCOL" => Some(0x0004),
532
533        // PCI binding variables at 0x01XX.
534        "fuchsia.BIND_PCI_VID" => Some(0x0100),
535        "fuchsia.BIND_PCI_DID" => Some(0x0101),
536        "fuchsia.BIND_PCI_CLASS" => Some(0x0102),
537        "fuchsia.BIND_PCI_SUBCLASS" => Some(0x0103),
538        "fuchsia.BIND_PCI_INTERFACE" => Some(0x0104),
539        "fuchsia.BIND_PCI_REVISION" => Some(0x0105),
540        "fuchsia.BIND_PCI_TOPO" => Some(0x0107),
541
542        // USB binding variables at 0x02XX.
543        "fuchsia.BIND_USB_VID" => Some(0x0200),
544        "fuchsia.BIND_USB_PID" => Some(0x0201),
545        "fuchsia.BIND_USB_CLASS" => Some(0x0202),
546        "fuchsia.BIND_USB_SUBCLASS" => Some(0x0203),
547        "fuchsia.BIND_USB_PROTOCOL" => Some(0x0204),
548        "fuchsia.BIND_USB_INTERFACE_NUMBER" => Some(0x0205),
549
550        // Platform bus binding variables at 0x03XX
551        "fuchsia.BIND_PLATFORM_DEV_VID" => Some(0x0300),
552        "fuchsia.BIND_PLATFORM_DEV_PID" => Some(0x0301),
553        "fuchsia.BIND_PLATFORM_DEV_DID" => Some(0x0302),
554        "fuchsia.BIND_PLATFORM_DEV_INSTANCE_ID" => Some(0x0304),
555        "fuchsia.BIND_PLATFORM_DEV_INTERRUPT_ID" => Some(0x0305),
556
557        // ACPI binding variables at 0x04XX
558        "fuchsia.BIND_ACPI_BUS_TYPE" => Some(0x0400),
559        "fuchsia.BIND_ACPI_ID" => Some(0x0401),
560
561        // Intel HDA Codec binding variables at 0x05XX
562        "fuchsia.BIND_IHDA_CODEC_VID" => Some(0x0500),
563        "fuchsia.BIND_IHDA_CODEC_DID" => Some(0x0501),
564        "fuchsia.BIND_IHDA_CODEC_MAJOR_REV" => Some(0x0502),
565        "fuchsia.BIND_IHDA_CODEC_MINOR_REV" => Some(0x0503),
566        "fuchsia.BIND_IHDA_CODEC_VENDOR_REV" => Some(0x0504),
567        "fuchsia.BIND_IHDA_CODEC_VENDOR_STEP" => Some(0x0505),
568
569        // Serial binding variables at 0x06XX
570        "fuchsia.BIND_SERIAL_CLASS" => Some(0x0600),
571        "fuchsia.BIND_SERIAL_VID" => Some(0x0601),
572        "fuchsia.BIND_SERIAL_PID" => Some(0x0602),
573
574        // NAND binding variables at 0x07XX
575        "fuchsia.BIND_NAND_CLASS" => Some(0x0700),
576
577        // SDIO binding variables at 0x09XX
578        "fuchsia.BIND_SDIO_VID" => Some(0x0900),
579        "fuchsia.BIND_SDIO_PID" => Some(0x0901),
580        "fuchsia.BIND_SDIO_FUNCTION" => Some(0x0902),
581
582        // I2C binding variables at 0x0A0X
583        "fuchsia.BIND_I2C_CLASS" => Some(0x0A00),
584        "fuchsia.BIND_I2C_BUS_ID" => Some(0x0A01),
585        "fuchsia.BIND_I2C_ADDRESS" => Some(0x0A02),
586        "fuchsia.BIND_I2C_VID" => Some(0x0A03),
587        "fuchsia.BIND_I2C_DID" => Some(0x0A04),
588
589        // GPIO binding variables at 0x0A1X
590        "fuchsia.BIND_GPIO_PIN" => Some(0x0A10),
591        "fuchsia.BIND_GPIO_CONTROLLER" => Some(0x0A11),
592
593        // POWER binding variables at 0x0A2X
594        "fuchsia.BIND_POWER_DOMAIN" => Some(0x0A20),
595        "fuchsia.BIND_POWER_DOMAIN_COMPOSITE" => Some(0x0A21),
596
597        // POWER binding variables at 0x0A3X
598        "fuchsia.BIND_CLOCK_ID" => Some(0x0A30),
599
600        // SPI binding variables at 0x0A4X
601        "fuchsia.BIND_SPI_BUS_ID" => Some(0x0A41),
602        "fuchsia.BIND_SPI_CHIP_SELECT" => Some(0x0A42),
603
604        // PWM binding variables at 0x0A5X
605        "fuchsia.BIND_PWM_ID" => Some(0x0A50),
606
607        // Init step binding variables at 0x0A6X.
608        "fuchsia.BIND_INIT_STEP" => Some(0x0A60),
609
610        // Codec binding variables at 0x0A7X.
611        "fuchsia.BIND_CODEC_INSTANCE" => Some(0x0A70),
612
613        // Power sensor binding variables at 0x0A9X
614        "fuchsia.BIND_POWER_SENSOR_DOMAIN" => Some(0x0A90),
615
616        // Mailbox binding variables at 0x0AAX
617        "fuchsia.BIND_MAILBOX_ID" => Some(0x0AA0),
618
619        _ => None,
620    }
621}
622
623#[cfg(test)]
624mod test {
625    use super::*;
626    use crate::make_identifier;
627    use crate::parser::bind_library;
628    use crate::parser::common::Include;
629
630    mod symbol_table {
631        use super::*;
632
633        #[test]
634        fn simple_key_and_value() {
635            let libraries = vec![bind_library::Ast {
636                name: make_identifier!("test"),
637                using: vec![],
638                declarations: vec![bind_library::Declaration {
639                    identifier: make_identifier!["symbol"],
640                    value_type: bind_library::ValueType::Number,
641                    extends: false,
642                    values: vec![(bind_library::Value::Number("x".to_string(), 1))],
643                }],
644            }];
645
646            let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
647            assert_eq!(
648                st.get(&make_identifier!("test", "symbol")),
649                Some(&Symbol::Key("test.symbol".to_string(), bind_library::ValueType::Number))
650            );
651            assert_eq!(
652                st.get(&make_identifier!("test", "symbol", "x")),
653                Some(&Symbol::NumberValue(1))
654            );
655        }
656
657        #[test]
658        fn all_value_types() {
659            let libraries = vec![bind_library::Ast {
660                name: make_identifier!("hummingbird"),
661                using: vec![],
662                declarations: vec![
663                    bind_library::Declaration {
664                        identifier: make_identifier!["sunbeam"],
665                        value_type: bind_library::ValueType::Number,
666                        extends: false,
667                        values: vec![(bind_library::Value::Number("shining".to_string(), 1))],
668                    },
669                    bind_library::Declaration {
670                        identifier: make_identifier!["mountaingem"],
671                        value_type: bind_library::ValueType::Bool,
672                        extends: false,
673                        values: vec![
674                            (bind_library::Value::Bool("white-bellied".to_string(), false)),
675                        ],
676                    },
677                    bind_library::Declaration {
678                        identifier: make_identifier!["brilliant"],
679                        value_type: bind_library::ValueType::Enum,
680                        extends: false,
681                        values: vec![(bind_library::Value::Enum("black-throated".to_string()))],
682                    },
683                    bind_library::Declaration {
684                        identifier: make_identifier!["woodnymph"],
685                        value_type: bind_library::ValueType::Str,
686                        extends: false,
687                        values: vec![
688                            (bind_library::Value::Str(
689                                "fork-tailed".to_string(),
690                                "sabrewing".to_string(),
691                            )),
692                        ],
693                    },
694                ],
695            }];
696
697            let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
698            assert_eq!(
699                st.get(&make_identifier!("hummingbird", "sunbeam", "shining")),
700                Some(&Symbol::NumberValue(1))
701            );
702            assert_eq!(
703                st.get(&make_identifier!("hummingbird", "mountaingem", "white-bellied")),
704                Some(&Symbol::BoolValue(false))
705            );
706            assert_eq!(
707                st.get(&make_identifier!("hummingbird", "brilliant", "black-throated")),
708                Some(&Symbol::EnumValue("hummingbird.brilliant.black-throated".to_string()))
709            );
710            assert_eq!(
711                st.get(&make_identifier!("hummingbird", "woodnymph", "fork-tailed")),
712                Some(&Symbol::StringValue("sabrewing".to_string()))
713            );
714        }
715
716        #[test]
717        fn extension() {
718            let libraries = vec![
719                bind_library::Ast {
720                    name: make_identifier!("lib_a"),
721                    using: vec![],
722                    declarations: vec![bind_library::Declaration {
723                        identifier: make_identifier!["symbol"],
724                        value_type: bind_library::ValueType::Number,
725                        extends: false,
726                        values: vec![(bind_library::Value::Number("x".to_string(), 1))],
727                    }],
728                },
729                bind_library::Ast {
730                    name: make_identifier!("lib_b"),
731                    using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
732                    declarations: vec![bind_library::Declaration {
733                        identifier: make_identifier!["lib_a", "symbol"],
734                        value_type: bind_library::ValueType::Number,
735                        extends: true,
736                        values: vec![(bind_library::Value::Number("y".to_string(), 2))],
737                    }],
738                },
739            ];
740
741            let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
742            assert_eq!(
743                st.get(&make_identifier!("lib_a", "symbol")),
744                Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
745            );
746            assert_eq!(
747                st.get(&make_identifier!("lib_a", "symbol", "x")),
748                Some(&Symbol::NumberValue(1))
749            );
750            assert_eq!(
751                st.get(&make_identifier!("lib_b", "symbol", "y")),
752                Some(&Symbol::NumberValue(2))
753            );
754        }
755
756        #[test]
757        fn extension_with_dependency_defined_after_library() {
758            let libraries = vec![
759                bind_library::Ast {
760                    name: make_identifier!("lib_b"),
761                    using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
762                    declarations: vec![bind_library::Declaration {
763                        identifier: make_identifier!["lib_a", "symbol"],
764                        value_type: bind_library::ValueType::Number,
765                        extends: true,
766                        values: vec![(bind_library::Value::Number("y".to_string(), 2))],
767                    }],
768                },
769                bind_library::Ast {
770                    name: make_identifier!("lib_a"),
771                    using: vec![],
772                    declarations: vec![bind_library::Declaration {
773                        identifier: make_identifier!["symbol"],
774                        value_type: bind_library::ValueType::Number,
775                        extends: false,
776                        values: vec![(bind_library::Value::Number("x".to_string(), 1))],
777                    }],
778                },
779            ];
780
781            let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
782            assert_eq!(
783                st.get(&make_identifier!("lib_a", "symbol")),
784                Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
785            );
786            assert_eq!(
787                st.get(&make_identifier!("lib_a", "symbol", "x")),
788                Some(&Symbol::NumberValue(1))
789            );
790            assert_eq!(
791                st.get(&make_identifier!("lib_b", "symbol", "y")),
792                Some(&Symbol::NumberValue(2))
793            );
794        }
795
796        #[test]
797        fn aliased_extension() {
798            let libraries = vec![
799                bind_library::Ast {
800                    name: make_identifier!("lib_a"),
801                    using: vec![],
802                    declarations: vec![bind_library::Declaration {
803                        identifier: make_identifier!["symbol"],
804                        value_type: bind_library::ValueType::Number,
805                        extends: false,
806                        values: vec![(bind_library::Value::Number("x".to_string(), 1))],
807                    }],
808                },
809                bind_library::Ast {
810                    name: make_identifier!("lib_b"),
811                    using: vec![Include {
812                        name: make_identifier!("lib_a"),
813                        alias: Some("alias".to_string()),
814                    }],
815                    declarations: vec![bind_library::Declaration {
816                        identifier: make_identifier!["alias", "symbol"],
817                        value_type: bind_library::ValueType::Number,
818                        extends: true,
819                        values: vec![(bind_library::Value::Number("y".to_string(), 2))],
820                    }],
821                },
822            ];
823
824            let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
825            assert_eq!(
826                st.get(&make_identifier!("lib_a", "symbol")),
827                Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
828            );
829            assert_eq!(
830                st.get(&make_identifier!("lib_a", "symbol", "x")),
831                Some(&Symbol::NumberValue(1))
832            );
833            assert_eq!(
834                st.get(&make_identifier!("lib_b", "symbol", "y")),
835                Some(&Symbol::NumberValue(2))
836            );
837        }
838
839        #[test]
840        fn aliased_extension_with_library_alias() {
841            let libraries = vec![
842                bind_library::Ast {
843                    name: make_identifier!("lib_a"),
844                    using: vec![],
845                    declarations: vec![bind_library::Declaration {
846                        identifier: make_identifier!["symbol"],
847                        value_type: bind_library::ValueType::Number,
848                        extends: false,
849                        values: vec![(bind_library::Value::Number("x".to_string(), 1))],
850                    }],
851                },
852                bind_library::Ast {
853                    name: make_identifier!("lib_b"),
854                    using: vec![Include {
855                        name: make_identifier!("lib_a"),
856                        alias: Some("alias".to_string()),
857                    }],
858                    declarations: vec![
859                        bind_library::Declaration {
860                            identifier: make_identifier!["alias", "symbol"],
861                            value_type: bind_library::ValueType::Number,
862                            extends: true,
863                            values: vec![(bind_library::Value::Number("y".to_string(), 2))],
864                        },
865                        bind_library::Declaration {
866                            identifier: make_identifier!["enum_symbol"],
867                            value_type: bind_library::ValueType::Enum,
868                            extends: false,
869                            values: vec![(bind_library::Value::Enum("the_val".to_string()))],
870                        },
871                    ],
872                },
873            ];
874
875            // The symbol table will be constructed with 'lib_b' aliased as 'opaque'.
876            let st = construct_symbol_table(
877                libraries.iter(),
878                HashMap::from([(make_identifier!("lib_b"), "opaque".to_string())]),
879            )
880            .unwrap();
881
882            assert_eq!(
883                st.get(&make_identifier!("lib_a", "symbol")),
884                Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
885            );
886            assert_eq!(
887                st.get(&make_identifier!("lib_a", "symbol", "x")),
888                Some(&Symbol::NumberValue(1))
889            );
890            assert_eq!(
891                st.get(&make_identifier!("opaque", "symbol", "y")),
892                Some(&Symbol::NumberValue(2))
893            );
894            assert_eq!(
895                st.get(&make_identifier!("lib_b", "symbol", "y")),
896                Some(&Symbol::NumberValue(2))
897            );
898            assert_eq!(
899                st.get(&make_identifier!("opaque", "enum_symbol")),
900                Some(&Symbol::Key("lib_b.enum_symbol".to_string(), bind_library::ValueType::Enum))
901            );
902            assert_eq!(
903                st.get(&make_identifier!("lib_b", "enum_symbol")),
904                Some(&Symbol::Key("lib_b.enum_symbol".to_string(), bind_library::ValueType::Enum))
905            );
906            assert_eq!(
907                st.get(&make_identifier!("opaque", "enum_symbol", "the_val")),
908                Some(&Symbol::EnumValue("lib_b.enum_symbol.the_val".to_string()))
909            );
910            assert_eq!(
911                st.get(&make_identifier!("lib_b", "enum_symbol", "the_val")),
912                Some(&Symbol::EnumValue("lib_b.enum_symbol.the_val".to_string()))
913            );
914        }
915
916        #[test]
917        fn deprecated_key_extension() {
918            let libraries = vec![bind_library::Ast {
919                name: make_identifier!("lib_a"),
920                using: vec![],
921                declarations: vec![bind_library::Declaration {
922                    identifier: make_identifier!["fuchsia", "BIND_PCI_DID"],
923                    value_type: bind_library::ValueType::Number,
924                    extends: true,
925                    values: vec![(bind_library::Value::Number("x".to_string(), 0x1234))],
926                }],
927            }];
928
929            let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
930            assert_eq!(
931                st.get(&make_identifier!("lib_a", "BIND_PCI_DID", "x")),
932                Some(&Symbol::NumberValue(0x1234))
933            );
934        }
935
936        #[test]
937        fn duplicate_key() {
938            let libraries = vec![bind_library::Ast {
939                name: make_identifier!("test"),
940                using: vec![],
941                declarations: vec![
942                    bind_library::Declaration {
943                        identifier: make_identifier!["symbol"],
944                        value_type: bind_library::ValueType::Number,
945                        extends: false,
946                        values: vec![],
947                    },
948                    bind_library::Declaration {
949                        identifier: make_identifier!["symbol"],
950                        value_type: bind_library::ValueType::Number,
951                        extends: false,
952                        values: vec![],
953                    },
954                ],
955            }];
956
957            assert_eq!(
958                construct_symbol_table(libraries.iter(), HashMap::new()),
959                Err(CompilerError::DuplicateIdentifier(make_identifier!("test", "symbol")))
960            );
961        }
962
963        #[test]
964        fn duplicate_value() {
965            let libraries = vec![bind_library::Ast {
966                name: make_identifier!("test"),
967                using: vec![],
968                declarations: vec![bind_library::Declaration {
969                    identifier: make_identifier!["symbol"],
970                    value_type: bind_library::ValueType::Number,
971                    extends: false,
972                    values: vec![
973                        bind_library::Value::Number("a".to_string(), 1),
974                        bind_library::Value::Number("a".to_string(), 2),
975                    ],
976                }],
977            }];
978
979            assert_eq!(
980                construct_symbol_table(libraries.iter(), HashMap::new()),
981                Err(CompilerError::DuplicateIdentifier(make_identifier!("test", "symbol", "a")))
982            );
983        }
984
985        #[test]
986        fn keys_are_qualified() {
987            // The same symbol declared in two libraries should not collide.
988            let libraries = vec![
989                bind_library::Ast {
990                    name: make_identifier!("lib_a"),
991                    using: vec![],
992                    declarations: vec![bind_library::Declaration {
993                        identifier: make_identifier!["symbol"],
994                        value_type: bind_library::ValueType::Number,
995                        extends: false,
996                        values: vec![],
997                    }],
998                },
999                bind_library::Ast {
1000                    name: make_identifier!("lib_b"),
1001                    using: vec![],
1002                    declarations: vec![bind_library::Declaration {
1003                        identifier: make_identifier!["symbol"],
1004                        value_type: bind_library::ValueType::Number,
1005                        extends: false,
1006                        values: vec![],
1007                    }],
1008                },
1009            ];
1010
1011            let st = construct_symbol_table(libraries.iter(), HashMap::new()).unwrap();
1012            assert_eq!(
1013                st.get(&make_identifier!("lib_a", "symbol")),
1014                Some(&Symbol::Key("lib_a.symbol".to_string(), bind_library::ValueType::Number))
1015            );
1016            assert_eq!(
1017                st.get(&make_identifier!("lib_b", "symbol")),
1018                Some(&Symbol::Key("lib_b.symbol".to_string(), bind_library::ValueType::Number))
1019            );
1020        }
1021
1022        #[test]
1023        fn missing_extend_keyword() {
1024            // A library referring to a previously declared symbol must use the "extend" keyword.
1025            let libraries = vec![
1026                bind_library::Ast {
1027                    name: make_identifier!("lib_a"),
1028                    using: vec![],
1029                    declarations: vec![bind_library::Declaration {
1030                        identifier: make_identifier!["symbol"],
1031                        value_type: bind_library::ValueType::Number,
1032                        extends: false,
1033                        values: vec![],
1034                    }],
1035                },
1036                bind_library::Ast {
1037                    name: make_identifier!("lib_b"),
1038                    using: vec![],
1039                    declarations: vec![bind_library::Declaration {
1040                        identifier: make_identifier!["lib_a", "symbol"],
1041                        value_type: bind_library::ValueType::Number,
1042                        extends: false,
1043                        values: vec![],
1044                    }],
1045                },
1046            ];
1047
1048            assert_eq!(
1049                construct_symbol_table(libraries.iter(), HashMap::new()),
1050                Err(CompilerError::MissingExtendsKeyword(make_identifier!("lib_a", "symbol")))
1051            );
1052        }
1053
1054        #[test]
1055        fn invalid_extend_keyword() {
1056            // A library cannot declare an unqualified (and therefore locally namespaced) symbol
1057            // with the "extend" keyword.
1058            let libraries = vec![bind_library::Ast {
1059                name: make_identifier!("lib_a"),
1060                using: vec![],
1061                declarations: vec![bind_library::Declaration {
1062                    identifier: make_identifier!["symbol"],
1063                    value_type: bind_library::ValueType::Number,
1064                    extends: true,
1065                    values: vec![],
1066                }],
1067            }];
1068
1069            assert_eq!(
1070                construct_symbol_table(libraries.iter(), HashMap::new()),
1071                Err(CompilerError::InvalidExtendsKeyword(make_identifier!("lib_a", "symbol")))
1072            );
1073        }
1074
1075        #[test]
1076        fn unresolved_qualification() {
1077            // A library cannot refer to a qualified identifier where the qualifier is not in its
1078            // list of includes.
1079            let libraries = vec![bind_library::Ast {
1080                name: make_identifier!("lib_a"),
1081                using: vec![],
1082                declarations: vec![bind_library::Declaration {
1083                    identifier: make_identifier!["lib_b", "symbol"],
1084                    value_type: bind_library::ValueType::Number,
1085                    extends: true,
1086                    values: vec![],
1087                }],
1088            }];
1089
1090            assert_eq!(
1091                construct_symbol_table(libraries.iter(), HashMap::new()),
1092                Err(CompilerError::UnresolvedQualification(make_identifier!("lib_b", "symbol")))
1093            );
1094        }
1095
1096        #[test]
1097        fn undeclared_key() {
1098            let libraries = vec![
1099                bind_library::Ast {
1100                    name: make_identifier!("lib_a"),
1101                    using: vec![],
1102                    declarations: vec![],
1103                },
1104                bind_library::Ast {
1105                    name: make_identifier!("lib_b"),
1106                    using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
1107                    declarations: vec![bind_library::Declaration {
1108                        identifier: make_identifier!["lib_a", "symbol"],
1109                        value_type: bind_library::ValueType::Number,
1110                        extends: true,
1111                        values: vec![],
1112                    }],
1113                },
1114            ];
1115
1116            assert_eq!(
1117                construct_symbol_table(libraries.iter(), HashMap::new()),
1118                Err(CompilerError::UndeclaredKey(make_identifier!("lib_a", "symbol")))
1119            );
1120        }
1121
1122        #[test]
1123        fn type_mismatch() {
1124            let libraries = vec![
1125                bind_library::Ast {
1126                    name: make_identifier!("lib_a"),
1127                    using: vec![],
1128                    declarations: vec![bind_library::Declaration {
1129                        identifier: make_identifier!["symbol"],
1130                        value_type: bind_library::ValueType::Str,
1131                        extends: false,
1132                        values: vec![],
1133                    }],
1134                },
1135                bind_library::Ast {
1136                    name: make_identifier!("lib_b"),
1137                    using: vec![Include { name: make_identifier!("lib_a"), alias: None }],
1138                    declarations: vec![bind_library::Declaration {
1139                        identifier: make_identifier!["lib_a", "symbol"],
1140                        value_type: bind_library::ValueType::Number,
1141                        extends: true,
1142                        values: vec![],
1143                    }],
1144                },
1145            ];
1146
1147            assert_eq!(
1148                construct_symbol_table(libraries.iter(), HashMap::new()),
1149                Err(CompilerError::TypeMismatch(make_identifier!("lib_a", "symbol")))
1150            );
1151        }
1152    }
1153}