Skip to main content

nwnrs_nwscript/
sema.rs

1use std::{
2    collections::{BTreeMap, BTreeSet},
3    error::Error,
4    fmt,
5};
6
7use serde::{Deserialize, Serialize};
8
9use crate::{
10    AssignmentOp, BinaryOp, BlockStmt, BuiltinType, BuiltinValue, CompilerErrorCode, Expr,
11    ExprKind, FunctionDecl, LangSpec, Literal, MagicLiteral, Script, Stmt, TopLevelItem, TypeKind,
12    TypeSpec, UnaryOp, nwscript_string_hash,
13};
14
15/// Options controlling semantic analysis checks.
16#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SemanticOptions {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "SemanticOptions", "require_entrypoint", &self.require_entrypoint,
            "allow_conditional_script", &&self.allow_conditional_script)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SemanticOptions {
    #[inline]
    fn clone(&self) -> SemanticOptions {
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SemanticOptions { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for SemanticOptions {
    #[inline]
    fn eq(&self, other: &SemanticOptions) -> bool {
        self.require_entrypoint == other.require_entrypoint &&
            self.allow_conditional_script == other.allow_conditional_script
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SemanticOptions {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq, #[automatically_derived]
impl ::core::hash::Hash for SemanticOptions {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.require_entrypoint, state);
        ::core::hash::Hash::hash(&self.allow_conditional_script, state)
    }
}Hash, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for SemanticOptions {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                let mut __serde_state =
                    _serde::Serializer::serialize_struct(__serializer,
                            "SemanticOptions", false as usize + 1 + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "require_entrypoint", &self.require_entrypoint)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "allow_conditional_script",
                        &self.allow_conditional_script)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for SemanticOptions {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field { __field0, __field1, __ignore, }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            _ => _serde::__private228::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "require_entrypoint" =>
                                _serde::__private228::Ok(__Field::__field0),
                            "allow_conditional_script" =>
                                _serde::__private228::Ok(__Field::__field1),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"require_entrypoint" =>
                                _serde::__private228::Ok(__Field::__field0),
                            b"allow_conditional_script" =>
                                _serde::__private228::Ok(__Field::__field1),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<SemanticOptions>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = SemanticOptions;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct SemanticOptions")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<bool>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct SemanticOptions with 2 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<bool>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct SemanticOptions with 2 elements")),
                            };
                        _serde::__private228::Ok(SemanticOptions {
                                require_entrypoint: __field0,
                                allow_conditional_script: __field1,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0: _serde::__private228::Option<bool> =
                            _serde::__private228::None;
                        let mut __field1: _serde::__private228::Option<bool> =
                            _serde::__private228::None;
                        while let _serde::__private228::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private228::Option::is_some(&__field0) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("require_entrypoint"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<bool>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private228::Option::is_some(&__field1) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("allow_conditional_script"));
                                    }
                                    __field1 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<bool>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private228::Some(__field0) => __field0,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("require_entrypoint")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private228::Some(__field1) => __field1,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("allow_conditional_script")?,
                            };
                        _serde::__private228::Ok(SemanticOptions {
                                require_entrypoint: __field0,
                                allow_conditional_script: __field1,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] =
                    &["require_entrypoint", "allow_conditional_script"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "SemanticOptions", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<SemanticOptions>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize, #[automatically_derived]
impl ::core::default::Default for SemanticOptions {
    #[inline]
    fn default() -> SemanticOptions {
        SemanticOptions {
            require_entrypoint: ::core::default::Default::default(),
            allow_conditional_script: ::core::default::Default::default(),
        }
    }
}Default)]
17pub struct SemanticOptions {
18    /// Require a valid `main()` or `StartingConditional()` entry point.
19    pub require_entrypoint:       bool,
20    /// Permit `StartingConditional()` as the required entry point when `main()`
21    /// is not present.
22    pub allow_conditional_script: bool,
23}
24
25/// One semantic-analysis error aligned to the upstream compiler's diagnostic
26/// space.
27#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SemanticError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "SemanticError",
            "code", &self.code, "span", &self.span, "message", &&self.message)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SemanticError {
    #[inline]
    fn clone(&self) -> SemanticError {
        SemanticError {
            code: ::core::clone::Clone::clone(&self.code),
            span: ::core::clone::Clone::clone(&self.span),
            message: ::core::clone::Clone::clone(&self.message),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for SemanticError {
    #[inline]
    fn eq(&self, other: &SemanticError) -> bool {
        self.code == other.code && self.span == other.span &&
            self.message == other.message
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SemanticError {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<CompilerErrorCode>;
        let _: ::core::cmp::AssertParamIsEq<crate::Span>;
        let _: ::core::cmp::AssertParamIsEq<String>;
    }
}Eq, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for SemanticError {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                let mut __serde_state =
                    _serde::Serializer::serialize_struct(__serializer,
                            "SemanticError", false as usize + 1 + 1 + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "code", &self.code)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "span", &self.span)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "message", &self.message)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for SemanticError {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field { __field0, __field1, __field2, __ignore, }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            2u64 => _serde::__private228::Ok(__Field::__field2),
                            _ => _serde::__private228::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "code" => _serde::__private228::Ok(__Field::__field0),
                            "span" => _serde::__private228::Ok(__Field::__field1),
                            "message" => _serde::__private228::Ok(__Field::__field2),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"code" => _serde::__private228::Ok(__Field::__field0),
                            b"span" => _serde::__private228::Ok(__Field::__field1),
                            b"message" => _serde::__private228::Ok(__Field::__field2),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<SemanticError>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = SemanticError;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct SemanticError")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<CompilerErrorCode>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct SemanticError with 3 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<crate::Span>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct SemanticError with 3 elements")),
                            };
                        let __field2 =
                            match _serde::de::SeqAccess::next_element::<String>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(2usize,
                                                &"struct SemanticError with 3 elements")),
                            };
                        _serde::__private228::Ok(SemanticError {
                                code: __field0,
                                span: __field1,
                                message: __field2,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0:
                                _serde::__private228::Option<CompilerErrorCode> =
                            _serde::__private228::None;
                        let mut __field1:
                                _serde::__private228::Option<crate::Span> =
                            _serde::__private228::None;
                        let mut __field2: _serde::__private228::Option<String> =
                            _serde::__private228::None;
                        while let _serde::__private228::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private228::Option::is_some(&__field0) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("code"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<CompilerErrorCode>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private228::Option::is_some(&__field1) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("span"));
                                    }
                                    __field1 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<crate::Span>(&mut __map)?);
                                }
                                __Field::__field2 => {
                                    if _serde::__private228::Option::is_some(&__field2) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("message"));
                                    }
                                    __field2 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<String>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private228::Some(__field0) => __field0,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("code")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private228::Some(__field1) => __field1,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("span")?,
                            };
                        let __field2 =
                            match __field2 {
                                _serde::__private228::Some(__field2) => __field2,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("message")?,
                            };
                        _serde::__private228::Ok(SemanticError {
                                code: __field0,
                                span: __field1,
                                message: __field2,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] =
                    &["code", "span", "message"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "SemanticError", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<SemanticError>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize)]
