use crate::ir::ast::Discipline;
use crate::ir::{AttributeNode, Attributes};
use crate::parser::error::Type::{
AttributeAlreadyDefined, DiscreteDisciplineHasNatures, UnexpectedToken,
};
use crate::parser::lexer::Token;
use crate::parser::{Error, Result};
use crate::symbol_table::SymbolDeclaration;
use crate::Parser;
impl<'lt, 'source_map> Parser<'lt, 'source_map> {
pub fn parse_discipline(&mut self, attributes: Attributes) -> Result {
let start = self.preprocessor.current_start();
self.consume_lookahead();
let name = self
.parse_identifier(false)
.map_err(|err| self.non_critical_errors.push(err));
self.try_expect(Token::Semicolon);
let mut potential_nature = None;
let mut flow_nature = None;
let mut continuous = None;
self.parse_and_recover_on_tokens(
Token::Semicolon,
Token::EndDiscipline,
true,
true,
|parser| {
match parser.next_with_span()? {
(Token::Potential, _) if potential_nature.is_none() => {
potential_nature = Some(parser.parse_identifier(false)?);
}
(Token::Flow, _) if flow_nature.is_none() => {
flow_nature = Some(parser.parse_identifier(false)?);
}
(Token::Domain, _) if continuous.is_none() => {
continuous = match parser.next_with_span()? {
(Token::Continuous, _) => Some(true),
(Token::Discrete, _) => Some(false),
(_, source) => {
return Err(Error {
error_type: UnexpectedToken {
expected: vec![Token::Discrete, Token::Continuous],
},
source,
})
}
};
}
(Token::Potential, source)
| (Token::Flow, source)
| (Token::Domain, source) => {
return Err(Error {
error_type: AttributeAlreadyDefined,
source,
})
}
(_, source) => {
return Err(Error {
error_type: UnexpectedToken {
expected: vec![Token::Potential, Token::Flow, Token::Domain],
},
source,
})
}
}
parser.expect(Token::Semicolon)?;
Ok(true)
},
)?;
let source = self.span_to_current_end(start);
let continuous = match continuous {
Some(true) => Some(true),
Some(false) if potential_nature.is_some() || potential_nature.is_some() => {
self.non_critical_errors.push(Error {
error_type: DiscreteDisciplineHasNatures,
source,
});
return Ok(());
}
None if potential_nature.is_some() || potential_nature.is_some() => Some(true),
v => v,
};
if let Ok(name) = name {
let id = self.ast.disciplines.push(AttributeNode {
attributes,
source,
contents: Discipline {
name,
flow_nature,
potential_nature,
continuous,
},
});
self.insert_symbol(name, SymbolDeclaration::Discipline(id))
}
Ok(())
}
}