open-vaf 0.4.2

A compiler frontend for VerilogA aimed predominently at compact modelling
Documentation
//  * ******************************************************************************************
//  * Copyright (c) 2019 Pascal Kuthe. This file is part of the OpenVAF project.
//  * It is subject to the license terms in the LICENSE file found in the top-level directory
//  *  of this distribution and at  https://gitlab.com/DSPOM/OpenVAF/blob/master/LICENSE.
//  *  No part of OpenVAF, including this file, may be copied, modified, propagated, or
//  *  distributed except according to the terms contained in the LICENSE file.
//  * *******************************************************************************************

#![allow(clippy::similar_names)]

use crate::ir::ast::Nature;
use crate::ir::{AttributeNode, Attributes};
use crate::parser::error::Result;
use crate::parser::error::Type::{
    AttributeAlreadyDefined, RequiredAttributeNotDefined, UnexpectedToken,
};
use crate::parser::lexer::Token;
use crate::parser::Error;
use crate::symbol::keywords;
use crate::symbol_table::SymbolDeclaration;
use crate::Parser;


impl<'lt, 'source_map> Parser<'lt, 'source_map> {
    #[allow(clippy::too_many_lines)]
    pub fn parse_nature(&mut self, attributes: Attributes) -> Result {
        self.consume_lookahead();
        let start = self.preprocessor.current_start();

        let name = self
            .parse_identifier(false)
            .map_err(|err| self.non_critical_errors.push(err));

        /* derived attributes are unsupported for now
        let parent = match self.parse_parent(){
            Err(error) => {
                self.non_critical_errors.push(error);
                self.recover_on(Token::EndNature,Token::Semicolon,false,false)?;
                None
            }
            Ok(res) => res,
        };*/

        self.expect(Token::Semicolon)?;
        let mut abstol = None;
        let mut units = None;
        let mut access = None;
        let mut idt_nature = None;
        let mut ddt_nature = None;
        // user defined attributes are unsupported for now
        self.parse_and_recover_on_tokens(
            Token::Semicolon,
            Token::EndNature,
            true,
            true,
            |parser| {
                let (token, source) = parser.next_with_span()?;
                match token {
                    Token::Abstol if abstol.is_none() => {
                        parser.expect(Token::Assign)?;
                        abstol = Some(parser.parse_expression_id()?);
                    }

                    Token::Access if access.is_none() => {
                        parser.expect(Token::Assign)?;
                        access = Some(parser.parse_identifier(false)?);
                    }

                    Token::TimeIntegralNature if idt_nature.is_none() => {
                        parser.expect(Token::Assign)?;
                        idt_nature = Some(parser.parse_identifier(false)?);
                    }

                    Token::TimeDerivativeNature if ddt_nature.is_none() => {
                        parser.expect(Token::Assign)?;
                        ddt_nature = Some(parser.parse_identifier(false)?);
                    }

                    Token::Units if units.is_none() => {
                        parser.expect(Token::Assign)?;
                        units = Some(parser.parse_expression_id()?);
                    }

                    Token::Abstol
                    | Token::Access
                    | Token::TimeIntegralNature
                    | Token::TimeDerivativeNature
                    | Token::Units => {
                        return Err(Error {
                            error_type: AttributeAlreadyDefined,
                            source: parser.preprocessor.span(),
                        })
                    }

                    _ => {
                        return Err(Error {
                            error_type: UnexpectedToken {
                                expected: vec![
                                    Token::Abstol,
                                    Token::Access,
                                    Token::TimeIntegralNature,
                                    Token::TimeDerivativeNature,
                                    Token::Units,
                                ],
                            },
                            source,
                        })
                    }
                }
                parser.try_expect(Token::Semicolon);
                Ok(true)
            },
        )?;

        let source = self.span_to_current_end(start);

        let mut missing = Vec::new();
        if abstol.is_none() {
            missing.push(keywords::ABSTOL)
        }

        if units.is_none() {
            missing.push(keywords::UNITS)
        }

        if access.is_none() {
            missing.push(keywords::ACCESS)
        }

        if missing.is_empty() {
            if let Ok(name) = name {
                let access = access.unwrap();
                let id = self.ast.natures.push(AttributeNode {
                    attributes,
                    source,
                    contents: Nature {
                        name,
                        abstol: abstol.unwrap(),
                        units: units.unwrap(),
                        access,
                        idt_nature,
                        ddt_nature,
                    },
                });
                self.insert_symbol(name, SymbolDeclaration::Nature(id));
                self.insert_symbol(access, SymbolDeclaration::Nature(id));
            }
        } else {
            self.non_critical_errors.push(Error {
                error_type: RequiredAttributeNotDefined(missing),
                source,
            })
        }

        Ok(())
    }
    /* Nature inheritance is unsupported for now (I don't think anyone has used that ever and its a lot of work)
    fn parse_parent(&mut self)->Result<Option<(Ident,NatureParentType)>>{
        let res = if self.look_ahead()?.0 == Token::Colon{
            let ident = self.parse_identifier(false)?;
            let ptype = if self.look_ahead()?.0 == Token::Accessor{
                self.consume_lookahead();
                match self.next()?{
                    (Token::Potential,_) => NatureParentType::DisciplinePotential,
                    (Token::Flow,_) => NatureParentType::DisciplineFlow,
                    (_,source) => return Err(Error{
                        error_type: UnexpectedToken {expected:vec![Token::Potential,Token::Flow]},
                        source
                    })
                }
            }else{
                NatureParentType::Nature
            };
            Some((ident,ptype))
        }else{
            None
        };
        Ok(res)
    }*/
}