28pub struct SemanticError {
29    /// Stable upstream-aligned compiler error code.
30    pub code:    CompilerErrorCode,
31    /// Source span where semantic analysis failed.
32    pub span:    crate::Span,
33    /// Human-readable error message.
34    pub message: String,
35}
36
37impl SemanticError {
38    fn new(code: CompilerErrorCode, span: crate::Span, message: impl Into<String>) -> Self {
39        Self {
40            code,
41            span,
42            message: message.into(),
43        }
44    }
45}
46
47impl fmt::Display for SemanticError {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        f.write_fmt(format_args!("{0} ({1})", self.message, self.code.code()))write!(f, "{} ({})", self.message, self.code.code())
50    }
51}
52
53impl Error for SemanticError {}
54
55/// One resolved semantic type.
56#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SemanticType {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            SemanticType::Void =>
                ::core::fmt::Formatter::write_str(f, "Void"),
            SemanticType::Int => ::core::fmt::Formatter::write_str(f, "Int"),
            SemanticType::Float =>
                ::core::fmt::Formatter::write_str(f, "Float"),
            SemanticType::String =>
                ::core::fmt::Formatter::write_str(f, "String"),
            SemanticType::Object =>
                ::core::fmt::Formatter::write_str(f, "Object"),
            SemanticType::Action =>
                ::core::fmt::Formatter::write_str(f, "Action"),
            SemanticType::Vector =>
                ::core::fmt::Formatter::write_str(f, "Vector"),
            SemanticType::Struct(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Struct",
                    &__self_0),
            SemanticType::EngineStructure(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "EngineStructure", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SemanticType {
    #[inline]
    fn clone(&self) -> SemanticType {
        match self {
            SemanticType::Void => SemanticType::Void,
            SemanticType::Int => SemanticType::Int,
            SemanticType::Float => SemanticType::Float,
            SemanticType::String => SemanticType::String,
            SemanticType::Object => SemanticType::Object,
            SemanticType::Action => SemanticType::Action,
            SemanticType::Vector => SemanticType::Vector,
            SemanticType::Struct(__self_0) =>
                SemanticType::Struct(::core::clone::Clone::clone(__self_0)),
            SemanticType::EngineStructure(__self_0) =>
                SemanticType::EngineStructure(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for SemanticType {
    #[inline]
    fn eq(&self, other: &SemanticType) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (SemanticType::Struct(__self_0),
                    SemanticType::Struct(__arg1_0)) => __self_0 == __arg1_0,
                (SemanticType::EngineStructure(__self_0),
                    SemanticType::EngineStructure(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SemanticType {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<String>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for SemanticType {
    #[inline]
    fn partial_cmp(&self, other: &SemanticType)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match (self, other) {
            (SemanticType::Struct(__self_0), SemanticType::Struct(__arg1_0))
                => ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (SemanticType::EngineStructure(__self_0),
                SemanticType::EngineStructure(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            _ =>
                ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
                    &__arg1_discr),
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for SemanticType {
    #[inline]
    fn cmp(&self, other: &SemanticType) -> ::core::cmp::Ordering {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
            ::core::cmp::Ordering::Equal =>
                match (self, other) {
                    (SemanticType::Struct(__self_0),
                        SemanticType::Struct(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (SemanticType::EngineStructure(__self_0),
                        SemanticType::EngineStructure(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    _ => ::core::cmp::Ordering::Equal,
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::hash::Hash for SemanticType {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            SemanticType::Struct(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            SemanticType::EngineStructure(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            _ => {}
        }
    }
}Hash, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for SemanticType {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                match *self {
                    SemanticType::Void =>
                        _serde::Serializer::serialize_unit_variant(__serializer,
                            "SemanticType", 0u32, "Void"),
                    SemanticType::Int =>
                        _serde::Serializer::serialize_unit_variant(__serializer,
                            "SemanticType", 1u32, "Int"),
                    SemanticType::Float =>
                        _serde::Serializer::serialize_unit_variant(__serializer,
                            "SemanticType", 2u32, "Float"),
                    SemanticType::String =>
                        _serde::Serializer::serialize_unit_variant(__serializer,
                            "SemanticType", 3u32, "String"),
                    SemanticType::Object =>
                        _serde::Serializer::serialize_unit_variant(__serializer,
                            "SemanticType", 4u32, "Object"),
                    SemanticType::Action =>
                        _serde::Serializer::serialize_unit_variant(__serializer,
                            "SemanticType", 5u32, "Action"),
                    SemanticType::Vector =>
                        _serde::Serializer::serialize_unit_variant(__serializer,
                            "SemanticType", 6u32, "Vector"),
                    SemanticType::Struct(ref __field0) =>
                        _serde::Serializer::serialize_newtype_variant(__serializer,
                            "SemanticType", 7u32, "Struct", __field0),
                    SemanticType::EngineStructure(ref __field0) =>
                        _serde::Serializer::serialize_newtype_variant(__serializer,
                            "SemanticType", 8u32, "EngineStructure", __field0),
                }
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for SemanticType {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field {
                    __field0,
                    __field1,
                    __field2,
                    __field3,
                    __field4,
                    __field5,
                    __field6,
                    __field7,
                    __field8,
                }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "variant identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            2u64 => _serde::__private228::Ok(__Field::__field2),
                            3u64 => _serde::__private228::Ok(__Field::__field3),
                            4u64 => _serde::__private228::Ok(__Field::__field4),
                            5u64 => _serde::__private228::Ok(__Field::__field5),
                            6u64 => _serde::__private228::Ok(__Field::__field6),
                            7u64 => _serde::__private228::Ok(__Field::__field7),
                            8u64 => _serde::__private228::Ok(__Field::__field8),
                            _ =>
                                _serde::__private228::Err(_serde::de::Error::invalid_value(_serde::de::Unexpected::Unsigned(__value),
                                        &"variant index 0 <= i < 9")),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "Void" => _serde::__private228::Ok(__Field::__field0),
                            "Int" => _serde::__private228::Ok(__Field::__field1),
                            "Float" => _serde::__private228::Ok(__Field::__field2),
                            "String" => _serde::__private228::Ok(__Field::__field3),
                            "Object" => _serde::__private228::Ok(__Field::__field4),
                            "Action" => _serde::__private228::Ok(__Field::__field5),
                            "Vector" => _serde::__private228::Ok(__Field::__field6),
                            "Struct" => _serde::__private228::Ok(__Field::__field7),
                            "EngineStructure" =>
                                _serde::__private228::Ok(__Field::__field8),
                            _ => {
                                _serde::__private228::Err(_serde::de::Error::unknown_variant(__value,
                                        VARIANTS))
                            }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"Void" => _serde::__private228::Ok(__Field::__field0),
                            b"Int" => _serde::__private228::Ok(__Field::__field1),
                            b"Float" => _serde::__private228::Ok(__Field::__field2),
                            b"String" => _serde::__private228::Ok(__Field::__field3),
                            b"Object" => _serde::__private228::Ok(__Field::__field4),
                            b"Action" => _serde::__private228::Ok(__Field::__field5),
                            b"Vector" => _serde::__private228::Ok(__Field::__field6),
                            b"Struct" => _serde::__private228::Ok(__Field::__field7),
                            b"EngineStructure" =>
                                _serde::__private228::Ok(__Field::__field8),
                            _ => {
                                let __value =
                                    &_serde::__private228::from_utf8_lossy(__value);
                                _serde::__private228::Err(_serde::de::Error::unknown_variant(__value,
                                        VARIANTS))
                            }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<SemanticType>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = SemanticType;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "enum SemanticType")
                    }
                    fn visit_enum<__A>(self, __data: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::EnumAccess<'de> {
                        match _serde::de::EnumAccess::variant(__data)? {
                            (__Field::__field0, __variant) => {
                                _serde::de::VariantAccess::unit_variant(__variant)?;
                                _serde::__private228::Ok(SemanticType::Void)
                            }
                            (__Field::__field1, __variant) => {
                                _serde::de::VariantAccess::unit_variant(__variant)?;
                                _serde::__private228::Ok(SemanticType::Int)
                            }
                            (__Field::__field2, __variant) => {
                                _serde::de::VariantAccess::unit_variant(__variant)?;
                                _serde::__private228::Ok(SemanticType::Float)
                            }
                            (__Field::__field3, __variant) => {
                                _serde::de::VariantAccess::unit_variant(__variant)?;
                                _serde::__private228::Ok(SemanticType::String)
                            }
                            (__Field::__field4, __variant) => {
                                _serde::de::VariantAccess::unit_variant(__variant)?;
                                _serde::__private228::Ok(SemanticType::Object)
                            }
                            (__Field::__field5, __variant) => {
                                _serde::de::VariantAccess::unit_variant(__variant)?;
                                _serde::__private228::Ok(SemanticType::Action)
                            }
                            (__Field::__field6, __variant) => {
                                _serde::de::VariantAccess::unit_variant(__variant)?;
                                _serde::__private228::Ok(SemanticType::Vector)
                            }
                            (__Field::__field7, __variant) =>
                                _serde::__private228::Result::map(_serde::de::VariantAccess::newtype_variant::<String>(__variant),
                                    SemanticType::Struct),
                            (__Field::__field8, __variant) =>
                                _serde::__private228::Result::map(_serde::de::VariantAccess::newtype_variant::<String>(__variant),
                                    SemanticType::EngineStructure),
                        }
                    }
                }
                #[doc(hidden)]
                const VARIANTS: &'static [&'static str] =
                    &["Void", "Int", "Float", "String", "Object", "Action",
                                "Vector", "Struct", "EngineStructure"];
                _serde::Deserializer::deserialize_enum(__deserializer,
                    "SemanticType", VARIANTS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<SemanticType>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize)]
57pub enum SemanticType {
58    /// `void`
59    Void,
60    /// `int`
61    Int,
62    /// `float`
63    Float,
64    /// `string`
65    String,
66    /// `object`
67    Object,
68    /// `action`
69    Action,
70    /// `vector`
71    Vector,
72    /// One user-defined structure.
73    Struct(String),
74    /// One engine-defined structure such as `effect` or `json`.
75    EngineStructure(String),
76}
77
78/// One resolved function parameter.
79#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SemanticParameter {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f,
            "SemanticParameter", "name", &self.name, "ty", &self.ty,
            "is_optional", &self.is_optional, "default", &&self.default)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SemanticParameter {
    #[inline]
    fn clone(&self) -> SemanticParameter {
        SemanticParameter {
            name: ::core::clone::Clone::clone(&self.name),
            ty: ::core::clone::Clone::clone(&self.ty),
            is_optional: ::core::clone::Clone::clone(&self.is_optional),
            default: ::core::clone::Clone::clone(&self.default),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for SemanticParameter {
    #[inline]
    fn eq(&self, other: &SemanticParameter) -> bool {
        self.is_optional == other.is_optional && self.name == other.name &&
                self.ty == other.ty && self.default == other.default
    }
}PartialEq, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for SemanticParameter {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                let mut __serde_state =
                    _serde::Serializer::serialize_struct(__serializer,
                            "SemanticParameter", false as usize + 1 + 1 + 1 + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "name", &self.name)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "ty", &self.ty)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "is_optional", &self.is_optional)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "default", &self.default)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for SemanticParameter {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field {
                    __field0,
                    __field1,
                    __field2,
                    __field3,
                    __ignore,
                }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            2u64 => _serde::__private228::Ok(__Field::__field2),
                            3u64 => _serde::__private228::Ok(__Field::__field3),
                            _ => _serde::__private228::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "name" => _serde::__private228::Ok(__Field::__field0),
                            "ty" => _serde::__private228::Ok(__Field::__field1),
                            "is_optional" =>
                                _serde::__private228::Ok(__Field::__field2),
                            "default" => _serde::__private228::Ok(__Field::__field3),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"name" => _serde::__private228::Ok(__Field::__field0),
                            b"ty" => _serde::__private228::Ok(__Field::__field1),
                            b"is_optional" =>
                                _serde::__private228::Ok(__Field::__field2),
                            b"default" => _serde::__private228::Ok(__Field::__field3),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<SemanticParameter>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = SemanticParameter;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct SemanticParameter")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<String>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct SemanticParameter with 4 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<SemanticType>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct SemanticParameter with 4 elements")),
                            };
                        let __field2 =
                            match _serde::de::SeqAccess::next_element::<bool>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(2usize,
                                                &"struct SemanticParameter with 4 elements")),
                            };
                        let __field3 =
                            match _serde::de::SeqAccess::next_element::<Option<Literal>>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(3usize,
                                                &"struct SemanticParameter with 4 elements")),
                            };
                        _serde::__private228::Ok(SemanticParameter {
                                name: __field0,
                                ty: __field1,
                                is_optional: __field2,
                                default: __field3,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0: _serde::__private228::Option<String> =
                            _serde::__private228::None;
                        let mut __field1:
                                _serde::__private228::Option<SemanticType> =
                            _serde::__private228::None;
                        let mut __field2: _serde::__private228::Option<bool> =
                            _serde::__private228::None;
                        let mut __field3:
                                _serde::__private228::Option<Option<Literal>> =
                            _serde::__private228::None;
                        while let _serde::__private228::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private228::Option::is_some(&__field0) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("name"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<String>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private228::Option::is_some(&__field1) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("ty"));
                                    }
                                    __field1 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<SemanticType>(&mut __map)?);
                                }
                                __Field::__field2 => {
                                    if _serde::__private228::Option::is_some(&__field2) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("is_optional"));
                                    }
                                    __field2 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<bool>(&mut __map)?);
                                }
                                __Field::__field3 => {
                                    if _serde::__private228::Option::is_some(&__field3) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("default"));
                                    }
                                    __field3 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<Option<Literal>>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private228::Some(__field0) => __field0,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("name")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private228::Some(__field1) => __field1,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("ty")?,
                            };
                        let __field2 =
                            match __field2 {
                                _serde::__private228::Some(__field2) => __field2,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("is_optional")?,
                            };
                        let __field3 =
                            match __field3 {
                                _serde::__private228::Some(__field3) => __field3,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("default")?,
                            };
                        _serde::__private228::Ok(SemanticParameter {
                                name: __field0,
                                ty: __field1,
                                is_optional: __field2,
                                default: __field3,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] =
                    &["name", "ty", "is_optional", "default"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "SemanticParameter", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<SemanticParameter>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize)]
80pub struct SemanticParameter {
81    /// Parameter name.
82    pub name:        String,
83    /// Resolved parameter type.
84    pub ty:          SemanticType,
85    /// Whether the parameter has a default value.
86    pub is_optional: bool,
87    /// Folded default value for omitted trailing arguments.
88    pub default:     Option<Literal>,
89}
90
91/// One resolved function signature.
92#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SemanticFunction {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field5_finish(f,
            "SemanticFunction", "name", &self.name, "return_type",
            &self.return_type, "parameters", &self.parameters, "has_body",
            &self.has_body, "is_builtin", &&self.is_builtin)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SemanticFunction {
    #[inline]
    fn clone(&self) -> SemanticFunction {
        SemanticFunction {
            name: ::core::clone::Clone::clone(&self.name),
            return_type: ::core::clone::Clone::clone(&self.return_type),
            parameters: ::core::clone::Clone::clone(&self.parameters),
            has_body: ::core::clone::Clone::clone(&self.has_body),
            is_builtin: ::core::clone::Clone::clone(&self.is_builtin),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for SemanticFunction {
    #[inline]
    fn eq(&self, other: &SemanticFunction) -> bool {
        self.has_body == other.has_body && self.is_builtin == other.is_builtin
                    && self.name == other.name &&
                self.return_type == other.return_type &&
            self.parameters == other.parameters
    }
}PartialEq, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for SemanticFunction {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                let mut __serde_state =
                    _serde::Serializer::serialize_struct(__serializer,
                            "SemanticFunction", false as usize + 1 + 1 + 1 + 1 + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "name", &self.name)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "return_type", &self.return_type)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "parameters", &self.parameters)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "has_body", &self.has_body)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "is_builtin", &self.is_builtin)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for SemanticFunction {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field {
                    __field0,
                    __field1,
                    __field2,
                    __field3,
                    __field4,
                    __ignore,
                }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            2u64 => _serde::__private228::Ok(__Field::__field2),
                            3u64 => _serde::__private228::Ok(__Field::__field3),
                            4u64 => _serde::__private228::Ok(__Field::__field4),
                            _ => _serde::__private228::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "name" => _serde::__private228::Ok(__Field::__field0),
                            "return_type" =>
                                _serde::__private228::Ok(__Field::__field1),
                            "parameters" => _serde::__private228::Ok(__Field::__field2),
                            "has_body" => _serde::__private228::Ok(__Field::__field3),
                            "is_builtin" => _serde::__private228::Ok(__Field::__field4),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"name" => _serde::__private228::Ok(__Field::__field0),
                            b"return_type" =>
                                _serde::__private228::Ok(__Field::__field1),
                            b"parameters" =>
                                _serde::__private228::Ok(__Field::__field2),
                            b"has_body" => _serde::__private228::Ok(__Field::__field3),
                            b"is_builtin" =>
                                _serde::__private228::Ok(__Field::__field4),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<SemanticFunction>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = SemanticFunction;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct SemanticFunction")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<String>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct SemanticFunction with 5 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<SemanticType>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct SemanticFunction with 5 elements")),
                            };
                        let __field2 =
                            match _serde::de::SeqAccess::next_element::<Vec<SemanticParameter>>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(2usize,
                                                &"struct SemanticFunction with 5 elements")),
                            };
                        let __field3 =
                            match _serde::de::SeqAccess::next_element::<bool>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(3usize,
                                                &"struct SemanticFunction with 5 elements")),
                            };
                        let __field4 =
                            match _serde::de::SeqAccess::next_element::<bool>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(4usize,
                                                &"struct SemanticFunction with 5 elements")),
                            };
                        _serde::__private228::Ok(SemanticFunction {
                                name: __field0,
                                return_type: __field1,
                                parameters: __field2,
                                has_body: __field3,
                                is_builtin: __field4,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0: _serde::__private228::Option<String> =
                            _serde::__private228::None;
                        let mut __field1:
                                _serde::__private228::Option<SemanticType> =
                            _serde::__private228::None;
                        let mut __field2:
                                _serde::__private228::Option<Vec<SemanticParameter>> =
                            _serde::__private228::None;
                        let mut __field3: _serde::__private228::Option<bool> =
                            _serde::__private228::None;
                        let mut __field4: _serde::__private228::Option<bool> =
                            _serde::__private228::None;
                        while let _serde::__private228::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private228::Option::is_some(&__field0) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("name"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<String>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private228::Option::is_some(&__field1) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("return_type"));
                                    }
                                    __field1 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<SemanticType>(&mut __map)?);
                                }
                                __Field::__field2 => {
                                    if _serde::__private228::Option::is_some(&__field2) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("parameters"));
                                    }
                                    __field2 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<Vec<SemanticParameter>>(&mut __map)?);
                                }
                                __Field::__field3 => {
                                    if _serde::__private228::Option::is_some(&__field3) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("has_body"));
                                    }
                                    __field3 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<bool>(&mut __map)?);
                                }
                                __Field::__field4 => {
                                    if _serde::__private228::Option::is_some(&__field4) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("is_builtin"));
                                    }
                                    __field4 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<bool>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private228::Some(__field0) => __field0,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("name")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private228::Some(__field1) => __field1,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("return_type")?,
                            };
                        let __field2 =
                            match __field2 {
                                _serde::__private228::Some(__field2) => __field2,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("parameters")?,
                            };
                        let __field3 =
                            match __field3 {
                                _serde::__private228::Some(__field3) => __field3,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("has_body")?,
                            };
                        let __field4 =
                            match __field4 {
                                _serde::__private228::Some(__field4) => __field4,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("is_builtin")?,
                            };
                        _serde::__private228::Ok(SemanticFunction {
                                name: __field0,
                                return_type: __field1,
                                parameters: __field2,
                                has_body: __field3,
                                is_builtin: __field4,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] =
                    &["name", "return_type", "parameters", "has_body",
                                "is_builtin"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "SemanticFunction", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<SemanticFunction>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize)]
93pub struct SemanticFunction {
94    /// Function name.
95    pub name:        String,
96    /// Resolved return type.
97    pub return_type: SemanticType,
98    /// Parameters in declaration order.
99    pub parameters:  Vec<SemanticParameter>,
100    /// Whether this function has a body in the current script.
101    pub has_body:    bool,
102    /// Whether this function came from `nwscript.nss`.
103    pub is_builtin:  bool,
104}
105
106/// One resolved global variable.
107#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SemanticGlobal {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f,
            "SemanticGlobal", "name", &self.name, "ty", &self.ty, "is_const",
            &&self.is_const)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SemanticGlobal {
    #[inline]
    fn clone(&self) -> SemanticGlobal {
        SemanticGlobal {
            name: ::core::clone::Clone::clone(&self.name),
            ty: ::core::clone::Clone::clone(&self.ty),
            is_const: ::core::clone::Clone::clone(&self.is_const),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for SemanticGlobal {
    #[inline]
    fn eq(&self, other: &SemanticGlobal) -> bool {
        self.is_const == other.is_const && self.name == other.name &&
            self.ty == other.ty
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SemanticGlobal {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<String>;
        let _: ::core::cmp::AssertParamIsEq<SemanticType>;
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for SemanticGlobal {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                let mut __serde_state =
                    _serde::Serializer::serialize_struct(__serializer,
                            "SemanticGlobal", false as usize + 1 + 1 + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "name", &self.name)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "ty", &self.ty)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "is_const", &self.is_const)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for SemanticGlobal {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field { __field0, __field1, __field2, __ignore, }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            2u64 => _serde::__private228::Ok(__Field::__field2),
                            _ => _serde::__private228::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "name" => _serde::__private228::Ok(__Field::__field0),
                            "ty" => _serde::__private228::Ok(__Field::__field1),
                            "is_const" => _serde::__private228::Ok(__Field::__field2),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"name" => _serde::__private228::Ok(__Field::__field0),
                            b"ty" => _serde::__private228::Ok(__Field::__field1),
                            b"is_const" => _serde::__private228::Ok(__Field::__field2),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<SemanticGlobal>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = SemanticGlobal;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct SemanticGlobal")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<String>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct SemanticGlobal with 3 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<SemanticType>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct SemanticGlobal with 3 elements")),
                            };
                        let __field2 =
                            match _serde::de::SeqAccess::next_element::<bool>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(2usize,
                                                &"struct SemanticGlobal with 3 elements")),
                            };
                        _serde::__private228::Ok(SemanticGlobal {
                                name: __field0,
                                ty: __field1,
                                is_const: __field2,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0: _serde::__private228::Option<String> =
                            _serde::__private228::None;
                        let mut __field1:
                                _serde::__private228::Option<SemanticType> =
                            _serde::__private228::None;
                        let mut __field2: _serde::__private228::Option<bool> =
                            _serde::__private228::None;
                        while let _serde::__private228::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private228::Option::is_some(&__field0) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("name"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<String>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private228::Option::is_some(&__field1) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("ty"));
                                    }
                                    __field1 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<SemanticType>(&mut __map)?);
                                }
                                __Field::__field2 => {
                                    if _serde::__private228::Option::is_some(&__field2) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("is_const"));
                                    }
                                    __field2 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<bool>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private228::Some(__field0) => __field0,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("name")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private228::Some(__field1) => __field1,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("ty")?,
                            };
                        let __field2 =
                            match __field2 {
                                _serde::__private228::Some(__field2) => __field2,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("is_const")?,
                            };
                        _serde::__private228::Ok(SemanticGlobal {
                                name: __field0,
                                ty: __field1,
                                is_const: __field2,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] =
                    &["name", "ty", "is_const"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "SemanticGlobal", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<SemanticGlobal>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize)]
