Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  resolver.rs   Sprache: unbekannt

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! #  Helpers for resolving UDL type expressions into concrete types.
//!
//! This module provides the [`TypeResolver`] trait, an abstraction for walking
//! the parse tree of a weedle type expression and using a [`TypeCollector`] to
//! convert it into a concrete type definition (so it assumes that you're already
//! used a [`TypeFinder`](super::TypeFinder) to populate the universe).
//!
//! Perhaps most importantly, it knows how to error out if the UDL tries to reference
//! an undefined or invalid type.

use anyhow::{bail, Result};

use super::{Type, TypeCollector};

/// Trait to help resolving an UDL type node to a [`Type`].
///
/// This trait does structural matching against type-related weedle AST nodes from
/// a parsed UDL file, turning them into a corresponding [`Type`] struct. It uses the
/// known type definitions in a [`TypeCollector`] to resolve names to types.
///
/// As a side-effect, resolving a type expression will grow the type universe with
/// references to the types seen during traversal. For example resolving the type
/// expression `sequence<<TestRecord>?` will:
///
///   * add `Optional<Sequence<TestRecord>` and `Sequence<TestRecord>` to the
///     known types in the universe.
///   * error out if the type name `TestRecord` is not already known.
///
pub(crate) trait TypeResolver {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type>;
}

impl TypeResolver for &weedle::types::Type<'_> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        (*self).resolve_type_expression(types)
    }
}

impl TypeResolver for weedle::types::Type<'_> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        match self {
            weedle::types::Type::Single(t) => match t {
                weedle::types::SingleType::Any(_) => bail!("no support for `any` types"),
                weedle::types::SingleType::NonAny(t) => t.resolve_type_expression(types),
            },
            weedle::types::Type::Union(_) => bail!("no support for union types yet"),
        }
    }
}

impl TypeResolver for weedle::types::NonAnyType<'_> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        match self {
            weedle::types::NonAnyType::Boolean(t) => t.resolve_type_expression(types),
            weedle::types::NonAnyType::Identifier(t) => t.resolve_type_expression(types),
            weedle::types::NonAnyType::Integer(t) => t.resolve_type_expression(types),
            weedle::types::NonAnyType::FloatingPoint(t) => t.resolve_type_expression(types),
            weedle::types::NonAnyType::Sequence(t) => t.resolve_type_expression(types),
            weedle::types::NonAnyType::RecordType(t) => t.resolve_type_expression(types),
            _ => bail!("no support for type {:?}", self),
        }
    }
}

impl TypeResolver for &weedle::types::AttributedNonAnyType<'_> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        if self.attributes.is_some() {
            bail!("type attributes are not supported yet");
        }
        self.type_.resolve_type_expression(types)
    }
}

impl TypeResolver for &weedle::types::AttributedType<'_> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        if self.attributes.is_some() {
            bail!("type attributes are not supported yet");
        }
        self.type_.resolve_type_expression(types)
    }
}

impl<T: TypeResolver> TypeResolver for weedle::types::MayBeNull<T> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        let type_ = self.type_.resolve_type_expression(types)?;
        match self.q_mark {
            None => Ok(type_),
            Some(_) => {
                let ty = Type::Optional {
                    inner_type: Box::new(type_),
                };
                Ok(ty)
            }
        }
    }
}

impl TypeResolver for weedle::types::IntegerType {
    fn resolve_type_expression(&self, _types: &mut TypeCollector) -> Result<Type> {
        bail!(
            "WebIDL integer types not implemented ({:?}); consider using u8, u16, u32 or u64",
            self
        )
    }
}

impl TypeResolver for weedle::types::FloatingPointType {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        match self {
            weedle::types::FloatingPointType::Float(t) => t.resolve_type_expression(types),
            weedle::types::FloatingPointType::Double(t) => t.resolve_type_expression(types),
        }
    }
}

impl TypeResolver for weedle::types::SequenceType<'_> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        let t = self.generics.body.as_ref().resolve_type_expression(types)?;
        let ty = Type::Sequence {
            inner_type: Box::new(t),
        };
        Ok(ty)
    }
}

impl TypeResolver for weedle::types::RecordKeyType<'_> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        use weedle::types::RecordKeyType::*;
        match self {
            Byte(_) | USV(_) => bail!(
                "WebIDL Byte or USV string type not implemented ({self:?}); \
                 consider using a string",
            ),
            DOM(_) => Ok(Type::String),
            NonAny(t) => t.resolve_type_expression(types),
        }
    }
}

