Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: multi dimensional access #16

Merged
merged 18 commits into from
Jan 30, 2024
9 changes: 5 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ resolver = "1" # Fixes lalrpop issue, see: https://github.com/lalrpop/lalrpop/is
[dependencies]
clap = "2.34.0"
dotenv = "0.15.0"
env_logger = "0.10.1"
env_logger = "0.11.1"
log = "0.4.20"
regex = "1.10.2"
rand = "0.8.5"
regex = "1.10.3"
serde_json = "1.0"
serde = { version = "1.0.193", features = ["derive"] }
thiserror = "1.0.50"
serde = { version = "1.0.196", features = ["derive"] }
thiserror = "1.0.56"

# DSL
circom-circom_algebra = { git = "https://github.com/iden3/circom", package = "circom_algebra"}
Expand Down
5 changes: 3 additions & 2 deletions src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

use circom_compiler::compiler_interface;
use circom_compiler::compiler_interface::{Config, VCP};
use circom_constraint_generation::{build_circuit, BuildConfig};
use circom_program_structure::error_definition::Report;
use circom_program_structure::program_archive::ProgramArchive;
use circom_type_analysis::check_types::check_types;
Expand Down Expand Up @@ -61,6 +62,7 @@ pub struct ExecutionConfig {
pub r1cs: String,
pub sym: String,
pub json_constraints: String,
pub json_substitutions: String,
pub no_rounds: usize,
pub flag_s: bool,
pub flag_f: bool,
Expand All @@ -79,11 +81,10 @@ pub fn execute_project(
program_archive: ProgramArchive,
config: ExecutionConfig,
) -> Result<VCP, ()> {
use circom_constraint_generation::{build_circuit, BuildConfig};

let build_config = BuildConfig {
no_rounds: config.no_rounds,
flag_json_sub: config.json_substitution_flag,
json_substitutions: config.json_substitutions,
flag_s: config.flag_s,
flag_f: config.flag_f,
flag_p: config.flag_p,
Expand Down
110 changes: 51 additions & 59 deletions src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use std::collections::HashMap;

use crate::circuit::{AGateType, ArithmeticCircuit};
use crate::program::ProgramError;
use crate::runtime::{DataContent, Runtime, ContextOrigin};
use crate::traverse::traverse_sequence_of_statements;
use crate::runtime::{ContextOrigin, DataAccess, DataType, Runtime};
use crate::traverse::{build_access, traverse_sequence_of_statements};
use circom_circom_algebra::num_traits::ToPrimitive;
use circom_program_structure::ast::{Access, Expression, ExpressionInfixOpcode, Statement};
use circom_program_structure::ast::{Expression, ExpressionInfixOpcode, Statement};
use circom_program_structure::program_archive::ProgramArchive;
use log::debug;

Expand All @@ -34,7 +34,7 @@ pub fn execute_statement(
loop {
let res = execute_expression(ac, runtime, cond, program_archive)?;
execute_statement(ac, runtime, stmt, program_archive)?;
if res == 0 {
if res == Some(0) {
break;
}
}
Expand All @@ -48,7 +48,7 @@ pub fn execute_statement(
} => {
let res = execute_expression(ac, runtime, cond, program_archive)?;
let else_case = else_case.as_ref().map(|e| e.as_ref());
if res == 0 {
if res == Some(0) {
if let Option::Some(else_stmt) = else_case {
execute_statement(ac, runtime, else_stmt, program_archive)
} else {
Expand All @@ -61,40 +61,39 @@ pub fn execute_statement(
Statement::Substitution {
var, access, rhe, ..
} => {
let mut name_access = String::from(var);
for a in access.iter() {
match a {
Access::ArrayAccess(expr) => {
debug!("Array access found");
let dim_u32_str = execute_expression(ac, runtime, expr, program_archive)?;
name_access.push('_');
name_access.push_str(&dim_u32_str.to_string());
debug!("Change var name to {}", name_access);
}
Access::ComponentAccess(_) => {
todo!("Component access not handled");
}
}
}
// This corresponds to a variable assignment.
let access = build_access(runtime, ac, program_archive, var, access)?;

// Get the value of the right hand expression
let rhe_val = execute_expression(ac, runtime, rhe, program_archive)?;

// Declare the variable if it is not declared yet
let ctx = runtime.get_current_context()?;
if ctx.get_data_item(&name_access).is_err() {
ctx.declare_variable(&name_access)?;
let declare = ctx.declare_item(DataType::Variable, &access.get_name(), &[]);
if declare.is_ok() {
declare?;
}
ctx.set_data_item(&name_access, DataContent::Scalar(rhe_val))?;

// Set the variable value
ctx.set_variable(access, rhe_val)?;

Ok(())
}
Statement::Return { value, .. } => {
debug!("Return expression found");
let access = DataAccess::new("return".to_string(), vec![]);
let res = execute_expression(ac, runtime, value, program_archive)?;
debug!("RETURN {}", res);
debug!("RETURN {:?}", res);

let ctx = runtime.get_current_context()?;
ctx.declare_variable("RETURN");
ctx.set_data_item("RETURN", DataContent::Scalar(res));
let declare = ctx.declare_item(DataType::Variable, &access.get_name(), &[]);

// Added check to avoid panic when the return is already declared
if declare.is_ok() {
declare?;
}

ctx.set_variable(access, res)?;

Ok(())
}
Statement::Block { stmts, .. } => {
Expand All @@ -115,36 +114,23 @@ pub fn execute_expression(
runtime: &mut Runtime,
expression: &Expression,
program_archive: &ProgramArchive,
) -> Result<u32, ProgramError> {
) -> Result<Option<u32>, ProgramError> {
match expression {
Expression::Number(_, value) => Ok(value.to_u32().ok_or(ProgramError::ParsingError)?),
Expression::Number(_, value) => Ok(value.to_u32()),
Expression::InfixOp {
lhe, infix_op, rhe, ..
} => {
let lhs_op = execute_expression(ac, runtime, lhe, program_archive)?;
let rhs_op = execute_expression(ac, runtime, rhe, program_archive)?;
let lhs_op = execute_expression(ac, runtime, lhe, program_archive)?
.ok_or(ProgramError::EmptyDataItem)?;
let rhs_op = execute_expression(ac, runtime, rhe, program_archive)?
.ok_or(ProgramError::EmptyDataItem)?;

Ok(execute_infix_op(&lhs_op, &rhs_op, infix_op))
Ok(Some(execute_infix_op(&lhs_op, &rhs_op, infix_op)))
}
Expression::Variable { name, access, .. } => {
let mut name_access = String::from(name);
for a in access.iter() {
match a {
Access::ArrayAccess(expr) => {
debug!("Array access found");
let dim_u32 = execute_expression(ac, runtime, expr, program_archive)?;
name_access.push('_');
name_access.push_str(&dim_u32.to_string());
debug!("Changed var name to {}", name_access);
}
Access::ComponentAccess(_) => {
todo!("Component access found");
}
}
}

let access = build_access(runtime, ac, program_archive, name, access)?;
let ctx = runtime.get_current_context()?;
Ok(ctx.get_data_item(&name_access)?.get_u32()?)
Ok(ctx.get_variable(&access)?)
}
Expression::Call { id, args, .. } => {
debug!("Call found {}", id);
Expand All @@ -157,15 +143,16 @@ pub fn execute_expression(
program_archive.get_template_data(id).get_name_of_params()
};

let mut args_map = HashMap::new();
let mut args_map: HashMap<String, u32> = HashMap::new();

// We start by setting argument values to argument names
for (_arg_name, arg_value) in arg_names.iter().zip(args) {
for (arg_name, arg_value) in arg_names.iter().zip(args) {
// We set arg_name to have arg_value
// Because arg_value is an expression (constant, variable, or an infix operation or a function call) we need to execute to have the actual value
let value = execute_expression(ac, runtime, arg_value, program_archive)?;
let value = execute_expression(ac, runtime, arg_value, program_archive)?
.ok_or(ProgramError::EmptyDataItem)?;
// We cache this to args hashmap
args_map.insert(_arg_name, value);
args_map.insert(arg_name.to_string(), value);
}

// Here we need to spawn a new context for calling a function or wiring with a component (template)
Expand All @@ -174,26 +161,31 @@ pub fn execute_expression(
let ctx = runtime.get_current_context()?;

// Now we put args to use
for (_arg_name, arg_value) in args_map.iter() {
let _ = ctx.declare_variable(&_arg_name);
let _ = ctx.set_data_item(_arg_name, DataContent::Scalar(*(arg_value)));
for (arg_name, &arg_value) in args_map.iter() {
// TODO: Review, all items are unidimensional
ctx.declare_item(DataType::Variable, arg_name, &[])?;
ctx.set_variable(
DataAccess::new(arg_name.to_string(), vec![]),
Some(arg_value),
)?;
}

let _body = if functions.contains(id) {
program_archive.get_function_data(id).get_body_as_vec()
} else {
program_archive.get_template_data(id).get_body_as_vec()
};

traverse_sequence_of_statements(ac, runtime, _body, program_archive, true)?;

if functions.contains(id) {
// let ret = ctx.get_data_item("RETURN").unwrap().get_u32().unwrap();
// runtime.pop_context();
Ok(0)
debug!("temp return");
Ok(Some(0))
} else {
// runtime.pop_context();
Ok(0)
Ok(Some(0))
}

// Err(ProgramError::CallError)
Expand Down
4 changes: 4 additions & 0 deletions src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ pub enum ProgramError {
AnalysisError,
#[error("Call error")]
CallError,
#[error("Empty data item")]
EmptyDataItem,
#[error("Invalid data type")]
InvalidDataType,
#[error("Parsing error")]
ParsingError,
#[error("Context error: {0}")]
Expand Down
Loading
Loading