108pub struct SemanticGlobal {
109    /// Variable name.
110    pub name:     String,
111    /// Resolved type.
112    pub ty:       SemanticType,
113    /// Whether the declaration used `const`.
114    pub is_const: bool,
115}
116
117/// One resolved structure field.
118#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SemanticField {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "SemanticField",
            "name", &self.name, "ty", &&self.ty)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SemanticField {
    #[inline]
    fn clone(&self) -> SemanticField {
        SemanticField {
            name: ::core::clone::Clone::clone(&self.name),
            ty: ::core::clone::Clone::clone(&self.ty),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for SemanticField {
    #[inline]
    fn eq(&self, other: &SemanticField) -> bool {
        self.name == other.name && self.ty == other.ty
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SemanticField {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<String>;
        let _: ::core::cmp::AssertParamIsEq<SemanticType>;
    }
}Eq, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for SemanticField {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                let mut __serde_state =
                    _serde::Serializer::serialize_struct(__serializer,
                            "SemanticField", false as usize + 1 + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "name", &self.name)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "ty", &self.ty)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for SemanticField {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field { __field0, __field1, __ignore, }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            _ => _serde::__private228::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "name" => _serde::__private228::Ok(__Field::__field0),
                            "ty" => _serde::__private228::Ok(__Field::__field1),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"name" => _serde::__private228::Ok(__Field::__field0),
                            b"ty" => _serde::__private228::Ok(__Field::__field1),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<SemanticField>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = SemanticField;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct SemanticField")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<String>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct SemanticField with 2 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<SemanticType>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct SemanticField with 2 elements")),
                            };
                        _serde::__private228::Ok(SemanticField {
                                name: __field0,
                                ty: __field1,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0: _serde::__private228::Option<String> =
                            _serde::__private228::None;
                        let mut __field1:
                                _serde::__private228::Option<SemanticType> =
                            _serde::__private228::None;
                        while let _serde::__private228::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private228::Option::is_some(&__field0) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("name"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<String>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private228::Option::is_some(&__field1) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("ty"));
                                    }
                                    __field1 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<SemanticType>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private228::Some(__field0) => __field0,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("name")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private228::Some(__field1) => __field1,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("ty")?,
                            };
                        _serde::__private228::Ok(SemanticField {
                                name: __field0,
                                ty: __field1,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] = &["name", "ty"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "SemanticField", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<SemanticField>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize)]
119pub struct SemanticField {
120    /// Field name.
121    pub name: String,
122    /// Resolved field type.
123    pub ty:   SemanticType,
124}
125
126/// One resolved user-defined structure.
127#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SemanticStruct {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "SemanticStruct", "name", &self.name, "fields", &&self.fields)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SemanticStruct {
    #[inline]
    fn clone(&self) -> SemanticStruct {
        SemanticStruct {
            name: ::core::clone::Clone::clone(&self.name),
            fields: ::core::clone::Clone::clone(&self.fields),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for SemanticStruct {
    #[inline]
    fn eq(&self, other: &SemanticStruct) -> bool {
        self.name == other.name && self.fields == other.fields
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SemanticStruct {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<String>;
        let _: ::core::cmp::AssertParamIsEq<Vec<SemanticField>>;
    }
}Eq, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for SemanticStruct {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                let mut __serde_state =
                    _serde::Serializer::serialize_struct(__serializer,
                            "SemanticStruct", false as usize + 1 + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "name", &self.name)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "fields", &self.fields)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for SemanticStruct {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field { __field0, __field1, __ignore, }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            _ => _serde::__private228::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "name" => _serde::__private228::Ok(__Field::__field0),
                            "fields" => _serde::__private228::Ok(__Field::__field1),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"name" => _serde::__private228::Ok(__Field::__field0),
                            b"fields" => _serde::__private228::Ok(__Field::__field1),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<SemanticStruct>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = SemanticStruct;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct SemanticStruct")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<String>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct SemanticStruct with 2 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<Vec<SemanticField>>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct SemanticStruct with 2 elements")),
                            };
                        _serde::__private228::Ok(SemanticStruct {
                                name: __field0,
                                fields: __field1,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0: _serde::__private228::Option<String> =
                            _serde::__private228::None;
                        let mut __field1:
                                _serde::__private228::Option<Vec<SemanticField>> =
                            _serde::__private228::None;
                        while let _serde::__private228::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private228::Option::is_some(&__field0) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("name"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<String>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private228::Option::is_some(&__field1) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("fields"));
                                    }
                                    __field1 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<Vec<SemanticField>>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private228::Some(__field0) => __field0,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("name")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private228::Some(__field1) => __field1,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("fields")?,
                            };
                        _serde::__private228::Ok(SemanticStruct {
                                name: __field0,
                                fields: __field1,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] = &["name", "fields"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "SemanticStruct", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<SemanticStruct>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize)]
128pub struct SemanticStruct {
129    /// Structure name.
130    pub name:   String,
131    /// Fields in declaration order.
132    pub fields: Vec<SemanticField>,
133}
134
135/// Semantic facts collected from one script.
136#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SemanticModel {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "SemanticModel",
            "structs", &self.structs, "globals", &self.globals, "functions",
            &&self.functions)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SemanticModel {
    #[inline]
    fn clone(&self) -> SemanticModel {
        SemanticModel {
            structs: ::core::clone::Clone::clone(&self.structs),
            globals: ::core::clone::Clone::clone(&self.globals),
            functions: ::core::clone::Clone::clone(&self.functions),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for SemanticModel {
    #[inline]
    fn eq(&self, other: &SemanticModel) -> bool {
        self.structs == other.structs && self.globals == other.globals &&
            self.functions == other.functions
    }
}PartialEq, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for SemanticModel {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                let mut __serde_state =
                    _serde::Serializer::serialize_struct(__serializer,
                            "SemanticModel", false as usize + 1 + 1 + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "structs", &self.structs)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "globals", &self.globals)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "functions", &self.functions)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for SemanticModel {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field { __field0, __field1, __field2, __ignore, }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            2u64 => _serde::__private228::Ok(__Field::__field2),
                            _ => _serde::__private228::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "structs" => _serde::__private228::Ok(__Field::__field0),
                            "globals" => _serde::__private228::Ok(__Field::__field1),
                            "functions" => _serde::__private228::Ok(__Field::__field2),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"structs" => _serde::__private228::Ok(__Field::__field0),
                            b"globals" => _serde::__private228::Ok(__Field::__field1),
                            b"functions" => _serde::__private228::Ok(__Field::__field2),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<SemanticModel>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = SemanticModel;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct SemanticModel")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<BTreeMap<String,
                                            SemanticStruct>>(&mut __seq)? {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct SemanticModel with 3 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<BTreeMap<String,
                                            SemanticGlobal>>(&mut __seq)? {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct SemanticModel with 3 elements")),
                            };
                        let __field2 =
                            match _serde::de::SeqAccess::next_element::<BTreeMap<String,
                                            SemanticFunction>>(&mut __seq)? {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(2usize,
                                                &"struct SemanticModel with 3 elements")),
                            };
                        _serde::__private228::Ok(SemanticModel {
                                structs: __field0,
                                globals: __field1,
                                functions: __field2,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0:
                                _serde::__private228::Option<BTreeMap<String,
                                SemanticStruct>> = _serde::__private228::None;
                        let mut __field1:
                                _serde::__private228::Option<BTreeMap<String,
                                SemanticGlobal>> = _serde::__private228::None;
                        let mut __field2:
                                _serde::__private228::Option<BTreeMap<String,
                                SemanticFunction>> = _serde::__private228::None;
                        while let _serde::__private228::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private228::Option::is_some(&__field0) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("structs"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<BTreeMap<String,
                                                        SemanticStruct>>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private228::Option::is_some(&__field1) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("globals"));
                                    }
                                    __field1 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<BTreeMap<String,
                                                        SemanticGlobal>>(&mut __map)?);
                                }
                                __Field::__field2 => {
                                    if _serde::__private228::Option::is_some(&__field2) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("functions"));
                                    }
                                    __field2 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<BTreeMap<String,
                                                        SemanticFunction>>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private228::Some(__field0) => __field0,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("structs")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private228::Some(__field1) => __field1,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("globals")?,
                            };
                        let __field2 =
                            match __field2 {
                                _serde::__private228::Some(__field2) => __field2,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("functions")?,
                            };
                        _serde::__private228::Ok(SemanticModel {
                                structs: __field0,
                                globals: __field1,
                                functions: __field2,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] =
                    &["structs", "globals", "functions"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "SemanticModel", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<SemanticModel>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize)]
137pub struct SemanticModel {
138    /// Resolved structures indexed by name.
139    pub structs:   BTreeMap<String, SemanticStruct>,
140    /// Resolved global variables indexed by name.
141    pub globals:   BTreeMap<String, SemanticGlobal>,
142    /// Resolved functions indexed by name.
143    pub functions: BTreeMap<String, SemanticFunction>,
144}
145
146/// Performs semantic analysis on one parsed script.
147///
148/// # Errors
149///
150/// Returns [`SemanticError`] if the script contains semantic violations.
151pub fn analyze_script(
152    script: &Script,
153    langspec: Option<&LangSpec>,
154) -> Result<SemanticModel, SemanticError> {
155    analyze_script_with_options(script, langspec, SemanticOptions::default())
156}
157
158/// Performs semantic analysis on one parsed script with explicit options.
159///
160/// # Errors
161///
162/// Returns [`SemanticError`] if the script contains semantic violations.
163pub fn analyze_script_with_options(
164    script: &Script,
165    langspec: Option<&LangSpec>,
166    options: SemanticOptions,
167) -> Result<SemanticModel, SemanticError> {
168    Analyzer::new(script, langspec, options).analyze()
169}
170
171#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ConstantValue {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ConstantValue::Int(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Int",
                    &__self_0),
            ConstantValue::Float(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Float",
                    &__self_0),
            ConstantValue::String(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "String",
                    &__self_0),
            ConstantValue::ObjectId(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ObjectId", &__self_0),
            ConstantValue::ObjectSelf =>
                ::core::fmt::Formatter::write_str(f, "ObjectSelf"),
            ConstantValue::ObjectInvalid =>
                ::core::fmt::Formatter::write_str(f, "ObjectInvalid"),
            ConstantValue::LocationInvalid =>
                ::core::fmt::Formatter::write_str(f, "LocationInvalid"),
            ConstantValue::Json(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Json",
                    &__self_0),
            ConstantValue::Vector(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Vector",
                    &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for ConstantValue {
    #[inline]
    fn clone(&self) -> ConstantValue {
        match self {
            ConstantValue::Int(__self_0) =>
                ConstantValue::Int(::core::clone::Clone::clone(__self_0)),
            ConstantValue::Float(__self_0) =>
                ConstantValue::Float(::core::clone::Clone::clone(__self_0)),
            ConstantValue::String(__self_0) =>
                ConstantValue::String(::core::clone::Clone::clone(__self_0)),
            ConstantValue::ObjectId(__self_0) =>
                ConstantValue::ObjectId(::core::clone::Clone::clone(__self_0)),
            ConstantValue::ObjectSelf => ConstantValue::ObjectSelf,
            ConstantValue::ObjectInvalid => ConstantValue::ObjectInvalid,
            ConstantValue::LocationInvalid => ConstantValue::LocationInvalid,
            ConstantValue::Json(__self_0) =>
                ConstantValue::Json(::core::clone::Clone::clone(__self_0)),
            ConstantValue::Vector(__self_0) =>
                ConstantValue::Vector(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for ConstantValue {
    #[inline]
    fn eq(&self, other: &ConstantValue) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (ConstantValue::Int(__self_0), ConstantValue::Int(__arg1_0))
                    => __self_0 == __arg1_0,
                (ConstantValue::Float(__self_0),
                    ConstantValue::Float(__arg1_0)) => __self_0 == __arg1_0,
                (ConstantValue::String(__self_0),
                    ConstantValue::String(__arg1_0)) => __self_0 == __arg1_0,
                (ConstantValue::ObjectId(__self_0),
                    ConstantValue::ObjectId(__arg1_0)) => __self_0 == __arg1_0,
                (ConstantValue::Json(__self_0), ConstantValue::Json(__arg1_0))
                    => __self_0 == __arg1_0,
                (ConstantValue::Vector(__self_0),
                    ConstantValue::Vector(__arg1_0)) => __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq)]
172enum ConstantValue {
173    Int(i32),
174    Float(f32),
175    String(String),
176    ObjectId(i32),
177    ObjectSelf,
178    ObjectInvalid,
179    LocationInvalid,
180    Json(String),
181    Vector([f32; 3]),
182}
183
184impl ConstantValue {
185    fn ty(&self) -> SemanticType {
186        match self {
187            Self::Int(_) => SemanticType::Int,
188            Self::Float(_) => SemanticType::Float,
189            Self::String(_) => SemanticType::String,
190            Self::ObjectId(_) | Self::ObjectSelf | Self::ObjectInvalid => SemanticType::Object,
191            Self::LocationInvalid => SemanticType::EngineStructure("location".to_string()),
192            Self::Json(_) => SemanticType::EngineStructure("json".to_string()),
193            Self::Vector(_) => SemanticType::Vector,
194        }
195    }
196}
197
198#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ValueBinding {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ValueBinding::Variable { ty: __self_0, is_const: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "Variable", "ty", __self_0, "is_const", &__self_1),
            ValueBinding::Constant(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Constant", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for ValueBinding {
    #[inline]
    fn clone(&self) -> ValueBinding {
        match self {
            ValueBinding::Variable { ty: __self_0, is_const: __self_1 } =>
                ValueBinding::Variable {
                    ty: ::core::clone::Clone::clone(__self_0),
                    is_const: ::core::clone::Clone::clone(__self_1),
                },
            ValueBinding::Constant(__self_0) =>
                ValueBinding::Constant(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for ValueBinding {
    #[inline]
    fn eq(&self, other: &ValueBinding) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (ValueBinding::Variable { ty: __self_0, is_const: __self_1 },
                    ValueBinding::Variable { ty: __arg1_0, is_const: __arg1_1 })
                    => __self_1 == __arg1_1 && __self_0 == __arg1_0,
                (ValueBinding::Constant(__self_0),
                    ValueBinding::Constant(__arg1_0)) => __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq)]
199enum ValueBinding {
200    Variable {
201        ty:       SemanticType,
202        is_const: bool,
203    },
204    Constant(ConstantValue),
205}
206
207impl ValueBinding {
208    fn ty(&self) -> SemanticType {
209        match self {
210            Self::Variable {
211                ty, ..
212            } => ty.clone(),
213            Self::Constant(value) => value.ty(),
214        }
215    }
216
217    fn is_const(&self) -> bool {
218        match self {
219            Self::Variable {
220                is_const, ..
221            } => *is_const,
222            Self::Constant(_) => true,
223        }
224    }
225}
226
227#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ScopeBinding {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "ScopeBinding",
            "ty", &self.ty, "is_const", &&self.is_const)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for ScopeBinding {
    #[inline]
    fn clone(&self) -> ScopeBinding {
        ScopeBinding {
            ty: ::core::clone::Clone::clone(&self.ty),
            is_const: ::core::clone::Clone::clone(&self.is_const),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for ScopeBinding {
    #[inline]
    fn eq(&self, other: &ScopeBinding) -> bool {
        self.is_const == other.is_const && self.ty == other.ty
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ScopeBinding {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<SemanticType>;
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq)]
228struct ScopeBinding {
229    ty:       SemanticType,
230    is_const: bool,
231}
232
233#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FunctionInfo {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "FunctionInfo",
            "signature", &self.signature, "declaration_span",
            &&self.declaration_span)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for FunctionInfo {
    #[inline]
    fn clone(&self) -> FunctionInfo {
        FunctionInfo {
            signature: ::core::clone::Clone::clone(&self.signature),
            declaration_span: ::core::clone::Clone::clone(&self.declaration_span),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for FunctionInfo {
    #[inline]
    fn eq(&self, other: &FunctionInfo) -> bool {
        self.signature == other.signature &&
            self.declaration_span == other.declaration_span
    }
}PartialEq)]
234struct FunctionInfo {
235    signature:        SemanticFunction,
236    declaration_span: crate::Span,
237}
238
239#[derive(#[automatically_derived]
impl ::core::fmt::Debug for AnalysisContext {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "AnalysisContext", "switch_stack", &&self.switch_stack)
    }
}Debug, #[automatically_derived]
impl ::core::default::Default for AnalysisContext {
    #[inline]
    fn default() -> AnalysisContext {
        AnalysisContext { switch_stack: ::core::default::Default::default() }
    }
}Default)]
240struct AnalysisContext {
241    switch_stack: Vec<SwitchContext>,
242}
243
244#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SwitchContext {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "SwitchContext",
            "case_values", &self.case_values, "has_default",
            &self.has_default, "scope_decl_counts", &&self.scope_decl_counts)
    }
}Debug, #[automatically_derived]
impl ::core::default::Default for SwitchContext {
    #[inline]
    fn default() -> SwitchContext {
        SwitchContext {
            case_values: ::core::default::Default::default(),
            has_default: ::core::default::Default::default(),
            scope_decl_counts: ::core::default::Default::default(),
        }
    }
}Default)]
245struct SwitchContext {
246    case_values:       BTreeSet<i32>,
247    has_default:       bool,
248    scope_decl_counts: Vec<usize>,
249}
250
251impl AnalysisContext {
252    fn enter_scope(&mut self) {
253        for switch in &mut self.switch_stack {
254            switch.scope_decl_counts.push(0);
255        }
256    }
257
258    fn exit_scope(&mut self) {
259        for switch in &mut self.switch_stack {
260            switch.scope_decl_counts.pop();
261            if switch.scope_decl_counts.is_empty() {
262                switch.scope_decl_counts.push(0);
263            }
264        }
265    }
266
267    fn record_declaration(&mut self) {
268        for switch in &mut self.switch_stack {
269            if let Some(current) = switch.scope_decl_counts.last_mut() {
270                *current += 1;
271            }
272        }
273    }
274
275    fn current_switch_mut(&mut self) -> Option<&mut SwitchContext> {
276        self.switch_stack.last_mut()
277    }
278}
279
280impl SwitchContext {
281    fn has_live_declarations(&self) -> bool {
282        self.scope_decl_counts.iter().any(|count| *count > 0)
283    }
284}
285
286struct Analyzer<'a> {
287    script:            &'a Script,
288    options:           SemanticOptions,
289    builtin_constants: BTreeMap<String, ConstantValue>,
290    global_constants:  BTreeMap<String, ConstantValue>,
291    functions:         BTreeMap<String, FunctionInfo>,
292    structs:           BTreeMap<String, SemanticStruct>,
293    globals:           BTreeMap<String, SemanticGlobal>,
294}
295
296impl<'a> Analyzer<'a> {
297    fn new(script: &'a Script, langspec: Option<&LangSpec>, options: SemanticOptions) -> Self {
298        let mut builtin_constants = BTreeMap::new();
299        let mut functions = BTreeMap::new();
300
301        if let Some(langspec) = langspec {
302            for constant in &langspec.constants {
303                if let Some(value) = constant_from_builtin_value(&constant.value) {
304                    builtin_constants.insert(constant.name.clone(), value);
305                }
306            }
307
308            for function in &langspec.functions {
309                let parameters = function
310                    .parameters
311                    .iter()
312                    .map(|parameter| SemanticParameter {
313                        name:        parameter.name.clone(),
314                        ty:          semantic_type_from_builtin_type(&parameter.ty),
315                        is_optional: parameter.default.is_some(),
316                        default:     parameter
317                            .default
318                            .as_ref()
319                            .and_then(literal_from_builtin_value),
320                    })
321                    .collect::<Vec<_>>();
322
323                functions.insert(
324                    function.name.clone(),
325                    FunctionInfo {
326                        signature:        SemanticFunction {
327                            name: function.name.clone(),
328                            return_type: semantic_type_from_builtin_type(&function.return_type),
329                            parameters,
330                            has_body: false,
331                            is_builtin: true,
332                        },
333                        declaration_span: crate::Span::new(crate::SourceId::new(0), 0, 0),
334                    },
335                );
336            }
337        }
338
339        Self {
340            script,
341            options,
342            builtin_constants,
343            global_constants: BTreeMap::new(),
344            functions,
345            structs: BTreeMap::new(),
346            globals: BTreeMap::new(),
347        }
348    }
349
350    fn analyze(mut self) -> Result<SemanticModel, SemanticError> {
351        self.collect_structs()?;
352        self.collect_const_globals_for_function_defaults()?;
353        self.collect_functions()?;
354        self.collect_globals()?;
355        self.analyze_function_bodies()?;
356        self.validate_entrypoint()?;
357
358        Ok(SemanticModel {
359            structs:   self.structs,
360            globals:   self.globals,
361            functions: self
362                .functions
363                .into_iter()
364                .map(|(name, info)| (name, info.signature))
365                .collect(),
366        })
367    }
368
369    fn collect_const_globals_for_function_defaults(&mut self) -> Result<(), SemanticError> {
370        for item in &self.script.items {
371            let TopLevelItem::Global(declaration) = item else {
372                continue;
373            };
374            if !declaration.ty.is_const {
375                continue;
376            }
377
378            let ty = self.resolve_type(&declaration.ty)?;
379            for declarator in &declaration.declarators {
380                let value = if let Some(initializer) = &declarator.initializer {
381                    self.evaluate_constant_expr(initializer).ok_or_else(|| {
382                        SemanticError::new(
383                            CompilerErrorCode::InvalidValueAssignedToConstant,
384                            initializer.span,
385                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("constant {0:?} must be initialized with a constant value",
                declarator.name))
    })format!(
386                                "constant {:?} must be initialized with a constant value",
387                                declarator.name
388                            ),
389                        )
390                    })?
391                } else {
392                    default_constant_value(&ty).ok_or_else(|| {
393                        SemanticError::new(
394                            CompilerErrorCode::InvalidValueAssignedToConstant,
395                            declarator.span,
396                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("constant {0:?} type {1:?} does not support default constant initialization",
                declarator.name, ty))
    })format!(
397                                "constant {:?} type {:?} does not support default constant \
398                                 initialization",
399                                declarator.name, ty
400                            ),
401                        )
402                    })?
403                };
404                if !types_compatible(&ty, &value.ty()) {
405                    return Err(SemanticError::new(
406                        CompilerErrorCode::InvalidValueAssignedToConstant,
407                        declarator
408                            .initializer
409                            .as_ref()
410                            .map_or(declarator.span, |initializer| initializer.span),
411                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("constant {0:?} initializer does not match type {1:?}",
                declarator.name, ty))
    })format!(
412                            "constant {:?} initializer does not match type {:?}",
413                            declarator.name, ty
414                        ),
415                    ));
416                }
417
418                self.global_constants.insert(declarator.name.clone(), value);
419            }
420        }
421
422        Ok(())
423    }
424
425    fn collect_structs(&mut self) -> Result<(), SemanticError> {
426        for item in &self.script.items {
427            let TopLevelItem::Struct(definition) = item else {
428                continue;
429            };
430
431            if self.structs.contains_key(&definition.name) {
432                return Err(SemanticError::new(
433                    CompilerErrorCode::StructureRedefined,
434                    definition.span,
435                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("structure {0:?} was defined more than once",
                definition.name))
    })format!("structure {:?} was defined more than once", definition.name),
436                ));
437            }
438
439            let mut fields = Vec::new();
440            let mut seen_names = BTreeMap::<String, crate::Span>::new();
441            for declaration in &definition.fields {
442                let field_type = self.resolve_type(&declaration.ty)?;
443                for field in &declaration.names {
444                    if seen_names.contains_key(&field.name) {
445                        return Err(SemanticError::new(
446                            CompilerErrorCode::VariableUsedTwiceInSameStructure,
447                            field.span,
448                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("field {0:?} was used twice in structure {1:?}",
                field.name, definition.name))
    })format!(
449                                "field {:?} was used twice in structure {:?}",
450                                field.name, definition.name
451                            ),
452                        ));
453                    }
454                    seen_names.insert(field.name.clone(), field.span);
455                    fields.push(SemanticField {
456                        name: field.name.clone(),
457                        ty:   field_type.clone(),
458                    });
459                }
460            }
461
462            self.structs.insert(
463                definition.name.clone(),
464                SemanticStruct {
465                    name: definition.name.clone(),
466                    fields,
467                },
468            );
469        }
470
471        Ok(())
472    }
473
474    fn collect_functions(&mut self) -> Result<(), SemanticError> {
475        for item in &self.script.items {
476            let TopLevelItem::Function(function) = item else {
477                continue;
478            };
479
480            let signature = self.resolve_function_signature(function)?;
481            if let Some(existing) = self.functions.get_mut(&function.name) {
482                if existing.signature.is_builtin {
483                    return Err(SemanticError::new(
484                        CompilerErrorCode::FunctionImplementationAndDefinitionDiffer,
485                        function.span,
486                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("function {0:?} conflicts with builtin declaration",
                function.name))
    })format!(
487                            "function {:?} conflicts with builtin declaration",
488                            function.name
489                        ),
490                    ));
491                }
492
493                if existing.signature.return_type != signature.return_type
494                    || !parameters_match(&existing.signature.parameters, &signature.parameters)
495                {
496                    return Err(SemanticError::new(
497                        CompilerErrorCode::FunctionImplementationAndDefinitionDiffer,
498                        function.span,
499                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("function {0:?} declaration differs from previous declaration",
                function.name))
    })format!(
500                            "function {:?} declaration differs from previous declaration",
501                            function.name
502                        ),
503                    ));
504                }
505
506                for (existing_parameter, new_parameter) in existing
507                    .signature
508                    .parameters
509                    .iter_mut()
510                    .zip(&signature.parameters)
511                {
512                    if existing_parameter.default.is_none() && new_parameter.default.is_some() {
513                        existing_parameter
514                            .default
515                            .clone_from(&new_parameter.default);
516                        existing_parameter.is_optional = true;
517                    }
518                }
519
520                if function.body.is_some() {
521                    if existing.signature.has_body {
522                        return Err(SemanticError::new(
523                            CompilerErrorCode::DuplicateFunctionImplementation,
524                            function.span,
525                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("function {0:?} was implemented more than once",
                function.name))
    })format!(
526                                "function {:?} was implemented more than once",
527                                function.name
528                            ),
529                        ));
530                    }
531                    existing.signature.has_body = true;
532                }
533                continue;
534            }
535
536            self.functions.insert(
537                function.name.clone(),
538                FunctionInfo {
539                    declaration_span: function.span,
540                    signature,
541                },
542            );
543        }
544
545        Ok(())
546    }
547
548    fn collect_globals(&mut self) -> Result<(), SemanticError> {
549        for item in &self.script.items {
550            let TopLevelItem::Global(declaration) = item else {
551                continue;
552            };
553
554            let ty = self.resolve_type(&declaration.ty)?;
555            for declarator in &declaration.declarators {
556                if self.globals.contains_key(&declarator.name) {
557                    return Err(SemanticError::new(
558                        CompilerErrorCode::VariableAlreadyUsedWithinScope,
559                        declarator.span,
560                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("global {0:?} was declared more than once",
                declarator.name))
    })format!("global {:?} was declared more than once", declarator.name),
561                    ));
562                }
563
564                if declaration.ty.is_const {
565                    let value = if let Some(initializer) = &declarator.initializer {
566                        self.evaluate_constant_expr(initializer).ok_or_else(|| {
567                            SemanticError::new(
568                                CompilerErrorCode::InvalidValueAssignedToConstant,
569                                initializer.span,
570                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("constant {0:?} must be initialized with a constant value",
                declarator.name))
    })format!(
571                                    "constant {:?} must be initialized with a constant value",
572                                    declarator.name
573                                ),
574                            )
575                        })?
576                    } else {
577                        default_constant_value(&ty).ok_or_else(|| {
578                            SemanticError::new(
579                                CompilerErrorCode::InvalidValueAssignedToConstant,
580                                declarator.span,
581                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("constant {0:?} type {1:?} does not support default constant initialization",
                declarator.name, ty))
    })format!(
582                                    "constant {:?} type {:?} does not support default constant \
583                                     initialization",
584                                    declarator.name, ty
585                                ),
586                            )
587                        })?
588                    };
589                    if !types_compatible(&ty, &value.ty()) {
590                        return Err(SemanticError::new(
591                            CompilerErrorCode::InvalidValueAssignedToConstant,
592                            declarator
593                                .initializer
594                                .as_ref()
595                                .map_or(declarator.span, |initializer| initializer.span),
596                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("constant {0:?} initializer does not match type {1:?}",
                declarator.name, ty))
    })format!(
597                                "constant {:?} initializer does not match type {:?}",
598                                declarator.name, ty
599                            ),
600                        ));
601                    }
602
603                    self.global_constants
604                        .insert(declarator.name.clone(), value.clone());
605                } else if let Some(initializer) = &declarator.initializer {
606                    let initializer_type = self
607                        .analyze_expr(initializer, &mut Vec::new())
608                        .map(|resolved| resolved.ty)?;
609                    if !types_compatible(&ty, &initializer_type) {
610                        return Err(SemanticError::new(
611                            CompilerErrorCode::MismatchedTypes,
612                            initializer.span,
613                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("initializer for global {0:?} has type {1:?}, expected {2:?}",
                declarator.name, initializer_type, ty))
    })format!(
614                                "initializer for global {:?} has type {:?}, expected {:?}",
615                                declarator.name, initializer_type, ty
616                            ),
617                        ));
618                    }
619                }
620
621                self.globals.insert(
622                    declarator.name.clone(),
623                    SemanticGlobal {
624                        name:     declarator.name.clone(),
625                        ty:       ty.clone(),
626                        is_const: declaration.ty.is_const,
627                    },
628                );
629            }
630        }
631
632        Ok(())
633    }
634
635    fn analyze_function_bodies(&self) -> Result<(), SemanticError> {
636        for item in &self.script.items {
637            let TopLevelItem::Function(function) = item else {
638                continue;
639            };
640            let Some(body) = &function.body else {
641                continue;
642            };
643
644            let info = self.functions.get(&function.name).ok_or_else(|| {
645                SemanticError::new(
646                    CompilerErrorCode::UnknownStateInCompiler,
647                    function.span,
648                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("function {0:?} missing from semantic table",
                function.name))
    })format!("function {:?} missing from semantic table", function.name),
649                )
650            })?;
651            let mut scopes = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [BTreeMap::new(), BTreeMap::new()]))vec![BTreeMap::new(), BTreeMap::new()];
652            for (signature_parameter, source_parameter) in
653                info.signature.parameters.iter().zip(&function.parameters)
654            {
655                let (parameter_scope, _) = scopes.split_at_mut(1);
656                insert_scope_binding(
657                    parameter_scope,
658                    &source_parameter.name,
659                    signature_parameter.ty.clone(),
660                    false,
661                    source_parameter.span,
662                )?;
663            }
664
665            let mut context = AnalysisContext::default();
666            self.analyze_block(
667                body,
668                &mut scopes,
669                &info.signature.return_type,
670                true,
671                &mut context,
672            )?;
673
674            if info.signature.return_type != SemanticType::Void
675                && !statement_guarantees_return(&Stmt::Block(body.clone()))
676            {
677                return Err(SemanticError::new(
678                    CompilerErrorCode::NotAllControlPathsReturnAValue,
679                    function.span,
680                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("function {0:?} does not return a value on all control paths",
                function.name))
    })format!(
681                        "function {:?} does not return a value on all control paths",
682                        function.name
683                    ),
684                ));
685            }
686        }
687
688        Ok(())
689    }
690
691    fn analyze_block(
692        &self,
693        block: &BlockStmt,
694        scopes: &mut Vec<BTreeMap<String, ScopeBinding>>,
695        return_type: &SemanticType,
696        is_function_body: bool,
697        context: &mut AnalysisContext,
698    ) -> Result<(), SemanticError> {
699        if !is_function_body {
700            scopes.push(BTreeMap::new());
701            context.enter_scope();
702        }
703
704        for statement in &block.statements {
705            self.analyze_stmt(statement, scopes, return_type, context)?;
706        }
707
708        if !is_function_body {
709            context.exit_scope();
710            scopes.pop();
711        }
712
713        Ok(())
714    }
715
716    #[allow(clippy::too_many_lines)]
717    fn analyze_stmt(
718        &self,
719        statement: &Stmt,
720        scopes: &mut Vec<BTreeMap<String, ScopeBinding>>,
721        return_type: &SemanticType,
722        context: &mut AnalysisContext,
723    ) -> Result<(), SemanticError> {
724        match statement {
725            Stmt::Block(block) => self.analyze_block(block, scopes, return_type, false, context),
726            Stmt::Declaration(declaration) => {
727                if declaration.ty.is_const {
728                    return Err(SemanticError::new(
729                        CompilerErrorCode::ConstKeywordCannotBeUsedOnNonGlobalVariables,
730                        declaration.span,
731                        "const cannot be used on non-global variables",
732                    ));
733                }
734
735                let ty = self.resolve_type(&declaration.ty)?;
736                for declarator in &declaration.declarators {
737                    if current_scope_contains(scopes, &declarator.name) {
738                        return Err(SemanticError::new(
739                            CompilerErrorCode::VariableAlreadyUsedWithinScope,
740                            declarator.span,
741                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("variable {0:?} was already declared in this scope",
                declarator.name))
    })format!(
742                                "variable {:?} was already declared in this scope",
743                                declarator.name
744                            ),
745                        ));
746                    }
747
748                    if let Some(initializer) = &declarator.initializer {
749                        let initializer_type = self.analyze_expr(initializer, scopes)?.ty;
750                        if !types_compatible(&ty, &initializer_type) {
751                            return Err(SemanticError::new(
752                                CompilerErrorCode::MismatchedTypes,
753                                initializer.span,
754                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("initializer for {0:?} has type {1:?}, expected {2:?}",
                declarator.name, initializer_type, ty))
    })format!(
755                                    "initializer for {:?} has type {:?}, expected {:?}",
756                                    declarator.name, initializer_type, ty
757                                ),
758                            ));
759                        }
760                    }
761
762                    let Some(scope) = scopes.last_mut() else {
763                        return Err(SemanticError::new(
764                            CompilerErrorCode::UnknownStateInCompiler,
765                            declarator.span,
766                            "scope stack must be non-empty",
767                        ));
768                    };
769                    scope.insert(
770                        declarator.name.clone(),
771                        ScopeBinding {
772                            ty:       ty.clone(),
773                            is_const: false,
774                        },
775                    );
776                }
777                context.record_declaration();
778                Ok(())
779            }
780            Stmt::Expression(statement) => {
781                self.analyze_expr(&statement.expr, scopes)?;
782                Ok(())
783            }
784            Stmt::If(statement) => {
785                let condition = self.analyze_expr(&statement.condition, scopes)?;
786                if condition.ty != SemanticType::Int {
787                    return Err(SemanticError::new(
788                        CompilerErrorCode::NonIntegerExpressionWhereIntegerRequired,
789                        statement.condition.span,
790                        "if condition must evaluate to int",
791                    ));
792                }
793                self.analyze_stmt(&statement.then_branch, scopes, return_type, context)?;
794                if let Some(branch) = &statement.else_branch {
795                    self.analyze_stmt(branch, scopes, return_type, context)?;
796                }
797                Ok(())
798            }
799            Stmt::Switch(statement) => {
800                let condition = self.analyze_expr(&statement.condition, scopes)?;
801                if condition.ty != SemanticType::Int {
802                    return Err(SemanticError::new(
803                        CompilerErrorCode::SwitchMustEvaluateToAnInteger,
804                        statement.condition.span,
805                        "switch condition must evaluate to int",
806                    ));
807                }
808                context.switch_stack.push(SwitchContext {
809                    case_values:       BTreeSet::new(),
810                    has_default:       false,
811                    scope_decl_counts: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [0]))vec![0],
812                });
813                let result = self.analyze_stmt(&statement.body, scopes, return_type, context);
814                context.switch_stack.pop();
815                result
816            }
817            Stmt::Return(statement) => match (&statement.value, return_type) {
818                (None, SemanticType::Void) => Ok(()),
819                (Some(value), SemanticType::Void) => Err(SemanticError::new(
820                    CompilerErrorCode::ReturnTypeAndFunctionTypeMismatched,
821                    value.span,
822                    "void functions cannot return a value",
823                )),
824                (None, _) => Err(SemanticError::new(
825                    CompilerErrorCode::ReturnTypeAndFunctionTypeMismatched,
826                    statement.span,
827                    "non-void functions must return a value",
828                )),
829                (Some(value), expected) => {
830                    let actual = self.analyze_expr(value, scopes)?.ty;
831                    if !types_compatible(expected, &actual) {
832                        return Err(SemanticError::new(
833                            CompilerErrorCode::ReturnTypeAndFunctionTypeMismatched,
834                            value.span,
835                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("return expression has type {0:?}, expected {1:?}",
                actual, expected))
    })format!("return expression has type {actual:?}, expected {expected:?}"),
836                        ));
837                    }
838                    Ok(())
839                }
840            },
841            Stmt::While(statement) => {
842                let condition = self.analyze_expr(&statement.condition, scopes)?;
843                if condition.ty != SemanticType::Int {
844                    return Err(SemanticError::new(
845                        CompilerErrorCode::NonIntegerExpressionWhereIntegerRequired,
846                        statement.condition.span,
847                        "while condition must evaluate to int",
848                    ));
849                }
850                self.analyze_stmt(&statement.body, scopes, return_type, context)
851            }
852            Stmt::DoWhile(statement) => {
853                self.analyze_stmt(&statement.body, scopes, return_type, context)?;
854                let condition = self.analyze_expr(&statement.condition, scopes)?;
855                if condition.ty != SemanticType::Int {
856                    return Err(SemanticError::new(
857                        CompilerErrorCode::NonIntegerExpressionWhereIntegerRequired,
858                        statement.condition.span,
859                        "do-while condition must evaluate to int",
860                    ));
861                }
862                Ok(())
863            }
864            Stmt::For(statement) => {
865                if let Some(initializer) = &statement.initializer {
866                    self.analyze_expr(initializer, scopes)?;
867                }
868                if let Some(condition) = &statement.condition {
869                    let resolved = self.analyze_expr(condition, scopes)?;
870                    if resolved.ty != SemanticType::Int {
871                        return Err(SemanticError::new(
872                            CompilerErrorCode::NonIntegerExpressionWhereIntegerRequired,
873                            condition.span,
874                            "for condition must evaluate to int",
875                        ));
876                    }
877                }
878                if let Some(update) = &statement.update {
879                    self.analyze_expr(update, scopes)?;
880                }
881                self.analyze_stmt(&statement.body, scopes, return_type, context)
882            }
883            Stmt::Case(statement) => {
884                let value = self
885                    .evaluate_switch_case_value(&statement.value)
886                    .ok_or_else(|| {
887                        SemanticError::new(
888                            CompilerErrorCode::CaseParameterNotAConstantInteger,
889                            statement.value.span,
890                            "case expression must be a constant integer or string",
891                        )
892                    })?;
893                let Some(current_switch) = context.current_switch_mut() else {
894                    return Err(SemanticError::new(
895                        CompilerErrorCode::UnknownStateInCompiler,
896                        statement.span,
897                        "case labels must appear within a switch statement",
898                    ));
899                };
900                if current_switch.has_live_declarations() {
901                    return Err(SemanticError::new(
902                        CompilerErrorCode::JumpingOverDeclarationStatementsCaseDisallowed,
903                        statement.span,
904                        "case label would jump over active declarations",
905                    ));
906                }
907                if !current_switch.case_values.insert(value) {
908                    return Err(SemanticError::new(
909                        CompilerErrorCode::MultipleCaseConstantStatementsWithinSwitch,
910                        statement.span,
911                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("case value {0:?} was used more than once in this switch",
                value))
    })format!("case value {value:?} was used more than once in this switch"),
912                    ));
913                }
914                Ok(())
915            }
916            Stmt::Default(statement) => {
917                let Some(current_switch) = context.current_switch_mut() else {
918                    return Err(SemanticError::new(
919                        CompilerErrorCode::UnknownStateInCompiler,
920                        statement.span,
921                        "default labels must appear within a switch statement",
922                    ));
923                };
924                if current_switch.has_live_declarations() {
925                    return Err(SemanticError::new(
926                        CompilerErrorCode::JumpingOverDeclarationStatementsDefaultDisallowed,
927                        statement.span,
928                        "default label would jump over active declarations",
929                    ));
930                }
931                if current_switch.has_default {
932                    return Err(SemanticError::new(
933                        CompilerErrorCode::MultipleDefaultStatementsWithinSwitch,
934                        statement.span,
935                        "default label appeared more than once in this switch",
936                    ));
937                }
938                current_switch.has_default = true;
939                Ok(())
940            }
941            Stmt::Break(_) | Stmt::Continue(_) | Stmt::Empty(_) => Ok(()),
942        }
943    }
944
945    #[allow(clippy::too_many_lines)]
946    fn analyze_expr(
947        &self,
948        expr: &Expr,
949        scopes: &mut Vec<BTreeMap<String, ScopeBinding>>,
950    ) -> Result<ResolvedExpr, SemanticError> {
951        match &expr.kind {
952            ExprKind::Literal(literal) => Ok(ResolvedExpr {
953                ty:        semantic_type_from_literal(literal),
954                is_lvalue: false,
955                is_const:  !#[allow(non_exhaustive_omitted_patterns)] match literal {
    Literal::Magic(_) => true,
    _ => false,
}matches!(literal, Literal::Magic(_)),
956            }),
957            ExprKind::Identifier(name) => {
958                let binding = self.lookup_value(name, scopes).ok_or_else(|| {
959                    SemanticError::new(
960                        CompilerErrorCode::UndefinedIdentifier,
961                        expr.span,
962                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("undefined identifier {0:?}", name))
    })format!("undefined identifier {name:?}"),
963                    )
964                })?;
965                Ok(ResolvedExpr {
966                    ty:        binding.ty(),
967                    is_lvalue: #[allow(non_exhaustive_omitted_patterns)] match binding {
    ValueBinding::Variable { .. } => true,
    _ => false,
}matches!(binding, ValueBinding::Variable { .. }),
968                    is_const:  binding.is_const(),
969                })
970            }
971            ExprKind::Call {
972                callee,
973                arguments,
974            } => {
975                let ExprKind::Identifier(name) = &callee.kind else {
976                    return Err(SemanticError::new(
977                        CompilerErrorCode::UndefinedIdentifier,
978                        callee.span,
979                        "only direct identifier calls are supported",
980                    ));
981                };
982
983                let function = self.functions.get(name).ok_or_else(|| {
984                    SemanticError::new(
985                        CompilerErrorCode::UndefinedIdentifier,
986                        callee.span,
987                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("undefined function {0:?}", name))
    })format!("undefined function {name:?}"),
988                    )
989                })?;
990
991                if arguments.len() > function.signature.parameters.len() {
992                    return Err(SemanticError::new(
993                        CompilerErrorCode::DeclarationDoesNotMatchParameters,
994                        expr.span,
995                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("call to {0:?} passed too many parameters: {1} > {2}",
                name, arguments.len(), function.signature.parameters.len()))
    })format!(
996                            "call to {:?} passed too many parameters: {} > {}",
997                            name,
998                            arguments.len(),
999                            function.signature.parameters.len()
1000                        ),
1001                    ));
1002                }
1003
1004                let non_optional = function
1005                    .signature
1006                    .parameters
1007                    .iter()
1008                    .filter(|parameter| !parameter.is_optional)
1009                    .count();
1010                if arguments.len() < non_optional {
1011                    return Err(SemanticError::new(
1012                        CompilerErrorCode::DeclarationDoesNotMatchParameters,
1013                        expr.span,
1014                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("call to {0:?} did not supply enough parameters: {1} < {2}",
                name, arguments.len(), non_optional))
    })format!(
1015                            "call to {:?} did not supply enough parameters: {} < {}",
1016                            name,
1017                            arguments.len(),
1018                            non_optional
1019                        ),
1020                    ));
1021                }
1022
1023                for (argument, parameter) in arguments.iter().zip(&function.signature.parameters) {
1024                    let resolved = self.analyze_expr(argument, scopes)?;
1025                    let is_action_argument = #[allow(non_exhaustive_omitted_patterns)] match (&parameter.ty,
        &argument.kind) {
    (SemanticType::Action, ExprKind::Call { callee: _, arguments: _ }) =>
        true,
    _ => false,
}matches!(
1026                        (&parameter.ty, &argument.kind),
1027                        (
1028                            SemanticType::Action,
1029                            ExprKind::Call {
1030                                callee:    _,
1031                                arguments: _,
1032                            }
1033                        )
1034                    ) && resolved.ty == SemanticType::Void;
1035                    if !is_action_argument && !types_compatible(&parameter.ty, &resolved.ty) {
1036                        return Err(SemanticError::new(
1037                            CompilerErrorCode::DeclarationDoesNotMatchParameters,
1038                            argument.span,
1039                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("parameter {0:?} expects {1:?}, got {2:?}",
                parameter.name, parameter.ty, resolved.ty))
    })format!(
1040                                "parameter {:?} expects {:?}, got {:?}",
1041                                parameter.name, parameter.ty, resolved.ty
1042                            ),
1043                        ));
1044                    }
1045                }
1046
1047                Ok(ResolvedExpr {
1048                    ty:        function.signature.return_type.clone(),
1049                    is_lvalue: false,
1050                    is_const:  false,
1051                })
1052            }
1053            ExprKind::FieldAccess {
1054                base,
1055                field,
1056            } => {
1057                let resolved_base = self.analyze_expr(base, scopes)?;
1058                let field_type = match &resolved_base.ty {
1059                    SemanticType::Vector => match field.as_str() {
1060                        "x" | "y" | "z" => Ok(SemanticType::Float),
1061                        _ => Err(SemanticError::new(
1062                            CompilerErrorCode::UndefinedFieldInStructure,
1063                            expr.span,
1064                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("field {0:?} does not exist on vector",
                field))
    })format!("field {field:?} does not exist on vector"),
1065                        )),
1066                    },
1067                    SemanticType::Struct(name) => self
1068                        .structs
1069                        .get(name)
1070                        .and_then(|structure| {
1071                            structure
1072                                .fields
1073                                .iter()
1074                                .find(|candidate| candidate.name == *field)
1075                                .map(|candidate| candidate.ty.clone())
1076                        })
1077                        .ok_or_else(|| {
1078                            SemanticError::new(
1079                                CompilerErrorCode::UndefinedFieldInStructure,
1080                                expr.span,
1081                                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("field {0:?} does not exist on structure {1:?}",
                field, name))
    })format!("field {field:?} does not exist on structure {name:?}"),