impl TypeResolver for weedle::types::RecordType<'_> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        let key_type = self.generics.body.0.resolve_type_expression(types)?;
        let value_type = self.generics.body.2.resolve_type_expression(types)?;
        let map = Type::Map {
            key_type: Box::new(key_type),
            value_type: Box::new(value_type),
        };
        Ok(map)
    }
}

impl TypeResolver for weedle::common::Identifier<'_> {
    fn resolve_type_expression(&self, types: &mut TypeCollector) -> Result<Type> {
        match resolve_builtin_type(self.0) {
            Some(type_) => Ok(type_),
            None => match types.get_type_definition(self.0) {
                Some(type_) => Ok(type_),
                None => bail!("unknown type reference: {}", self.0),
            },
        }
    }
}

impl TypeResolver for weedle::term::Boolean {
    fn resolve_type_expression(&self, _types: &mut TypeCollector) -> Result<Type> {
        Ok(Type::Boolean)
    }
}

impl TypeResolver for weedle::types::FloatType {
    fn resolve_type_expression(&self, _types: &mut TypeCollector) -> Result<Type> {
        if self.unrestricted.is_some() {
            bail!("we don't support `unrestricted float`");
        }
        Ok(Type::Float32)
    }
}

impl TypeResolver for weedle::types::DoubleType {
    fn resolve_type_expression(&self, _types: &mut TypeCollector) -> Result<Type> {
        if self.unrestricted.is_some() {
            bail!("we don't support `unrestricted double`");
        }
        Ok(Type::Float64)
    }
}

/// Resolve built-in API types by name.
///
/// Given an identifier from the UDL, this will return `Some(Type)` if it names one of the
/// built-in primitive types or `None` if it names something else.
pub(crate) fn resolve_builtin_type(name: &str) -> Option<Type> {
    match name {
        "string" => Some(Type::String),
        "bytes" => Some(Type::Bytes),
        "u8" => Some(Type::UInt8),
        "i8" => Some(Type::Int8),
        "u16" => Some(Type::UInt16),
        "i16" => Some(Type::Int16),
        "u32" => Some(Type::UInt32),
        "i32" => Some(Type::Int32),
        "u64" => Some(Type::UInt64),
        "i64" => Some(Type::Int64),
        "f32" => Some(Type::Float32),
        "f64" => Some(Type::Float64),
        "timestamp" => Some(Type::Timestamp),
        "duration" => Some(Type::Duration),
        _ => None,
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use weedle::Parse;

    #[test]
    fn test_named_type_resolution() -> Result<()> {
        let mut types = TypeCollector::default();
        types.add_type_definition(
            "TestRecord",
            Type::Record {
                name: "TestRecord".into(),
                module_path: "".into(),
            },
        )?;
        assert_eq!(types.type_definitions.len(), 1);

        let (_, expr) = weedle::types::Type::parse("TestRecord").unwrap();
        let t = types.resolve_type_expression(expr).unwrap();
        assert!(matches!(t, Type::Record { name, .. } if name == "TestRecord"));
        assert_eq!(types.type_definitions.len(), 1);

        let (_, expr) = weedle::types::Type::parse("TestRecord?").unwrap();
        let t = types.resolve_type_expression(expr).unwrap();
        assert!(matches!(t, Type::Optional { .. }));
        assert!(match t {
            Type::Optional { inner_type } =>
                matches!(*inner_type, Type::Record { name, .. } if name == "TestRecord"),
            _ => false,
        });
        //        assert_eq!(types.type_definitions.len(), 2);

        Ok(())
    }

    #[test]
    fn test_error_on_unknown_type() -> Result<()> {
        let mut types = TypeCollector::default();
        types.add_type_definition(
            "TestRecord",
            Type::Record {
                name: "TestRecord".into(),
                module_path: "".into(),
            },
        )?;
        // Oh no, someone made a typo in the type-o...
        let (_, expr) = weedle::types::Type::parse("TestRecrd").unwrap();
        let err = types.resolve_type_expression(expr).unwrap_err();
        assert_eq!(err.to_string(), "unknown type reference: TestRecrd");
        Ok(())
    }

    #[test]
    fn test_error_on_union_type() -> Result<()> {
        let mut types = TypeCollector::default();
        types.add_type_definition(
            "TestRecord",
            Type::Record {
                name: "TestRecord".into(),
                module_path: "".into(),
            },
        )?;
        let (_, expr) = weedle::types::Type::parse("(TestRecord or u32)").unwrap();
        let err = types.resolve_type_expression(expr).unwrap_err();
        assert_eq!(err.to_string(), "no support for union types yet");
        Ok(())
    }
}

[ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge