diff --git a/compiler/src/hir/component_preprocess.rs b/compiler/src/hir/component_preprocess.rs index e2512adca..60362f04f 100644 --- a/compiler/src/hir/component_preprocess.rs +++ b/compiler/src/hir/component_preprocess.rs @@ -18,9 +18,15 @@ fn rm_statement(stmt: &mut Statement) { rm_init(stmt); } else if stmt.is_substitution(){ rm_substitution(stmt); + } else if stmt.is_underscore_substitution(){ + rm_underscore_substitution(stmt); } - else{ +} +fn rm_underscore_substitution(stmt: &mut Statement){ + use Statement::{Block, UnderscoreSubstitution}; + if let UnderscoreSubstitution { meta, .. } = stmt{ + *stmt = Block{ meta: meta.clone(), stmts: Vec::new() }; } } diff --git a/compiler/src/hir/merger.rs b/compiler/src/hir/merger.rs index c655ed5de..4cb428b79 100644 --- a/compiler/src/hir/merger.rs +++ b/compiler/src/hir/merger.rs @@ -109,6 +109,8 @@ fn produce_vcf_stmt(stmt: &Statement, state: &mut State, environment: &mut E) { produce_vcf_while(stmt, state, environment); } else if stmt.is_if_then_else() { produce_vcf_conditional(stmt, state, environment); + } else if stmt.is_underscore_substitution() { + //No code should be produced for an instruction of the form _ <== exp; } else { unreachable!(); } @@ -359,6 +361,8 @@ fn link_stmt(stmt: &mut Statement, state: &State, env: &mut E) { link_declaration(stmt, state, env); } else if stmt.is_substitution() { link_substitution(stmt, state, env); + } else if stmt.is_underscore_substitution() { + //No code should be produced for an instruction of the form _ <== exp; } else { unreachable!(); } diff --git a/compiler/src/hir/sugar_cleaner.rs b/compiler/src/hir/sugar_cleaner.rs index 10bc5b606..3572ce7cd 100644 --- a/compiler/src/hir/sugar_cleaner.rs +++ b/compiler/src/hir/sugar_cleaner.rs @@ -62,7 +62,7 @@ fn extend_statement(stmt: &mut Statement, state: &mut State, context: &Context) extend_log_call(stmt, state, context) } else if stmt.is_assert() { extend_assert(stmt, state, context) - } else { + } else{ unreachable!() } } diff --git a/compiler/src/hir/type_inference.rs b/compiler/src/hir/type_inference.rs index 9b3c69200..02b82ee9d 100644 --- a/compiler/src/hir/type_inference.rs +++ b/compiler/src/hir/type_inference.rs @@ -40,7 +40,7 @@ fn infer_type_stmt(stmt: &Statement, state: &State, context: &mut SearchInfo) -> Option::None } else if stmt.is_assert() { Option::None - } else { + } else{ unreachable!() } } diff --git a/constraint_generation/src/environment_utils/component_representation.rs b/constraint_generation/src/environment_utils/component_representation.rs index 23c151b10..c1f85b796 100644 --- a/constraint_generation/src/environment_utils/component_representation.rs +++ b/constraint_generation/src/environment_utils/component_representation.rs @@ -129,9 +129,18 @@ impl ComponentRepresentation { for (symbol, route) in node.outputs() { component.outputs.insert(symbol.clone(), SignalSlice::new_with_route(route, &true)); + let tags_output = node.signal_to_tags.get(symbol); - if tags_output.is_some(){ - component.outputs_tags.insert(symbol.to_string(), tags_output.unwrap().clone()); + let component_tags_output = component.outputs_tags.get_mut(symbol); + if tags_output.is_some() && component_tags_output.is_some(){ + let result_tags_output = tags_output.unwrap(); + let result_component_tags_output = component_tags_output.unwrap(); + for (tag, value) in result_tags_output{ + // only update the output tag in case it contains the tag in the definition + if result_component_tags_output.contains_key(tag){ + result_component_tags_output.insert(tag.clone(), value.clone()); + } + } } } component.node_pointer = Option::Some(node_pointer); diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index ae03fd224..1fe21d291 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -459,6 +459,30 @@ fn execute_statement( &runtime.call_trace, )? } + UnderscoreSubstitution{ meta, rhe, op} =>{ + let f_result = execute_expression(rhe, program_archive, runtime, flag_verbose)?; + let arithmetic_slice = safe_unwrap_to_arithmetic_slice(f_result, line!()); + if *op == AssignOp::AssignConstraintSignal{ + for i in 0..AExpressionSlice::get_number_of_cells(&arithmetic_slice){ + let _value_cell = treat_result_with_memory_error( + AExpressionSlice::access_value_by_index(&arithmetic_slice, i), + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + //let constraint_expression = AExpr::transform_expression_to_constraint_form( + // value_cell, + // runtime.constants.get_p(), + //).unwrap(); + //if let Option::Some(node) = actual_node { + //for signal in constraint_expression.take_signals(){ + // node.add_underscored_signal(signal); + //} + //} + } + } + Option::None + } }; Result::Ok(res) } @@ -960,8 +984,7 @@ fn perform_assign( } } } - /* else { // it is a tag that does not belong to the value - + else { // it is a tag that does not belong to the signal reference_to_tags.insert(tag.clone(), value.clone()); if let Option::Some(node) = actual_node{ node.add_tag_signal(symbol, &tag, value.clone()); @@ -969,7 +992,6 @@ fn perform_assign( unreachable!(); } } - */ } } } diff --git a/constraint_generation/src/execution_data/filters.rs b/constraint_generation/src/execution_data/filters.rs index 06c14d230..20b080ab4 100644 --- a/constraint_generation/src/execution_data/filters.rs +++ b/constraint_generation/src/execution_data/filters.rs @@ -100,6 +100,10 @@ pub fn apply_computed(stmt: &mut Statement, analysis: &Analysis) { *arg = computed_or_original(analysis, arg); apply_computed_expr(arg, analysis); } + UnderscoreSubstitution { rhe, .. } => { + *rhe = computed_or_original(analysis, rhe); + apply_computed_expr(rhe, analysis); + }, } } diff --git a/constraint_list/src/constraint_simplification.rs b/constraint_list/src/constraint_simplification.rs index 0fdb43d71..af57e1bde 100644 --- a/constraint_list/src/constraint_simplification.rs +++ b/constraint_list/src/constraint_simplification.rs @@ -457,7 +457,7 @@ pub fn simplification(smp: &mut Simplifier) -> (ConstraintStorage, SignalMap) { let mut deleted = HashSet::new(); let mut lconst = LinkedList::new(); let mut no_rounds = smp.no_rounds; - let remove_unused = apply_linear; + let remove_unused = true; let relevant_signals = { // println!("Creating first relevant set"); @@ -529,7 +529,7 @@ pub fn simplification(smp: &mut Simplifier) -> (ConstraintStorage, SignalMap) { relevant }; - let linear_substitutions = if remove_unused { + let linear_substitutions = if apply_linear { let now = SystemTime::now(); let (subs, mut cons) = linear_simplification( &mut substitution_log, @@ -585,7 +585,7 @@ pub fn simplification(smp: &mut Simplifier) -> (ConstraintStorage, SignalMap) { let mut round_id = 0; let _ = round_id; let mut linear = with_linear; - let mut apply_round = remove_unused && no_rounds > 0 && !linear.is_empty(); + let mut apply_round = no_rounds > 0 && !linear.is_empty(); let mut non_linear_map = if apply_round || remove_unused { // println!("Building non-linear map"); let now = SystemTime::now(); diff --git a/parser/src/lib.rs b/parser/src/lib.rs index b77e7bb20..ddda36f02 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -131,8 +131,8 @@ pub fn run_parser( let lib = program_archive.get_file_library().clone(); let program_archive_result = apply_syntactic_sugar( &mut program_archive); match program_archive_result { - Result::Err(v) => {Result::Err((lib,vec![v]))} - Result::Ok(()) => {Ok((program_archive, warnings))} + Result::Err(v) => Result::Err((lib,vec![v])), + Result::Ok(_) => Ok((program_archive, warnings)), } } } diff --git a/parser/src/syntax_sugar_remover.rs b/parser/src/syntax_sugar_remover.rs index 713c05e66..21085bff2 100644 --- a/parser/src/syntax_sugar_remover.rs +++ b/parser/src/syntax_sugar_remover.rs @@ -13,133 +13,340 @@ use num_bigint::BigInt; use crate::errors::{AnonymousCompError,TupleError}; +pub fn apply_syntactic_sugar(program_archive : &mut ProgramArchive) -> Result<(), Report> { + let mut new_templates : HashMap = HashMap::new(); + if program_archive.get_main_expression().is_anonymous_comp() { + return Result::Err(AnonymousCompError::anonymous_general_error(program_archive.get_main_expression().get_meta().clone(),"The main component cannot contain an anonymous call ".to_string())); + + } + for temp in program_archive.templates.clone() { + let t = temp.1.clone(); + let body = t.get_body().clone(); + check_anonymous_components_statement(&body)?; + let (new_body, initializations) = remove_anonymous_from_statement(&mut program_archive.templates, &program_archive.file_library, body, &None)?; + if let Statement::Block { meta, mut stmts } = new_body { + let (component_decs, variable_decs, mut substitutions) = separate_declarations_in_comp_var_subs(initializations); + let mut init_block = vec![ + build_initialization_block(meta.clone(), VariableType::Var, variable_decs), + build_initialization_block(meta.clone(), VariableType::Component, component_decs)]; + init_block.append(&mut substitutions); + init_block.append(&mut stmts); + let new_body_with_inits = build_block(meta, init_block); + check_tuples_statement(&new_body_with_inits)?; + let new_body = remove_tuples_from_statement(new_body_with_inits)?; + let t2 = TemplateData::copy(t.get_name().to_string(), t.get_file_id(), new_body, t.get_num_of_params(), t.get_name_of_params().clone(), + t.get_param_location(), t.get_inputs().clone(), t.get_outputs().clone(), t.is_parallel(), t.is_custom_gate(), t.get_declaration_inputs().clone(), t.get_declaration_outputs().clone()); + new_templates.insert(temp.0.clone(), t2); + } else{ + unreachable!() + } + } + program_archive.templates = new_templates; + Result::Ok(()) +} -fn remove_anonymous_from_statement( - templates : &mut HashMap, - file_lib : &FileLibrary, - stm : Statement, - var_access: &Option -) -> Result<(Statement,Vec),Report>{ - match stm.clone() { - Statement::MultSubstitution { meta, lhe, op, rhe } => { +fn check_anonymous_components_statement( + stm : &Statement, +) -> Result<(), Report>{ + match stm { + Statement::MultSubstitution {meta, lhe, rhe, ..} => { if lhe.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(lhe.get_meta().clone(),"An anonymous component cannot be used in the left side of an assignment".to_string())); - } else{ - let (mut stmts, declarations, new_rhe) = remove_anonymous_from_expression(templates, file_lib, rhe, var_access)?; - let subs = Statement::MultSubstitution { meta: meta.clone(), lhe: lhe, op: op, rhe: new_rhe }; - let mut substs = Vec::new(); - if stmts.is_empty(){ - Result::Ok((subs, declarations)) - }else{ - substs.append(&mut stmts); - substs.push(subs); - Result::Ok((Statement::Block { meta : meta, stmts : substs}, declarations)) - } + Result::Err(AnonymousCompError::anonymous_general_error( + meta.clone(), + "An anonymous component cannot be used in the left side of an assignment".to_string()) + ) + } else{ + check_anonymous_components_expression(rhe) } }, - Statement::IfThenElse { meta, cond, if_case, else_case } + Statement::IfThenElse { meta, cond, if_case, else_case, .. } => { if cond.contains_anonymous_comp() { - Result::Err(AnonymousCompError::anonymous_inside_condition_error(cond.get_meta().clone())) + Result::Err(AnonymousCompError::anonymous_inside_condition_error(meta.clone())) } else{ - let (if_ok,mut declarations) = remove_anonymous_from_statement(templates, file_lib, *if_case, var_access)?; - let b_if = Box::new(if_ok); - if else_case.is_none(){ - Result::Ok((Statement::IfThenElse { meta : meta, cond : cond, if_case: b_if, else_case: Option::None},declarations)) - }else { - let else_c = *(else_case.unwrap()); - let (else_ok, mut declarations2) = remove_anonymous_from_statement(templates, file_lib, else_c, var_access)?; - let b_else = Box::new(else_ok); - declarations.append(&mut declarations2); - Result::Ok((Statement::IfThenElse { meta : meta, cond : cond, if_case: b_if, else_case: Option::Some(b_else)},declarations)) + check_anonymous_components_statement(if_case)?; + if else_case.is_some(){ + check_anonymous_components_statement(else_case.as_ref().unwrap())?; } + Result::Ok(()) } } - Statement::While { meta, cond, stmt } => { + Statement::While { meta, cond, stmt, .. } => { if cond.contains_anonymous_comp() { - Result::Err(AnonymousCompError::anonymous_inside_condition_error(cond.get_meta().clone())) + Result::Err(AnonymousCompError::anonymous_inside_condition_error(meta.clone())) } else{ - - let id_var_while = "anon_var_".to_string() + &file_lib.get_line(meta.start, meta.get_file_id()).unwrap().to_string() + "_" + &meta.start.to_string(); - let var_access = Expression::Variable{meta: meta.clone(), name: id_var_while.clone(), access: Vec::new()}; - let mut declarations = vec![]; - let (while_ok, mut declarations2) = remove_anonymous_from_statement(templates, file_lib, *stmt, &Some(var_access.clone()))?; - let b_while = if !declarations2.is_empty(){ - declarations.push( - build_declaration( - meta.clone(), - VariableType::Var, - id_var_while.clone(), - Vec::new(), - ) - ); - declarations.push( - build_substitution( - meta.clone(), - id_var_while.clone(), - vec![], - AssignOp::AssignVar, - Expression::Number(meta.clone(), BigInt::from(0)) - ) - ); - declarations.append(&mut declarations2); - let next_access = Expression::InfixOp{ - meta: meta.clone(), - infix_op: ExpressionInfixOpcode::Add, - lhe: Box::new(var_access), - rhe: Box::new(Expression::Number(meta.clone(), BigInt::from(1))), - }; - let subs_access = Statement::Substitution{ - meta: meta.clone(), - var: id_var_while, - access: Vec::new(), - op: AssignOp::AssignVar, - rhe: next_access, - }; - - let new_block = Statement::Block{ - meta: meta.clone(), - stmts: vec![while_ok, subs_access], - }; - Box::new(new_block) - } else{ - Box::new(while_ok) - }; - - Result::Ok((Statement::While { meta: meta, cond: cond, stmt: b_while}, declarations)) + check_anonymous_components_statement(stmt) } } Statement::LogCall {meta, args } => { - for arg in &args { + for arg in args { if let program_structure::ast::LogArgument::LogExp( exp ) = arg { if exp.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(meta,"An anonymous component cannot be used inside a log".to_string())) + return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone() ,"An anonymous component cannot be used inside a log".to_string())) } } } - Result::Ok((build_log_call(meta, args),Vec::new())) + Result::Ok(()) } - Statement::Assert { meta, arg} => { Result::Ok((build_assert(meta, arg),Vec::new()))} + Statement::Assert { meta, arg} => { + if arg.contains_anonymous_comp() { + Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(), "An anonymous component cannot be used inside an assert".to_string())) + } else{ + Result::Ok(()) + } + } Statement::Return { meta, value: arg}=> { if arg.contains_anonymous_comp(){ - Result::Err(AnonymousCompError::anonymous_general_error(meta,"An anonymous component cannot be used inside a function ".to_string())) + Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(), "An anonymous component cannot be used inside a function ".to_string())) + } else{ + Result::Ok(()) } - else{ Result::Ok((build_return(meta, arg),Vec::new()))} } Statement::ConstraintEquality {meta, lhe, rhe } => { if lhe.contains_anonymous_comp() || rhe.contains_anonymous_comp() { - Result::Err(AnonymousCompError::anonymous_general_error(meta,"An anonymous component cannot be used with operator === ".to_string())) + Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(), "An anonymous component cannot be used with operator === ".to_string())) + } + else{ + Result::Ok(()) } - else{ Result::Ok((build_constraint_equality(meta, lhe, rhe),Vec::new())) } } - Statement::Declaration { meta , xtype , name , - dimensions, .. } => { - for exp in dimensions.clone(){ + Statement::Declaration { meta, dimensions, .. } => { + for exp in dimensions{ if exp.contains_anonymous_comp(){ - return Result::Err(AnonymousCompError::anonymous_general_error(exp.get_meta().clone(),"An anonymous component cannot be used to define a dimension of an array".to_string())); + return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used to define a dimension of an array".to_string())); + } + } + Result::Ok(()) + } + Statement::InitializationBlock { initializations, .. } => + { + for stmt in initializations { + check_anonymous_components_statement(stmt)?; + } + Result::Ok(()) + } + Statement::Block {stmts, .. } => { + + for stmt in stmts { + check_anonymous_components_statement(stmt)?; + } + Result::Ok(()) + } + Statement::Substitution { meta, rhe, access, ..} => { + use program_structure::ast::Access::ComponentAccess; + use program_structure::ast::Access::ArrayAccess; + for acc in access{ + match acc{ + ArrayAccess(exp) =>{ + if exp.contains_anonymous_comp(){ + return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used to define a dimension of an array".to_string())); + } + }, + ComponentAccess(_)=>{}, + } + } + check_anonymous_components_expression(rhe) + } + Statement::UnderscoreSubstitution { .. } => unreachable!(), + } +} + +pub fn check_anonymous_components_expression( + exp : &Expression, +) -> Result<(),Report>{ + use Expression::*; + match exp { + ArrayInLine { meta, values, .. } => { + for value in values{ + if value.contains_anonymous_comp() { + return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used to define a dimension of an array".to_string())); + } + } + Result::Ok(()) + }, + UniformArray { meta, value, dimension } => { + if value.contains_anonymous_comp() || dimension.contains_anonymous_comp() { + Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used to define a dimension of an array".to_string())) + } else{ + Result::Ok(()) + } + }, + Number(_, _) => { + Result::Ok(()) + }, + Variable { meta, access, .. } => { + use program_structure::ast::Access::ComponentAccess; + use program_structure::ast::Access::ArrayAccess; + for acc in access{ + match acc{ + ArrayAccess(exp) =>{ + if exp.contains_anonymous_comp(){ + return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used to define a dimension of an array".to_string())); + } + }, + ComponentAccess(_)=>{}, } } + Result::Ok(()) + }, + InfixOp { meta, lhe, rhe, .. } => { + if lhe.contains_anonymous_comp() || rhe.contains_anonymous_comp() { + Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used in the middle of an operation ".to_string())) + } else{ + Result::Ok(()) + } + }, + PrefixOp { meta, rhe, .. } => { + if rhe.contains_anonymous_comp() { + Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used in the middle of an operation ".to_string())) + } else{ + Result::Ok(()) + } + }, + InlineSwitchOp { meta, cond, if_true, if_false } => { + if cond.contains_anonymous_comp() || if_true.contains_anonymous_comp() || if_false.contains_anonymous_comp() { + Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used inside an inline switch ".to_string())) + } else{ + Result::Ok(()) + } + }, + Call { meta, args, .. } => { + for value in args{ + if value.contains_anonymous_comp() { + return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used as a parameter in a template call ".to_string())); + } + } + Result::Ok(()) + }, + AnonymousComp {meta, params, signals, .. } => { + for value in params{ + if value.contains_anonymous_comp() { + return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used as a parameter in a template call ".to_string())); + } + } + for value in signals{ + check_anonymous_components_expression(value)?; + } + Result::Ok(()) + }, + Tuple {values, .. } => { + + for val in values{ + check_anonymous_components_expression(val)?; + } + Result::Ok(()) + }, + ParallelOp { meta, rhe } => { + if !rhe.is_call() && !rhe.is_anonymous_comp() && rhe.contains_anonymous_comp() { + return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"Bad use of parallel operator in combination with anonymous components ".to_string())); + } + else if rhe.is_call() && rhe.contains_anonymous_comp() { + return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used as a parameter in a template call ".to_string())); + } + Result::Ok(()) + }, + } +} + + +fn remove_anonymous_from_statement( + templates : &HashMap, + file_lib : &FileLibrary, + stm : Statement, + var_access: &Option +) -> Result<(Statement, Vec),Report>{ + match stm { + Statement::MultSubstitution { meta, lhe, op, rhe } => { + + let (mut stmts, declarations, new_rhe) = remove_anonymous_from_expression(templates, file_lib, rhe, var_access)?; + let subs = Statement::MultSubstitution { meta: meta.clone(), lhe: lhe, op: op, rhe: new_rhe }; + let mut substs = Vec::new(); + if stmts.is_empty(){ + Result::Ok((subs, declarations)) + }else{ + substs.append(&mut stmts); + substs.push(subs); + Result::Ok((Statement::Block { meta : meta, stmts : substs}, declarations)) + } + }, + Statement::IfThenElse { meta, cond, if_case, else_case } + => { + + let (if_ok,mut declarations) = remove_anonymous_from_statement(templates, file_lib, *if_case, var_access)?; + let b_if = Box::new(if_ok); + if else_case.is_none(){ + Result::Ok((Statement::IfThenElse { meta : meta, cond : cond, if_case: b_if, else_case: Option::None},declarations)) + }else { + let else_c = *(else_case.unwrap()); + let (else_ok, mut declarations2) = remove_anonymous_from_statement(templates, file_lib, else_c, var_access)?; + let b_else = Box::new(else_ok); + declarations.append(&mut declarations2); + Result::Ok((Statement::IfThenElse { meta : meta, cond : cond, if_case: b_if, else_case: Option::Some(b_else)},declarations)) + } + } + Statement::While { meta, cond, stmt } => { + let id_var_while = "anon_var_".to_string() + &file_lib.get_line(meta.start, meta.get_file_id()).unwrap().to_string() + "_" + &meta.start.to_string(); + let var_access = Expression::Variable{meta: meta.clone(), name: id_var_while.clone(), access: Vec::new()}; + let mut declarations = vec![]; + let (while_ok, mut declarations2) = remove_anonymous_from_statement(templates, file_lib, *stmt, &Some(var_access.clone()))?; + let b_while = if !declarations2.is_empty(){ + declarations.push( + build_declaration( + meta.clone(), + VariableType::Var, + id_var_while.clone(), + Vec::new(), + ) + ); + declarations.push( + build_substitution( + meta.clone(), + id_var_while.clone(), + vec![], + AssignOp::AssignVar, + Expression::Number(meta.clone(), BigInt::from(0)) + ) + ); + declarations.append(&mut declarations2); + let next_access = Expression::InfixOp{ + meta: meta.clone(), + infix_op: ExpressionInfixOpcode::Add, + lhe: Box::new(var_access), + rhe: Box::new(Expression::Number(meta.clone(), BigInt::from(1))), + }; + let subs_access = Statement::Substitution{ + meta: meta.clone(), + var: id_var_while, + access: Vec::new(), + op: AssignOp::AssignVar, + rhe: next_access, + }; + + let new_block = Statement::Block{ + meta: meta.clone(), + stmts: vec![while_ok, subs_access], + }; + Box::new(new_block) + } else{ + Box::new(while_ok) + }; + Result::Ok((Statement::While { meta: meta, cond: cond, stmt: b_while}, declarations)) + }, + Statement::LogCall {meta, args } => { + Result::Ok((build_log_call(meta, args),Vec::new())) + } + Statement::Assert { meta, arg} => { + Result::Ok((build_assert(meta, arg),Vec::new())) + } + Statement::Return { meta, value: arg}=> { + Result::Ok((build_return(meta, arg),Vec::new())) + } + Statement::ConstraintEquality {meta, lhe, rhe } => { + Result::Ok((build_constraint_equality(meta, lhe, rhe),Vec::new())) + } + Statement::Declaration { meta , xtype , name , + dimensions, .. } => { Result::Ok((build_declaration(meta, xtype, name, dimensions),Vec::new())) } Statement::InitializationBlock { meta, xtype, initializations } => @@ -175,87 +382,30 @@ fn remove_anonymous_from_statement( Result::Ok((Statement::Block { meta : meta, stmts : substs}, declarations)) } } + Statement::UnderscoreSubstitution { .. } => unreachable!(), } } // returns a block with the substitutions, the declarations and finally the output expression pub fn remove_anonymous_from_expression( - templates : &mut HashMap, - file_lib : & FileLibrary, + templates : &HashMap, + file_lib : &FileLibrary, exp : Expression, var_access: &Option, // in case the call is inside a loop, variable used to control the access ) -> Result<(Vec, Vec, Expression),Report>{ use Expression::*; - match exp.clone() { - ArrayInLine { values, .. } => { - for value in values{ - if value.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(value.get_meta().clone(),"An anonymous component cannot be used to define a dimension of an array".to_string())); - } - } - Result::Ok((Vec::new(),Vec::new(),exp)) - }, - UniformArray { meta, value, dimension } => { - if value.contains_anonymous_comp() || dimension.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used to define a dimension of an array".to_string())); - } - Result::Ok((Vec::new(),Vec::new(),exp)) - }, - Number(_, _) => { Result::Ok((Vec::new(),Vec::new(),exp)) }, - Variable { meta, .. } => { - if exp.contains_anonymous_comp(){ - return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used to access an array".to_string())); - } - Result::Ok((Vec::new(),Vec::new(),exp)) - }, - InfixOp { meta, lhe, rhe, .. } => { - if lhe.contains_anonymous_comp() || rhe.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used in the middle of an operation ".to_string())); - } - Result::Ok((Vec::new(),Vec::new(),exp)) - }, - PrefixOp { meta, rhe, .. } => { - if rhe.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used in the middle of an operation ".to_string())); - } - Result::Ok((Vec::new(),Vec::new(),exp)) - }, - InlineSwitchOp { meta, cond, if_true, if_false } => { - if cond.contains_anonymous_comp() || if_true.contains_anonymous_comp() || if_false.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used inside an inline switch ".to_string())); - } - Result::Ok((Vec::new(),Vec::new(),exp)) - /* This code is useful if we want to allow anonymous components inside InLineSwitch. - let result_if = remove_anonymous_from_expression( templates, file_lib, *if_true); - let result_else = remove_anonymous_from_expression( templates, file_lib, *if_false); - if result_if.is_err() { Result::Err(result_if.err().unwrap())} - else if result_else.is_err() { Result::Err(result_else.err().unwrap())} - else { - let (result_if2,exp_if) = result_if.ok().unwrap(); - let (result_else2, exp_else) = result_else.ok().unwrap(); - let block_if = if result_if2.is_none() { build_block(meta.clone(), Vec::new())} else { result_if2.unwrap()}; - - Result::Ok((Option::Some(build_conditional_block(meta.clone(), *cond.clone(), block_if, result_else2)), - build_inline_switch_op(meta.clone(), *cond.clone(), exp_if, exp_else)))*/ - - }, - Call { meta, args, .. } => { - for value in args{ - if value.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used as a parameter in a template call ".to_string())); - } - } - Result::Ok((Vec::new(),Vec::new(),exp)) - }, + match exp { AnonymousComp { meta, id, params, signals, names, is_parallel } => { - let template = templates.get(&id); let mut declarations = Vec::new(); + let mut seq_substs = Vec::new(); + // get the template we are calling to + let template = templates.get(&id); if template.is_none(){ return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"The template does not exist ".to_string())); } - let mut i = 0; - let mut seq_substs = Vec::new(); let id_anon_temp = id.to_string() + "_" + &file_lib.get_line(meta.start, meta.get_file_id()).unwrap().to_string() + "_" + &meta.start.to_string(); + + // in case we are not inside a loop, we can automatically convert into a component if var_access.is_none(){ declarations.push(build_declaration( meta.clone(), @@ -263,7 +413,7 @@ pub fn remove_anonymous_from_expression( id_anon_temp.clone(), Vec::new(), )); - } else{ + } else{ // we generate an anonymous component, it depends on the var_access indicating the loop declarations.push(build_declaration( meta.clone(), VariableType::AnonymousComponent, @@ -271,71 +421,82 @@ pub fn remove_anonymous_from_expression( vec![var_access.as_ref().unwrap().clone()], )); } - let call = build_call(meta.clone(), id, params); - if call.contains_anonymous_comp(){ - return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used as a parameter in a template call ".to_string())); - } + // build the call generating the component + let call = build_call(meta.clone(), id.clone(), params.clone()); let exp_with_call = if is_parallel { build_parallel_op(meta.clone(), call) - } else { + } else { call }; + // in case we are in a loop in only generates a position, needs the var_access reference let access = if var_access.is_none(){ Vec::new() } else{ vec![build_array_access(var_access.as_ref().unwrap().clone())] }; - let sub = build_substitution(meta.clone(), id_anon_temp.clone(), - access.clone(), AssignOp::AssignVar, exp_with_call); + // in loop: id_anon_temp[var_access] = (parallel) Template(params); + // out loop: id_anon_temp = (parallel) Template(params) + let sub = build_substitution( + meta.clone(), + id_anon_temp.clone(), + access.clone(), + AssignOp::AssignVar, + exp_with_call + ); seq_substs.push(sub); + + // assign the inputs + // reorder the signals in new_signals (case names) let inputs = template.unwrap().get_declaration_inputs(); let mut new_signals = Vec::new(); let mut new_operators = Vec::new(); if let Some(m) = names { let (operators, names) : (Vec, Vec) = m.iter().cloned().unzip(); - for inp in inputs{ - if !names.contains(&inp.0) { - let error = inp.0.clone() + " has not been found in the anonymous call"; + for (signal, _) in inputs{ + if !names.contains(signal) { + let error = signal.clone() + " has not been found in the anonymous call"; return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),error)); } else { - let pos = names.iter().position(|r| *r == inp.0).unwrap(); + let pos = names.iter().position(|r| r == signal).unwrap(); new_signals.push(signals.get(pos).unwrap().clone()); new_operators.push(*operators.get(pos).unwrap()); } } } else{ - new_signals = signals.clone(); - for _i in 0..signals.len() { + new_signals = signals; + for _i in 0..new_signals.len() { new_operators.push(AssignOp::AssignConstraintSignal); } } - if inputs.len() != new_signals.len() || inputs.len() != signals.len() { + if inputs.len() != new_signals.len() { return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"The number of template input signals must coincide with the number of input parameters ".to_string())); } - for inp in inputs{ + + // generate the substitutions for the inputs + let mut num_input = 0; + for (name_signal, _) in inputs{ let mut acc = if var_access.is_none(){ Vec::new() } else{ vec![build_array_access(var_access.as_ref().unwrap().clone())] }; - acc.push(Access::ComponentAccess(inp.0.clone())); + acc.push(Access::ComponentAccess(name_signal.clone())); let (mut stmts, mut declarations2, new_exp) = remove_anonymous_from_expression( - &mut templates.clone(), + templates, file_lib, - new_signals.get(i).unwrap().clone(), + new_signals.get(num_input).unwrap().clone(), var_access )?; - if new_exp.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(new_exp.get_meta().clone(),"Inputs of an anonymous component cannot contain anonymous calls".to_string())); - } + seq_substs.append(&mut stmts); declarations.append(&mut declarations2); - let subs = Statement::Substitution { meta: meta.clone(), var: id_anon_temp.clone(), access: acc, op: *new_operators.get(i).unwrap(), rhe: new_exp }; - i+=1; + let subs = Statement::Substitution { meta: meta.clone(), var: id_anon_temp.clone(), access: acc, op: *new_operators.get(num_input).unwrap(), rhe: new_exp }; + num_input += 1; seq_substs.push(subs); } + // generate the expression for the outputs -> return as expression (if single out) or tuple let outputs = template.unwrap().get_declaration_outputs(); if outputs.len() == 1 { let output = outputs.get(0).unwrap().0.clone(); @@ -347,7 +508,7 @@ pub fn remove_anonymous_from_expression( acc.push(Access::ComponentAccess(output.clone())); let out_exp = Expression::Variable { meta: meta.clone(), name: id_anon_temp, access: acc }; - Result::Ok((vec![Statement::Block { meta: meta, stmts: seq_substs }],declarations,out_exp)) + Result::Ok((vec![Statement::Block { meta: meta.clone(), stmts: seq_substs }], declarations, out_exp)) } else{ let mut new_values = Vec::new(); @@ -362,7 +523,7 @@ pub fn remove_anonymous_from_expression( new_values.push(out_exp); } let out_exp = Tuple {meta : meta.clone(), values : new_values}; - Result::Ok((vec![Statement::Block { meta: meta, stmts: seq_substs }], declarations, out_exp)) + Result::Ok((vec![Statement::Block { meta: meta.clone(), stmts: seq_substs }], declarations, out_exp)) } }, @@ -381,21 +542,19 @@ pub fn remove_anonymous_from_expression( Err(er) => {return Result::Err(er);}, } } - Result::Ok((new_stmts, declarations, build_tuple(meta, new_values))) + Result::Ok((new_stmts, declarations, build_tuple(meta.clone(), new_values))) }, ParallelOp { meta, rhe } => { - if !rhe.is_call() && !rhe.is_anonymous_comp() && rhe.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"Bad use of parallel operator in combination with anonymous components ".to_string())); - } - else if rhe.is_call() && rhe.contains_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(meta.clone(),"An anonymous component cannot be used as a parameter in a template call ".to_string())); - } - else if rhe.is_anonymous_comp(){ + if rhe.is_anonymous_comp(){ let rhe2 = rhe.make_anonymous_parallel(); - return remove_anonymous_from_expression(templates, file_lib, rhe2, var_access); + remove_anonymous_from_expression(templates, file_lib, rhe2, var_access) + } else{ + Result::Ok((Vec::new(),Vec::new(), ParallelOp { meta, rhe })) } - Result::Ok((Vec::new(),Vec::new(),exp)) }, + _ =>{ + Result::Ok((Vec::new(),Vec::new(),exp)) + } } } @@ -423,42 +582,200 @@ pub fn separate_declarations_in_comp_var_subs(declarations: Vec) -> ( } (components_dec, variables_dec, substitutions) } -pub fn apply_syntactic_sugar(program_archive : &mut ProgramArchive) -> Result<(),Report> { - let mut new_templates : HashMap = HashMap::new(); - if program_archive.get_main_expression().is_anonymous_comp() { - return Result::Err(AnonymousCompError::anonymous_general_error(program_archive.get_main_expression().get_meta().clone(),"The main component cannot contain an anonymous call ".to_string())); - + +fn check_tuples_statement(stm: &Statement)-> Result<(), Report>{ + match stm{ + Statement::MultSubstitution { lhe, rhe, .. } => { + check_tuples_expression(lhe)?; + check_tuples_expression(rhe)?; + Result::Ok(()) + }, + Statement::IfThenElse { cond, if_case, else_case, meta, .. } + => { + if cond.contains_tuple() { + Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used inside a condition ".to_string())) + } else{ + check_tuples_statement(if_case)?; + if else_case.is_some(){ + check_tuples_statement(else_case.as_ref().unwrap())?; + } + Result::Ok(()) + } + } + + Statement::While { meta, cond, stmt } => { + if cond.contains_tuple() { + Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used inside a condition ".to_string())) + } else{ + check_tuples_statement(stmt) + } + } + Statement::LogCall {args, .. } => { + for arg in args { + match arg { + LogArgument::LogStr(_) => {}, + LogArgument::LogExp(exp) => { + check_tuples_expression(&exp)?; + }, + } + } + Result::Ok(()) + } + Statement::Assert { meta, arg} => { + if arg.contains_tuple(){ + Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used in a return ".to_string())) + } + else{ + Result::Ok(()) + } + } + Statement::Return { meta, value: arg}=> { + if arg.contains_tuple(){ + Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used inside a function ".to_string())) + } + else{ + Result::Ok(()) + } + } + Statement::ConstraintEquality {meta, lhe, rhe } => { + if lhe.contains_tuple() || rhe.contains_tuple() { + Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used with the operator === ".to_string())) + } + else{ + Result::Ok(()) + } + } + Statement::Declaration { meta, + dimensions, .. } => + { + for exp in dimensions.clone(){ + if exp.contains_tuple(){ + return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used to define a dimension of an array ".to_string())); + } + } + Result::Ok(()) + } + Statement::InitializationBlock {initializations, ..} => + { + for stmt in initializations { + check_tuples_statement(stmt)?; + } + Result::Ok(()) + } + Statement::Block { stmts, ..} => { + for stmt in stmts { + check_tuples_statement(stmt)?; + } + Result::Ok(()) + } + Statement::Substitution { rhe, access, meta, ..} => { + use program_structure::ast::Access::ComponentAccess; + use program_structure::ast::Access::ArrayAccess; + for acc in access{ + match acc{ + ArrayAccess(exp) =>{ + if exp.contains_tuple(){ + return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used to define a dimension of an array".to_string())); + } + }, + ComponentAccess(_)=>{}, + } + } + check_tuples_expression(rhe) + } + Statement::UnderscoreSubstitution { .. } => unreachable!(), } - for temp in program_archive.templates.clone() { - let t = temp.1.clone(); - let body = t.get_body().clone(); - let (new_body, initializations) = remove_anonymous_from_statement(&mut program_archive.templates, &program_archive.file_library, body, &None)?; - if let Statement::Block { meta, mut stmts } = new_body { - let (component_decs, variable_decs, mut substitutions) = separate_declarations_in_comp_var_subs(initializations); - let mut init_block = vec![ - build_initialization_block(meta.clone(), VariableType::Var, variable_decs), - build_initialization_block(meta.clone(), VariableType::Component, component_decs)]; - init_block.append(&mut substitutions); - init_block.append(&mut stmts); - let new_body_with_inits = build_block(meta, init_block); - let new_body = remove_tuples_from_statement(&mut program_archive.templates, &program_archive.file_library, new_body_with_inits)?; - let t2 = TemplateData::copy(t.get_name().to_string(), t.get_file_id(), new_body, t.get_num_of_params(), t.get_name_of_params().clone(), - t.get_param_location(), t.get_inputs().clone(), t.get_outputs().clone(), t.is_parallel(), t.is_custom_gate(), t.get_declaration_inputs().clone(), t.get_declaration_outputs().clone()); - new_templates.insert(temp.0.clone(), t2); - } else{ - unreachable!() +} + + +pub fn check_tuples_expression(exp: &Expression) -> Result<(), Report>{ + use Expression::*; + match exp{ + ArrayInLine { meta, values } => { + for value in values{ + if value.contains_tuple() { + return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used to define a dimension of an array ".to_string())); + } + } + Result::Ok(()) + }, + UniformArray { meta, value, dimension } => { + if value.contains_tuple() || dimension.contains_tuple() { + return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used to define a dimension of an array ".to_string())); + } + Result::Ok(()) + }, + Number(_, _) => { + Result::Ok(()) + }, + Variable { access, meta, .. } => { + use program_structure::ast::Access::*; + for acc in access{ + match acc{ + ArrayAccess(exp) =>{ + if exp.contains_tuple(){ + return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used to define a dimension of an array".to_string())); + } + }, + ComponentAccess(_)=>{}, + } + } + Result::Ok(()) + }, + InfixOp { meta, lhe, rhe, .. } => { + if lhe.contains_tuple() || rhe.contains_tuple() { + Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used in the middle of an operation".to_string())) + } else{ + Result::Ok(()) + } + }, + PrefixOp { meta, rhe, .. } => { + if rhe.contains_tuple() { + Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used in the middle of an operation".to_string())) + } else{ + Result::Ok(()) + } + }, + InlineSwitchOp { meta, cond, if_true, if_false } => { + if cond.contains_tuple() || if_true.contains_tuple() || if_false.contains_tuple() { + Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used inside an inline switch".to_string())) + } else{ + Result::Ok(()) + } + }, + Call { meta, args, .. } => { + for value in args{ + if value.contains_tuple() { + return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used as a parameter of a function call".to_string())); + } + } + Result::Ok(()) + }, + AnonymousComp { .. } => { + unreachable!(); } + Tuple { values, .. } => { + for val in values { + check_tuples_expression(val)?; + } + Result::Ok(()) + }, + ParallelOp { meta, rhe} => { + if rhe.contains_tuple() { + Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used in a parallel operator ".to_string())) + } else{ + Result::Ok(()) + } + }, } - program_archive.templates = new_templates; - Result::Ok(()) } -fn remove_tuples_from_statement(templates: &mut HashMap, file_lib: &FileLibrary, stm: Statement) -> Result { - match stm.clone() { +fn remove_tuples_from_statement(stm: Statement) -> Result { + match stm{ Statement::MultSubstitution { meta, lhe, op, rhe } => { - let ok = remove_tuple_from_expression(templates, file_lib, lhe)?; - let ok2 = remove_tuple_from_expression(templates, file_lib, rhe)?; - match (ok, ok2) { + let new_exp_lhe = remove_tuple_from_expression(lhe); + let new_exp_rhe = remove_tuple_from_expression(rhe); + match (new_exp_lhe, new_exp_rhe) { (Expression::Tuple { values: mut values1, .. }, Expression::Tuple { values: mut values2, .. }) => { if values1.len() == values2.len() { @@ -468,7 +785,9 @@ fn remove_tuples_from_statement(templates: &mut HashMap, f if let Expression::Variable { meta, name, access } = lhe { let rhe = values2.remove(0); if name != "_" { - substs.push(build_substitution(meta.clone(), name.clone(), access.to_vec(), op, rhe)); + substs.push(build_substitution(meta, name, access, op, rhe)); + } else{ + substs.push(Statement::UnderscoreSubstitution { meta: meta, op, rhe: rhe }); } } else{ return Result::Err(TupleError::tuple_general_error(meta.clone(),"The elements of the receiving tuple must be signals or variables.".to_string())); @@ -492,72 +811,43 @@ fn remove_tuples_from_statement(templates: &mut HashMap, f }, Statement::IfThenElse { meta, cond, if_case, else_case } => { - if cond.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used inside a condition ".to_string())); - } else{ - let if_ok = remove_tuples_from_statement(templates, file_lib, *if_case)?; - let b_if = Box::new(if_ok); - if else_case.is_none(){ - Result::Ok(Statement::IfThenElse { meta : meta, cond : cond, if_case: b_if, else_case: Option::None}) - }else { - let else_c = *(else_case.unwrap()); - let else_ok = remove_tuples_from_statement(templates, file_lib, else_c)?; - let b_else = Box::new(else_ok); - Result::Ok(Statement::IfThenElse { meta : meta, cond : cond, if_case: b_if, else_case: Option::Some(b_else)}) - } + let if_ok = remove_tuples_from_statement(*if_case)?; + let b_if = Box::new(if_ok); + if else_case.is_none(){ + Result::Ok(Statement::IfThenElse { meta : meta, cond : cond, if_case: b_if, else_case: Option::None}) + }else { + let else_c = *(else_case.unwrap()); + let else_ok = remove_tuples_from_statement(else_c)?; + let b_else = Box::new(else_ok); + Result::Ok(Statement::IfThenElse { meta : meta, cond : cond, if_case: b_if, else_case: Option::Some(b_else)}) } } Statement::While { meta, cond, stmt } => { - if cond.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used inside a condition ".to_string())); - } else{ - let while_ok = remove_tuples_from_statement(templates, file_lib, *stmt)?; - let b_while = Box::new(while_ok); - Result::Ok(Statement::While { meta : meta, cond : cond, stmt : b_while}) - } + let while_ok = remove_tuples_from_statement(*stmt)?; + let b_while = Box::new(while_ok); + Result::Ok(Statement::While { meta : meta, cond : cond, stmt : b_while}) } Statement::LogCall {meta, args } => { let mut newargs = Vec::new(); for arg in args { match arg { - LogArgument::LogStr(str) => {newargs.push(LogArgument::LogStr(str));}, + LogArgument::LogStr(str) => { + newargs.push(LogArgument::LogStr(str)); + }, LogArgument::LogExp(exp) => { - let mut args2 = separate_tuple_for_logcall(vec![exp]); - newargs.append(&mut args2); + let mut args2 = separate_tuple_for_logcall(vec![exp]); + newargs.append(&mut args2); }, } } Result::Ok(build_log_call(meta, newargs)) } - Statement::Assert { meta, arg} => { Result::Ok(build_assert(meta, arg))} - Statement::Return { meta, value: arg}=> { - if arg.contains_tuple(){ - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used inside a function ".to_string())); - } - else{ Result::Ok(build_return(meta, arg))} - } - Statement::ConstraintEquality {meta, lhe, rhe } => { - if lhe.contains_tuple() || rhe.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used with the operator === ".to_string())); - } - else{ Result::Ok(build_constraint_equality(meta, lhe, rhe)) } - } - Statement::Declaration { meta , xtype , name , - dimensions, .. } => - { - for exp in dimensions.clone(){ - if exp.contains_tuple(){ - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used to define a dimension of an array ".to_string())); - } - } - Result::Ok(build_declaration(meta, xtype, name, dimensions)) - } Statement::InitializationBlock { meta, xtype, initializations } => { let mut new_inits = Vec::new(); for stmt in initializations { - let stmt_ok = remove_tuples_from_statement(templates, file_lib, stmt)?; + let stmt_ok = remove_tuples_from_statement(stmt)?; new_inits.push(stmt_ok); } Result::Ok(Statement::InitializationBlock { meta: meta, xtype: xtype, initializations: new_inits }) @@ -565,23 +855,25 @@ fn remove_tuples_from_statement(templates: &mut HashMap, f Statement::Block { meta, stmts } => { let mut new_stmts = Vec::new(); for stmt in stmts { - let stmt_ok = remove_tuples_from_statement(templates, file_lib, stmt)?; + let stmt_ok = remove_tuples_from_statement(stmt)?; new_stmts.push(stmt_ok); } Result::Ok(Statement::Block { meta : meta, stmts: new_stmts}) } Statement::Substitution { meta, var, op, rhe, access} => { - let new_rhe = remove_tuple_from_expression(templates, file_lib, rhe)?; - if new_rhe.is_tuple() { + let new_rhe = remove_tuple_from_expression(rhe); + if new_rhe.is_tuple() { return Result::Err(TupleError::tuple_general_error(meta.clone(),"Left-side of the statement is not a tuple".to_string())); } if var != "_" { Result::Ok(Statement::Substitution { meta: meta.clone(), var: var, access: access, op: op, rhe: new_rhe }) } - else {//If this - Result::Ok(build_block(meta, Vec::new())) + else { + Result::Ok(Statement::UnderscoreSubstitution { meta: meta, op, rhe: new_rhe }) } } + Statement::UnderscoreSubstitution { .. } => unreachable!(), + _ => Result::Ok(stm), // The rest of cases do not change the stmt (cannot contain tuples) } } @@ -602,77 +894,25 @@ fn separate_tuple_for_logcall(values: Vec) -> Vec { } -pub fn remove_tuple_from_expression(templates : &mut HashMap, file_lib : & FileLibrary, exp : Expression) -> Result{ +pub fn remove_tuple_from_expression(exp : Expression) -> Expression{ use Expression::*; - match exp.clone() { - ArrayInLine { meta, values } => { - for value in values{ - if value.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used to define a dimension of an array ".to_string())); - } - } - Result::Ok(exp) - }, - UniformArray { meta, value, dimension } => { - if value.contains_tuple() || dimension.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used to define a dimension of an array ".to_string())); - } - Result::Ok(exp) - }, - Number(_, _) => { Result::Ok(exp) }, - Variable { meta, .. } => { - if exp.contains_tuple(){ - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used to access an array ".to_string())); - - } - Result::Ok(exp) - }, - InfixOp { meta, lhe, rhe, .. } => { - if lhe.contains_tuple() || rhe.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used in the middle of an operation".to_string())); - } - Result::Ok(exp) - }, - PrefixOp { meta, rhe, .. } => { - if rhe.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used in the middle of an operation".to_string())); - } - Result::Ok(exp) - }, - InlineSwitchOp { meta, cond, if_true, if_false } => { - if cond.contains_tuple() || if_true.contains_tuple() || if_false.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used inside an inline switch".to_string())); - } - Result::Ok(exp) - }, - Call { meta, args, .. } => { - for value in args{ - if value.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used as a parameter of a function call".to_string())); - } - } - Result::Ok(exp) - }, + match exp { AnonymousComp { .. } => { unreachable!(); } Tuple { meta, values } => { let mut unfolded_values = Vec::new(); for val in values { - let exp = remove_tuple_from_expression(templates, file_lib, val)?; + let exp = remove_tuple_from_expression(val); if let Tuple { values: mut values2, ..} = exp { unfolded_values.append(&mut values2); } else { unfolded_values.push(exp); } } - Result::Ok(build_tuple(meta, unfolded_values)) - }, - ParallelOp { meta, rhe} => { - if rhe.contains_tuple() { - return Result::Err(TupleError::tuple_general_error(meta.clone(),"A tuple cannot be used in a parallel operator ".to_string())); - } - Result::Ok(exp) + build_tuple(meta, unfolded_values) }, + _ => exp, } } + diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index f8ca3b26f..8ebece7af 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -201,6 +201,11 @@ pub enum Statement { op: AssignOp, rhe: Expression, }, + UnderscoreSubstitution{ + meta: Meta, + op: AssignOp, + rhe: Expression, + }, ConstraintEquality { meta: Meta, lhe: Expression, diff --git a/program_structure/src/abstract_syntax_tree/statement_impl.rs b/program_structure/src/abstract_syntax_tree/statement_impl.rs index 496eac1dd..48f681012 100644 --- a/program_structure/src/abstract_syntax_tree/statement_impl.rs +++ b/program_structure/src/abstract_syntax_tree/statement_impl.rs @@ -15,6 +15,7 @@ impl Statement { | ConstraintEquality { meta, .. } | InitializationBlock { meta, .. } => meta, | MultSubstitution { meta, ..} => meta, + | UnderscoreSubstitution { meta, .. } => meta, } } pub fn get_mut_meta(&mut self) -> &mut Meta { @@ -31,6 +32,7 @@ impl Statement { | ConstraintEquality { meta, .. } | InitializationBlock { meta, .. } => meta, | MultSubstitution { meta, ..} => meta, + | UnderscoreSubstitution { meta, .. } => meta, } } @@ -82,6 +84,15 @@ impl Statement { false } } + + pub fn is_underscore_substitution(&self) -> bool { + use Statement::UnderscoreSubstitution; + if let UnderscoreSubstitution { .. } = self { + true + } else { + false + } + } pub fn is_constraint_equality(&self) -> bool { use Statement::ConstraintEquality; if let ConstraintEquality { .. } = self { @@ -146,11 +157,15 @@ impl FillMeta for Statement { LogCall { meta, args, .. } => fill_log_call(meta, args, file_id, element_id), Block { meta, stmts, .. } => fill_block(meta, stmts, file_id, element_id), Assert { meta, arg, .. } => fill_assert(meta, arg, file_id, element_id), + UnderscoreSubstitution { meta, rhe, .. } => { + fill_underscore_substitution(meta, rhe, file_id, element_id); + }, } } } + fn fill_conditional( meta: &mut Meta, cond: &mut Expression, @@ -268,3 +283,9 @@ fn fill_assert(meta: &mut Meta, arg: &mut Expression, file_id: usize, element_id meta.set_file_id(file_id); arg.fill(file_id, element_id); } + +fn fill_underscore_substitution(meta: &mut Meta, rhe: &mut Expression, file_id: usize, element_id: &mut usize) { + meta.set_file_id(file_id); + rhe.fill(file_id, element_id); + +} \ No newline at end of file diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index ccb2accc7..42a50f045 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -14,6 +14,7 @@ pub enum ReportCode { UnableToTypeFunction, UnreachableConstraints, UnreachableTags, + UnreachableSignals, UnknownIndex, UnknownDimension, SameFunctionDeclaredTwice, @@ -101,8 +102,6 @@ impl fmt::Display for ReportCode { UninitializedSymbolInExpression => "T2003", UnableToTypeFunction => "T2004", UnreachableConstraints => "T2005", - UnreachableTags => "T2015", - MainComponentWithTags => "T2016", SameFunctionDeclaredTwice => "T2006", SameTemplateDeclaredTwice => "T2007", SameSymbolDeclaredTwice => "T2008", @@ -152,6 +151,9 @@ impl fmt::Display for ReportCode { MustBeSameDimension => "T2046", MustBeArithmetic => "T2047", OutputTagCannotBeModifiedOutside => "T2048", + UnreachableTags => "T2049", + UnreachableSignals => "T2050", + MainComponentWithTags => "T2051", RuntimeError => "T3001", RuntimeWarning => "T3002", UnknownDimension => "T20460", @@ -171,7 +173,7 @@ impl fmt::Display for ReportCode { CustomGatesPragmaError => "CG04", CustomGatesVersionError => "CG05", AnonymousCompError => "TAC01", - TupleError => "TAC02" + TupleError => "TAC02", }; f.write_str(string_format) } diff --git a/type_analysis/src/analyzers/custom_gate_analysis.rs b/type_analysis/src/analyzers/custom_gate_analysis.rs index 6e4e879de..8269bbde2 100644 --- a/type_analysis/src/analyzers/custom_gate_analysis.rs +++ b/type_analysis/src/analyzers/custom_gate_analysis.rs @@ -101,6 +101,24 @@ pub fn custom_gate_analysis( custom_gate_analysis(custom_gate_name, stmt, errors, warnings); } } + UnderscoreSubstitution { meta, op, .. } => { + use AssignOp::*; + match op { + AssignConstraintSignal => { + let mut error = Report::error( + String::from("Added constraint inside custom template"), + ReportCode::CustomGateConstraintError + ); + error.add_primary( + meta.location.clone(), + meta.file_id.unwrap(), + String::from("Added constraint") + ); + errors.push(error); + } + _ => {} + } + } _ => {} }; } diff --git a/type_analysis/src/analyzers/functions_free_of_template_elements.rs b/type_analysis/src/analyzers/functions_free_of_template_elements.rs index b508f05c6..b5330864c 100644 --- a/type_analysis/src/analyzers/functions_free_of_template_elements.rs +++ b/type_analysis/src/analyzers/functions_free_of_template_elements.rs @@ -115,6 +115,19 @@ fn analyse_statement( Return { value, .. } => { analyse_expression(value, function_names, reports); } + UnderscoreSubstitution { meta, op, rhe } => { + if op.is_signal_operator() { + let mut report = Report::error( + "Function uses template operators".to_string(), + ReportCode::UndefinedFunction, + ); + let location = + file_definition::generate_file_location(meta.get_start(), meta.get_end()); + report.add_primary(location, file_id, "Template operator found".to_string()); + reports.push(report); + } + analyse_expression(rhe, function_names, reports); + }, } } diff --git a/type_analysis/src/analyzers/symbol_analysis.rs b/type_analysis/src/analyzers/symbol_analysis.rs index 0ecc67167..1d92ce25e 100644 --- a/type_analysis/src/analyzers/symbol_analysis.rs +++ b/type_analysis/src/analyzers/symbol_analysis.rs @@ -168,6 +168,9 @@ fn analyze_statement( Statement::Return { value, .. } => { analyze_expression(value, file_id, function_info, template_info, reports, environment) } + Statement::UnderscoreSubstitution { rhe, .. } => { + analyze_expression(rhe, file_id, function_info, template_info, reports, environment); + } Statement::Substitution { meta, var, access, rhe, .. } => { analyze_expression(rhe, file_id, function_info, template_info, reports, environment); treat_variable( diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index aa5f5cc95..82c153c88 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -379,6 +379,21 @@ fn type_statement( analysis_information.environment.remove_variable_block(); } MultSubstitution { .. } => unreachable!(), + UnderscoreSubstitution { rhe , ..} => { + let rhe_response = type_expression(rhe, program_archive, analysis_information); + let rhe_type = if let Result::Ok(r_type) = rhe_response { + r_type + } else { + return; + }; + if rhe_type.is_template() { + add_report( + ReportCode::MustBeArithmetic, + rhe.get_meta(), + &mut analysis_information.reports, + ); + } + }, } } fn type_expression( diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index 7806c5174..01c4cb582 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -152,6 +152,15 @@ fn analyze(stmt: &Statement, entry_information: EntryInformation) -> ExitInforma } } } + UnderscoreSubstitution { op, rhe, .. } => { + let _expression_tag = tag(rhe, &environment); + if *op == AssignOp::AssignConstraintSignal { + constraints_declared = true; + if is_non_quadratic(rhe, &environment) { + add_report(ReportCode::NonQuadratic, rhe.get_meta(), file_id, &mut reports); + } + } + }, ConstraintEquality { lhe, rhe, .. } => { constraints_declared = true; if is_non_quadratic(lhe, &environment) { diff --git a/type_analysis/src/decorators/constants_handler.rs b/type_analysis/src/decorators/constants_handler.rs index 11782ddc9..bbffe78d7 100644 --- a/type_analysis/src/decorators/constants_handler.rs +++ b/type_analysis/src/decorators/constants_handler.rs @@ -291,7 +291,8 @@ fn expand_statement(stmt: &mut Statement, environment: &mut ExpressionHolder) { LogCall { args, .. } => expand_log_call(args, environment), Assert { arg, .. } => expand_assert(arg, environment), Block { stmts, .. } => expand_block(stmts, environment), - MultSubstitution { .. } => unreachable!() + MultSubstitution { .. } => unreachable!(), + UnderscoreSubstitution { rhe, .. } => expand_underscore_substitution(rhe, environment), } } @@ -362,6 +363,13 @@ fn expand_substitution( } } +fn expand_underscore_substitution( + rhe: &mut Expression, + environment: &ExpressionHolder, +) { + *rhe = expand_expression(rhe.clone(), environment); +} + fn expand_constraint_equality( lhe: &mut Expression, rhe: &mut Expression, diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index bade4526a..3e42a1027 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -48,7 +48,10 @@ fn reduce_types_in_statement(stmt: &mut Statement, environment: &mut Environment ConstraintEquality { lhe, rhe, .. } => { reduce_types_in_constraint_equality(lhe, rhe, environment) } - MultSubstitution { .. } => unreachable!() + MultSubstitution { .. } => unreachable!(), + UnderscoreSubstitution { rhe, .. } => { + reduce_types_in_expression(rhe, environment); + }, } }