Skip to content

Commit

Permalink
creates generic logging function and implements string kind for loggi…
Browse files Browse the repository at this point in the history
…ng string literal
  • Loading branch information
0xnullifier committed Jan 5, 2025
1 parent ef8e6e2 commit dfbd7cd
Show file tree
Hide file tree
Showing 10 changed files with 296 additions and 249 deletions.
2 changes: 1 addition & 1 deletion examples/log.no
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

fn main(pub public_input: Field) -> Field {
// log("stuff here");
log("stuff here");

log(1234);
log(true);
Expand Down
9 changes: 7 additions & 2 deletions src/backends/kimchi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<KimchiCellVar>,

/// mapping to containt log_info
pub(crate) log_info: Vec<(String, Span, VarInfo<VestaField, KimchiCellVar>)>,
}

impl Witness {
Expand Down Expand Up @@ -174,6 +177,7 @@ impl KimchiVesta {
finalized: false,
public_input_size: 0,
private_input_cell_vars: vec![],
log_info: vec![],
}
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()));
}
}
274 changes: 274 additions & 0 deletions src/backends/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -424,4 +426,276 @@ pub trait Backend: Clone {
fn generate_asm(&self, sources: &Sources, debug: bool) -> String;

fn log_var(&mut self, var: &VarInfo<Self::Field, Self::Var>, msg: String, span: Span);

/// print the log given the log_info
fn print_log<B: Backend>(
&self,
witness_env: &mut WitnessEnv<Self::Field>,
logs: &[(String, Span, VarInfo<Self::Field, Self::Var>)],
sources: &Sources,
typed: &Mast<B>,
) -> 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<B: Backend, B1: Backend>(
backend: &B,
module: &ModulePath,
struct_name: &String,
typed: &Mast<B1>,
var_info_var: &[ConstOrCell<B::Field, B::Var>],
witness: &mut WitnessEnv<B::Field>,
span: &Span,
string_vec: &mut Vec<String>,
) -> Result<(String, Vec<ConstOrCell<B::Field, B::Var>>)> {
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<B: Backend, B1: Backend>(
backend: &B,
var_info_var: &[ConstOrCell<B::Field, B::Var>],
base_type: &TyKind,
size: u32,
witness: &mut WitnessEnv<B::Field>,
typed: &Mast<B1>,
span: &Span,
) -> Result<(String, Vec<ConstOrCell<B::Field, B::Var>>)> {
match base_type {
TyKind::Field { .. } => {
let values: Vec<String> = 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<String> = 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!"),
}
}
Loading

0 comments on commit dfbd7cd

Please sign in to comment.