sway-core 0.1.2

Sway core language.
Documentation
use crate::build_config::BuildConfig;
use crate::parse_tree::{declaration::TypeParameter, Visibility};
use crate::parser::Rule;
use crate::span::Span;
use crate::style::{is_snake_case, is_upper_camel_case};
use crate::type_engine::TypeInfo;
use crate::{error::*, Ident};
use pest::iterators::Pair;

#[derive(Debug, Clone)]
pub struct StructDeclaration<'sc> {
    pub name: Ident<'sc>,
    pub(crate) fields: Vec<StructField<'sc>>,
    pub(crate) type_parameters: Vec<TypeParameter<'sc>>,
    pub visibility: Visibility,
}

#[derive(Debug, Clone)]
pub(crate) struct StructField<'sc> {
    pub(crate) name: Ident<'sc>,
    pub(crate) r#type: TypeInfo,
    pub(crate) span: Span<'sc>,
    pub(crate) type_span: Span<'sc>,
}

impl<'sc> StructDeclaration<'sc> {
    pub(crate) fn parse_from_pair(
        decl: Pair<'sc, Rule>,
        config: Option<&BuildConfig>,
    ) -> CompileResult<'sc, Self> {
        let path = config.map(|c| c.path());
        let mut warnings = Vec::new();
        let mut errors = Vec::new();
        let decl = decl.into_inner();
        let mut visibility = Visibility::Private;
        let mut name = None;
        let mut type_params_pair = None;
        let mut where_clause_pair = None;
        let mut fields_pair = None;
        for pair in decl {
            match pair.as_rule() {
                Rule::type_params => {
                    type_params_pair = Some(pair);
                }
                Rule::trait_bounds => {
                    where_clause_pair = Some(pair);
                }
                Rule::struct_fields => {
                    fields_pair = Some(pair);
                }
                Rule::struct_keyword => (),
                Rule::struct_name => {
                    name = Some(pair);
                }
                Rule::visibility => {
                    visibility = Visibility::parse_from_pair(pair);
                }
                a => unreachable!("{:?}", a),
            }
        }
        let name = name.expect("guaranteed to exist by grammar");

        let type_parameters = TypeParameter::parse_from_type_params_and_where_clause(
            type_params_pair,
            where_clause_pair,
            config,
        )
        .unwrap_or_else(&mut warnings, &mut errors, Vec::new);

        let fields = if let Some(fields) = fields_pair {
            check!(
                StructField::parse_from_pairs(fields, config),
                Vec::new(),
                warnings,
                errors
            )
        } else {
            Vec::new()
        };

        let span = Span {
            span: name.as_span(),
            path,
        };
        let name = check!(
            Ident::parse_from_pair(name, config),
            return err(warnings, errors),
            warnings,
            errors
        );
        assert_or_warn!(
            is_upper_camel_case(name.primary_name),
            warnings,
            span,
            Warning::NonClassCaseStructName {
                struct_name: name.primary_name
            }
        );
        ok(
            StructDeclaration {
                name,
                fields,
                type_parameters,
                visibility,
            },
            warnings,
            errors,
        )
    }
}

impl<'sc> StructField<'sc> {
    pub(crate) fn parse_from_pairs(
        pair: Pair<'sc, Rule>,
        config: Option<&BuildConfig>,
    ) -> CompileResult<'sc, Vec<Self>> {
        let path = config.map(|c| c.path());
        let mut warnings = Vec::new();
        let mut errors = Vec::new();
        let fields = pair.into_inner().collect::<Vec<_>>();
        let mut fields_buf = Vec::new();
        for i in (0..fields.len()).step_by(2) {
            let span = Span {
                span: fields[i].as_span(),
                path: path.clone(),
            };
            let name = check!(
                Ident::parse_from_pair(fields[i].clone(), config),
                return err(warnings, errors),
                warnings,
                errors
            );
            assert_or_warn!(
                is_snake_case(name.primary_name),
                warnings,
                span.clone(),
                Warning::NonSnakeCaseStructFieldName {
                    field_name: name.primary_name,
                }
            );
            let type_pair = fields[i + 1].clone();
            let type_span = Span {
                span: type_pair.as_span(),
                path: path.clone(),
            };
            let r#type = check!(
                TypeInfo::parse_from_pair(fields[i + 1].clone(), config),
                TypeInfo::Unit,
                warnings,
                errors
            );
            fields_buf.push(StructField {
                name,
                r#type,
                span,
                type_span,
            });
        }
        ok(fields_buf, warnings, errors)
    }
}