1082                            )
1083                        }),
1084                    _ => Err(SemanticError::new(
1085                        CompilerErrorCode::LeftOfStructurePartNotStructure,
1086                        base.span,
1087                        "left side of field access must be a structure",
1088                    )),
1089                }?;
1090
1091                Ok(ResolvedExpr {
1092                    ty:        field_type,
1093                    is_lvalue: resolved_base.is_lvalue,
1094                    is_const:  resolved_base.is_const,
1095                })
1096            }
1097            ExprKind::Unary {
1098                op,
1099                expr: inner,
1100            } => {
1101                let resolved = self.analyze_expr(inner, scopes)?;
1102                match op {
1103                    UnaryOp::Negate => match resolved.ty {
1104                        SemanticType::Int | SemanticType::Float => Ok(ResolvedExpr {
1105                            ty:        resolved.ty,
1106                            is_lvalue: false,
1107                            is_const:  resolved.is_const,
1108                        }),
1109                        _ => Err(SemanticError::new(
1110                            CompilerErrorCode::ArithmeticOperationHasInvalidOperands,
1111                            expr.span,
1112                            "negation requires an int or float operand",
1113                        )),
1114                    },
1115                    UnaryOp::OnesComplement => {
1116                        if resolved.ty != SemanticType::Int {
1117                            return Err(SemanticError::new(
1118                                CompilerErrorCode::ArithmeticOperationHasInvalidOperands,
1119                                expr.span,
1120                                "ones-complement requires an int operand",
1121                            ));
1122                        }
1123                        Ok(ResolvedExpr {
1124                            ty:        SemanticType::Int,
1125                            is_lvalue: false,
1126                            is_const:  resolved.is_const,
1127                        })
1128                    }
1129                    UnaryOp::BooleanNot => {
1130                        if resolved.ty != SemanticType::Int {
1131                            return Err(SemanticError::new(
1132                                CompilerErrorCode::LogicalOperationHasInvalidOperands,
1133                                expr.span,
1134                                "boolean-not requires an int operand",
1135                            ));
1136                        }
1137                        Ok(ResolvedExpr {
1138                            ty:        SemanticType::Int,
1139                            is_lvalue: false,
1140                            is_const:  resolved.is_const,
1141                        })
1142                    }
1143                    UnaryOp::PreIncrement
1144                    | UnaryOp::PreDecrement
1145                    | UnaryOp::PostIncrement
1146                    | UnaryOp::PostDecrement => {
1147                        if resolved.ty != SemanticType::Int || !resolved.is_lvalue {
1148                            return Err(SemanticError::new(
1149                                CompilerErrorCode::OperandMustBeAnIntegerLValue,
1150                                expr.span,
1151                                "increment and decrement require an int lvalue",
1152                            ));
1153                        }
1154                        Ok(ResolvedExpr {
1155                            ty:        SemanticType::Int,
1156                            is_lvalue: false,
1157                            is_const:  false,
1158                        })
1159                    }
1160                }
1161            }
1162            ExprKind::Binary {
1163                op,
1164                left,
1165                right,
1166            } => {
1167                let left = self.analyze_expr(left, scopes)?;
1168                let right = self.analyze_expr(right, scopes)?;
1169                let ty = Self::binary_result_type(*op, &left.ty, &right.ty, expr.span)?;
1170                Ok(ResolvedExpr {
1171                    ty,
1172                    is_lvalue: false,
1173                    is_const: left.is_const && right.is_const,
1174                })
1175            }
1176            ExprKind::Conditional {
1177                condition: _,
1178                when_true,
1179                when_false,
1180            } => {
1181                let when_true = self.analyze_expr(when_true, scopes)?;
1182                let when_false = self.analyze_expr(when_false, scopes)?;
1183                if !types_compatible(&when_true.ty, &when_false.ty) {
1184                    return Err(SemanticError::new(
1185                        CompilerErrorCode::ConditionalMustHaveMatchingReturnTypes,
1186                        expr.span,
1187                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("conditional expression branches must match: {0:?} vs {1:?}",
                when_true.ty, when_false.ty))
    })format!(
1188                            "conditional expression branches must match: {:?} vs {:?}",
1189                            when_true.ty, when_false.ty
1190                        ),
1191                    ));
1192                }
1193                Ok(ResolvedExpr {
1194                    ty:        when_true.ty,
1195                    is_lvalue: false,
1196                    is_const:  when_true.is_const && when_false.is_const,
1197                })
1198            }
1199            ExprKind::Assignment {
1200                op,
1201                left,
1202                right,
1203            } => {
1204                let left_resolved = self.analyze_expr(left, scopes)?;
1205                if !left_resolved.is_lvalue {
1206                    return Err(SemanticError::new(
1207                        CompilerErrorCode::BadLValue,
1208                        left.span,
1209                        "left side of assignment must be an lvalue",
1210                    ));
1211                }
1212                let right_resolved = self.analyze_expr(right, scopes)?;
1213                let result_type = match op {
1214                    AssignmentOp::Assign => right_resolved.ty.clone(),
1215                    AssignmentOp::AssignMinus => Self::binary_result_type(
1216                        BinaryOp::Subtract,
1217                        &left_resolved.ty,
1218                        &right_resolved.ty,
1219                        expr.span,
1220                    )?,
1221                    AssignmentOp::AssignPlus => Self::binary_result_type(
1222                        BinaryOp::Add,
1223                        &left_resolved.ty,
1224                        &right_resolved.ty,
1225                        expr.span,
1226                    )?,
1227                    AssignmentOp::AssignMultiply => Self::binary_result_type(
1228                        BinaryOp::Multiply,
1229                        &left_resolved.ty,
1230                        &right_resolved.ty,
1231                        expr.span,
1232                    )?,
1233                    AssignmentOp::AssignDivide => Self::binary_result_type(
1234                        BinaryOp::Divide,
1235                        &left_resolved.ty,
1236                        &right_resolved.ty,
1237                        expr.span,
1238                    )?,
1239                    AssignmentOp::AssignModulus => Self::binary_result_type(
1240                        BinaryOp::Modulus,
1241                        &left_resolved.ty,
1242                        &right_resolved.ty,
1243                        expr.span,
1244                    )?,
1245                    AssignmentOp::AssignAnd => Self::binary_result_type(
1246                        BinaryOp::BooleanAnd,
1247                        &left_resolved.ty,
1248                        &right_resolved.ty,
1249                        expr.span,
1250                    )?,
1251                    AssignmentOp::AssignXor => Self::binary_result_type(
1252                        BinaryOp::ExclusiveOr,
1253                        &left_resolved.ty,
1254                        &right_resolved.ty,
1255                        expr.span,
1256                    )?,
1257                    AssignmentOp::AssignOr => Self::binary_result_type(
1258                        BinaryOp::InclusiveOr,
1259                        &left_resolved.ty,
1260                        &right_resolved.ty,
1261                        expr.span,
1262                    )?,
1263                    AssignmentOp::AssignShiftLeft => Self::binary_result_type(
1264                        BinaryOp::ShiftLeft,
1265                        &left_resolved.ty,
1266                        &right_resolved.ty,
1267                        expr.span,
1268                    )?,
1269                    AssignmentOp::AssignShiftRight => Self::binary_result_type(
1270                        BinaryOp::ShiftRight,
1271                        &left_resolved.ty,
1272                        &right_resolved.ty,
1273                        expr.span,
1274                    )?,
1275                    AssignmentOp::AssignUnsignedShiftRight => Self::binary_result_type(
1276                        BinaryOp::UnsignedShiftRight,
1277                        &left_resolved.ty,
1278                        &right_resolved.ty,
1279                        expr.span,
1280                    )?,
1281                };
1282
1283                if !types_compatible(&left_resolved.ty, &result_type) {
1284                    return Err(SemanticError::new(
1285                        CompilerErrorCode::MismatchedTypes,
1286                        expr.span,
1287                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("assignment target has type {0:?}, expression has type {1:?}",
                left_resolved.ty, result_type))
    })format!(
1288                            "assignment target has type {:?}, expression has type {:?}",
1289                            left_resolved.ty, result_type
1290                        ),
1291                    ));
1292                }
1293
1294                Ok(ResolvedExpr {
1295                    ty:        left_resolved.ty,
1296                    is_lvalue: false,
1297                    is_const:  false,
1298                })
1299            }
1300        }
1301    }
1302
1303    fn binary_result_type(
1304        op: BinaryOp,
1305        left: &SemanticType,
1306        right: &SemanticType,
1307        span: crate::Span,
1308    ) -> Result<SemanticType, SemanticError> {
1309        match op {
1310            BinaryOp::LogicalAnd
1311            | BinaryOp::LogicalOr
1312            | BinaryOp::InclusiveOr
1313            | BinaryOp::ExclusiveOr
1314            | BinaryOp::BooleanAnd => {
1315                if left == &SemanticType::Int && right == &SemanticType::Int {
1316                    Ok(SemanticType::Int)
1317                } else {
1318                    Err(SemanticError::new(
1319                        CompilerErrorCode::LogicalOperationHasInvalidOperands,
1320                        span,
1321                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("logical operation requires int operands, got {0:?} and {1:?}",
                left, right))
    })format!(
1322                            "logical operation requires int operands, got {left:?} and {right:?}"
1323                        ),
1324                    ))
1325                }
1326            }
1327            BinaryOp::EqualEqual | BinaryOp::NotEqual => {
1328                if left == right
1329                    && #[allow(non_exhaustive_omitted_patterns)] match left {
    SemanticType::Int | SemanticType::Float | SemanticType::String |
        SemanticType::Object | SemanticType::Vector | SemanticType::Struct(_)
        | SemanticType::EngineStructure(_) => true,
    _ => false,
}matches!(
1330                        left,
1331                        SemanticType::Int
1332                            | SemanticType::Float
1333                            | SemanticType::String
1334                            | SemanticType::Object
1335                            | SemanticType::Vector
1336                            | SemanticType::Struct(_)
1337                            | SemanticType::EngineStructure(_)
1338                    )
1339                {
1340                    Ok(SemanticType::Int)
1341                } else {
1342                    Err(SemanticError::new(
1343                        CompilerErrorCode::EqualityTestHasInvalidOperands,
1344                        span,
1345                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("equality test requires matching operand types, got {0:?} and {1:?}",
                left, right))
    })format!(
1346                            "equality test requires matching operand types, got {left:?} and \
1347                             {right:?}"
1348                        ),
1349                    ))
1350                }
1351            }
1352            BinaryOp::GreaterEqual
1353            | BinaryOp::GreaterThan
1354            | BinaryOp::LessThan
1355            | BinaryOp::LessEqual => match (left, right) {
1356                (SemanticType::Int, SemanticType::Int)
1357                | (SemanticType::Float, SemanticType::Float) => Ok(SemanticType::Int),
1358                _ => Err(SemanticError::new(
1359                    CompilerErrorCode::ComparisonTestHasInvalidOperands,
1360                    span,
1361                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("comparison requires int/int or float/float operands, got {0:?} and {1:?}",
                left, right))
    })format!(
1362                        "comparison requires int/int or float/float operands, got {left:?} and \
1363                         {right:?}"
1364                    ),
1365                )),
1366            },
1367            BinaryOp::ShiftLeft | BinaryOp::ShiftRight | BinaryOp::UnsignedShiftRight => {
1368                if left == &SemanticType::Int && right == &SemanticType::Int {
1369                    Ok(SemanticType::Int)
1370                } else {
1371                    Err(SemanticError::new(
1372                        CompilerErrorCode::ShiftOperationHasInvalidOperands,
1373                        span,
1374                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("shift operation requires int operands, got {0:?} and {1:?}",
                left, right))
    })format!(
1375                            "shift operation requires int operands, got {left:?} and {right:?}"
1376                        ),
1377                    ))
1378                }
1379            }
1380            BinaryOp::Add | BinaryOp::Subtract | BinaryOp::Multiply | BinaryOp::Divide => {
1381                match (left, right) {
1382                    (SemanticType::Int, SemanticType::Int) => Ok(SemanticType::Int),
1383                    (SemanticType::Float, SemanticType::Int | SemanticType::Float)
1384                    | (SemanticType::Int, SemanticType::Float) => Ok(SemanticType::Float),
1385                    (SemanticType::String, SemanticType::String) if op == BinaryOp::Add => {
1386                        Ok(SemanticType::String)
1387                    }
1388                    (SemanticType::Vector, SemanticType::Vector)
1389                        if #[allow(non_exhaustive_omitted_patterns)] match op {
    BinaryOp::Add | BinaryOp::Subtract => true,
    _ => false,
}matches!(op, BinaryOp::Add | BinaryOp::Subtract) =>
1390                    {
1391                        Ok(SemanticType::Vector)
1392                    }
1393                    (SemanticType::Vector, SemanticType::Float)
1394                        if #[allow(non_exhaustive_omitted_patterns)] match op {
    BinaryOp::Multiply | BinaryOp::Divide => true,
    _ => false,
}matches!(op, BinaryOp::Multiply | BinaryOp::Divide) =>
1395                    {
1396                        Ok(SemanticType::Vector)
1397                    }
1398                    (SemanticType::Float, SemanticType::Vector) if op == BinaryOp::Multiply => {
1399                        Ok(SemanticType::Vector)
1400                    }
1401                    _ => Err(SemanticError::new(
1402                        CompilerErrorCode::ArithmeticOperationHasInvalidOperands,
1403                        span,
1404                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("arithmetic operation {0:?} is invalid for {1:?} and {2:?}",
                op, left, right))
    })format!(
1405                            "arithmetic operation {op:?} is invalid for {left:?} and {right:?}"
1406                        ),
1407                    )),
1408                }
1409            }
1410            BinaryOp::Modulus => {
1411                if left == &SemanticType::Int && right == &SemanticType::Int {
1412                    Ok(SemanticType::Int)
1413                } else {
1414                    Err(SemanticError::new(
1415                        CompilerErrorCode::ArithmeticOperationHasInvalidOperands,
1416                        span,
1417                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("modulus requires int operands, got {0:?} and {1:?}",
                left, right))
    })format!("modulus requires int operands, got {left:?} and {right:?}"),
1418                    ))
1419                }
1420            }
1421        }
1422    }
1423
1424    fn resolve_function_signature(
1425        &self,
1426        function: &FunctionDecl,
1427    ) -> Result<SemanticFunction, SemanticError> {
1428        let return_type = self.resolve_type(&function.return_type)?;
1429        let mut parameters = Vec::new();
1430        let mut optional_started = false;
1431        for parameter in &function.parameters {
1432            let parameter_type = self.resolve_type(&parameter.ty)?;
1433            let default = if let Some(default) = &parameter.default {
1434                let value = self
1435                    .evaluate_function_default_expr(default)
1436                    .ok_or_else(|| {
1437                        SemanticError::new(
1438                            CompilerErrorCode::NonConstantInFunctionDeclaration,
1439                            default.span,
1440                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("parameter {0:?} default value must be a constant",
                parameter.name))
    })format!(
1441                                "parameter {:?} default value must be a constant",
1442                                parameter.name
1443                            ),
1444                        )
1445                    })?;
1446
1447                if !type_supports_optional_parameter(&parameter_type) {
1448                    return Err(SemanticError::new(
1449                        CompilerErrorCode::TypeDoesNotHaveAnOptionalParameter,
1450                        default.span,
1451                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("type {0:?} does not support optional parameters",
                parameter_type))
    })format!("type {parameter_type:?} does not support optional parameters"),
