diff --git a/examples/log.no b/examples/log.no index a7a596d31..5de4244a2 100644 --- a/examples/log.no +++ b/examples/log.no @@ -1,6 +1,6 @@ fn main(pub public_input: Field) -> Field { - // log("stuff here"); + log("stuff here"); log(1234); log(true); diff --git a/src/backends/kimchi/mod.rs b/src/backends/kimchi/mod.rs index ee5e9160b..df7c2a3e1 100644 --- a/src/backends/kimchi/mod.rs +++ b/src/backends/kimchi/mod.rs @@ -22,7 +22,7 @@ use crate::{ backends::kimchi::asm::parse_coeffs, circuit_writer::{ writer::{AnnotatedCell, Cell, PendingGate}, - DebugInfo, Gate, GateKind, Wiring, + DebugInfo, Gate, GateKind, VarInfo, Wiring, }, compiler::Sources, constants::Span, @@ -128,6 +128,9 @@ pub struct KimchiVesta { /// Indexes used by the private inputs /// (this is useful to check that they appear in the circuit) pub(crate) private_input_cell_vars: Vec, + + /// mapping to containt log_info + pub(crate) log_info: Vec<(String, Span, VarInfo)>, } impl Witness { @@ -174,6 +177,7 @@ impl KimchiVesta { finalized: false, public_input_size: 0, private_input_cell_vars: vec![], + log_info: vec![], } } @@ -471,6 +475,7 @@ impl Backend for KimchiVesta { } public_outputs.push(val); } + self.print_log(witness_env, &self.log_info, sources, _typed)?; // sanity check the witness for (row, (gate, witness_row, debug_info)) in @@ -802,6 +807,6 @@ impl Backend for KimchiVesta { msg: String, span: Span, ) { - println!("todo: implement log_var for kimchi backend"); + self.log_info.push((msg, span, var.clone())); } } diff --git a/src/backends/mod.rs b/src/backends/mod.rs index a0947f19e..c683afb14 100644 --- a/src/backends/mod.rs +++ b/src/backends/mod.rs @@ -13,6 +13,8 @@ use crate::{ error::{Error, ErrorKind, Result}, helpers::PrettyField, imports::FnHandle, + parser::types::{ModulePath, TyKind}, + type_checker::FullyQualified, var::{ConstOrCell, Value, Var}, witness::WitnessEnv, }; @@ -424,4 +426,276 @@ pub trait Backend: Clone { fn generate_asm(&self, sources: &Sources, debug: bool) -> String; fn log_var(&mut self, var: &VarInfo, msg: String, span: Span); + + /// print the log given the log_info + fn print_log( + &self, + witness_env: &mut WitnessEnv, + logs: &[(String, Span, VarInfo)], + sources: &Sources, + typed: &Mast, + ) -> Result<()> { + for (_, span, var_info) in logs { + let (filename, source) = sources.get(&span.filename_id).unwrap(); + let (line, _, line_str) = crate::utils::find_exact_line(source, *span); + let line_str = line_str.trim_start(); + let dbg_msg = format!("[{filename}:{line}] `{line_str}` -> "); + + match &var_info.typ { + // Field + Some(TyKind::Field { .. }) => match &var_info.var[0] { + ConstOrCell::Const(cst) => { + println!("{dbg_msg}{}", cst.pretty()); + } + ConstOrCell::Cell(cell) => { + let val = self.compute_var(witness_env, cell)?; + println!("{dbg_msg}{}", val.pretty()); + } + }, + + // Bool + Some(TyKind::Bool) => match &var_info.var[0] { + ConstOrCell::Const(cst) => { + let val = *cst == Self::Field::one(); + println!("{dbg_msg}{}", val); + } + ConstOrCell::Cell(cell) => { + let val = self.compute_var(witness_env, cell)? == Self::Field::one(); + println!("{dbg_msg}{}", val); + } + }, + + // Array + Some(TyKind::Array(b, s)) => { + let (output, remaining) = + log_array_type(self, &var_info.var.cvars, b, *s, witness_env, typed, span)?; + assert!(remaining.is_empty()); + println!("{dbg_msg}{}", output); + } + + // Custom types + Some(TyKind::Custom { + module, + name: struct_name, + }) => { + let mut string_vec = Vec::new(); + let (output, remaining) = log_custom_type( + self, + module, + struct_name, + typed, + &var_info.var.cvars, + witness_env, + span, + &mut string_vec, + )?; + assert!(remaining.is_empty()); + println!("{dbg_msg}{}{}", struct_name, output); + } + + // GenericSizedArray + Some(TyKind::GenericSizedArray(_, _)) => { + unreachable!("GenericSizedArray should be monomorphized") + } + + Some(TyKind::String(s)) => { + println!("{dbg_msg}{}", s); + } + + None => { + return Err(Error::new( + "log", + ErrorKind::UnexpectedError("No type info for logging"), + *span, + )) + } + } + } + + Ok(()) + } +} + +fn log_custom_type( + backend: &B, + module: &ModulePath, + struct_name: &String, + typed: &Mast, + var_info_var: &[ConstOrCell], + witness: &mut WitnessEnv, + span: &Span, + string_vec: &mut Vec, +) -> Result<(String, Vec>)> { + let qualified = FullyQualified::new(module, struct_name); + let struct_info = typed + .struct_info(&qualified) + .ok_or( + typed + .0 + .error(ErrorKind::UnexpectedError("struct not found"), *span), + ) + .unwrap(); + + let mut remaining = var_info_var.to_vec(); + + for (field_name, field_typ) in &struct_info.fields { + let len = typed.size_of(field_typ); + match field_typ { + TyKind::Field { .. } => match &remaining[0] { + ConstOrCell::Const(cst) => { + string_vec.push(format!("{field_name}: {}", cst.pretty())); + remaining = remaining[len..].to_vec(); + } + ConstOrCell::Cell(cell) => { + let val = backend.compute_var(witness, cell)?; + string_vec.push(format!("{field_name}: {}", val.pretty())); + remaining = remaining[len..].to_vec(); + } + }, + + TyKind::Bool => match &remaining[0] { + ConstOrCell::Const(cst) => { + let val = *cst == B::Field::one(); + string_vec.push(format!("{field_name}: {}", val)); + remaining = remaining[len..].to_vec(); + } + ConstOrCell::Cell(cell) => { + let val = backend.compute_var(witness, cell)? == B::Field::one(); + string_vec.push(format!("{field_name}: {}", val)); + remaining = remaining[len..].to_vec(); + } + }, + + TyKind::Array(b, s) => { + let (output, new_remaining) = + log_array_type(backend, &remaining, b, *s, witness, typed, span)?; + string_vec.push(format!("{field_name}: {}", output)); + remaining = new_remaining; + } + + TyKind::Custom { + module, + name: struct_name, + } => { + let mut custom_string_vec = Vec::new(); + let (output, new_remaining) = log_custom_type( + backend, + module, + struct_name, + typed, + &remaining, + witness, + span, + &mut custom_string_vec, + )?; + string_vec.push(format!("{}: {}{}", field_name, struct_name, output)); + remaining = new_remaining; + } + + TyKind::GenericSizedArray(_, _) => { + unreachable!("GenericSizedArray should be monomorphized") + } + TyKind::String(s) => { + todo!("String cannot be a type for customs it is only for logging") + } + } + } + + Ok((format!("{{ {} }}", string_vec.join(", ")), remaining)) +} + +// this takes two generics because of the Mast is generic +fn log_array_type( + backend: &B, + var_info_var: &[ConstOrCell], + base_type: &TyKind, + size: u32, + witness: &mut WitnessEnv, + typed: &Mast, + span: &Span, +) -> Result<(String, Vec>)> { + match base_type { + TyKind::Field { .. } => { + let values: Vec = var_info_var + .iter() + .take(size as usize) + .map(|cvar| match cvar { + ConstOrCell::Const(cst) => cst.pretty(), + ConstOrCell::Cell(cell) => backend.compute_var(witness, cell).unwrap().pretty(), + }) + .collect(); + + let remaining = var_info_var[size as usize..].to_vec(); + Ok((format!("[{}]", values.join(", ")), remaining)) + } + + TyKind::Bool => { + let values: Vec = var_info_var + .iter() + .take(size as usize) + .map(|cvar| match cvar { + ConstOrCell::Const(cst) => { + let val = *cst == B::Field::one(); + val.to_string() + } + ConstOrCell::Cell(cell) => { + let val = backend.compute_var(witness, cell).unwrap() == B::Field::one(); + val.to_string() + } + }) + .collect(); + + let remaining = var_info_var[size as usize..].to_vec(); + Ok((format!("[{}]", values.join(", ")), remaining)) + } + + TyKind::Array(inner_type, inner_size) => { + let mut nested_result = Vec::new(); + let mut remaining = var_info_var.to_vec(); + for _ in 0..size { + let (chunk_result, new_remaining) = log_array_type( + backend, + &remaining, + inner_type, + *inner_size, + witness, + typed, + span, + )?; + nested_result.push(chunk_result); + remaining = new_remaining; + } + Ok((format!("[{}]", nested_result.join(", ")), remaining)) + } + + TyKind::Custom { + module, + name: struct_name, + } => { + let mut nested_result = Vec::new(); + let mut remaining = var_info_var.to_vec(); + for _ in 0..size { + let mut string_vec = Vec::new(); + let (output, new_remaining) = log_custom_type( + backend, + module, + struct_name, + typed, + &remaining, + witness, + span, + &mut string_vec, + )?; + nested_result.push(format!("{}{}", struct_name, output)); + remaining = new_remaining; + } + Ok((format!("[{}]", nested_result.join(", ")), remaining)) + } + + TyKind::GenericSizedArray(_, _) => { + unreachable!("GenericSizedArray should be monomorphized") + } + + TyKind::String(_) => todo!("String type cannot be used in circuits!"), + } } diff --git a/src/backends/r1cs/mod.rs b/src/backends/r1cs/mod.rs index a48160498..25b121f59 100644 --- a/src/backends/r1cs/mod.rs +++ b/src/backends/r1cs/mod.rs @@ -517,78 +517,7 @@ where witness[var.index] = val; } - // print out the log info - for (_, span, var_info) in &self.log_info { - let (filename, source) = sources.get(&span.filename_id).unwrap(); - let (line, _, line_str) = crate::utils::find_exact_line(source, *span); - let line_str = line_str.trim_start(); - let dbg_msg = format!("[{filename}:{line}] `{line_str}` -> "); - - match &var_info.typ { - // Field - Some(TyKind::Field { .. }) => match &var_info.var[0] { - ConstOrCell::Const(cst) => { - println!("{dbg_msg}{}", cst.pretty()); - } - ConstOrCell::Cell(cell) => { - let val = cell.evaluate(&witness); - println!("{dbg_msg}{}", val.pretty()); - } - }, - - // Bool - Some(TyKind::Bool) => match &var_info.var[0] { - ConstOrCell::Const(cst) => { - let val = *cst == F::one(); - println!("{dbg_msg}{}", val); - } - ConstOrCell::Cell(cell) => { - let val = cell.evaluate(&witness) == F::one(); - println!("{dbg_msg}{}", val); - } - }, - - // Array - Some(TyKind::Array(b, s)) => { - let (output, remaining) = - log_array_type(&var_info.var.cvars, b, *s, &witness, typed, span); - assert!(remaining.is_empty()); - println!("{dbg_msg}{}", output); - } - - // Custom types - Some(TyKind::Custom { - module, - name: struct_name, - }) => { - let mut string_vec = Vec::new(); - let (output, remaining) = log_custom_type( - module, - struct_name, - typed, - &var_info.var.cvars, - &witness, - span, - &mut string_vec, - ); - assert!(remaining.is_empty()); - println!("{dbg_msg}{}{}", struct_name, output); - } - - // GenericSizedArray - Some(TyKind::GenericSizedArray(_, _)) => { - unreachable!("GenericSizedArray should be monomorphized") - } - - None => { - return Err(Error::new( - "log", - ErrorKind::UnexpectedError("No type info for logging"), - *span, - )) - } - } - } + self.print_log(witness_env, &self.log_info, sources, typed)?; for (index, (constraint, debug_info)) in izip!(&self.constraints, &self.debug_info).enumerate() @@ -761,173 +690,6 @@ where } } -fn log_custom_type( - module: &ModulePath, - struct_name: &String, - typed: &Mast, - var_info_var: &[ConstOrCell>], - witness: &[F], - span: &Span, - string_vec: &mut Vec, -) -> (String, Vec>>) { - let qualified = FullyQualified::new(module, struct_name); - let struct_info = typed - .struct_info(&qualified) - .ok_or( - typed - .0 - .error(ErrorKind::UnexpectedError("struct not found"), *span), - ) - .unwrap(); - - let mut remaining = var_info_var.to_vec(); - - for (field_name, field_typ) in &struct_info.fields { - let len = typed.size_of(field_typ); - match field_typ { - TyKind::Field { .. } => match &remaining[0] { - ConstOrCell::Const(cst) => { - string_vec.push(format!("{field_name}: {}", cst.pretty())); - remaining = remaining[len..].to_vec(); - } - ConstOrCell::Cell(cell) => { - let val = cell.evaluate(witness); - string_vec.push(format!("{field_name}: {}", val.pretty())); - remaining = remaining[len..].to_vec(); - } - }, - - TyKind::Bool => match &remaining[0] { - ConstOrCell::Const(cst) => { - let val = *cst == F::one(); - string_vec.push(format!("{field_name}: {}", val)); - remaining = remaining[len..].to_vec(); - } - ConstOrCell::Cell(cell) => { - let val = cell.evaluate(witness) == F::one(); - string_vec.push(format!("{field_name}: {}", val)); - remaining = remaining[len..].to_vec(); - } - }, - - TyKind::Array(b, s) => { - let (output, new_remaining) = - log_array_type(&remaining, b, *s, witness, typed, span); - string_vec.push(format!("{field_name}: {}", output)); - remaining = new_remaining; - } - - TyKind::Custom { - module, - name: struct_name, - } => { - let mut custom_string_vec = Vec::new(); - let (output, new_remaining) = log_custom_type( - module, - struct_name, - typed, - &remaining, - witness, - span, - &mut custom_string_vec, - ); - string_vec.push(format!("{}: {}{}", field_name, struct_name, output)); - remaining = new_remaining; - } - - TyKind::GenericSizedArray(_, _) => { - unreachable!("GenericSizedArray should be monomorphized") - } - } - } - - (format!("{{ {} }}", string_vec.join(", ")), remaining) -} - -fn log_array_type( - var_info_var: &[ConstOrCell>], - base_type: &TyKind, - size: u32, - witness: &[F], - typed: &Mast, - span: &Span, -) -> (String, Vec>>) { - match base_type { - TyKind::Field { .. } => { - let values: Vec = var_info_var - .iter() - .take(size as usize) - .map(|cvar| match cvar { - ConstOrCell::Const(cst) => cst.pretty(), - ConstOrCell::Cell(cell) => cell.evaluate(witness).pretty(), - }) - .collect(); - - let remaining = var_info_var[size as usize..].to_vec(); - (format!("[{}]", values.join(", ")), remaining) - } - - TyKind::Bool => { - let values: Vec = var_info_var - .iter() - .take(size as usize) - .map(|cvar| match cvar { - ConstOrCell::Const(cst) => { - let val = *cst == F::one(); - val.to_string() - } - ConstOrCell::Cell(cell) => { - let val = cell.evaluate(witness) == F::one(); - val.to_string() - } - }) - .collect(); - - let remaining = var_info_var[size as usize..].to_vec(); - (format!("[{}]", values.join(", ")), remaining) - } - - TyKind::Array(inner_type, inner_size) => { - let mut nested_result = Vec::new(); - let mut remaining = var_info_var.to_vec(); - for _ in 0..size { - let (chunk_result, new_remaining) = - log_array_type(&remaining, inner_type, *inner_size, witness, typed, span); - nested_result.push(chunk_result); - remaining = new_remaining; - } - (format!("[{}]", nested_result.join(", ")), remaining) - } - - TyKind::Custom { - module, - name: struct_name, - } => { - let mut nested_result = Vec::new(); - let mut remaining = var_info_var.to_vec(); - for _ in 0..size { - let mut string_vec = Vec::new(); - let (output, new_remaining) = log_custom_type( - module, - struct_name, - typed, - &remaining, - witness, - span, - &mut string_vec, - ); - nested_result.push(format!("{}{}", struct_name, output)); - remaining = new_remaining; - } - (format!("[{}]", nested_result.join(", ")), remaining) - } - - TyKind::GenericSizedArray(_, _) => { - unreachable!("GenericSizedArray should be monomorphized") - } - } -} - #[cfg(test)] mod tests { use crate::{ diff --git a/src/circuit_writer/writer.rs b/src/circuit_writer/writer.rs index 74eba3ad0..8380707ee 100644 --- a/src/circuit_writer/writer.rs +++ b/src/circuit_writer/writer.rs @@ -331,6 +331,7 @@ impl CircuitWriter { TyKind::GenericSizedArray(_, _) => { unreachable!("generic array should have been resolved") } + TyKind::String(_) => todo!("String type is not supported for constraints"), }; Ok(()) } diff --git a/src/error.rs b/src/error.rs index d843a8ab4..a4542e4a2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -365,7 +365,4 @@ pub enum ErrorKind { #[error("division by zero")] DivisionByZero, - - #[error("String literal not closed")] - LiteralNotClosed, } diff --git a/src/mast/mod.rs b/src/mast/mod.rs index fcb946a67..8de758bdf 100644 --- a/src/mast/mod.rs +++ b/src/mast/mod.rs @@ -457,6 +457,7 @@ impl Mast { unreachable!("generic arrays should have been resolved") } TyKind::Bool => 1, + TyKind::String(s) => s.len(), } } } @@ -883,10 +884,7 @@ fn monomorphize_expr( .collect(); ExprMonoInfo::new( mexpr, - Some(TyKind::Array( - Box::new(TyKind::Field { constant: true }), - inner.len() as u32, - )), + Some(TyKind::String(inner.clone())), Some(PropagatedConstant::Array(string_literal_val)), ) } diff --git a/src/name_resolution/context.rs b/src/name_resolution/context.rs index d4d196eea..f06338772 100644 --- a/src/name_resolution/context.rs +++ b/src/name_resolution/context.rs @@ -133,6 +133,7 @@ impl NameResCtx { TyKind::Array(typ_kind, _) => self.resolve_typ_kind(typ_kind)?, TyKind::GenericSizedArray(typ_kind, _) => self.resolve_typ_kind(typ_kind)?, TyKind::Bool => (), + TyKind::String { .. } => (), }; Ok(()) diff --git a/src/parser/types.rs b/src/parser/types.rs index 4b79db677..361f2ad4a 100644 --- a/src/parser/types.rs +++ b/src/parser/types.rs @@ -291,6 +291,9 @@ pub enum TyKind { /// This is an intermediate type. /// After monomorphized, it will be converted to `Array`. GenericSizedArray(Box, Symbolic), + + /// A string type current purpose it to pass around for logging + String(String), } impl TyKind { @@ -334,6 +337,7 @@ impl TyKind { name: expected_name, }, ) => module == expected_module && name == expected_name, + (TyKind::String { .. }, TyKind::String { .. }) => true, (x, y) if x == y => true, _ => false, } @@ -356,6 +360,7 @@ impl TyKind { generics.extend(ty.extract_generics()); generics.extend(sym.extract_generics()); } + TyKind::String { .. } => (), } generics @@ -395,6 +400,7 @@ impl Display for TyKind { TyKind::Array(ty, size) => write!(f, "[{}; {}]", ty, size), TyKind::Bool => write!(f, "Bool"), TyKind::GenericSizedArray(ty, size) => write!(f, "[{}; {}]", ty, size), + TyKind::String(S) => write!(f, "String"), } } } diff --git a/src/type_checker/mod.rs b/src/type_checker/mod.rs index baa5ee9fa..2b405c477 100644 --- a/src/type_checker/mod.rs +++ b/src/type_checker/mod.rs @@ -496,6 +496,9 @@ impl TypeChecker { } TyKind::Field { constant: true } => unreachable!(), TyKind::GenericSizedArray(_, _) => unreachable!(), + TyKind::String(_) => { + todo!("String Type for circuits is not implemented") + } } } }