blob: 7f1cbe2b52c095846f4a4888d6251e9c07fdc87d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2021 CentraleSupelec, CEA-LIST
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Erwan Mahé (CentraleSupelec) - initial API and implementation
*******************************************************************************/
use pest::Parser;
use pest::iterators::{Pair,Pairs};
use crate::core::context::general::GeneralContext;
use crate::core::syntax::data::td_type::TD_DataType;
use crate::core::syntax::data::generic::TD_Generic;
use crate::core::syntax::data::builtin::number::{ARITH_FACTOR_SIGN, ARITH_ADD_SIGN};
use crate::core::syntax::data::builtin::integer::TD_Integer;
use crate::core::syntax::data::builtin::float::TD_Float;
use crate::core::syntax::data::var_ref::VariableReference;
use crate::from_text::error::HibouParsingError;
use crate::from_text::parser::*;
#[derive(Clone, PartialEq, Eq)]
pub enum ParsingNumberKind {
Integer,
Float
}
pub fn parse_arith_expr(gen_ctx : &GeneralContext, arth_pair : Pair<Rule>, opt_ms_id : &Option<usize>) -> Result<TD_Generic,HibouParsingError> {
let mut pairs = arth_pair.into_inner();
let factor_pair = pairs.next().unwrap();
// ***
let as_raw_string_for_error = factor_pair.as_str().to_string();
// ***
match parse_factor_expr(gen_ctx,factor_pair,opt_ms_id) {
Err(e) => {
return Err(e);
},
Ok( factor_td_gen ) => {
match factor_td_gen {
TD_Generic::Integer( factor_td_int ) => {
let mut adds : Vec<(ARITH_ADD_SIGN,TD_Integer)> = Vec::new();
adds.push( (ARITH_ADD_SIGN::Plus,factor_td_int) );
while let Some(next_add) = pairs.next() {
match parse_add_expr(gen_ctx,next_add,opt_ms_id) {
Err(e) => {
return Err(e);
},
Ok( (sign,add_td_gen) ) => {
match add_td_gen {
TD_Generic::Integer( add_td_int ) => {
adds.push( (sign,add_td_int) );
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
}
if adds.len() == 1 {
let (_,prim) = adds.get(0).unwrap();
return Ok( TD_Generic::Integer(prim.clone()) );
} else {
return Ok( TD_Generic::Integer( TD_Integer::Add(adds) ) );
}
},
TD_Generic::Float( factor_td_float ) => {
let mut adds : Vec<(ARITH_ADD_SIGN,TD_Float)> = Vec::new();
adds.push( (ARITH_ADD_SIGN::Plus,factor_td_float) );
while let Some(next_add) = pairs.next() {
match parse_add_expr(gen_ctx,next_add,opt_ms_id) {
Err(e) => {
return Err(e);
},
Ok( (sign,add_td_gen) ) => {
match add_td_gen {
TD_Generic::Float( add_td_float ) => {
adds.push( (sign,add_td_float) );
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
}
if adds.len() == 1 {
let(_,prim) = adds.get(0).unwrap();
return Ok( TD_Generic::Float(prim.clone()) );
} else {
return Ok( TD_Generic::Float( TD_Float::Add(adds) ) );
}
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
}
fn parse_add_expr(gen_ctx : &GeneralContext, add_pair : Pair<Rule>, opt_ms_id : &Option<usize>) -> Result<(ARITH_ADD_SIGN,TD_Generic),HibouParsingError> {
let mut pairs = add_pair.into_inner();
let sign_pair = pairs.next().unwrap();
let factor_pair = pairs.next().unwrap();
match parse_factor_expr(gen_ctx,factor_pair,opt_ms_id) {
Err(e) => {
return Err(e);
},
Ok( factor_td_gen ) => {
match sign_pair.as_rule() {
Rule::ARITH_PLUS => {
return Ok( (ARITH_ADD_SIGN::Plus,factor_td_gen) );
},
Rule::ARITH_MINUS => {
return Ok( (ARITH_ADD_SIGN::Minus,factor_td_gen) );
},
_ => {
unreachable!();
}
}
}
}
}
fn parse_primary_expr(gen_ctx : &GeneralContext, primary_pair : Pair<Rule>, opt_ms_id : &Option<usize>) -> Result<TD_Generic,HibouParsingError> {
let mut contents = primary_pair.into_inner();
let first_pair = contents.next().unwrap();
// ***
let as_raw_string_for_error = first_pair.as_str().to_string();
// ***
match first_pair.as_rule() {
Rule::ARITH_EXPR => {
return parse_arith_expr(gen_ctx,first_pair,opt_ms_id);
},
Rule::ARITH_FLOAT => {
let content_str : String = first_pair.as_str().chars().filter(|c| !c.is_whitespace()).collect();
let my_val : f64 = content_str.parse::<f64>().unwrap();
let td_float = TD_Float::Value( my_val );
return Ok( TD_Generic::Float(td_float) );
},
Rule::ARITH_INTEGER => {
let content_str : String = first_pair.as_str().chars().filter(|c| !c.is_whitespace()).collect();
let my_val : i64 = content_str.parse::<i64>().unwrap();
let td_int = TD_Integer::Value( my_val );
return Ok( TD_Generic::Integer(td_int) );
},
Rule::MSG_PRM_REF => {
match opt_ms_id {
None => {
return Err( HibouParsingError::ParameterUsageError("need contextual message to parse data with message parameter reference".to_string()));
},
Some( ms_id ) => {
match gen_ctx.get_ms_spec(*ms_id) {
Err(e) => {
panic!();
},
Ok( ms_spec ) => {
let content = first_pair.into_inner().next().unwrap();
match content.as_rule() {
Rule::PRM_LABEL => {
let prm_label : String = content.as_str().chars().filter(|c| !c.is_whitespace()).collect();
let mut idx : usize = 0;
for (pr_type,opt_pr_name) in ms_spec {
if let Some(got_pr_name) = opt_pr_name {
if got_pr_name == prm_label {
let var_ref = VariableReference::MSG_PARAMETER(*ms_id,idx);
match pr_type {
TD_DataType::Integer => {
return Ok( TD_Generic::Integer(TD_Integer::Reference(var_ref)) );
},
TD_DataType::Float => {
return Ok( TD_Generic::Float(TD_Float::Reference(var_ref)) );
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
idx = idx +1;
}
return Err(HibouParsingError::ParameterUsageError( format!("no parameter '{}' in message '{}'",prm_label,gen_ctx.get_ms_name(*ms_id).unwrap()) ));
},
Rule::ARITH_INTEGER => {
let pr_id : usize = content.as_str().parse::<usize>().unwrap();
match ms_spec.get(pr_id) {
None => {
return Err(HibouParsingError::ParameterUsageError( format!("no parameter number '{}' in message '{}'",pr_id,gen_ctx.get_ms_name(*ms_id).unwrap()) ));
},
Some( (pr_type,opt_pr_name) ) => {
let var_ref = VariableReference::MSG_PARAMETER(*ms_id,pr_id);
match pr_type {
TD_DataType::Integer => {
return Ok( TD_Generic::Integer(TD_Integer::Reference(var_ref)) );
},
TD_DataType::Float => {
return Ok( TD_Generic::Float(TD_Float::Reference(var_ref)) );
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
},
_ => {
panic!("what rule then ? : {:?}", content.as_rule() );
}
}
}
}
}
}
},
Rule::VAR_LABEL => {
let content_str : String = first_pair.as_str().chars().filter(|c| !c.is_whitespace()).collect();
match gen_ctx.get_vr_id(&content_str) {
None => {
return Err( HibouParsingError::MissingVariableDeclarationError( content_str ) );
},
Some( vr_id ) => {
let var_ref = VariableReference::VARIABLE(vr_id);
match gen_ctx.get_vr_type( vr_id ).unwrap() {
TD_DataType::Integer => {
return Ok( TD_Generic::Integer(TD_Integer::Reference(var_ref)) );
},
TD_DataType::Float => {
return Ok( TD_Generic::Float(TD_Float::Reference(var_ref)) );
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
},
Rule::ARITH_MINUS => {
let second_pair = contents.next().unwrap();
match parse_primary_expr(gen_ctx,second_pair,opt_ms_id) {
Err(e) => {
return Err(e);
},
Ok( td_gen ) => {
match td_gen {
TD_Generic::Integer(td_int) => {
return Ok( TD_Generic::Integer(TD_Integer::Minus(Box::new(td_int))) );
},
TD_Generic::Float(td_float) => {
return Ok( TD_Generic::Float(TD_Float::Minus(Box::new(td_float))) );
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
},
_ => {
unreachable!();
}
}
}
fn parse_factor_expr(gen_ctx : &GeneralContext, factor_pair : Pair<Rule>, opt_ms_id : &Option<usize>) -> Result<TD_Generic,HibouParsingError> {
let mut pairs = factor_pair.into_inner();
let primary_pair = pairs.next().unwrap();
// ***
let as_raw_string_for_error = primary_pair.as_str().to_string();
// ***
match parse_primary_expr(gen_ctx,primary_pair,opt_ms_id) {
Err(e) => {
return Err(e);
},
Ok( primary_td_gen ) => {
match primary_td_gen {
TD_Generic::Integer( primary_td_int ) => {
let mut exprs : Vec<(ARITH_FACTOR_SIGN,TD_Integer)> = Vec::new();
exprs.push( (ARITH_FACTOR_SIGN::Mult,primary_td_int) );
while let Some(next_exp) = pairs.next() {
match parse_mult_expr(gen_ctx,next_exp,opt_ms_id) {
Err(e) => {
return Err(e);
},
Ok( (sign,mult_td_gen) ) => {
match mult_td_gen {
TD_Generic::Integer( mult_td_int ) => {
exprs.push( (sign,mult_td_int) );
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
}
if exprs.len() == 1 {
let (_,prim) = exprs.get(0).unwrap();
return Ok( TD_Generic::Integer(prim.clone()) );
} else {
return Ok( TD_Generic::Integer(TD_Integer::Factor(exprs)));
}
},
TD_Generic::Float( primary_td_float ) => {
let mut exprs : Vec<(ARITH_FACTOR_SIGN,TD_Float)> = Vec::new();
exprs.push( (ARITH_FACTOR_SIGN::Mult,primary_td_float) );
while let Some(next_exp) = pairs.next() {
match parse_mult_expr(gen_ctx,next_exp,opt_ms_id) {
Err(e) => {
return Err(e);
},
Ok( (sign,mult_td_gen) ) => {
match mult_td_gen {
TD_Generic::Float( mult_td_float ) => {
exprs.push( (sign,mult_td_float) );
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
}
if exprs.len() == 1 {
let (_,prim) = exprs.get(0).unwrap();
return Ok( TD_Generic::Float( prim.clone() ) );
} else {
return Ok( TD_Generic::Float(TD_Float::Factor(exprs)));
}
},
_ => {
return Err( HibouParsingError::MalformedArithmeticExpression( as_raw_string_for_error ) );
}
}
}
}
}
fn parse_mult_expr(gen_ctx : &GeneralContext, mult_pair : Pair<Rule>, opt_ms_id : &Option<usize>) -> Result<(ARITH_FACTOR_SIGN,TD_Generic),HibouParsingError> {
let mut pairs = mult_pair.into_inner();
let sign_pair = pairs.next().unwrap();
let primary_pair = pairs.next().unwrap();
match parse_primary_expr(gen_ctx,primary_pair,opt_ms_id) {
Err(e) => {
return Err(e);
},
Ok( primary_td_gen ) => {
match sign_pair.as_rule() {
Rule::ARITH_MULT => {
return Ok( (ARITH_FACTOR_SIGN::Mult,primary_td_gen) );
},
Rule::ARITH_DIV => {
return Ok( (ARITH_FACTOR_SIGN::Div,primary_td_gen) );
},
_ => {
unreachable!();
}
}
}
}
}