1452                    ));
1453                }
1454                if !types_compatible(&parameter_type, &value.ty()) {
1455                    return Err(SemanticError::new(
1456                        CompilerErrorCode::NonConstantInFunctionDeclaration,
1457                        default.span,
1458                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("parameter {0:?} default type {1:?} does not match {2:?}",
                parameter.name, value.ty(), parameter_type))
    })format!(
1459                            "parameter {:?} default type {:?} does not match {:?}",
1460                            parameter.name,
1461                            value.ty(),
1462                            parameter_type
1463                        ),
1464                    ));
1465                }
1466                optional_started = true;
1467                Some(value)
1468            } else {
1469                if optional_started {
1470                    return Err(SemanticError::new(
1471                        CompilerErrorCode::NonOptionalParameterCannotFollowOptionalParameter,
1472                        parameter.span,
1473                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("parameter {0:?} cannot follow an optional parameter",
                parameter.name))
    })format!(
1474                            "parameter {:?} cannot follow an optional parameter",
1475                            parameter.name
1476                        ),
1477                    ));
1478                }
1479                None
1480            };
1481
1482            parameters.push(SemanticParameter {
1483                name:        parameter.name.clone(),
1484                ty:          parameter_type,
1485                is_optional: default.is_some(),
1486                default:     default.as_ref().map(literal_from_constant_value),
1487            });
1488        }
1489
1490        Ok(SemanticFunction {
1491            name: function.name.clone(),
1492            return_type,
1493            parameters,
1494            has_body: function.body.is_some(),
1495            is_builtin: false,
1496        })
1497    }
1498
1499    fn resolve_type(&self, ty: &TypeSpec) -> Result<SemanticType, SemanticError> {
1500        match &ty.kind {
1501            TypeKind::Void => Ok(SemanticType::Void),
1502            TypeKind::Int => Ok(SemanticType::Int),
1503            TypeKind::Float => Ok(SemanticType::Float),
1504            TypeKind::String => Ok(SemanticType::String),
1505            TypeKind::Object => Ok(SemanticType::Object),
1506            TypeKind::Vector => Ok(SemanticType::Vector),
1507            TypeKind::Struct(name) => {
1508                if !self.structs.contains_key(name) && name != "vector" {
1509                    return Err(SemanticError::new(
1510                        CompilerErrorCode::UndefinedStructure,
1511                        ty.span,
1512                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("undefined structure {0:?}", name))
    })format!("undefined structure {name:?}"),
1513                    ));
1514                }
1515                if name == "vector" {
1516                    Ok(SemanticType::Vector)
1517                } else {
1518                    Ok(SemanticType::Struct(name.clone()))
1519                }
1520            }
1521            TypeKind::EngineStructure(name) => Ok(SemanticType::EngineStructure(name.clone())),
1522        }
1523    }
1524
1525    fn evaluate_constant_expr(&self, expr: &Expr) -> Option<ConstantValue> {
1526        match &expr.kind {
1527            ExprKind::Literal(literal) => constant_from_literal(literal),
1528            ExprKind::Identifier(name) => self.lookup_constant(name),
1529            ExprKind::Unary {
1530                op: UnaryOp::Negate,
1531                expr,
1532            } => {
1533                let value = self.evaluate_constant_expr(expr)?;
1534                match value {
1535                    ConstantValue::Int(value) => Some(ConstantValue::Int(value.wrapping_neg())),
1536                    ConstantValue::Float(value) => Some(ConstantValue::Float(-value)),
1537                    _ => None,
1538                }
1539            }
1540            ExprKind::Unary {
1541                op: UnaryOp::BooleanNot,
1542                expr,
1543            } => match self.evaluate_constant_expr(expr)? {
1544                ConstantValue::Int(value) => Some(ConstantValue::Int(i32::from(value == 0))),
1545                _ => None,
1546            },
1547            ExprKind::Unary {
1548                op: UnaryOp::OnesComplement,
1549                expr,
1550            } => match self.evaluate_constant_expr(expr)? {
1551                ConstantValue::Int(value) => Some(ConstantValue::Int(!value)),
1552                _ => None,
1553            },
1554            ExprKind::Binary {
1555                op,
1556                left,
1557                right,
1558            } => self.evaluate_constant_binary(*op, left, right),
1559            ExprKind::Conditional {
1560                condition,
1561                when_true,
1562                when_false,
1563            } => {
1564                let condition = self.evaluate_constant_expr(condition)?;
1565                let take_true = match condition {
1566                    ConstantValue::Int(value) => value != 0,
1567                    _ => return None,
1568                };
1569                if take_true {
1570                    self.evaluate_constant_expr(when_true)
1571                } else {
1572                    self.evaluate_constant_expr(when_false)
1573                }
1574            }
1575            _ => None,
1576        }
1577    }
1578
1579    fn evaluate_function_default_expr(&self, expr: &Expr) -> Option<ConstantValue> {
1580        self.evaluate_constant_expr(expr)
1581    }
1582
1583    fn evaluate_constant_binary(
1584        &self,
1585        op: BinaryOp,
1586        left: &Expr,
1587        right: &Expr,
1588    ) -> Option<ConstantValue> {
1589        if #[allow(non_exhaustive_omitted_patterns)] match op {
    BinaryOp::LogicalOr | BinaryOp::LogicalAnd => true,
    _ => false,
}matches!(op, BinaryOp::LogicalOr | BinaryOp::LogicalAnd)
1590            && let Some(ConstantValue::Int(left_value)) = self.evaluate_constant_expr(left)
1591        {
1592            if op == BinaryOp::LogicalOr && left_value != 0 {
1593                return Some(ConstantValue::Int(1));
1594            }
1595            if op == BinaryOp::LogicalAnd && left_value == 0 {
1596                return Some(ConstantValue::Int(0));
1597            }
1598        }
1599
1600        let left = self.evaluate_constant_expr(left)?;
1601        let right = self.evaluate_constant_expr(right)?;
1602
1603        match (left, right) {
1604            (ConstantValue::Int(left), ConstantValue::Int(right)) => {
1605                evaluate_int_constant_binary(op, left, right).map(ConstantValue::Int)
1606            }
1607            (ConstantValue::Float(left), ConstantValue::Float(right)) => {
1608                evaluate_float_constant_binary(op, left, right)
1609            }
1610            (ConstantValue::String(left), ConstantValue::String(right)) => {
1611                evaluate_string_constant_binary(op, &left, &right)
1612            }
1613            _ => None,
1614        }
1615    }
1616
1617    fn evaluate_switch_case_value(&self, expr: &Expr) -> Option<i32> {
1618        match self.evaluate_constant_expr(expr)? {
1619            ConstantValue::Int(value) => Some(value),
1620            ConstantValue::String(value) => Some(nwscript_string_hash(&value)),
1621            _ => None,
1622        }
1623    }
1624
1625    fn lookup_constant(&self, name: &str) -> Option<ConstantValue> {
1626        self.global_constants
1627            .get(name)
1628            .cloned()
1629            .or_else(|| self.builtin_constants.get(name).cloned())
1630    }
1631
1632    fn lookup_value(
1633        &self,
1634        name: &str,
1635        scopes: &[BTreeMap<String, ScopeBinding>],
1636    ) -> Option<ValueBinding> {
1637        for scope in scopes.iter().rev() {
1638            if let Some(binding) = scope.get(name) {
1639                return Some(ValueBinding::Variable {
1640                    ty:       binding.ty.clone(),
1641                    is_const: binding.is_const,
1642                });
1643            }
1644        }
1645
1646        if let Some(global) = self.globals.get(name) {
1647            if global.is_const
1648                && let Some(value) = self.global_constants.get(name).cloned()
1649            {
1650                return Some(ValueBinding::Constant(value));
1651            }
1652
1653            return Some(ValueBinding::Variable {
1654                ty:       global.ty.clone(),
1655                is_const: global.is_const,
1656            });
1657        }
1658
1659        self.lookup_constant(name).map(ValueBinding::Constant)
1660    }
1661
1662    fn validate_entrypoint(&self) -> Result<(), SemanticError> {
1663        if !self.options.require_entrypoint {
1664            return Ok(());
1665        }
1666
1667        if let Some(main) = self.functions.get("main") {
1668            if main.signature.return_type != SemanticType::Void {
1669                return Err(SemanticError::new(
1670                    CompilerErrorCode::FunctionMainMustHaveVoidReturnValue,
1671                    main.declaration_span,
1672                    "main must return void",
1673                ));
1674            }
1675            if !main.signature.parameters.is_empty() {
1676                return Err(SemanticError::new(
1677                    CompilerErrorCode::FunctionMainMustHaveNoParameters,
1678                    main.declaration_span,
1679                    "main must not take parameters",
1680                ));
1681            }
1682            return Ok(());
1683        }
1684
1685        if self.options.allow_conditional_script {
1686            if let Some(function) = self.functions.get("StartingConditional") {
1687                if function.signature.return_type != SemanticType::Int {
1688                    return Err(SemanticError::new(
1689                        CompilerErrorCode::FunctionIntscMustHaveVoidReturnValue,
1690                        function.declaration_span,
1691                        "StartingConditional must return int",
1692                    ));
1693                }
1694                if !function.signature.parameters.is_empty() {
1695                    return Err(SemanticError::new(
1696                        CompilerErrorCode::FunctionIntscMustHaveNoParameters,
1697                        function.declaration_span,
1698                        "StartingConditional must not take parameters",
1699                    ));
1700                }
1701                return Ok(());
1702            }
1703            return Err(SemanticError::new(
1704                CompilerErrorCode::NoFunctionIntscInScript,
1705                crate::Span::new(crate::SourceId::new(0), 0, 0),
1706                "script must define StartingConditional",
1707            ));
1708        }
1709
1710        Err(SemanticError::new(
1711            CompilerErrorCode::NoFunctionMainInScript,
1712            crate::Span::new(crate::SourceId::new(0), 0, 0),
1713            "script must define main",
1714        ))
1715    }
1716}
1717
1718#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ResolvedExpr {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "ResolvedExpr",
            "ty", &self.ty, "is_lvalue", &self.is_lvalue, "is_const",
            &&self.is_const)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for ResolvedExpr {
    #[inline]
    fn clone(&self) -> ResolvedExpr {
        ResolvedExpr {
            ty: ::core::clone::Clone::clone(&self.ty),
            is_lvalue: ::core::clone::Clone::clone(&self.is_lvalue),
            is_const: ::core::clone::Clone::clone(&self.is_const),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for ResolvedExpr {
    #[inline]
    fn eq(&self, other: &ResolvedExpr) -> bool {
        self.is_lvalue == other.is_lvalue && self.is_const == other.is_const
            && self.ty == other.ty
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ResolvedExpr {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<SemanticType>;
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq)]
1719struct ResolvedExpr {
1720    ty:        SemanticType,
1721    is_lvalue: bool,
1722    is_const:  bool,
1723}
1724
1725fn semantic_type_from_builtin_type(ty: &BuiltinType) -> SemanticType {
1726    match ty {
1727        BuiltinType::Int => SemanticType::Int,
1728        BuiltinType::Float => SemanticType::Float,
1729        BuiltinType::String => SemanticType::String,
1730        BuiltinType::Object => SemanticType::Object,
1731        BuiltinType::Void => SemanticType::Void,
1732        BuiltinType::Action => SemanticType::Action,
1733        BuiltinType::Vector => SemanticType::Vector,
1734        BuiltinType::EngineStructure(name) => SemanticType::EngineStructure(name.clone()),
1735    }
1736}
1737
1738fn constant_from_builtin_value(value: &BuiltinValue) -> Option<ConstantValue> {
1739    match value {
1740        BuiltinValue::Int(value) => Some(ConstantValue::Int(*value)),
1741        BuiltinValue::Float(value) => Some(ConstantValue::Float(*value)),
1742        BuiltinValue::String(value) => Some(ConstantValue::String(value.clone())),
1743        BuiltinValue::ObjectId(value) => Some(ConstantValue::ObjectId(*value)),
1744        BuiltinValue::ObjectSelf => Some(ConstantValue::ObjectSelf),
1745        BuiltinValue::ObjectInvalid => Some(ConstantValue::ObjectInvalid),
1746        BuiltinValue::LocationInvalid => Some(ConstantValue::LocationInvalid),
1747        BuiltinValue::Json(value) => Some(ConstantValue::Json(value.clone())),
1748        BuiltinValue::Vector(value) => Some(ConstantValue::Vector(*value)),
1749        BuiltinValue::Raw(_) => None,
1750    }
1751}
1752
1753fn literal_from_builtin_value(value: &BuiltinValue) -> Option<Literal> {
1754    constant_from_builtin_value(value).map(|value| literal_from_constant_value(&value))
1755}
1756
1757fn constant_from_literal(literal: &Literal) -> Option<ConstantValue> {
1758    match literal {
1759        Literal::Integer(value) => Some(ConstantValue::Int(*value)),
1760        Literal::Float(value) => Some(ConstantValue::Float(*value)),
1761        Literal::String(value) => Some(ConstantValue::String(value.clone())),
1762        Literal::ObjectSelf => Some(ConstantValue::ObjectSelf),
1763        Literal::ObjectInvalid => Some(ConstantValue::ObjectInvalid),
1764        Literal::LocationInvalid => Some(ConstantValue::LocationInvalid),
1765        Literal::Json(value) => Some(ConstantValue::Json(value.clone())),
1766        Literal::Vector(value) => Some(ConstantValue::Vector(*value)),
1767        Literal::Magic(
1768            MagicLiteral::Function
1769            | MagicLiteral::File
1770            | MagicLiteral::Line
1771            | MagicLiteral::Date
1772            | MagicLiteral::Time,
1773        ) => None,
1774    }
1775}
1776
1777fn literal_from_constant_value(value: &ConstantValue) -> Literal {
1778    match value {
1779        ConstantValue::Int(value) | ConstantValue::ObjectId(value) => Literal::Integer(*value),
1780        ConstantValue::Float(value) => Literal::Float(*value),
1781        ConstantValue::String(value) => Literal::String(value.clone()),
1782        ConstantValue::ObjectSelf => Literal::ObjectSelf,
1783        ConstantValue::ObjectInvalid => Literal::ObjectInvalid,
1784        ConstantValue::LocationInvalid => Literal::LocationInvalid,
1785        ConstantValue::Json(value) => Literal::Json(value.clone()),
1786        ConstantValue::Vector(value) => Literal::Vector(*value),
1787    }
1788}
1789
1790fn semantic_type_from_literal(literal: &Literal) -> SemanticType {
1791    match literal {
1792        Literal::Integer(_) | Literal::Magic(MagicLiteral::Line) => SemanticType::Int,
1793        Literal::Float(_) => SemanticType::Float,
1794        Literal::String(_)
1795        | Literal::Magic(
1796            MagicLiteral::Function | MagicLiteral::File | MagicLiteral::Date | MagicLiteral::Time,
1797        ) => SemanticType::String,
1798        Literal::ObjectSelf | Literal::ObjectInvalid => SemanticType::Object,
1799        Literal::LocationInvalid => SemanticType::EngineStructure("location".to_string()),
1800        Literal::Json(_) => SemanticType::EngineStructure("json".to_string()),
1801        Literal::Vector(_) => SemanticType::Vector,
1802    }
1803}
1804
1805fn default_constant_value(ty: &SemanticType) -> Option<ConstantValue> {
1806    match ty {
1807        SemanticType::Int => Some(ConstantValue::Int(0)),
1808        SemanticType::Float => Some(ConstantValue::Float(0.0)),
1809        SemanticType::String => Some(ConstantValue::String(String::new())),
1810        _ => None,
1811    }
1812}
1813
1814fn evaluate_int_constant_binary(op: BinaryOp, left: i32, right: i32) -> Option<i32> {
1815    match op {
1816        BinaryOp::LogicalOr => Some(i32::from(left != 0 || right != 0)),
1817        BinaryOp::LogicalAnd => Some(i32::from(left != 0 && right != 0)),
1818        BinaryOp::InclusiveOr => Some(left | right),
1819        BinaryOp::ExclusiveOr => Some(left ^ right),
1820        BinaryOp::BooleanAnd => Some(left & right),
1821        BinaryOp::EqualEqual => Some(i32::from(left == right)),
1822        BinaryOp::NotEqual => Some(i32::from(left != right)),
1823        BinaryOp::GreaterEqual => Some(i32::from(left >= right)),
1824        BinaryOp::GreaterThan => Some(i32::from(left > right)),
1825        BinaryOp::LessThan => Some(i32::from(left < right)),
1826        BinaryOp::LessEqual => Some(i32::from(left <= right)),
1827        BinaryOp::ShiftLeft => Some(left.wrapping_shl(right.cast_unsigned())),
1828        BinaryOp::ShiftRight => Some(left.wrapping_shr(right.cast_unsigned())),
1829        BinaryOp::UnsignedShiftRight => {
1830            Some(((left.cast_unsigned()).wrapping_shr(right.cast_unsigned())).cast_signed())
1831        }
1832        BinaryOp::Add => Some(left.wrapping_add(right)),
1833        BinaryOp::Subtract => Some(left.wrapping_sub(right)),
1834        BinaryOp::Multiply => Some(left.wrapping_mul(right)),
1835        BinaryOp::Divide => left.checked_div(right),
1836        BinaryOp::Modulus => left.checked_rem(right),
1837    }
1838}
1839
1840#[allow(clippy::float_cmp)]
1841fn evaluate_float_constant_binary(op: BinaryOp, left: f32, right: f32) -> Option<ConstantValue> {
1842    match op {
1843        BinaryOp::Add => Some(ConstantValue::Float(left + right)),
1844        BinaryOp::Subtract => Some(ConstantValue::Float(left - right)),
1845        BinaryOp::Multiply => Some(ConstantValue::Float(left * right)),
1846        BinaryOp::Divide => Some(ConstantValue::Float(left / right)),
1847        BinaryOp::EqualEqual => Some(ConstantValue::Int(i32::from(left == right))),
1848        BinaryOp::NotEqual => Some(ConstantValue::Int(i32::from(left != right))),
1849        BinaryOp::GreaterEqual => Some(ConstantValue::Int(i32::from(left >= right))),
1850        BinaryOp::GreaterThan => Some(ConstantValue::Int(i32::from(left > right))),
1851        BinaryOp::LessThan => Some(ConstantValue::Int(i32::from(left < right))),
1852        BinaryOp::LessEqual => Some(ConstantValue::Int(i32::from(left <= right))),
1853        _ => None,
1854    }
1855}
1856
1857fn evaluate_string_constant_binary(op: BinaryOp, left: &str, right: &str) -> Option<ConstantValue> {
1858    match op {
1859        BinaryOp::Add => {
1860            if left.len().saturating_add(right.len()) >= 0x8000 {
1861                None
1862            } else {
1863                Some(ConstantValue::String(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}", left, right))
    })format!("{left}{right}")))
1864            }
1865        }
1866        BinaryOp::EqualEqual => Some(ConstantValue::Int(i32::from(left == right))),
1867        BinaryOp::NotEqual => Some(ConstantValue::Int(i32::from(left != right))),
1868        _ => None,
1869    }
1870}
1871
1872fn type_supports_optional_parameter(ty: &SemanticType) -> bool {
1873    match ty {
1874        SemanticType::Int
1875        | SemanticType::Float
1876        | SemanticType::String
1877        | SemanticType::Object
1878        | SemanticType::Vector => true,
1879        SemanticType::EngineStructure(name) => name == "location" || name == "json",
1880        _ => false,
1881    }
1882}
1883
1884fn types_compatible(expected: &SemanticType, actual: &SemanticType) -> bool {
1885    expected == actual
1886}
1887
1888fn parameters_match(left: &[SemanticParameter], right: &[SemanticParameter]) -> bool {
1889    left.len() == right.len()
1890        && left
1891            .iter()
1892            .zip(right)
1893            .all(|(left, right)| left.ty == right.ty)
1894}
1895
1896fn insert_scope_binding(
1897    scopes: &mut [BTreeMap<String, ScopeBinding>],
1898    name: &str,
1899    ty: SemanticType,
1900    is_const: bool,
1901    span: crate::Span,
1902) -> Result<(), SemanticError> {
1903    if current_scope_contains(scopes, name) {
1904        return Err(SemanticError::new(
1905            CompilerErrorCode::VariableAlreadyUsedWithinScope,
1906            span,
1907            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("variable {0:?} was already declared in this scope",
                name))
    })format!("variable {name:?} was already declared in this scope"),
1908        ));
1909    }
1910
1911    let Some(scope) = scopes.last_mut() else {
1912        return Err(SemanticError::new(
1913            CompilerErrorCode::UnknownStateInCompiler,
1914            span,
1915            "scope stack must be non-empty",
1916        ));
1917    };
1918    scope.insert(
1919        name.to_string(),
1920        ScopeBinding {
1921            ty,
1922            is_const,
1923        },
1924    );
1925    Ok(())
1926}
1927
1928fn current_scope_contains(scopes: &[BTreeMap<String, ScopeBinding>], name: &str) -> bool {
1929    scopes.last().is_some_and(|scope| scope.contains_key(name))
1930}
1931
1932fn statement_guarantees_return(statement: &Stmt) -> bool {
1933    match statement {
1934        Stmt::Return(_) => true,
1935        Stmt::Block(block) => {
1936            for statement in &block.statements {
1937                if statement_guarantees_return(statement) {
1938                    return true;
1939                }
1940            }
1941            false
1942        }
1943        Stmt::If(statement) => match &statement.else_branch {
1944            Some(else_branch) => {
1945                statement_guarantees_return(&statement.then_branch)
1946                    && statement_guarantees_return(else_branch)
1947            }
1948            None => false,
1949        },
1950        _ => false,
1951    }
1952}
1953
1954#[cfg(test)]
1955mod tests {
1956    use super::{SemanticType, analyze_script, analyze_script_with_options};
1957    use crate::{LangSpec, Literal, SemanticOptions, SourceId, parse_text};
1958
1959    fn test_langspec() -> LangSpec {
1960        LangSpec {
1961            engine_num_structures: 3,
1962            engine_structures:     vec![
1963                "effect".to_string(),
1964                "location".to_string(),
1965                "json".to_string(),
1966            ],
1967            constants:             vec![
1968                crate::BuiltinConstant {
1969                    name:  "TRUE".to_string(),
1970                    ty:    crate::BuiltinType::Int,
1971                    value: crate::BuiltinValue::Int(1),
1972                },
1973                crate::BuiltinConstant {
1974                    name:  "FALSE".to_string(),
1975                    ty:    crate::BuiltinType::Int,
1976                    value: crate::BuiltinValue::Int(0),
1977                },
1978                crate::BuiltinConstant {
1979                    name:  "OBJECT_INVALID".to_string(),
1980                    ty:    crate::BuiltinType::Object,
1981                    value: crate::BuiltinValue::ObjectInvalid,
1982                },
1983            ],
1984            functions:             vec![
1985                crate::BuiltinFunction {
1986                    name:        "DelayCommand".to_string(),
1987                    return_type: crate::BuiltinType::Void,
1988                    parameters:  vec![
1989                        crate::BuiltinParameter {
1990                            name:    "fSeconds".to_string(),
1991                            ty:      crate::BuiltinType::Float,
1992                            default: None,
1993                        },
1994                        crate::BuiltinParameter {
1995                            name:    "aAction".to_string(),
1996                            ty:      crate::BuiltinType::Action,
1997                            default: None,
1998                        },
1999                    ],
2000                },
2001                crate::BuiltinFunction {
2002                    name:        "EffectDamage".to_string(),
2003                    return_type: crate::BuiltinType::EngineStructure("effect".to_string()),
2004                    parameters:  vec![crate::BuiltinParameter {
2005                        name:    "nAmount".to_string(),
2006                        ty:      crate::BuiltinType::Int,
2007                        default: None,
2008                    }],
2009                },
2010            ],
2011        }
2012    }
2013
2014    #[test]
2015    fn resolves_functions_globals_and_structs() -> Result<(), Box<dyn std::error::Error>> {
2016        let script = parse_text(
2017            SourceId::new(40),
2018            "struct Foo { int value; }; effect gFx; void helper(int n = TRUE); void helper(int n \
2019             = TRUE) { int x = n; } void main() { struct Foo f; int x = f.value; }",
2020            Some(&test_langspec()),
2021        )?;
2022
2023        let model = analyze_script(&script, Some(&test_langspec()))?;
2024        assert!(model.structs.contains_key("Foo"));
2025        assert!(model.functions.contains_key("helper"));
2026        assert!(model.functions.contains_key("EffectDamage"));
2027        assert_eq!(
2028            model
2029                .globals
2030                .get("gFx")
2031                .ok_or_else(|| std::io::Error::other("missing global gFx"))?
2032                .ty,
2033            SemanticType::EngineStructure("effect".to_string())
2034        );
2035        Ok(())
2036    }
2037
2038    #[test]
2039    fn rejects_optional_parameter_ordering() {
2040        let script = parse_text(
2041            SourceId::new(41),
2042            "void helper(int n = 1, int m); void main() { return; }",
2043            Some(&test_langspec()),
2044        )
2045        .expect("script should parse");
2046
2047        let error =
2048            analyze_script(&script, Some(&test_langspec())).expect_err("analysis should fail");
2049        assert_eq!(
2050            error.code,
2051            crate::CompilerErrorCode::NonOptionalParameterCannotFollowOptionalParameter
2052        );
2053    }
2054
2055    #[test]
2056    fn folds_constant_globals_and_uses_default_constant_values()
2057    -> Result<(), Box<dyn std::error::Error>> {
2058        let script = parse_text(
2059            SourceId::new(46),
2060            r#"
2061                const int MASK = (1 + 2) * 4;
2062                const int ZERO;
2063                const string LABEL = "ab" + "cd";
2064                const int PICK = TRUE ? 7 : 9;
2065                void main() {
2066                    int x = MASK;
2067                    int y = ZERO;
2068                    string s = LABEL;
2069                    int z = PICK;
2070                }
2071            "#,
2072            Some(&test_langspec()),
2073        )?;
2074
2075        let model = analyze_script(&script, Some(&test_langspec()))?;
2076        assert_eq!(
2077            model.globals.get("MASK").map(|global| global.is_const),
2078            Some(true)
2079        );
2080        assert_eq!(
2081            model.globals.get("ZERO").map(|global| global.is_const),
2082            Some(true)
2083        );
2084        assert_eq!(
2085            model.globals.get("LABEL").map(|global| global.is_const),
2086            Some(true)
2087        );
2088        assert_eq!(
2089            model.globals.get("PICK").map(|global| global.is_const),
2090            Some(true)
2091        );
2092        Ok(())
2093    }
2094
2095    #[test]
2096    fn accepts_case_labels_backed_by_const_globals() {
2097        let script = parse_text(
2098            SourceId::new(47),
2099            r#"
2100                const int CASE_A = 1 + 2;
2101                const int CASE_B = FALSE ? 8 : 4;
2102                void main() {
2103                    int n = 0;
2104                    switch (n) {
2105                        case CASE_A:
2106                            break;
2107                        case CASE_B:
2108                            break;
2109                        default:
2110                            break;
2111                    }
2112                }
2113            "#,
2114            Some(&test_langspec()),
2115        )
2116        .expect("script should parse");
2117
2118        analyze_script(&script, Some(&test_langspec()))
2119            .expect("const global should be valid in case label");
2120    }
2121
2122    #[test]
2123    fn accepts_function_defaults_backed_by_const_globals_and_expressions() {
2124        let script = parse_text(
2125            SourceId::new(48),
2126            r#"
2127                const int EXECUTE_END = 1;
2128                const int POLICY_DEFAULT = EXECUTE_END + 2;
2129                void helper(int nValue = EXECUTE_END, int nPolicy = POLICY_DEFAULT) {
2130                    return;
2131                }
2132                void main() {
2133                    helper();
2134                }
2135            "#,
2136            Some(&test_langspec()),
2137        )
2138        .expect("script should parse");
2139
2140        analyze_script(&script, Some(&test_langspec()))
2141            .expect("const global defaults should resolve in function signatures");
2142    }
2143
2144    #[test]
2145    fn accepts_string_case_labels_by_upstream_hash_rule() {
2146        let script = parse_text(
2147            SourceId::new(49),
2148            r#"
2149                const string LABEL = "abc";
2150                void main() {
2151                    int n = 0;
2152                    switch (n) {
2153                        case "abc":
2154                            break;
2155                        case LABEL:
2156                            break;
2157                    }
2158                }
2159            "#,
2160            Some(&test_langspec()),
2161        )
2162        .expect("script should parse");
2163
2164        let error =
2165            analyze_script(&script, Some(&test_langspec())).expect_err("analysis should fail");
2166        assert_eq!(
2167            error.code,
2168            crate::CompilerErrorCode::MultipleCaseConstantStatementsWithinSwitch
2169        );
2170    }
2171
2172    #[test]
2173    fn rejects_duplicate_default_labels_within_one_switch() {
2174        let script = parse_text(
2175            SourceId::new(50),
2176            r#"
2177                void main() {
2178                    int n = 0;
2179                    switch (n) {
2180                        default:
2181                            break;
2182                        default:
2183                            break;
2184                    }
2185                }
2186            "#,
2187            Some(&test_langspec()),
2188        )
2189        .expect("script should parse");
2190
2191        let error =
2192            analyze_script(&script, Some(&test_langspec())).expect_err("analysis should fail");
2193        assert_eq!(
2194            error.code,
2195            crate::CompilerErrorCode::MultipleDefaultStatementsWithinSwitch
2196        );
2197    }
2198
2199    #[test]
2200    fn rejects_case_and_default_labels_that_jump_over_live_declarations() {
2201        let case_script = parse_text(
2202            SourceId::new(51),
2203            r#"
2204                void main() {
2205                    int n = 0;
2206                    switch (n) {
2207                        int x = 1;
2208                        case 1:
2209                            break;
2210                    }
2211                }
2212            "#,
2213            Some(&test_langspec()),
2214        )
2215        .expect("script should parse");
2216
2217        let case_error =
2218            analyze_script(&case_script, Some(&test_langspec())).expect_err("analysis should fail");
2219        assert_eq!(
2220            case_error.code,
2221            crate::CompilerErrorCode::JumpingOverDeclarationStatementsCaseDisallowed
2222        );
2223
2224        let default_script = parse_text(
2225            SourceId::new(52),
2226            r#"
2227                void main() {
2228                    int n = 0;
2229                    switch (n) {
2230                        int x = 1;
2231                        default:
2232                            break;
2233                    }
2234                }
2235            "#,
2236            Some(&test_langspec()),
2237        )
2238        .expect("script should parse");
2239
2240        let default_error = analyze_script(&default_script, Some(&test_langspec()))
2241            .expect_err("analysis should fail");
2242        assert_eq!(
2243            default_error.code,
2244            crate::CompilerErrorCode::JumpingOverDeclarationStatementsDefaultDisallowed
2245        );
2246    }
2247
2248    #[test]
2249    fn duplicate_case_detection_is_scoped_to_the_innermost_switch() {
2250        let script = parse_text(
2251            SourceId::new(53),
2252            r#"
2253                void main() {
2254                    int n = 0;
2255                    switch (n) {
2256                        case 1:
2257                            switch (n) {
2258                                case 1:
2259                                    break;
2260                                default:
2261                                    break;
2262                            }
2263                            break;
2264                        default:
2265                            break;
2266                    }
2267                }
2268            "#,
2269            Some(&test_langspec()),
2270        )
2271        .expect("script should parse");
2272
2273        analyze_script(&script, Some(&test_langspec()))
2274            .expect("nested switch labels should be tracked independently");
2275    }
2276
2277    #[test]
2278    fn parser_accepts_constant_function_default_expressions_like_upstream() {
2279        let script = parse_text(
2280            SourceId::new(48),
2281            "void helper(int n = 1 + 2); void main() {}",
2282            Some(&test_langspec()),
2283        )
2284        .expect("parser should accept constant default expressions");
2285
2286        analyze_script(&script, Some(&test_langspec()))
2287            .expect("semantic analysis should accept constant default expressions");
2288    }
2289
2290    #[test]
2291    fn rejects_undefined_identifiers_and_bad_field_access() {
2292        let script = parse_text(
2293            SourceId::new(42),
2294            "struct Foo { int value; }; void main() { struct Foo f; int x = f.missing; }",
2295            Some(&test_langspec()),
2296        )
2297        .expect("script should parse");
2298
2299        let error =
2300            analyze_script(&script, Some(&test_langspec())).expect_err("analysis should fail");
2301        assert!(matches!(
2302            error.code,
2303            crate::CompilerErrorCode::UndefinedFieldInStructure
2304                | crate::CompilerErrorCode::UndefinedIdentifier
2305        ));
2306    }
2307
2308    #[test]
2309    fn action_parameters_require_direct_void_calls() {
2310        let valid = parse_text(
2311            SourceId::new(54),
2312            "void helper() {} void main() { DelayCommand(1.0, helper()); }",
2313            Some(&test_langspec()),
2314        )
2315        .expect("script should parse");
2316        analyze_script(&valid, Some(&test_langspec()))
2317            .expect("void call should be valid for action parameter");
2318
2319        let invalid = parse_text(
2320            SourceId::new(55),
2321            "void main() { DelayCommand(1.0, EffectDamage(1)); }",
2322            Some(&test_langspec()),
2323        )
2324        .expect("script should parse");
2325        let error =
2326            analyze_script(&invalid, Some(&test_langspec())).expect_err("analysis should fail");
2327        assert_eq!(
2328            error.code,
2329            crate::CompilerErrorCode::DeclarationDoesNotMatchParameters
2330        );
2331    }
2332
2333    #[test]
2334    fn function_name_reuse_requires_identical_parameter_lists() {
2335        let mismatch = parse_text(
2336            SourceId::new(56),
2337            "void helper(int n); void helper(float n); void main() {}",
2338            Some(&test_langspec()),
2339        )
2340        .expect("script should parse");
2341        let mismatch_error =
2342            analyze_script(&mismatch, Some(&test_langspec())).expect_err("analysis should fail");
2343        assert_eq!(
2344            mismatch_error.code,
2345            crate::CompilerErrorCode::FunctionImplementationAndDefinitionDiffer
2346        );
2347
2348        let return_mismatch = parse_text(
2349            SourceId::new(65),
2350            "int helper(int n); void helper(int n) {} void main() {}",
2351            Some(&test_langspec()),
2352        )
2353        .expect("script should parse");
2354        let return_mismatch_error = analyze_script(&return_mismatch, Some(&test_langspec()))
2355            .expect_err("analysis should fail");
2356        assert_eq!(
2357            return_mismatch_error.code,
2358            crate::CompilerErrorCode::FunctionImplementationAndDefinitionDiffer
2359        );
2360
2361        let duplicate_impl = parse_text(
2362            SourceId::new(57),
2363            "void helper(int n) {} void helper(int n) {} void main() {}",
2364            Some(&test_langspec()),
2365        )
2366        .expect("script should parse");
2367        let duplicate_impl_error = analyze_script(&duplicate_impl, Some(&test_langspec()))
2368            .expect_err("analysis should fail");
2369        assert_eq!(
2370            duplicate_impl_error.code,
2371            crate::CompilerErrorCode::DuplicateFunctionImplementation
2372        );
2373    }
2374
2375    #[test]
2376    fn function_redeclarations_may_add_or_remove_trailing_defaults_like_upstream() {
2377        let later_default = parse_text(
2378            SourceId::new(60),
2379            "void helper(int n); void helper(int n = 1) {} void main() {}",
2380            Some(&test_langspec()),
2381        )
2382        .expect("script should parse");
2383        analyze_script(&later_default, Some(&test_langspec()))
2384            .expect("later implementation default should be accepted");
2385
2386        let earlier_default = parse_text(
2387            SourceId::new(61),
2388            "void helper(int n = 1); void helper(int n) {} void main() {}",
2389            Some(&test_langspec()),
2390        )
2391        .expect("script should parse");
2392        let earlier_default_semantic = analyze_script(&earlier_default, Some(&test_langspec()))
2393            .expect("later implementation without default should be accepted");
2394        let helper = earlier_default_semantic
2395            .functions
2396            .get("helper")
2397            .expect("helper should be present in the semantic model");
2398        let first_parameter = helper
2399            .parameters
2400            .first()
2401            .expect("helper should have one parameter");
2402        assert_eq!(
2403            first_parameter.default,
2404            Some(Literal::Integer(1)),
2405            "forward declaration defaults should survive into the merged signature"
2406        );
2407
2408        let renamed_parameter = parse_text(
2409            SourceId::new(64),
2410            "int helper(int nDurationType); int helper(int nDurationCompare) { return \
2411             nDurationCompare; } void main() {}",
2412            Some(&test_langspec()),
2413        )
2414        .expect("script should parse");
2415        analyze_script(&renamed_parameter, Some(&test_langspec()))
2416            .expect("implementation parameter names should be visible inside the body");
2417    }
2418
2419    #[test]
2420    fn nested_scopes_may_shadow_outer_names_but_same_scope_duplicates_fail() {
2421        let shadowing = parse_text(
2422            SourceId::new(62),
2423            "int g = 1; void main() { int x = g; { int x = 2; int y = x; } int z = x; }",
2424            Some(&test_langspec()),
2425        )
2426        .expect("script should parse");
2427        analyze_script(&shadowing, Some(&test_langspec()))
2428            .expect("nested scopes should be allowed to shadow outer names");
2429
2430        let duplicate = parse_text(
2431            SourceId::new(63),
2432            "void main() { int x = 1; int x = 2; }",
2433            Some(&test_langspec()),
2434        )
2435        .expect("script should parse");
2436        let duplicate_error =
2437            analyze_script(&duplicate, Some(&test_langspec())).expect_err("analysis should fail");
2438        assert_eq!(
2439            duplicate_error.code,
2440            crate::CompilerErrorCode::VariableAlreadyUsedWithinScope
2441        );
2442    }
2443
2444    #[test]
2445    fn function_body_scope_may_shadow_parameter_names() {
2446        let script = parse_text(
2447            SourceId::new(65),
2448            "int helper(object oSpellTarget) { object oSpellTarget = OBJECT_SELF; return TRUE; } \
2449             void main() {}",
2450            Some(&test_langspec()),
2451        )
2452        .expect("script should parse");
2453        analyze_script(&script, Some(&test_langspec()))
2454            .expect("function body locals should be allowed to shadow parameter names");
2455    }
2456
2457    #[test]
2458    fn rejects_local_const_declarations_like_upstream() {
2459        let script = parse_text(
2460            SourceId::new(43),
2461            "void main() { const int x = 1; }",
2462            Some(&test_langspec()),
2463        )
2464        .expect("script should parse");
2465
2466        let error =
2467            analyze_script(&script, Some(&test_langspec())).expect_err("analysis should fail");
2468        assert_eq!(
2469            error.code,
2470            crate::CompilerErrorCode::ConstKeywordCannotBeUsedOnNonGlobalVariables
2471        );
2472    }
2473
2474    #[test]
2475    fn rejects_missing_return_paths() {
2476        let script = parse_text(
2477            SourceId::new(44),
2478            "int main() { if (TRUE) { return 1; } }",
2479            Some(&test_langspec()),
2480        )
2481        .expect("script should parse");
2482
2483        let error =
2484            analyze_script(&script, Some(&test_langspec())).expect_err("analysis should fail");
2485        assert_eq!(
2486            error.code,
2487            crate::CompilerErrorCode::NotAllControlPathsReturnAValue
2488        );
2489    }
2490
2491    #[test]
2492    fn validates_required_entrypoints_when_requested() {
2493        let script = parse_text(
2494            SourceId::new(45),
2495            "int helper() { return 1; }",
2496            Some(&test_langspec()),
2497        )
2498        .expect("script should parse");
2499
2500        let error = analyze_script_with_options(
2501            &script,
2502            Some(&test_langspec()),
2503            SemanticOptions {
2504                require_entrypoint:       true,
2505                allow_conditional_script: false,
2506            },
2507        )
2508        .expect_err("analysis should fail");
2509        assert_eq!(error.code, crate::CompilerErrorCode::NoFunctionMainInScript);
2510    }
2511}