diff --git a/circom/Cargo.toml b/circom/Cargo.toml index 27d1ef2a1..9bf116eab 100644 --- a/circom/Cargo.toml +++ b/circom/Cargo.toml @@ -1,10 +1,16 @@ [package] name = "circom" version = "2.0.6" -authors = ["Costa Group UCM & iden3"] -edition = "2021" +authors = ["Costa Group UCM","iden3"] +edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +description = "circom is a zkSnark circuit compiler" +homepage = "https://iden3.io/circom" +documentation = "https://docs.circom.io" +repository = "https://github.com/iden3/circom" +readme = "README.md" +keywords = ["zkproofs", "zksanrks","circuits","compiler"] +categories = ["compilers"] [dependencies] parser = {path = "../parser"} diff --git a/circom_algebra/Cargo.toml b/circom_algebra/Cargo.toml index b8682b767..568053463 100644 --- a/circom_algebra/Cargo.toml +++ b/circom_algebra/Cargo.toml @@ -1,11 +1,9 @@ [package] name = "circom_algebra" -version = "2.0.0" -authors = ["hermeGarcia "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] num-bigint-dig = "0.6.0" num-traits = "0.2.6" diff --git a/code_producers/Cargo.toml b/code_producers/Cargo.toml index 8b88a95a4..b39bfc43c 100644 --- a/code_producers/Cargo.toml +++ b/code_producers/Cargo.toml @@ -1,11 +1,9 @@ [package] name = "code_producers" -version = "2.0.1" -authors = ["hermeGarcia "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] handlebars = "4.1.3" lz_fnv = "0.1.2" diff --git a/code_producers/src/c_elements/mod.rs b/code_producers/src/c_elements/mod.rs index bc8c12897..f4f530b38 100644 --- a/code_producers/src/c_elements/mod.rs +++ b/code_producers/src/c_elements/mod.rs @@ -1,4 +1,5 @@ pub mod c_code_generator; + pub use crate::components::*; pub type CInstruction = String; @@ -25,6 +26,7 @@ pub struct CProducer { pub field_tracking: Vec, version: usize, name_tag: String, + string_table: Vec, } impl Default for CProducer { @@ -88,6 +90,7 @@ impl Default for CProducer { // fix values version: 2, name_tag: "name".to_string(), + string_table : Vec::new(), } } } @@ -150,4 +153,12 @@ impl CProducer { pub fn get_size_32_bit(&self) -> usize { self.size_32_bit } + + pub fn get_string_table(&self) -> &Vec { + &self.string_table + } + + pub fn set_string_table(&mut self, string_table: Vec) { + self.string_table = string_table; + } } diff --git a/code_producers/src/wasm_elements/bls12381/witness_calculator.js b/code_producers/src/wasm_elements/bls12381/witness_calculator.js index 2fd08bff7..0db042162 100755 --- a/code_producers/src/wasm_elements/bls12381/witness_calculator.js +++ b/code_producers/src/wasm_elements/bls12381/witness_calculator.js @@ -13,31 +13,34 @@ module.exports = async function builder(code, options) { let wc; + let errStr = ""; const instance = await WebAssembly.instantiate(wasmModule, { runtime: { exceptionHandler : function(code) { - let errStr; + let err; if (code == 1) { - errStr= "Signal not found. "; + err = "Signal not found.\n"; } else if (code == 2) { - errStr= "Too many signals set. "; + err = "Too many signals set.\n"; } else if (code == 3) { - errStr= "Signal already set. "; + err = "Signal already set.\n"; } else if (code == 4) { - errStr= "Assert Failed. "; + err = "Assert Failed.\n"; } else if (code == 5) { - errStr= "Not enough memory. "; + err = "Not enough memory.\n"; } else if (code == 6) { - errStr= "Input signal array access exceeds the size"; + err = "Input signal array access exceeds the size.\n"; } else { - errStr= "Unknown error\n"; + err = "Unknown error.\n"; } - // get error message from wasm - errStr += getMessage(); - throw new Error(errStr); + throw new Error(err + errStr); }, - showSharedRWMemory: function() { + printErrorMessage : function() { + errStr += getMessage() + "\n"; + // console.error(getMessage()); + }, + showSharedRWMemory : function() { printSharedRWMemory (); } @@ -75,12 +78,7 @@ module.exports = async function builder(code, options) { for (let j=0; j, } impl Default for WASMProducer { @@ -103,6 +106,8 @@ impl Default for WASMProducer { create_loop_sub_cmp_tag: "$createloopsubcmp".to_string(), create_loop_offset_tag: "$createloopoffset".to_string(), create_loop_counter_tag: "$createloopcounter".to_string(), + merror_tag: "$merror".to_string(), + string_table: Vec::new(), } } } @@ -295,9 +300,14 @@ impl WASMProducer { pub fn get_message_list_start(&self) -> usize { self.get_message_buffer_start() + self.size_of_message_buffer_in_bytes } - pub fn get_constant_numbers_start(&self) -> usize { + pub fn get_string_list_start(&self) -> usize { self.get_message_list_start() + self.size_of_message_in_bytes * self.message_list.len() } + + pub fn get_constant_numbers_start(&self) -> usize { + self.get_string_list_start() + self.size_of_message_in_bytes * self.string_table.len() + } + pub fn get_var_stack_memory_start(&self) -> usize { self.get_constant_numbers_start() + (self.size_32_bit + 2) * 4 * self.field_tracking.len() } @@ -361,7 +371,18 @@ impl WASMProducer { pub fn get_create_loop_counter_tag(&self) -> &str { &self.create_loop_counter_tag } + pub fn get_merror_tag(&self) -> &str { + &self.merror_tag + } pub fn needs_comments(&self) -> bool{ self.wat_flag } + + pub fn get_string_table(&self) -> &Vec { + &self.string_table + } + + pub fn set_string_table(&mut self, string_table: Vec) { + self.string_table = string_table; + } } diff --git a/code_producers/src/wasm_elements/wasm_code_generator.rs b/code_producers/src/wasm_elements/wasm_code_generator.rs index f9437e226..bb064ad20 100644 --- a/code_producers/src/wasm_elements/wasm_code_generator.rs +++ b/code_producers/src/wasm_elements/wasm_code_generator.rs @@ -494,6 +494,14 @@ pub fn generate_imports_list() -> Vec { "(import \"runtime\" \"exceptionHandler\" (func $exceptionHandler (type $_t_i32)))" .to_string(), ); + imports.push( + "(import \"runtime\" \"printErrorMessage\" (func $printErrorMessage (type $_t_void)))" + .to_string(), + ); + imports.push( + "(import \"runtime\" \"writeBufferMessage\" (func $writeBufferMessage (type $_t_void)))" + .to_string(), + ); imports.push( "(import \"runtime\" \"showSharedRWMemory\" (func $showSharedRWMemory (type $_t_void)))" .to_string(), @@ -596,9 +604,26 @@ pub fn generate_data_list(producer: &WASMProducer) -> Vec { )); } else { wdata.push(format!( - "(data (i32.const {}) \"{}\")", + "(data (i32.const {}) \"{}\\00\")", m + i * producer.get_size_of_message_in_bytes(), - ml[i] + &ml[i][..producer.get_size_of_message_in_bytes()-1] + )); + } + } + let st = producer.get_string_table(); + let s = producer.get_string_list_start(); + for i in 0..st.len() { + if st[i].len() < producer.get_size_of_message_in_bytes() { + wdata.push(format!( + "(data (i32.const {}) \"{}\\00\")", + s + i * producer.get_size_of_message_in_bytes(), + st[i] + )); + } else { + wdata.push(format!( + "(data (i32.const {}) \"{}\\00\")", + s + i * producer.get_size_of_message_in_bytes(), + &st[i][..producer.get_size_of_message_in_bytes()-1] )); } } @@ -893,6 +918,7 @@ pub fn set_input_signal_generator(producer: &WASMProducer) -> Vec Vec Vec Vec { + let mut instructions = vec![]; + let header = "(func $buildLogMessage (type $_t_i32)".to_string(); + instructions.push(header); + instructions.push(" (param $m i32)".to_string()); //string position + instructions.push(" (local $em i32)".to_string()); //position in error message + instructions.push(" (local $bm i32)".to_string()); //position in buffer + instructions.push(" (local $mc i32)".to_string()); //message char + instructions.push(get_local("$m")); + instructions.push(set_local("$em")); instructions.push(set_constant(&producer.get_message_buffer_start().to_string())); - instructions.push(get_local("$c")); + instructions.push(set_local("$bm")); + instructions.push(add_block()); + instructions.push(add_loop()); //move bytes until end of message or zero found + // check if end of message + let final_pos = producer.get_size_of_message_in_bytes() + producer.get_message_buffer_start(); + instructions.push(set_constant(&final_pos.to_string())); + instructions.push(get_local("$em")); + instructions.push(eq32()); + instructions.push(br_if("1")); // jump to end of block 1 + instructions.push(get_local("$em")); + instructions.push(load32_8u(None)); + instructions.push(set_local("$mc")); + instructions.push(get_local("$mc")); + instructions.push(eqz32()); + instructions.push(br_if("1")); // jump to end of block 1 + instructions.push(get_local("$bm")); + instructions.push(get_local("$mc")); + instructions.push(store32_8(None)); + instructions.push(get_local("$em")); + instructions.push(set_constant("1")); instructions.push(add32()); - instructions.push(load32_8u(None)); // load value at current position in buffer - - instructions.push(add_return()); + instructions.push(set_local("$em")); + instructions.push(get_local("$bm")); + instructions.push(set_constant("1")); + instructions.push(add32()); + instructions.push(set_local("$bm")); + instructions.push(br("0")); + instructions.push(add_end()); instructions.push(add_end()); + //fill rest of buffer with 0's + instructions.push(add_block()); + instructions.push(add_loop()); + instructions.push(get_local("$bm")); + let buff_final_pos = + producer.get_message_buffer_start() + producer.get_size_of_message_buffer_in_bytes(); + instructions.push(set_constant(&buff_final_pos.to_string())); + instructions.push(eq32()); + instructions.push(br_if("1")); //jump to the end of block + instructions.push(get_local("$bm")); instructions.push(set_constant("0")); + instructions.push(store32_8(None)); // stores the digit in the buffer + instructions.push(get_local("$bm")); + instructions.push(set_constant("1")); + instructions.push(add32()); + instructions.push(set_local("$bm")); + instructions.push(br("0")); // jump to the loop + instructions.push(add_end()); + instructions.push(add_end()); + // initialize message buffer position to 0 + instructions.push(set_constant(&producer.get_message_buffer_counter_position().to_string())); + instructions.push(set_constant("0")); + instructions.push(store32(None)); instructions.push(")".to_string()); instructions } @@ -1684,6 +1770,9 @@ mod tests { code_aux = build_buffer_message_generator(&producer); code.append(&mut code_aux); + code_aux = build_log_message_generator(&producer); + code.append(&mut code_aux); + //code_aux = main_sample_generator(&producer); //code.append(&mut code_aux); diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index d0691d115..c744f16d0 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "compiler" -version = "2.0.1" -authors = ["hermeGarcia "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] constant_tracking = {path = "../constant_tracking"} program_structure = {path = "../program_structure"} code_producers = {path = "../code_producers"} num-bigint-dig = "0.6.0" +num-traits = "0.2.6" + diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index a331bfc23..e3190dfc6 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -25,10 +25,11 @@ fn build_template_instances( c_info: &CircuitInfo, ti: Vec, mut field_tracker: FieldTracker, -) -> FieldTracker { +) -> (FieldTracker, HashMap) { let mut cmp_id = 0; let mut tmp_id = 0; let parallels: Vec<_> = ti.iter().map(|i| i.is_parallel ).collect(); + let mut string_table = HashMap::new(); for template in ti { let header = template.template_header; let name = template.template_name; @@ -65,6 +66,7 @@ fn build_template_instances( components: template.components, template_database: &c_info.template_database, is_parallel: template.is_parallel, + string_table : string_table, }; let mut template_info = TemplateCodeInfo { name, @@ -85,11 +87,12 @@ fn build_template_instances( template_info.expression_stack_depth = out.expression_depth; template_info.var_stack_depth = out.stack_depth; template_info.signal_stack_depth = out.signal_depth; + string_table = out.string_table; cmp_id = out.next_cmp_id; circuit.add_template_code(template_info); tmp_id += 1; } - field_tracker + (field_tracker, string_table) } fn build_function_instances( @@ -97,7 +100,8 @@ fn build_function_instances( c_info: &CircuitInfo, instances: Vec, mut field_tracker: FieldTracker, -) -> (FieldTracker, HashMap) { + mut string_table : HashMap +) -> (FieldTracker, HashMap, HashMap) { let mut function_to_arena_size = HashMap::new(); for instance in instances { let msg = format!("Error in function {}", instance.header); @@ -124,6 +128,7 @@ fn build_function_instances( component_to_parallel: HashMap::with_capacity(0), template_database: &c_info.template_database, is_parallel: false, + string_table : string_table }; let mut function_info = FunctionCodeInfo { name, @@ -134,6 +139,7 @@ fn build_function_instances( }; let code = instance.body; let out = translate::translate_code(code, code_info); + string_table = out.string_table; field_tracker = out.constant_tracker; function_info.body = out.code; function_info.max_number_of_ops_in_expression = out.expression_depth; @@ -141,7 +147,7 @@ fn build_function_instances( function_to_arena_size.insert(header, function_info.max_number_of_vars); circuit.add_function_code(function_info); } - (field_tracker, function_to_arena_size) + (field_tracker, function_to_arena_size, string_table) } // WASM producer builder @@ -310,11 +316,14 @@ pub fn build_circuit(vcp: VCP, flag: CompilationFlags) -> Circuit { functions: vcp.quick_knowledge, }; - let field_tracker = + let (field_tracker, string_table) = build_template_instances(&mut circuit, &circuit_info, vcp.templates, field_tracker); - let (field_tracker, function_to_arena_size) = - build_function_instances(&mut circuit, &circuit_info, vcp.functions, field_tracker); + let (field_tracker, function_to_arena_size, table_string_to_usize) = + build_function_instances(&mut circuit, &circuit_info, vcp.functions, field_tracker,string_table); + let table_usize_to_string = create_table_usize_to_string(table_string_to_usize); + circuit.wasm_producer.set_string_table(table_usize_to_string.clone()); + circuit.c_producer.set_string_table(table_usize_to_string); for i in 0..field_tracker.next_id() { let constant = field_tracker.get_constant(i).unwrap().clone(); circuit.wasm_producer.field_tracking.push(constant.clone()); @@ -329,3 +338,13 @@ pub fn build_circuit(vcp: VCP, flag: CompilationFlags) -> Circuit { circuit } + +pub fn create_table_usize_to_string( string_table : HashMap) -> Vec { + let size = string_table.len(); + let mut table_usize_to_string = vec![String::new(); size]; + + for (string, us) in string_table { + table_usize_to_string[us] = string; + } + table_usize_to_string +} \ No newline at end of file diff --git a/compiler/src/circuit_design/circuit.rs b/compiler/src/circuit_design/circuit.rs index 396a3a5a0..4eb18dcb4 100644 --- a/compiler/src/circuit_design/circuit.rs +++ b/compiler/src/circuit_design/circuit.rs @@ -105,6 +105,9 @@ impl WriteWasm for Circuit { code_aux = build_buffer_message_generator(&producer); code.append(&mut code_aux); + code_aux = build_log_message_generator(&producer); + code.append(&mut code_aux); + // Actual code from the program for f in &self.functions { @@ -253,6 +256,11 @@ impl WriteWasm for Circuit { writer.write_all(code.as_bytes()).map_err(|_| {})?; writer.flush().map_err(|_| {})?; + code_aux = build_log_message_generator(&producer); + code = merge_code(code_aux); + writer.write_all(code.as_bytes()).map_err(|_| {})?; + writer.flush().map_err(|_| {})?; + // Actual code from the program for f in &self.functions { diff --git a/compiler/src/circuit_design/function.rs b/compiler/src/circuit_design/function.rs index dd8c5ae5f..24034faa0 100644 --- a/compiler/src/circuit_design/function.rs +++ b/compiler/src/circuit_design/function.rs @@ -33,10 +33,11 @@ impl WriteWasm for FunctionCodeInfo { use code_producers::wasm_elements::wasm_code_generator::*; //to be revised let mut instructions = vec![]; - let funcdef = format!("(func ${} (type $_t_i32i32)", self.header); + let funcdef = format!("(func ${} (type $_t_i32i32ri32)", self.header); instructions.push(funcdef); instructions.push(format!("(param {} i32)", producer.get_result_address_tag())); instructions.push(format!("(param {} i32)", producer.get_result_size_tag())); + instructions.push("(result i32)".to_string()); //state 0 = OK; > 0 error instructions.push(format!("(local {} i32)", producer.get_cstack_tag())); instructions.push(format!("(local {} i32)", producer.get_lvar_tag())); instructions.push(format!("(local {} i32)", producer.get_expaux_tag())); @@ -45,6 +46,7 @@ impl WriteWasm for FunctionCodeInfo { instructions.push(format!("(local {} i32)", producer.get_store_aux_2_tag())); instructions.push(format!("(local {} i32)", producer.get_copy_counter_tag())); instructions.push(format!("(local {} i32)", producer.get_call_lvar_tag())); + instructions.push(format!(" (local {} i32)", producer.get_merror_tag())); let local_info_size_u32 = producer.get_local_info_size_u32(); //set lvar (start of auxiliar memory for vars) instructions.push(set_constant("0")); @@ -76,6 +78,7 @@ impl WriteWasm for FunctionCodeInfo { let mut instructions_body = t.produce_wasm(producer); instructions.append(&mut instructions_body); } + instructions.push(set_constant("0")); instructions.push(")".to_string()); instructions } diff --git a/compiler/src/circuit_design/template.rs b/compiler/src/circuit_design/template.rs index 35054d859..519849a59 100644 --- a/compiler/src/circuit_design/template.rs +++ b/compiler/src/circuit_design/template.rs @@ -41,7 +41,8 @@ impl WriteWasm for TemplateCodeInfo { instructions.push(format!(" (param {} i32)", producer.get_signal_offset_tag())); instructions.push("(result i32)".to_string()); instructions.push(format!(" (local {} i32)", producer.get_offset_tag())); //here is a local var to be returned - instructions.push(set_constant(&producer.get_component_free_pos().to_string())); + instructions.push(format!(" (local {} i32)", producer.get_merror_tag())); + instructions.push(set_constant(&producer.get_component_free_pos().to_string())); instructions.push(load32(None)); instructions.push(set_local(producer.get_offset_tag())); // set component id @@ -66,20 +67,16 @@ impl WriteWasm for TemplateCodeInfo { instructions.push(set_constant(&nbytes_component.to_string())); instructions.push(add32()); instructions.push(store32(None)); - //if has no intput should be run - if self.number_of_inputs == 0 { - instructions.push(get_local(producer.get_offset_tag())); - instructions.push(call(&format!("${}_run", self.header))); - } //add the position of the component in the tree as result instructions.push(get_local(producer.get_offset_tag())); instructions.push(")".to_string()); // run function code - let funcdef2 = format!("(func ${}_run (type $_t_i32)", self.header); + let funcdef2 = format!("(func ${}_run (type $_t_i32ri32)", self.header); instructions.push(funcdef2); instructions.push(format!(" (param {} i32)", producer.get_offset_tag())); + instructions.push("(result i32)".to_string()); //state 0 = OK; > 0 error instructions.push(format!(" (local {} i32)", producer.get_cstack_tag())); instructions.push(format!(" (local {} i32)", producer.get_signal_start_tag())); instructions.push(format!(" (local {} i32)", producer.get_sub_cmp_tag())); @@ -95,6 +92,7 @@ impl WriteWasm for TemplateCodeInfo { instructions.push(format!(" (local {} i32)", producer.get_create_loop_sub_cmp_tag())); instructions.push(format!(" (local {} i32)", producer.get_create_loop_offset_tag())); instructions.push(format!(" (local {} i32)", producer.get_create_loop_counter_tag())); + instructions.push(format!(" (local {} i32)", producer.get_merror_tag())); let local_info_size_u32 = producer.get_local_info_size_u32(); // in the future we can add some info like pointer to run father or text father //set lvar (start of auxiliar memory for vars) instructions.push(set_constant("0")); @@ -137,6 +135,7 @@ impl WriteWasm for TemplateCodeInfo { //free stack let mut free_stack_code = free_stack(producer); instructions.append(&mut free_stack_code); + instructions.push(set_constant("0")); instructions.push(")".to_string()); instructions } diff --git a/compiler/src/hir/component_preprocess.rs b/compiler/src/hir/component_preprocess.rs index 5ef5474e5..071dca73f 100644 --- a/compiler/src/hir/component_preprocess.rs +++ b/compiler/src/hir/component_preprocess.rs @@ -20,6 +20,7 @@ fn rm_statement(stmt: &mut Statement) { rm_substitution(stmt); } else{ + } } diff --git a/compiler/src/hir/merger.rs b/compiler/src/hir/merger.rs index 8f5bc80d5..e7a0d4146 100644 --- a/compiler/src/hir/merger.rs +++ b/compiler/src/hir/merger.rs @@ -4,6 +4,8 @@ use super::sugar_cleaner; use super::very_concrete_program::*; use program_structure::ast::*; use program_structure::program_archive::ProgramArchive; +use num_traits::{ToPrimitive}; + pub fn run_preprocessing(vcp: &mut VCP, program_archive: ProgramArchive) { let mut state = build_function_knowledge(program_archive); @@ -152,8 +154,13 @@ fn produce_vcf_assert(stmt: &Statement, state: &mut State, environment: &E) { fn produce_vcf_log_call(stmt: &Statement, state: &mut State, environment: &E) { use Statement::LogCall; - if let LogCall { arg, .. } = stmt { - produce_vcf_expr(arg, state, environment); + if let LogCall { args, .. } = stmt { + for arglog in args { + if let LogArgument::LogExp(arg) = arglog { + produce_vcf_expr(arg, state, environment); + } + else {}// unimplemented!(); } + } } else { unreachable!(); } @@ -242,11 +249,14 @@ fn produce_vcf_conditional(stmt: &Statement, state: &mut State, environment: &mu } fn produce_vcf_array(expr: &Expression, state: &mut State, environment: &E) { - use Expression::ArrayInLine; + use Expression::{ArrayInLine, UniformArray}; if let ArrayInLine { values, .. } = expr { for v in values { produce_vcf_expr(v, state, environment); } + } else if let UniformArray { value, dimension, .. } = expr { + produce_vcf_expr(value, state, environment); + produce_vcf_expr(dimension, state, environment); } else { unreachable!(); } @@ -392,8 +402,12 @@ fn link_while(stmt: &mut Statement, state: &State, env: &mut E) { fn link_log_call(stmt: &mut Statement, state: &State, env: &mut E) { use Statement::LogCall; - if let LogCall { arg, .. } = stmt { - link_expression(arg, state, env); + if let LogCall { args, .. } = stmt { + for arglog in args { + if let LogArgument::LogExp(arg) = arglog{ + link_expression(arg, state, env); + } + } } else { unreachable!(); } @@ -491,11 +505,14 @@ fn link_call(expr: &mut Expression, state: &State, env: &E) { } fn link_array(expr: &mut Expression, state: &State, env: &E) { - use Expression::ArrayInLine; + use Expression::{ArrayInLine, UniformArray}; if let ArrayInLine { values, .. } = expr { for v in values { link_expression(v, state, env) } + } else if let UniformArray { value, dimension, .. } = expr { + link_expression(value, state, env); + link_expression(dimension, state, env); } else { unreachable!(); } @@ -584,13 +601,34 @@ fn cast_type_variable(expr: &Expression, state: &State, environment: &E) -> VCT } } +fn cast_dimension(ae_index: &Expression) -> Option { + use Expression::Number; + + if let Number(_, value) = ae_index { + value.to_usize() + } else { + Option::None + } +} + + fn cast_type_array(expr: &Expression, state: &State, environment: &E) -> VCT { - use Expression::ArrayInLine; + use Expression::{ArrayInLine, UniformArray}; if let ArrayInLine { values, .. } = expr { let mut result = vec![values.len()]; let mut inner_type = cast_type_expression(&values[0], state, environment); result.append(&mut inner_type); result + } else if let UniformArray { value, dimension, .. } = expr { + let usable_dimension = if let Option::Some(dimension) = cast_dimension(&dimension) { + dimension + } else { + unreachable!() + }; + let mut lengths = vec![usable_dimension]; + let mut inner_type = cast_type_expression(value, state, environment); + lengths.append(&mut inner_type); + lengths } else { unreachable!(); } diff --git a/compiler/src/hir/sugar_cleaner.rs b/compiler/src/hir/sugar_cleaner.rs index 41a73e0fd..785dac9bf 100644 --- a/compiler/src/hir/sugar_cleaner.rs +++ b/compiler/src/hir/sugar_cleaner.rs @@ -1,5 +1,7 @@ use super::very_concrete_program::*; use program_structure::ast::*; +use num_traits::{ToPrimitive}; + struct ExtendedSyntax { initializations: Vec, @@ -164,8 +166,15 @@ fn extend_return(stmt: &mut Statement, state: &mut State, context: &Context) -> fn extend_log_call(stmt: &mut Statement, state: &mut State, context: &Context) -> Vec { use Statement::LogCall; - if let LogCall { arg, .. } = stmt { - extend_expression(arg, state, context).initializations + if let LogCall { args, .. } = stmt { + let mut initializations = Vec::new(); + for arglog in args { + if let LogArgument::LogExp(arg) = arglog { + let mut exp = extend_expression(arg, state, context); + initializations.append(&mut exp.initializations); + } + } + initializations } else { unreachable!() } @@ -275,7 +284,7 @@ fn extend_switch(expr: &mut Expression, state: &mut State, context: &Context) -> } fn extend_array(expr: &mut Expression, state: &mut State, context: &Context) -> ExtendedSyntax { - use Expression::ArrayInLine; + use Expression::{ArrayInLine, UniformArray}; if let ArrayInLine { values, .. } = expr { let mut initializations = vec![]; for v in values.iter_mut() { @@ -284,6 +293,16 @@ fn extend_array(expr: &mut Expression, state: &mut State, context: &Context) -> } sugar_filter(values, state, &mut initializations); ExtendedSyntax { initializations } + } else if let UniformArray { value, dimension, .. } = expr { + let mut value_expand = extend_expression(value, state, context); + let mut dimension_expand = extend_expression(dimension, state, context); + value_expand.initializations.append(&mut dimension_expand.initializations); + let mut extended = value_expand; + let mut expr = vec![*value.clone(), *dimension.clone()]; + sugar_filter(&mut expr, state, &mut extended.initializations); + *dimension = Box::new(expr.pop().unwrap()); + *value = Box::new(expr.pop().unwrap()); + extended } else { unreachable!(); } @@ -492,9 +511,19 @@ fn rhe_switch_case(stmt: Statement, stmts: &mut Vec) { } } +fn cast_dimension(ae_index: &Expression) -> Option { + use Expression::Number; + + if let Number(_, value) = ae_index { + value.to_usize() + } else { + Option::None + } +} + fn rhe_array_case(stmt: Statement, stmts: &mut Vec) { use num_bigint_dig::BigInt; - use Expression::{ArrayInLine, Number}; + use Expression::{ArrayInLine, Number, UniformArray}; use Statement::Substitution; if let Substitution { var, access, op, rhe, meta } = stmt { if let ArrayInLine { values, .. } = rhe { @@ -516,10 +545,34 @@ fn rhe_array_case(stmt: Statement, stmts: &mut Vec) { stmts.push(sub); index += 1; } + } else if let UniformArray { value, dimension, .. } = rhe { + let usable_dimension = if let Option::Some(dimension) = cast_dimension(&dimension) { + dimension + } else { + unreachable!() + }; + let mut index: usize = 0; + while index < usable_dimension { + let mut index_meta = meta.clone(); + index_meta.get_mut_memory_knowledge().set_concrete_dimensions(vec![]); + let expr_index = Number(index_meta, BigInt::from(index)); + let as_access = Access::ArrayAccess(expr_index); + let mut accessed_with = access.clone(); + accessed_with.push(as_access); + let sub = Substitution { + op, + var: var.clone(), + access: accessed_with, + meta: meta.clone(), + rhe: *value.clone(), + }; + stmts.push(sub); + index += 1; + } } else { unreachable!() } } else { unreachable!() } -} +} \ No newline at end of file diff --git a/compiler/src/hir/type_inference.rs b/compiler/src/hir/type_inference.rs index 79756eeda..4baa811b9 100644 --- a/compiler/src/hir/type_inference.rs +++ b/compiler/src/hir/type_inference.rs @@ -2,6 +2,7 @@ use super::analysis_utilities::*; use super::very_concrete_program::*; use program_structure::ast::*; use std::collections::HashSet; +use num_traits::{ToPrimitive}; struct SearchInfo { environment: E, @@ -171,8 +172,18 @@ fn infer_type_variable(expr: &Expression, _state: &State, context: &mut SearchIn } } +fn cast_dimension(ae_index: &Expression) -> Option { + use Expression::Number; + + if let Number(_, value) = ae_index { + value.to_usize() + } else { + Option::None + } +} + fn infer_type_array(expr: &Expression, state: &State, context: &mut SearchInfo) -> Option { - use Expression::ArrayInLine; + use Expression::{ArrayInLine, UniformArray}; if let ArrayInLine { values, .. } = expr { let mut lengths = vec![values.len()]; let with_type = infer_type_expresion(&values[0], state, context); @@ -180,6 +191,18 @@ fn infer_type_array(expr: &Expression, state: &State, context: &mut SearchInfo) lengths.append(&mut l); lengths }) + } else if let UniformArray { value, dimension, .. } = expr { + let usable_dimension = if let Option::Some(dimension) = cast_dimension(&dimension) { + dimension + } else { + unreachable!() + }; + let mut lengths = vec![usable_dimension]; + let with_type = infer_type_expresion(&value, state, context); + with_type.map(|mut l| { + lengths.append(&mut l); + lengths + }) } else { unreachable!() } diff --git a/compiler/src/hir/very_concrete_program.rs b/compiler/src/hir/very_concrete_program.rs index 84ae72aa9..2fcff65aa 100644 --- a/compiler/src/hir/very_concrete_program.rs +++ b/compiler/src/hir/very_concrete_program.rs @@ -58,6 +58,7 @@ pub struct Trigger { pub component_name: String, pub indexed_with: Vec, pub external_signals: Vec, + pub has_inputs: bool, } #[derive(Clone)] diff --git a/compiler/src/intermediate_representation/assert_bucket.rs b/compiler/src/intermediate_representation/assert_bucket.rs index c6988a122..320d4925c 100644 --- a/compiler/src/intermediate_representation/assert_bucket.rs +++ b/compiler/src/intermediate_representation/assert_bucket.rs @@ -55,8 +55,9 @@ impl WriteWasm for AssertBucket { instructions.push(set_constant(&self.message_id.to_string())); instructions.push(set_constant(&self.line.to_string())); instructions.push(call("$buildBufferMessage")); + instructions.push(call("$printErrorMessage")); instructions.push(set_constant(&exception_code_assert_fail().to_string())); - instructions.push(call("$exceptionHandler")); + instructions.push(add_return()); instructions.push(add_end()); if producer.needs_comments() { instructions.push(";; end of assert bucket".to_string()); diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index 48069e9a4..3e669132b 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -139,6 +139,12 @@ impl WriteWasm for CallBucket { instructions.push(add32()); instructions.push(set_constant("1")); instructions.push(call(&format!("${}", self.symbol))); + instructions.push(tee_local(producer.get_merror_tag())); + instructions.push(add_if()); + instructions.push(call("$printErrorMessage")); + instructions.push(get_local(producer.get_merror_tag())); + instructions.push(add_return()); + instructions.push(add_end()); } ReturnType::Final(data) => { let mut my_template_header = Option::::None; @@ -263,6 +269,15 @@ impl WriteWasm for CallBucket { } instructions.push(set_constant(&data.context.size.to_string())); instructions.push(call(&format!("${}", self.symbol))); + instructions.push(tee_local(producer.get_merror_tag())); + instructions.push(add_if()); + instructions.push(set_constant(&self.message_id.to_string())); + instructions.push(set_constant(&self.line.to_string())); + instructions.push(call("$buildBufferMessage")); + instructions.push(call("$printErrorMessage")); + instructions.push(get_local(producer.get_merror_tag())); + instructions.push(add_return()); + instructions.push(add_end()); match &data.dest_address_type { AddressType::SubcmpSignal { .. } => { // if subcomponent input check if run needed @@ -296,6 +311,15 @@ impl WriteWasm for CallBucket { LocationRule::Indexed { .. } => { if let Some(name) = &my_template_header { instructions.push(call(&format!("${}_run", name))); + instructions.push(tee_local(producer.get_merror_tag())); + instructions.push(add_if()); + instructions.push(set_constant(&self.message_id.to_string())); + instructions.push(set_constant(&self.line.to_string())); + instructions.push(call("$buildBufferMessage")); + instructions.push(call("$printErrorMessage")); + instructions.push(get_local(producer.get_merror_tag())); + instructions.push(add_return()); + instructions.push(add_end()); } else { assert!(false); } @@ -305,8 +329,17 @@ impl WriteWasm for CallBucket { instructions.push(load32(None)); // get template id instructions.push(call_indirect( &"$runsmap".to_string(), - &"(type $_t_i32)".to_string(), + &"(type $_t_i32ri32)".to_string(), )); + instructions.push(tee_local(producer.get_merror_tag())); + instructions.push(add_if()); + instructions.push(set_constant(&self.message_id.to_string())); + instructions.push(set_constant(&self.line.to_string())); + instructions.push(call("$buildBufferMessage")); + instructions.push(call("$printErrorMessage")); + instructions.push(get_local(producer.get_merror_tag())); + instructions.push(add_return()); + instructions.push(add_end()); } } if producer.needs_comments() { diff --git a/compiler/src/intermediate_representation/create_component_bucket.rs b/compiler/src/intermediate_representation/create_component_bucket.rs index c6e5da7aa..bf91abc5e 100644 --- a/compiler/src/intermediate_representation/create_component_bucket.rs +++ b/compiler/src/intermediate_representation/create_component_bucket.rs @@ -23,6 +23,7 @@ pub struct CreateCmpBucket { pub component_offset: usize, pub component_offset_jump:usize, pub number_of_cmp: usize, + pub has_inputs: bool, pub is_parallel: bool, } @@ -86,8 +87,25 @@ impl WriteWasm for CreateCmpBucket { instructions.push(add32()); if self.number_of_cmp == 1 { instructions.push(call(&format!("${}_create", self.symbol))); - instructions.push(store32(None)); //store the offset given by create in the subcomponent address - } else { + if !self.has_inputs { + instructions.push(tee_local(producer.get_temp_tag())); //here we use $temp to keep the offset created subcomponet + instructions.push(store32(None)); //store the offset given by create in the subcomponent address + instructions.push(get_local(producer.get_temp_tag())); + instructions.push(call(&format!("${}_run", self.symbol))); + instructions.push(tee_local(producer.get_merror_tag())); + instructions.push(add_if()); + instructions.push(set_constant(&self.message_id.to_string())); + instructions.push(set_constant(&self.line.to_string())); + instructions.push(call("$buildBufferMessage")); + instructions.push(call("$printErrorMessage")); + instructions.push(get_local(producer.get_merror_tag())); + instructions.push(add_return()); + instructions.push(add_end()); + } + else { + instructions.push(store32(None)); //store the offset given by create in the subcomponent address + } + } else { instructions.push(set_local(producer.get_create_loop_offset_tag())); if self.number_of_cmp == self.defined_positions.len() { instructions.push(set_constant(&self.number_of_cmp.to_string())); @@ -98,7 +116,24 @@ impl WriteWasm for CreateCmpBucket { instructions.push(get_local(producer.get_create_loop_offset_tag())); //sub_component signal address start instructions.push(call(&format!("${}_create", self.symbol))); - instructions.push(store32(None)); //store the offset given by create in the subcomponent address + if !self.has_inputs { + instructions.push(tee_local(producer.get_temp_tag())); //here we use $temp to keep the offset created subcomponet + instructions.push(store32(None)); //store the offset given by create in the subcomponent address + instructions.push(get_local(producer.get_temp_tag())); + instructions.push(call(&format!("${}_run", self.symbol))); + instructions.push(tee_local(producer.get_merror_tag())); + instructions.push(add_if()); + instructions.push(set_constant(&self.message_id.to_string())); + instructions.push(set_constant(&self.line.to_string())); + instructions.push(call("$buildBufferMessage")); + instructions.push(call("$printErrorMessage")); + instructions.push(get_local(producer.get_merror_tag())); + instructions.push(add_return()); + instructions.push(add_end()); + } + else { + instructions.push(store32(None)); //store the offset given by create in the subcomponent address + } instructions.push(get_local(producer.get_create_loop_counter_tag())); instructions.push(set_constant("1")); instructions.push(sub32()); @@ -218,4 +253,4 @@ impl WriteC for CreateCmpBucket { instructions.push("}".to_string()); (instructions, "".to_string()) } -} \ No newline at end of file +} diff --git a/compiler/src/intermediate_representation/ir_interface.rs b/compiler/src/intermediate_representation/ir_interface.rs index 564bf6799..086a9e515 100644 --- a/compiler/src/intermediate_representation/ir_interface.rs +++ b/compiler/src/intermediate_representation/ir_interface.rs @@ -10,6 +10,7 @@ pub use super::log_bucket::LogBucket; pub use super::loop_bucket::LoopBucket; pub use super::return_bucket::ReturnBucket; pub use super::store_bucket::StoreBucket; +pub use super::log_bucket::LogBucketArg; pub use super::types::{InstrContext, ValueType}; pub use super::value_bucket::ValueBucket; diff --git a/compiler/src/intermediate_representation/log_bucket.rs b/compiler/src/intermediate_representation/log_bucket.rs index f53d21f8f..a6e846a98 100644 --- a/compiler/src/intermediate_representation/log_bucket.rs +++ b/compiler/src/intermediate_representation/log_bucket.rs @@ -3,13 +3,19 @@ use crate::translating_traits::*; use code_producers::c_elements::*; use code_producers::wasm_elements::*; + +#[derive(Clone)] +pub enum LogBucketArg { + LogExp(InstructionPointer), + LogStr(usize) +} + #[derive(Clone)] pub struct LogBucket { pub line: usize, pub message_id: usize, - pub print: InstructionPointer, + pub argsprint: Vec, pub is_parallel: bool, - pub label: Option, } impl IntoInstruction for LogBucket { @@ -37,8 +43,15 @@ impl ToString for LogBucket { fn to_string(&self) -> String { let line = self.line.to_string(); let template_id = self.message_id.to_string(); - let print = self.print.to_string(); - format!("LOG(line: {},template_id: {},evaluate: {})", line, template_id, print) + let mut ret = String::new(); + for print in self.argsprint.clone() { + if let LogBucketArg::LogExp(exp) = print { + let print = exp.to_string(); + let log = format!("LOG(line: {},template_id: {},evaluate: {})", line, template_id, print); + ret = ret + &log; + } + } + ret } } @@ -48,33 +61,32 @@ impl WriteWasm for LogBucket { let mut instructions = vec![]; if producer.needs_comments() { instructions.push(";; log bucket".to_string()); - } - let mut instructions_print = self.print.produce_wasm(producer); - instructions.append(&mut instructions_print); - instructions.push(call("$copyFr2SharedRWMemory")); - if let Some(label) = &self.label { - if producer.needs_comments() { - instructions.push(";; log label".to_string()); - } - - let mut trunc_label = label.clone(); - trunc_label.truncate(producer.get_size_of_message_in_bytes()); - trunc_label.push('\0'); // terminate message with a null byte - - // write out the label one character at a time - for (i, c) in trunc_label.chars().enumerate() { - instructions.push(set_constant(&(producer.get_message_buffer_start() + i).to_string())); - instructions.push(set_constant(&(c as usize).to_string())); - instructions.push(store32(None)); + } + for logarg in self.argsprint.clone() { + match &logarg { + LogBucketArg::LogExp(exp) => { + let mut instructions_print = exp.produce_wasm(producer); + instructions.append(&mut instructions_print); + instructions.push(call("$copyFr2SharedRWMemory")); + instructions.push(call("$showSharedRWMemory")); + } + LogBucketArg::LogStr(stringid) => { + let pos = producer.get_string_list_start() + + stringid * producer.get_size_of_message_in_bytes(); + instructions.push(set_constant(&pos.to_string())); + instructions.push(call("$buildLogMessage")); + instructions.push(call("$writeBufferMessage")); + } } - - // initialize message buffer position to 0 - instructions.push(set_constant(&producer.get_message_buffer_counter_position().to_string())); - instructions.push(set_constant("0")); - instructions.push(store32(None)); - } - instructions.push(call("$showSharedRWMemory")); - + } + // add nl + instructions.push(set_constant(&producer.get_message_buffer_start().to_string())); + instructions.push(set_constant("0x0000000a")); + instructions.push(store32(None)); // stores \n000 + instructions.push(set_constant(&producer.get_message_buffer_counter_position().to_string())); + instructions.push(set_constant("0")); + instructions.push(store32(None)); + instructions.push(call("$writeBufferMessage")); if producer.needs_comments() { instructions.push(";; end of log bucket".to_string()); } @@ -85,23 +97,46 @@ impl WriteWasm for LogBucket { impl WriteC for LogBucket { fn produce_c(&self, producer: &CProducer) -> (Vec, String) { use c_code_generator::*; - let (argument_code, argument_result) = self.print.produce_c(producer); - let to_string_call = build_call("Fr_element2str".to_string(), vec![argument_result]); - let temp_var = "temp".to_string(); - let into_temp = format!("char* temp = {}", to_string_call); - let print_c = if let Some(label) = &self.label { - let label_str = format!("\"{}\"", label.to_string()); - build_call("printf".to_string(), vec!["\"%s: %s\\n\"".to_string(), label_str, temp_var.clone()]) - } else { - build_call("printf".to_string(), vec!["\"%s\\n\"".to_string(), temp_var.clone()]) - }; - let delete_temp = format!("delete [] {}", temp_var); - let mut log_c = argument_code; + let mut log_c = Vec::new(); + for logarg in &self.argsprint { + if let LogBucketArg::LogExp(exp) = logarg { + let (mut argument_code, argument_result) = exp.produce_c(producer); + let to_string_call = build_call("Fr_element2str".to_string(), vec![argument_result]); + let temp_var = "temp".to_string(); + let into_temp = format!("char* temp = {}", to_string_call); + let print_c = + build_call("printf".to_string(), vec!["\"%s\"".to_string(), temp_var.clone()]); + let delete_temp = format!("delete [] {}", temp_var); + log_c.append(&mut argument_code); + log_c.push("{".to_string()); + log_c.push(format!("{};", into_temp)); + log_c.push(format!("{};", print_c)); + log_c.push(format!("{};", delete_temp)); + log_c.push("}".to_string()); + } + else if let LogBucketArg::LogStr(string_id) = logarg { + let string_value = &producer.get_string_table()[*string_id]; + + let print_c = + build_call( + "printf".to_string(), + vec![format!("\"{}\"", string_value)] + ); + log_c.push("{".to_string()); + log_c.push(format!("{};", print_c)); + log_c.push("}".to_string()); + } + else{ + unreachable!(); + } + } + let print_end_line = build_call( + "printf".to_string(), + vec![format!("\"\\n\"")] + ); log_c.push("{".to_string()); - log_c.push(format!("{};", into_temp)); - log_c.push(format!("{};", print_c)); - log_c.push(format!("{};", delete_temp)); - log_c.push("}".to_string()); + log_c.push(format!("{};", print_end_line)); + log_c.push("}".to_string()); (log_c, "".to_string()) } } diff --git a/compiler/src/intermediate_representation/return_bucket.rs b/compiler/src/intermediate_representation/return_bucket.rs index cea3cf640..42748b364 100644 --- a/compiler/src/intermediate_representation/return_bucket.rs +++ b/compiler/src/intermediate_representation/return_bucket.rs @@ -85,6 +85,7 @@ impl WriteWasm for ReturnBucket { } let mut free_stack_code = free_stack(producer); instructions.append(&mut free_stack_code); + instructions.push(set_constant("0")); instructions.push(add_return()); if producer.needs_comments() { instructions.push(";; end of return bucket".to_string()); diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 745722453..d409ca652 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -245,6 +245,15 @@ impl WriteWasm for StoreBucket { LocationRule::Indexed { .. } => { if let Some(name) = &my_template_header { instructions.push(call(&format!("${}_run", name))); + instructions.push(tee_local(producer.get_merror_tag())); + instructions.push(add_if()); + instructions.push(set_constant(&self.message_id.to_string())); + instructions.push(set_constant(&self.line.to_string())); + instructions.push(call("$buildBufferMessage")); + instructions.push(call("$printErrorMessage")); + instructions.push(get_local(producer.get_merror_tag())); + instructions.push(add_return()); + instructions.push(add_end()); } else { assert!(false); } @@ -254,8 +263,17 @@ impl WriteWasm for StoreBucket { instructions.push(load32(None)); // get template id instructions.push(call_indirect( &"$runsmap".to_string(), - &"(type $_t_i32)".to_string(), + &"(type $_t_i32ri32)".to_string(), )); + instructions.push(tee_local(producer.get_merror_tag())); + instructions.push(add_if()); + instructions.push(set_constant(&self.message_id.to_string())); + instructions.push(set_constant(&self.line.to_string())); + instructions.push(call("$buildBufferMessage")); + instructions.push(call("$printErrorMessage")); + instructions.push(get_local(producer.get_merror_tag())); + instructions.push(add_return()); + instructions.push(add_end()); } } if producer.needs_comments() { diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index 34ac97bef..9f3bb30a4 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -1,5 +1,6 @@ use super::ir_interface::*; use crate::hir::very_concrete_program::*; +use crate::intermediate_representation::log_bucket::LogBucketArg; use constant_tracking::ConstantTracker; use num_bigint_dig::BigInt; use program_structure::ast::*; @@ -90,6 +91,8 @@ struct State { component_address_stack: usize, is_parallel: bool, code: InstructionList, + // string_table + string_table: HashMap, } impl State { @@ -114,6 +117,7 @@ impl State { fresh_cmp_id: cmp_id_offset, max_stack_depth: 0, code: vec![], + string_table : HashMap::new(), } } fn reserve(fresh: &mut usize, size: usize) -> usize { @@ -315,11 +319,12 @@ fn create_uniform_components(state: &mut State, triggers: &[Trigger], cluster: T sub_cmp_id: symbol.access_instruction.clone(), template_id: c_info.template_id, signal_offset: c_info.offset, - component_offset: c_info.component_offset, + component_offset: c_info.component_offset, + has_inputs: c_info.has_inputs, number_of_cmp: compute_number_cmp(&symbol.dimensions), dimensions: symbol.dimensions, signal_offset_jump: offset_jump, - component_offset_jump: component_offset_jump, + component_offset_jump: component_offset_jump, } .allocate(); state.code.push(creation_instr); @@ -377,6 +382,7 @@ fn create_mixed_components(state: &mut State, triggers: &[Trigger], cluster: Tri template_id: c_info.template_id, signal_offset: c_info.offset, component_offset: c_info.component_offset, + has_inputs: c_info.has_inputs, number_of_cmp: 1, signal_offset_jump: 0, component_offset_jump: 0, @@ -581,15 +587,33 @@ fn translate_assert(stmt: Statement, state: &mut State, context: &Context) { fn translate_log(stmt: Statement, state: &mut State, context: &Context) { use Statement::LogCall; - if let LogCall { meta, arg, label, .. } = stmt { + if let LogCall { meta, args, .. } = stmt { let line = context.files.get_line(meta.start, meta.get_file_id()).unwrap(); - let code = translate_expression(arg, state, context); + let mut logbucket_args = Vec::new(); + for arglog in args { + match arglog { + LogArgument::LogExp(arg) => { + let code = translate_expression(arg, state, context); + logbucket_args.push(LogBucketArg::LogExp(code)); + } + LogArgument::LogStr(exp) => { + match state.string_table.get(&exp) { + Some( idx) => {logbucket_args.push(LogBucketArg::LogStr(*idx));}, + None => { + logbucket_args.push(LogBucketArg::LogStr(state.string_table.len())); + state.string_table.insert(exp, state.string_table.len()); + }, + } + + } + } + } + let log = LogBucket { line, message_id: state.message_id, - print: code, is_parallel: state.is_parallel, - label: label, + argsprint: logbucket_args, }.allocate(); state.code.push(log); } @@ -1149,6 +1173,7 @@ pub struct CodeInfo<'a> { pub functions: &'a HashMap>, pub field_tracker: FieldTracker, pub component_to_parallel: HashMap, + pub string_table: HashMap } pub struct CodeOutput { @@ -1158,6 +1183,7 @@ pub struct CodeOutput { pub next_cmp_id: usize, pub code: InstructionList, pub constant_tracker: FieldTracker, + pub string_table: HashMap, } pub fn translate_code(body: Statement, code_info: CodeInfo) -> CodeOutput { @@ -1169,6 +1195,7 @@ pub fn translate_code(body: Statement, code_info: CodeInfo) -> CodeOutput { code_info.field_tracker, code_info.component_to_parallel, ); + state.string_table = code_info.string_table; initialize_components(&mut state, code_info.components); initialize_signals(&mut state, code_info.signals); initialize_constants(&mut state, code_info.constants); @@ -1198,5 +1225,6 @@ pub fn translate_code(body: Statement, code_info: CodeInfo) -> CodeOutput { stack_depth: state.max_stack_depth, signal_depth: state.signal_stack, constant_tracker: state.field_tracker, + string_table : state.string_table } } diff --git a/compiler/src/ir_processing/build_stack.rs b/compiler/src/ir_processing/build_stack.rs index dbebe6228..84f54507a 100644 --- a/compiler/src/ir_processing/build_stack.rs +++ b/compiler/src/ir_processing/build_stack.rs @@ -1,4 +1,5 @@ use crate::intermediate_representation::ir_interface::*; + pub fn build_list(instructions: &mut InstructionList, fresh: usize) -> usize { let mut max_depth = 0; for i in instructions { @@ -87,7 +88,17 @@ pub fn build_return(bucket: &mut ReturnBucket, fresh: usize) -> usize { } pub fn build_log(bucket: &mut LogBucket, fresh: usize) -> usize { - build_instruction(&mut bucket.print, fresh) + let mut in_log = usize::min_value(); + for arglog in bucket.argsprint.clone() { + match arglog { + LogBucketArg::LogExp(mut arg) => { + let new_log = build_instruction(&mut arg, fresh); + in_log = std::cmp::max(in_log, new_log); + } + LogBucketArg::LogStr(..) => {} + } + } + in_log } pub fn build_assert(bucket: &mut AssertBucket, fresh: usize) -> usize { diff --git a/compiler/src/ir_processing/reduce_stack.rs b/compiler/src/ir_processing/reduce_stack.rs index 39c8ee9b1..0698133ea 100644 --- a/compiler/src/ir_processing/reduce_stack.rs +++ b/compiler/src/ir_processing/reduce_stack.rs @@ -82,7 +82,22 @@ pub fn reduce_loop(mut bucket: LoopBucket) -> Instruction { } pub fn reduce_log(mut bucket: LogBucket) -> Instruction { - bucket.print = Allocate::allocate(reduce_instruction(*bucket.print)); + let mut new_args_prints : Vec = Vec::new(); + for print in bucket.argsprint { + match print { + LogBucketArg::LogExp(exp)=> { + let print_aux = Allocate::allocate(reduce_instruction(*exp)); + new_args_prints.push(LogBucketArg::LogExp(print_aux)); + + }, + LogBucketArg::LogStr(s) => { + new_args_prints.push(LogBucketArg::LogStr(s)); + }, + } + + } + + bucket.argsprint = new_args_prints; IntoInstruction::into_instruction(bucket) } diff --git a/compiler/src/ir_processing/set_arena_size.rs b/compiler/src/ir_processing/set_arena_size.rs index e372a8d9c..8d772b8e0 100644 --- a/compiler/src/ir_processing/set_arena_size.rs +++ b/compiler/src/ir_processing/set_arena_size.rs @@ -77,7 +77,12 @@ pub fn visit_return(bucket: &mut ReturnBucket, function_to_arena_size: &HashMap< } pub fn visit_log(bucket: &mut LogBucket, function_to_arena_size: &HashMap) { - visit_instruction(&mut bucket.print, function_to_arena_size); + for print in bucket.argsprint.clone() { + if let LogBucketArg::LogExp(mut exp) = print { + visit_instruction(&mut exp, function_to_arena_size); + } + } + } pub fn visit_assert(bucket: &mut AssertBucket, function_to_arena_size: &HashMap) { diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index 955840cd7..a9c4871e0 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -2,6 +2,8 @@ mod circuit_design; mod intermediate_representation; mod ir_processing; +pub extern crate num_bigint_dig as num_bigint; +pub extern crate num_traits; pub mod compiler_interface; pub mod hir; diff --git a/constant_tracking/Cargo.toml b/constant_tracking/Cargo.toml index 047b96d4b..0d00b8e28 100644 --- a/constant_tracking/Cargo.toml +++ b/constant_tracking/Cargo.toml @@ -1,9 +1,7 @@ [package] name = "constant_tracking" version = "2.0.0" -authors = ["hermeGarcia "] +authors = ["Costa Group UCM","iden3"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] diff --git a/constraint_generation/Cargo.toml b/constraint_generation/Cargo.toml index db0e1d97a..3493d0e8c 100644 --- a/constraint_generation/Cargo.toml +++ b/constraint_generation/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "constraint_generation" -version = "2.0.1" -authors = ["hermeGarcia "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" [dependencies] diff --git a/constraint_generation/src/execute.rs b/constraint_generation/src/execute.rs index 607e1c095..5826e581b 100644 --- a/constraint_generation/src/execute.rs +++ b/constraint_generation/src/execute.rs @@ -81,9 +81,7 @@ enum ExecutionError { pub fn constraint_execution( program_archive: &ProgramArchive, flag_verbose: bool, - prime: &String, -) -> Result { - let main_file_id = program_archive.get_file_id_main(); + prime: &String,) -> Result<(ExecutedProgram, ReportCollection), ReportCollection> { let main_file_id = program_archive.get_file_id_main(); let mut runtime_information = RuntimeInformation::new(*main_file_id, program_archive.id_max, prime); runtime_information.public_inputs = program_archive.get_public_inputs_main_component().clone(); let folded_value_result = execute_expression( @@ -96,7 +94,7 @@ pub fn constraint_execution( Result::Err(_) => Result::Err(runtime_information.runtime_errors), Result::Ok(folded_value) => { debug_assert!(FoldedValue::valid_node_pointer(&folded_value)); - Result::Ok(runtime_information.exec_program) + Result::Ok((runtime_information.exec_program, runtime_information.runtime_errors)) } } } @@ -156,7 +154,7 @@ fn execute_statement( arithmetic_values .push(safe_unwrap_to_single_arithmetic_expression(f_dimensions, line!())); } - treat_result_with_memory_error( + treat_result_with_memory_error_void( valid_array_declaration(&arithmetic_values), meta, &mut runtime.runtime_errors, @@ -300,20 +298,26 @@ fn execute_statement( ExecutionEnvironment::remove_variable_block(&mut runtime.environment); return_value } - LogCall { arg, .. } => { + LogCall { args, .. } => { if flag_verbose{ - let f_result = execute_expression(arg, program_archive, runtime, flag_verbose)?; - let arith = safe_unwrap_to_single_arithmetic_expression(f_result, line!()); - if AExpr::is_number(&arith){ - println!("{}", arith); - } - else{ - println!("Unknown") + for arglog in args { + if let LogArgument::LogExp(arg) = arglog{ + let f_result = execute_expression(arg, program_archive, runtime, flag_verbose)?; + let arith = safe_unwrap_to_single_arithmetic_expression(f_result, line!()); + if AExpr::is_number(&arith){ + print!("{}", arith); + } + else{ + print!("Unknown") + } + } + else if let LogArgument::LogStr(s) = arglog { + print!("{}",s); + } } + println!(""); } Option::None - - } Assert { arg, meta, .. } => { let f_result = execute_expression(arg, program_archive, runtime, flag_verbose)?; @@ -379,7 +383,42 @@ fn execute_expression( &[row], &arithmetic_slice_array[row], ); - treat_result_with_memory_error( + treat_result_with_memory_error_void( + memory_insert_result, + meta, + &mut runtime.runtime_errors, + &runtime.call_trace, + )?; + row += 1; + } + FoldedValue { arithmetic_slice: Option::Some(array_slice), ..FoldedValue::default() } + } + UniformArray { meta, value, dimension, .. } => { + let f_dimension = execute_expression(dimension, program_archive, runtime, flag_verbose)?; + let arithmetic_dimension = safe_unwrap_to_single_arithmetic_expression(f_dimension, line!()); + let usable_dimension = if let Option::Some(dimension) = cast_index(&arithmetic_dimension) { + dimension + } else { + unreachable!() + }; + + let f_value = execute_expression(value, program_archive, runtime, flag_verbose)?; + let slice_value = safe_unwrap_to_arithmetic_slice(f_value, line!()); + + let mut dims = vec![usable_dimension]; + for dim in slice_value.route() { + dims.push(*dim); + } + + let mut array_slice = AExpressionSlice::new_with_route(&dims, &AExpr::default()); + let mut row: SliceCapacity = 0; + while row < usable_dimension { + let memory_insert_result = AExpressionSlice::insert_values( + &mut array_slice, + &[row], + &slice_value, + ); + treat_result_with_memory_error_void( memory_insert_result, meta, &mut runtime.runtime_errors, @@ -548,7 +587,7 @@ fn perform_assign( AExpressionSlice::new_with_route(symbol_content.route(), &AExpr::NonQuadratic); let memory_result = AExpressionSlice::insert_values(symbol_content, &vec![], &new_value); - treat_result_with_memory_error( + treat_result_with_memory_error_void( memory_result, meta, &mut runtime.runtime_errors, @@ -560,7 +599,7 @@ fn perform_assign( &accessing_information.before_signal, &r_slice, ); - treat_result_with_memory_error( + treat_result_with_memory_error_void( memory_result, meta, &mut runtime.runtime_errors, @@ -600,7 +639,7 @@ fn perform_assign( &SignalSlice::new(&true), ) }; - treat_result_with_memory_error( + treat_result_with_memory_error_void( access_response, meta, &mut runtime.runtime_errors, @@ -643,7 +682,7 @@ fn perform_assign( node_pointer, &runtime.exec_program, ); - treat_result_with_memory_error( + treat_result_with_memory_error_void( memory_result, meta, &mut runtime.runtime_errors, @@ -660,7 +699,7 @@ fn perform_assign( &signal_accessed, &accessing_information.after_signal, ); - treat_result_with_memory_error( + treat_result_with_memory_error_void( memory_response, meta, &mut runtime.runtime_errors, @@ -1168,6 +1207,14 @@ fn cast_indexing(ae_indexes: &[AExpr]) -> Option> { Option::Some(sc_indexes) } +fn cast_index(ae_index: &AExpr) -> Option { + if !ae_index.is_number() { + return Option::None; + } + let index = AExpr::get_usize(ae_index).unwrap(); + Option::Some(index) +} + /* Usable representation of a series of accesses performed over a symbol. AccessingInformation { @@ -1265,6 +1312,47 @@ fn treat_result_with_arithmetic_error( } } +fn treat_result_with_memory_error_void( + memory_error: Result<(), MemoryError>, + meta: &Meta, + runtime_errors: &mut ReportCollection, + call_trace: &[String], +) -> Result<(), ()> { + use ReportCode::RuntimeError; + match memory_error { + Result::Ok(()) => Result::Ok(()), + Result::Err(MemoryError::MismatchedDimensionsWeak) => { + let report = Report::warning("Typing warning: Mismatched dimensions, assigning to an array an expression of smaller length, the remaining positions are assigned to 0".to_string(), RuntimeError); + add_report_to_runtime(report, meta, runtime_errors, call_trace); + Ok(()) + }, + Result::Err(memory_error) => { + let report = match memory_error { + MemoryError::InvalidAccess => { + Report::error("Exception caused by invalid access".to_string(), RuntimeError) + } + MemoryError::AssignmentError => Report::error( + "Exception caused by invalid assignment".to_string(), + RuntimeError, + ), + MemoryError::OutOfBoundsError => { + Report::error("Out of bounds exception".to_string(), RuntimeError) + }, + MemoryError::MismatchedDimensions => { + Report::error(" Typing error found: mismatched dimensions, assigning to an array an expression of greater length".to_string(), RuntimeError) + }, + + MemoryError::UnknownSizeDimension => { + Report::error("Array dimension with unknown size".to_string(), RuntimeError) + } + _ => unreachable!(), + }; + add_report_to_runtime(report, meta, runtime_errors, call_trace); + Result::Err(()) + } + } +} + fn treat_result_with_memory_error( memory_error: Result, meta: &Meta, @@ -1285,10 +1373,14 @@ fn treat_result_with_memory_error( ), MemoryError::OutOfBoundsError => { Report::error("Out of bounds exception".to_string(), RuntimeError) - } + }, + MemoryError::MismatchedDimensions => { + Report::error(" Typing error found: mismatched dimensions".to_string(), RuntimeError) + }, MemoryError::UnknownSizeDimension => { Report::error("Array dimension with unknown size".to_string(), RuntimeError) } + _ => unreachable!(), }; add_report_to_runtime(report, meta, runtime_errors, call_trace); Result::Err(()) diff --git a/constraint_generation/src/execution_data/executed_template.rs b/constraint_generation/src/execution_data/executed_template.rs index 22ceed3fc..a1228419a 100644 --- a/constraint_generation/src/execution_data/executed_template.rs +++ b/constraint_generation/src/execution_data/executed_template.rs @@ -235,6 +235,7 @@ impl ExecutedTemplate { runs: instances[data.goes_to].template_header.clone(), template_id: data.goes_to, external_signals: instances[data.goes_to].signals.clone(), + has_inputs: instances[data.goes_to].number_of_inputs > 0, }; triggers.push(trigger); } diff --git a/constraint_generation/src/execution_data/filters.rs b/constraint_generation/src/execution_data/filters.rs index bd7f0837b..c5f3de2eb 100644 --- a/constraint_generation/src/execution_data/filters.rs +++ b/constraint_generation/src/execution_data/filters.rs @@ -86,9 +86,13 @@ pub fn apply_computed(stmt: &mut Statement, analysis: &Analysis) { apply_computed_expr(lhe, analysis); apply_computed_expr(rhe, analysis); } - LogCall { arg, .. } => { - *arg = computed_or_original(analysis, arg); - apply_computed_expr(arg, analysis); + LogCall { args, .. } => { + for arglog in args { + if let LogArgument::LogExp(arg) = arglog{ + *arg = computed_or_original(analysis, arg); + apply_computed_expr(arg, analysis); + } + } } Assert { arg, .. } => { *arg = computed_or_original(analysis, arg); @@ -169,5 +173,11 @@ fn apply_computed_expr(expr: &mut Expression, analysis: &Analysis) { ArrayInLine { values, .. } => { apply_computed_expr_vec(values, analysis); } + UniformArray { value, dimension, .. } => { + *value = Box::new(computed_or_original(analysis, value)); + *dimension = Box::new(computed_or_original(analysis, dimension)); + apply_computed_expr(value, analysis); + apply_computed_expr(dimension, analysis); + } } } diff --git a/constraint_generation/src/lib.rs b/constraint_generation/src/lib.rs index f57810ef2..7b0fe53f0 100644 --- a/constraint_generation/src/lib.rs +++ b/constraint_generation/src/lib.rs @@ -37,9 +37,10 @@ pub type ConstraintWriter = Box; type BuildResponse = Result<(ConstraintWriter, VCP), ()>; pub fn build_circuit(program: ProgramArchive, config: BuildConfig) -> BuildResponse { let files = program.file_library.clone(); - let exe = instantiation(&program, config.flag_verbose, &config.prime).map_err(|r| { + let (exe, warnings) = instantiation(&program, config.flag_verbose, &config.prime).map_err(|r| { Report::print_reports(&r, &files); })?; + Report::print_reports(&warnings, &files); let (mut dag, mut vcp, warnings) = export(exe, program, config.flag_verbose).map_err(|r| { Report::print_reports(&r, &files); })?; @@ -55,16 +56,16 @@ pub fn build_circuit(program: ProgramArchive, config: BuildConfig) -> BuildRespo } } -type InstantiationResponse = Result; +type InstantiationResponse = Result<(ExecutedProgram, ReportCollection), ReportCollection>; fn instantiation(program: &ProgramArchive, flag_verbose: bool, prime: &String) -> InstantiationResponse { let execution_result = execute::constraint_execution(&program, flag_verbose, prime); match execution_result { - Ok(program_exe) => { + Ok((program_exe, warnings)) => { let no_nodes = program_exe.number_of_nodes(); let success = Colour::Green.paint("template instances"); let nodes_created = format!("{}: {}", success, no_nodes); println!("{}", &nodes_created); - InstantiationResponse::Ok(program_exe) + InstantiationResponse::Ok((program_exe,warnings)) } Err(reports) => InstantiationResponse::Err(reports), } diff --git a/constraint_list/Cargo.toml b/constraint_list/Cargo.toml index 319dc9038..a28bc5302 100644 --- a/constraint_list/Cargo.toml +++ b/constraint_list/Cargo.toml @@ -1,10 +1,9 @@ [package] name = "constraint_list" -version = "2.0.0" -authors = ["hermeGarcia "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] constraint_writers = { path = "../constraint_writers" } diff --git a/constraint_writers/Cargo.toml b/constraint_writers/Cargo.toml index 9a52eff43..a058416c1 100644 --- a/constraint_writers/Cargo.toml +++ b/constraint_writers/Cargo.toml @@ -1,11 +1,9 @@ [package] name = "constraint_writers" -version = "2.0.1" -authors = ["hermeGarcia "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] circom_algebra = { path = "../circom_algebra" } json = "0.12.4" diff --git a/dag/Cargo.toml b/dag/Cargo.toml index 6ea62f9e9..1e4899f4d 100644 --- a/dag/Cargo.toml +++ b/dag/Cargo.toml @@ -1,11 +1,9 @@ [package] name = "dag" -version = "2.0.1" -authors = ["hermeGarcia "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] constraint_list = { path = "../constraint_list" } constraint_writers = { path = "../constraint_writers" } diff --git a/mkdocs/docs/circom-language/code-quality/debugging-operations.md b/mkdocs/docs/circom-language/code-quality/debugging-operations.md index 933123a6b..09a5b111e 100644 --- a/mkdocs/docs/circom-language/code-quality/debugging-operations.md +++ b/mkdocs/docs/circom-language/code-quality/debugging-operations.md @@ -8,5 +8,12 @@ log(c.b); log(x==y); ``` - - +Since circom 2.0.6, operation `log` admits a list of non-conditional expressions and also strings written in the standard way. For instance: +```text +log("The expected result is ",135," but the value of a is",a); +``` +Finally, this operations admits an empty list of expressions which is equivalent to print an end-of-line. The next two instructions are equivalent: +```text +log(""); +log(); +``` diff --git a/parser/Cargo.toml b/parser/Cargo.toml index 5a22ec526..d71c52637 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "parser" -version = "2.0.1" -authors = ["Hermenegildo "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" build = "build.rs" diff --git a/parser/src/lang.lalrpop b/parser/src/lang.lalrpop index ad4b88db6..a20601c24 100644 --- a/parser/src/lang.lalrpop +++ b/parser/src/lang.lalrpop @@ -313,11 +313,7 @@ ParseStatement2 : Statement = { "===" ";" => build_constraint_equality(Meta::new(s,e),lhe,rhe), - "log" "(" ")" ";" - => build_log_call(Meta::new(s,e),arg,None), - - "log" "(" "," ")" ";" - => build_log_call(Meta::new(s,e),arg,Some(label)), + ParseStatementLog, "assert" "(" ")" ";" => build_assert(Meta::new(s,e),arg), @@ -325,6 +321,14 @@ ParseStatement2 : Statement = { ParseBlock }; +ParseStatementLog : Statement = { + "log" "(" ")" ";" + => build_log_call(Meta::new(s,e),args), + + "log" "(" ")" ";" + => build_log_call(Meta::new(s,e),Vec::new()), +}; + ParseStatement3 : Statement = { ";" => dec, @@ -366,6 +370,34 @@ Listable: Vec = { }, }; +ParseString : LogArgument = { + + => { + build_log_string(e) + }, +}; + +ParseLogExp: LogArgument = { + + => { + build_log_expression(e) + } +} + +ParseLogArgument : LogArgument = { + ParseLogExp, + ParseString +}; + +LogListable: Vec = { + ",")*> + => { + let mut e = e; + e.push(tail); + e + }, +}; + InfixOpTier : Expression = { > => build_infix(Meta::new(s,e),lhe,infix_op,rhe), diff --git a/program_structure/Cargo.toml b/program_structure/Cargo.toml index ca781e9e0..60eb10120 100644 --- a/program_structure/Cargo.toml +++ b/program_structure/Cargo.toml @@ -1,11 +1,9 @@ [package] name = "program_structure" -version = "2.0.1" -authors = ["hermeGarcia "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] codespan = "0.9.0" codespan-reporting = "0.9.0" diff --git a/program_structure/src/abstract_syntax_tree/ast.rs b/program_structure/src/abstract_syntax_tree/ast.rs index 1b09a0f64..eec7ed4bf 100644 --- a/program_structure/src/abstract_syntax_tree/ast.rs +++ b/program_structure/src/abstract_syntax_tree/ast.rs @@ -202,8 +202,7 @@ pub enum Statement { }, LogCall { meta: Meta, - arg: Expression, - label: Option, + args: Vec, }, Block { meta: Meta, @@ -270,6 +269,11 @@ pub enum Expression { meta: Meta, values: Vec, }, + UniformArray { + meta: Meta, + value: Box, + dimension: Box, + } } #[derive(Clone)] @@ -331,6 +335,19 @@ pub enum TypeReduction { Signal, } +#[derive(Clone)] +pub enum LogArgument { + LogStr(String), + LogExp(Expression), +} +pub fn build_log_string(acc: String) -> LogArgument { + LogArgument::LogStr(acc) +} +pub fn build_log_expression(expr: Expression) -> LogArgument { + LogArgument::LogExp(expr) +} + + #[derive(Default, Clone)] pub struct TypeKnowledge { reduces_to: Option, diff --git a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs index 188351b54..cb199fa07 100644 --- a/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs +++ b/program_structure/src/abstract_syntax_tree/ast_shortcuts.rs @@ -51,6 +51,8 @@ pub fn split_declaration_into_single_nodes( symbols: Vec, op: AssignOp, ) -> Statement { + use crate::ast_shortcuts::VariableType::Var; + let mut initializations = Vec::new(); for symbol in symbols { @@ -59,13 +61,23 @@ pub fn split_declaration_into_single_nodes( let name = symbol.name.clone(); let dimensions = symbol.is_array; let possible_init = symbol.init; - let single_declaration = build_declaration(with_meta, has_type, name, dimensions); + let single_declaration = build_declaration(with_meta, has_type, name, dimensions.clone()); initializations.push(single_declaration); if let Option::Some(init) = possible_init { let substitution = build_substitution(meta.clone(), symbol.name, vec![], op, init); initializations.push(substitution); } + else if xtype == Var { + let mut value = Expression:: Number(meta.clone(), BigInt::from(0)); + for dim_expr in dimensions.iter().rev(){ + value = build_uniform_array(meta.clone(), value, dim_expr.clone()); + } + + let substitution = + build_substitution(meta.clone(), symbol.name, vec![], op, value); + initializations.push(substitution); + } } build_initialization_block(meta, xtype, initializations) } \ No newline at end of file diff --git a/program_structure/src/abstract_syntax_tree/expression_builders.rs b/program_structure/src/abstract_syntax_tree/expression_builders.rs index b0dbeae4b..69358c8b8 100644 --- a/program_structure/src/abstract_syntax_tree/expression_builders.rs +++ b/program_structure/src/abstract_syntax_tree/expression_builders.rs @@ -44,3 +44,7 @@ pub fn build_call(meta: Meta, id: String, args: Vec) -> Expression { pub fn build_array_in_line(meta: Meta, values: Vec) -> Expression { ArrayInLine { meta, values } } + +pub fn build_uniform_array(meta: Meta, value: Expression, dimension: Expression) -> Expression { + UniformArray { meta, value: Box::new(value), dimension: Box::new(dimension) } +} diff --git a/program_structure/src/abstract_syntax_tree/expression_impl.rs b/program_structure/src/abstract_syntax_tree/expression_impl.rs index f84b77bd5..86d441286 100644 --- a/program_structure/src/abstract_syntax_tree/expression_impl.rs +++ b/program_structure/src/abstract_syntax_tree/expression_impl.rs @@ -11,6 +11,7 @@ impl Expression { | Number(meta, ..) | Call { meta, .. } | ArrayInLine { meta, .. } => meta, + | UniformArray { meta, .. } => meta, } } pub fn get_mut_meta(&mut self) -> &mut Meta { @@ -23,6 +24,7 @@ impl Expression { | Number(meta, ..) | Call { meta, .. } | ArrayInLine { meta, .. } => meta, + | UniformArray { meta, .. } => meta, } } @@ -30,6 +32,8 @@ impl Expression { use Expression::*; if let ArrayInLine { .. } = self { true + } else if let UniformArray { .. } = self{ + true } else { false } @@ -107,6 +111,9 @@ impl FillMeta for Expression { ArrayInLine { meta, values, .. } => { fill_array_inline(meta, values, file_id, element_id) } + UniformArray { meta, value, dimension, .. } => { + fill_uniform_array(meta, value, dimension, file_id, element_id) + } } } } @@ -173,3 +180,15 @@ fn fill_array_inline( v.fill(file_id, element_id); } } + +fn fill_uniform_array( + meta: &mut Meta, + value: &mut Expression, + dimensions: &mut Expression, + file_id: usize, + element_id: &mut usize, +) { + meta.set_file_id(file_id); + value.fill(file_id, element_id); + dimensions.fill(file_id, element_id); +} diff --git a/program_structure/src/abstract_syntax_tree/statement_builders.rs b/program_structure/src/abstract_syntax_tree/statement_builders.rs index 39c39adbe..3caee213e 100644 --- a/program_structure/src/abstract_syntax_tree/statement_builders.rs +++ b/program_structure/src/abstract_syntax_tree/statement_builders.rs @@ -53,8 +53,27 @@ pub fn build_constraint_equality(meta: Meta, lhe: Expression, rhe: Expression) - ConstraintEquality { meta, lhe, rhe } } -pub fn build_log_call(meta: Meta, arg: Expression, label: Option) -> Statement { - LogCall { meta, arg, label } +pub fn build_log_call(meta: Meta, args: Vec) -> Statement { + let mut new_args = Vec::new(); + for arg in args { + match arg { + LogArgument::LogExp(..) => { new_args.push(arg);} + LogArgument::LogStr(str) => { new_args.append(&mut split_string(str));} + } + } + LogCall { meta, args: new_args } +} + +fn split_string(str: String) -> Vec { + let mut v = vec![]; + let sub_len = 230; + let mut cur = str; + while !cur.is_empty() { + let (chunk, rest) = cur.split_at(std::cmp::min(sub_len, cur.len())); + v.push(LogArgument::LogStr(chunk.to_string())); + cur = rest.to_string(); + } + v } pub fn build_assert(meta: Meta, arg: Expression) -> Statement { diff --git a/program_structure/src/abstract_syntax_tree/statement_impl.rs b/program_structure/src/abstract_syntax_tree/statement_impl.rs index ece2dbcf9..c78912ad8 100644 --- a/program_structure/src/abstract_syntax_tree/statement_impl.rs +++ b/program_structure/src/abstract_syntax_tree/statement_impl.rs @@ -137,7 +137,7 @@ impl FillMeta for Statement { ConstraintEquality { meta, lhe, rhe } => { fill_constraint_equality(meta, lhe, rhe, file_id, element_id) } - LogCall { meta, arg, .. } => fill_log_call(meta, arg, file_id, element_id), + 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), } @@ -229,9 +229,13 @@ fn fill_constraint_equality( rhe.fill(file_id, element_id); } -fn fill_log_call(meta: &mut Meta, arg: &mut Expression, file_id: usize, element_id: &mut usize) { +fn fill_log_call(meta: &mut Meta, args: &mut Vec, file_id: usize, element_id: &mut usize) { meta.set_file_id(file_id); - arg.fill(file_id, element_id); + for arg in args { + if let LogArgument::LogExp(e) = arg { + e.fill(file_id, element_id); + } + } } fn fill_block(meta: &mut Meta, stmts: &mut [Statement], file_id: usize, element_id: &mut usize) { diff --git a/program_structure/src/program_library/error_code.rs b/program_structure/src/program_library/error_code.rs index 919bcb481..151808254 100644 --- a/program_structure/src/program_library/error_code.rs +++ b/program_structure/src/program_library/error_code.rs @@ -72,7 +72,6 @@ pub enum ReportCode { CustomGateConstraintError, CustomGateSubComponentError, CustomGatesPragmaError, - LabelTooLongError(usize), CustomGatesVersionError, } impl fmt::Display for ReportCode { @@ -148,7 +147,6 @@ impl fmt::Display for ReportCode { CustomGateConstraintError => "CG02", CustomGateSubComponentError => "CG03", CustomGatesPragmaError => "CG04", - LabelTooLongError(..) => "L01", CustomGatesVersionError => "CG05", }; f.write_str(string_format) diff --git a/program_structure/src/utils/memory_slice.rs b/program_structure/src/utils/memory_slice.rs index 4c274c3d2..5ccfd80c3 100644 --- a/program_structure/src/utils/memory_slice.rs +++ b/program_structure/src/utils/memory_slice.rs @@ -5,6 +5,8 @@ pub enum MemoryError { AssignmentError, InvalidAccess, UnknownSizeDimension, + MismatchedDimensions, + MismatchedDimensionsWeak } pub type SliceCapacity = usize; pub type SimpleSlice = MemorySlice; @@ -48,6 +50,7 @@ impl MemorySlice { memory_slice: &MemorySlice, access: &[SliceCapacity], ) -> Result { + if access.len() > memory_slice.route.len() { return Result::Err(MemoryError::OutOfBoundsError); } @@ -65,6 +68,40 @@ impl MemorySlice { } Result::Ok(cell) } + pub fn check_correct_dims( + memory_slice: &MemorySlice, + access: &[SliceCapacity], + new_values: &MemorySlice, + ) -> Result<(), MemoryError> { + + if access.len() + new_values.route.len() > memory_slice.route.len() { + return Result::Err(MemoryError::OutOfBoundsError); + } + + let mut i: SliceCapacity = 0; + + while i < access.len() { + if access[i] >= memory_slice.route[i] { + return Result::Err(MemoryError::OutOfBoundsError); + } + i += 1; + } + + let initial_index_new: SliceCapacity = i; + i = 0; + + while i < new_values.route.len() { + if new_values.route[i] < memory_slice.route[initial_index_new + i] { + return Result::Err(MemoryError::MismatchedDimensionsWeak); + } + if new_values.route[i] > memory_slice.route[initial_index_new + i] { + return Result::Err(MemoryError::MismatchedDimensions); + } + i += 1; + } + Result::Ok(()) + } + // Returns the new route and the total number of cells // that a slice with such route will have fn generate_new_route_from_access( @@ -131,17 +168,35 @@ impl MemorySlice { access: &[SliceCapacity], new_values: &MemorySlice, ) -> Result<(), MemoryError> { - let mut cell = MemorySlice::get_initial_cell(memory_slice, access)?; - if MemorySlice::get_number_of_cells(new_values) - > (MemorySlice::get_number_of_cells(memory_slice) - cell) - { - return Result::Err(MemoryError::OutOfBoundsError); - } - for value in new_values.values.iter() { - memory_slice.values[cell] = value.clone(); - cell += 1; + match MemorySlice::check_correct_dims(memory_slice, access, new_values){ + Result::Ok(_) => { + let mut cell = MemorySlice::get_initial_cell(memory_slice, access)?; + // if MemorySlice::get_number_of_cells(new_values) + // > (MemorySlice::get_number_of_cells(memory_slice) - cell) + // { + // return Result::Err(MemoryError::OutOfBoundsError); + // } + for value in new_values.values.iter() { + memory_slice.values[cell] = value.clone(); + cell += 1; + } + Result::Ok(()) + }, + Result::Err(MemoryError::MismatchedDimensionsWeak) => { + let mut cell = MemorySlice::get_initial_cell(memory_slice, access)?; + // if MemorySlice::get_number_of_cells(new_values) + // > (MemorySlice::get_number_of_cells(memory_slice) - cell) + // { + // return Result::Err(MemoryError::OutOfBoundsError); + // } + for value in new_values.values.iter() { + memory_slice.values[cell] = value.clone(); + cell += 1; + } + Result::Err(MemoryError::MismatchedDimensionsWeak) + }, + Result::Err(error) => return Err(error), } - Result::Ok(()) } pub fn access_values( @@ -175,7 +230,6 @@ impl MemorySlice { pub fn is_single(&self) -> bool { self.route.is_empty() } - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! Calling this function with a MemorySlice ! diff --git a/type_analysis/Cargo.toml b/type_analysis/Cargo.toml index 9a31d5c3f..5e7941303 100644 --- a/type_analysis/Cargo.toml +++ b/type_analysis/Cargo.toml @@ -1,10 +1,9 @@ [package] name = "type_analysis" -version = "2.0.0" -authors = ["hermeGarcia "] +version = "2.0.4" +authors = ["Costa Group UCM","iden3"] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] program_structure = {path = "../program_structure"} num-bigint-dig = "0.6.0" 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 00ff96ac9..216a2dbc2 100644 --- a/type_analysis/src/analyzers/functions_free_of_template_elements.rs +++ b/type_analysis/src/analyzers/functions_free_of_template_elements.rs @@ -101,7 +101,14 @@ fn analyse_statement( analyse_expression(lhe, function_names, reports); analyse_expression(rhe, function_names, reports); } - LogCall { arg, .. } | Assert { arg, .. } => { + LogCall { args, .. } => { + for logarg in args { + if let LogArgument::LogExp(arg) = logarg { + analyse_expression(arg, function_names, reports); + } + } + } + Assert { arg, .. } => { analyse_expression(arg, function_names, reports); } Return { value, .. } => { @@ -175,5 +182,11 @@ fn analyse_expression( analyse_expression(value, function_names, reports); } } + UniformArray {value, dimension, .. } => { + analyse_expression(value, function_names, reports); + analyse_expression(dimension, function_names, reports); + + + } } } diff --git a/type_analysis/src/analyzers/symbol_analysis.rs b/type_analysis/src/analyzers/symbol_analysis.rs index 941127563..02157d0e5 100644 --- a/type_analysis/src/analyzers/symbol_analysis.rs +++ b/type_analysis/src/analyzers/symbol_analysis.rs @@ -1,4 +1,4 @@ -use program_structure::ast::{Access, Expression, Meta, Statement}; +use program_structure::ast::{Access, Expression, Meta, Statement, LogArgument}; use program_structure::error_code::ReportCode; use program_structure::error_definition::{Report, ReportCollection}; use program_structure::file_definition::{self, FileID, FileLocation}; @@ -220,8 +220,12 @@ fn analyze_statement( reports.push(report); } } - Statement::LogCall { arg, .. } => { - analyze_expression(arg, file_id, function_info, template_info, reports, environment) + Statement::LogCall { args, .. } => { + for logarg in args { + if let LogArgument::LogExp(arg) = logarg { + analyze_expression(arg, file_id, function_info, template_info, reports, environment); + } + } } Statement::Assert { arg, .. } => { analyze_expression(arg, file_id, function_info, template_info, reports, environment) @@ -385,6 +389,24 @@ fn analyze_expression( ); } } + Expression::UniformArray{ value, dimension, .. } => { + analyze_expression( + value, + file_id, + function_info, + template_info, + reports, + environment, + ); + analyze_expression( + dimension, + file_id, + function_info, + template_info, + reports, + environment, + ); + }, _ => {} } } diff --git a/type_analysis/src/analyzers/tag_analysis.rs b/type_analysis/src/analyzers/tag_analysis.rs index 6daa5fb58..e98c5fee7 100644 --- a/type_analysis/src/analyzers/tag_analysis.rs +++ b/type_analysis/src/analyzers/tag_analysis.rs @@ -163,6 +163,9 @@ fn expression_inspection( ArrayInLine { .. } => { ExpressionResult::ArithmeticExpression(SignalElementType::FieldElement) } + UniformArray { .. } => { + ExpressionResult::ArithmeticExpression(SignalElementType::FieldElement) + } } } diff --git a/type_analysis/src/analyzers/type_check.rs b/type_analysis/src/analyzers/type_check.rs index 658690312..9e363e74a 100644 --- a/type_analysis/src/analyzers/type_check.rs +++ b/type_analysis/src/analyzers/type_check.rs @@ -242,29 +242,24 @@ fn type_statement( ); } } - LogCall { arg, meta, label, .. } => { - let arg_response = type_expression(arg, program_archive, analysis_information); - let arg_type = if let Result::Ok(t) = arg_response { - t - } else { - return; - }; - if let Some(label) = label { - if label.len() > 240 { - add_report( - ReportCode::LabelTooLongError(label.len()), - meta, - &mut analysis_information.reports, - ) + LogCall { args, meta } => { + for arglog in args { + if let LogArgument::LogExp(arg) = arglog{ + let arg_response = type_expression(arg, program_archive, analysis_information); + let arg_type = if let Result::Ok(t) = arg_response { + t + } else { + return; + }; + if arg_type.is_template() || arg_type.dim() > 0 { + add_report( + ReportCode::MustBeSingleArithmetic, + meta, + &mut analysis_information.reports, + ) + } } } - if arg_type.is_template() || arg_type.dim() > 0 { - add_report( - ReportCode::MustBeSingleArithmetic, - meta, - &mut analysis_information.reports, - ) - } } Assert { arg, meta } => { let arg_response = type_expression(arg, program_archive, analysis_information); @@ -379,6 +374,32 @@ fn type_expression( } Result::Ok(FoldedType::arithmetic_type(inferred_dim + 1)) } + UniformArray { meta, value, dimension } => { + let value_type = type_expression(value, program_archive, analysis_information).unwrap(); + if value_type.is_template() { + add_report( + ReportCode::InvalidArrayType, + meta, + &mut analysis_information.reports, + ); + }; + let dim_type = type_expression(dimension, program_archive, analysis_information).unwrap(); + if dim_type.is_template() { + add_report( + ReportCode::InvalidArrayType, + expression.get_meta(), + &mut analysis_information.reports, + ); + } else if dim_type.dim() != 0 { + add_report( + ReportCode::InvalidArrayType, + expression.get_meta(), + &mut analysis_information.reports, + ); + } + + Result::Ok(FoldedType::arithmetic_type(value_type.dim() + 1)) + } InfixOp { lhe, rhe, .. } => { let lhe_response = type_expression(lhe, program_archive, analysis_information); let rhe_response = type_expression(rhe, program_archive, analysis_information); @@ -784,7 +805,6 @@ fn add_report(error_code: ReportCode, meta: &Meta, reports: &mut ReportCollectio WrongNumberOfArguments(expected, got) => { format!("Expecting {} arguments, {} where obtained", expected, got) } - LabelTooLongError(len) => format!("Label too long. Label is {} characters but must be <240", len), _ => panic!("Unimplemented error code"), }; report.add_primary(location, file_id, message); diff --git a/type_analysis/src/analyzers/type_given_function.rs b/type_analysis/src/analyzers/type_given_function.rs index 045b02e19..cdb608125 100644 --- a/type_analysis/src/analyzers/type_given_function.rs +++ b/type_analysis/src/analyzers/type_given_function.rs @@ -273,6 +273,23 @@ fn look_for_type_in_expression( &values[0], ) .map(|v| v + 1), + Expression::UniformArray { value, .. } => { + let value_type = look_for_type_in_expression( + function_name, + environment, + explored_functions, + function_data, + function_info, + value, + ); + if value_type.is_some(){ + Option::Some(value_type.unwrap() + 1) + } + else{ + None + } + + } Expression::Call { id, args, .. } => { if explored_functions.contains(id) { return Option::None; diff --git a/type_analysis/src/analyzers/unknown_known_analysis.rs b/type_analysis/src/analyzers/unknown_known_analysis.rs index 315f8df04..a3b360616 100644 --- a/type_analysis/src/analyzers/unknown_known_analysis.rs +++ b/type_analysis/src/analyzers/unknown_known_analysis.rs @@ -280,6 +280,11 @@ fn tag(expression: &Expression, environment: &Environment) -> Tag { ArrayInLine { values, .. } | Call { args: values, .. } => { expression_iterator(values, Known, Unknown, environment) } + UniformArray { value, dimension, .. } => { + let tag_value = tag(value, environment); + let tag_dimension = tag(dimension, environment); + max(tag_value, tag_dimension) + } InlineSwitchOp { cond, if_true, if_false, .. } => { let tag_cond = tag(cond, environment); let tag_true = tag(if_true, environment); @@ -397,6 +402,7 @@ fn unknown_index(exp: &Expression, environment: &Environment) -> bool { } (false, bucket) } + UniformArray{ value, dimension, .. } => (false, vec![value.as_ref(), dimension.as_ref()]), }; let mut has_unknown_index = init; let mut index = 0; diff --git a/type_analysis/src/decorators/constants_handler.rs b/type_analysis/src/decorators/constants_handler.rs index 4c828c458..25d14067c 100644 --- a/type_analysis/src/decorators/constants_handler.rs +++ b/type_analysis/src/decorators/constants_handler.rs @@ -221,6 +221,7 @@ fn has_constant_value(expr: &Expression, environment: &Constants) -> bool { } Variable { name, .. } => variable(name, environment), ArrayInLine { .. } => array_inline(), + UniformArray { .. } => uniform_array(), } } @@ -239,6 +240,9 @@ fn call(params: &[Expression], environment: &Constants) -> bool { fn array_inline() -> bool { false } +fn uniform_array() -> bool { + false +} fn variable(name: &str, environment: &Constants) -> bool { *environment.get_variable_or_break(name, file!(), line!()) } @@ -277,7 +281,7 @@ fn expand_statement(stmt: &mut Statement, environment: &mut ExpressionHolder) { Declaration { dimensions, .. } => expand_declaration(dimensions, environment), Substitution { access, rhe, .. } => expand_substitution(access, rhe, environment), ConstraintEquality { lhe, rhe, .. } => expand_constraint_equality(lhe, rhe, environment), - LogCall { arg, .. } => expand_log_call(arg, environment), + LogCall { args, .. } => expand_log_call(args, environment), Assert { arg, .. } => expand_assert(arg, environment), Block { stmts, .. } => expand_block(stmts, environment), } @@ -359,8 +363,12 @@ fn expand_constraint_equality( *rhe = expand_expression(rhe.clone(), environment); } -fn expand_log_call(arg: &mut Expression, environment: &ExpressionHolder) { - *arg = expand_expression(arg.clone(), environment); +fn expand_log_call(args: &mut Vec, environment: &ExpressionHolder) { + for arglog in args { + if let LogArgument::LogExp(arg) = arglog { + *arg = expand_expression(arg.clone(), environment); + } + } } fn expand_assert(arg: &mut Expression, environment: &ExpressionHolder) { @@ -380,6 +388,7 @@ fn expand_expression(expr: Expression, environment: &ExpressionHolder) -> Expres match expr { Number(meta, value) => expand_number(meta, value), ArrayInLine { meta, values } => expand_array(meta, values, environment), + UniformArray { meta, value, dimension} => expand_uniform_array(meta, *value, *dimension, environment), Call { id, meta, args } => expand_call(id, meta, args, environment), InfixOp { meta, lhe, rhe, infix_op } => { expand_infix(meta, *lhe, infix_op, *rhe, environment) @@ -409,6 +418,17 @@ fn expand_array( build_array_in_line(meta, values) } +fn expand_uniform_array( + meta: Meta, + old_value: Expression, + old_dimension: Expression, + environment: &ExpressionHolder, +) -> Expression { + let value = expand_expression(old_value, environment); + let dimension = expand_expression(old_dimension, environment); + build_uniform_array(meta, value, dimension) +} + fn expand_call( id: String, meta: Meta, diff --git a/type_analysis/src/decorators/type_reduction.rs b/type_analysis/src/decorators/type_reduction.rs index ec86ee2eb..3fa51700c 100644 --- a/type_analysis/src/decorators/type_reduction.rs +++ b/type_analysis/src/decorators/type_reduction.rs @@ -39,7 +39,10 @@ fn reduce_types_in_statement(stmt: &mut Statement, environment: &mut Environment IfThenElse { cond, if_case, else_case, .. } => { reduce_types_in_conditional(cond, if_case, else_case, environment) } - LogCall { arg, .. } => reduce_types_in_expression(arg, environment), + LogCall { args, .. } => { + reduce_types_in_log_call(args, environment) + + }, Assert { arg, .. } => reduce_types_in_expression(arg, environment), Return { value, .. } => reduce_types_in_expression(value, environment), ConstraintEquality { lhe, rhe, .. } => { @@ -47,6 +50,15 @@ fn reduce_types_in_statement(stmt: &mut Statement, environment: &mut Environment } } } + +fn reduce_types_in_log_call(args: &mut Vec, environment: &Environment){ + for arg in args { + if let LogArgument::LogExp(exp) = arg { + reduce_types_in_expression(exp, environment); + } + } +} + fn reduce_types_in_expression(expression: &mut Expression, environment: &Environment) { use Expression::*; match expression { @@ -60,6 +72,10 @@ fn reduce_types_in_expression(expression: &mut Expression, environment: &Environ } Call { args, .. } => reduce_types_in_vec_of_expressions(args, environment), ArrayInLine { values, .. } => reduce_types_in_vec_of_expressions(values, environment), + UniformArray { value, dimension, .. } => { + reduce_types_in_expression(value, environment); + reduce_types_in_expression(dimension, environment); + } Number(..) => {} } }