add parsing for .in and .state files and update errors

This commit is contained in:
collin 2020-07-29 13:20:44 -07:00
parent 3d3e8f5e72
commit ac8c940169
27 changed files with 310 additions and 100 deletions

View File

@ -32,10 +32,10 @@ pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
}
impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
pub fn new(package_name: String) -> Self {
pub fn new(package_name: String, main_file_path: PathBuf) -> Self {
Self {
package_name: package_name.clone(),
main_file_path: PathBuf::new(),
main_file_path,
program: Program::new(package_name),
program_inputs: Inputs::new(),
imported_programs: ImportParser::new(),
@ -44,37 +44,48 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
}
}
pub fn new_from_path(
package_name: String,
main_file_path: PathBuf,
inputs_string: &str,
) -> Result<Self, CompilerError> {
let mut compiler = Self::new(package_name);
compiler.set_path(main_file_path);
/// Parses program files.
/// Returns a compiler struct that stores the typed program abstract syntax trees (ast).
pub fn parse_program_without_inputs(package_name: String, main_file_path: PathBuf) -> Result<Self, CompilerError> {
let mut compiler = Self::new(package_name, main_file_path);
// Generate the inputs file abstract syntax tree and store definitions
compiler.parse_inputs(inputs_string)?;
// Generate the program abstract syntax tree and assemble the program
let program_string = compiler.load_program()?;
compiler.parse_program(&program_string)?;
Ok(compiler)
}
pub fn set_path(&mut self, main_file_path: PathBuf) {
self.main_file_path = main_file_path
/// Parses input, state, and program files.
/// Returns a compiler struct that stores the typed inputs and typed program abstract syntax trees (ast).
pub fn parse_program_with_inputs(
package_name: String,
main_file_path: PathBuf,
inputs_string: &str,
state_string: &str,
) -> Result<Self, CompilerError> {
let mut compiler = Self::new(package_name, main_file_path);
compiler.parse_inputs(inputs_string, state_string)?;
let program_string = compiler.load_program()?;
compiler.parse_program(&program_string)?;
Ok(compiler)
}
pub fn set_inputs(&mut self, program_inputs: MainInputs) {
self.program_inputs.set_main_inputs(program_inputs);
}
fn load_program(&mut self) -> Result<String, CompilerError> {
// Load the program syntax tree from the file path
Ok(LeoParser::load_file(&self.main_file_path)?)
/// Parse the input and state files.
/// Stores a typed ast of all inputs to the program.
pub fn parse_inputs(&mut self, inputs_string: &str, state_string: &str) -> Result<(), CompilerError> {
let inputs_syntax_tree = LeoInputsParser::parse_file(&inputs_string)?;
let state_syntax_tree = LeoInputsParser::parse_file(&state_string)?;
self.program_inputs.parse_inputs(inputs_syntax_tree)?;
self.program_inputs.parse_state(state_syntax_tree)?;
Ok(())
}
/// Parse the program file and all associated import files.
pub fn parse_program(&mut self, program_string: &str) -> Result<(), CompilerError> {
// Parse the program syntax tree
let syntax_tree = LeoParser::parse_file(&self.main_file_path, program_string)?;
@ -90,12 +101,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
Ok(())
}
pub fn parse_inputs(&mut self, inputs_string: &str) -> Result<(), CompilerError> {
let syntax_tree = LeoInputsParser::parse_file(&inputs_string)?;
/// Loads the program file at `main_file_path`.
fn load_program(&mut self) -> Result<String, CompilerError> {
Ok(LeoParser::load_file(&self.main_file_path)?)
}
self.program_inputs.parse(syntax_tree)?;
Ok(())
/// Manually set the inputs to the `main` program function.
pub fn set_main_inputs(&mut self, program_inputs: MainInputs) {
self.program_inputs.set_main_inputs(program_inputs);
}
pub fn checksum(&self) -> Result<String, CompilerError> {
@ -111,6 +124,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
Ok(hex::encode(hash))
}
/// Synthesizes the circuit without program inputs to verify correctness.
pub fn compile_constraints<CS: ConstraintSystem<F>>(
self,
cs: &mut CS,
@ -125,6 +139,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
})
}
/// Synthesizes the circuit for test functions with program inputs.
pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem<F>) -> Result<(), CompilerError> {
generate_test_constraints::<F, G>(cs, self.program, self.program_inputs, &self.imported_programs)
}
@ -150,6 +165,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
}
impl<F: Field + PrimeField, G: GroupType<F>> ConstraintSynthesizer<F> for Compiler<F, G> {
/// Synthesizes the circuit with program inputs.
fn generate_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
let result = generate_constraints::<_, G, _>(cs, self.program, self.program_inputs, &self.imported_programs)
.map_err(|e| {

View File

@ -80,7 +80,7 @@ fn test_input_pass() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Address(TEST_ADDRESS_1.to_string()))]);
program.set_main_inputs(vec![Some(InputValue::Address(TEST_ADDRESS_1.to_string()))]);
let _output = get_output(program);
}
@ -90,7 +90,7 @@ fn test_input_fail_bool() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
program.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
let _err = get_error(program);
}
@ -101,11 +101,11 @@ fn test_ternary() {
let mut program_1 = parse_program(bytes).unwrap();
let mut program_2 = program_1.clone();
program_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
program_1.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
output_test_address(program_1, TEST_ADDRESS_1);
program_2.set_inputs(vec![Some(InputValue::Boolean(false))]);
program_2.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
output_test_address(program_2, TEST_ADDRESS_2);
}
@ -116,14 +116,14 @@ fn test_equal() {
let mut program_1 = parse_program(bytes).unwrap();
let mut program_2 = program_1.clone();
program_1.set_inputs(vec![
program_1.set_main_inputs(vec![
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
]);
output_true(program_1);
program_2.set_inputs(vec![
program_2.set_main_inputs(vec![
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
Some(InputValue::Address(TEST_ADDRESS_2.to_string())),
]);

View File

@ -107,7 +107,7 @@ fn test_input_array() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Array(vec![input_value_u32_one(); 3]))]);
program.set_main_inputs(vec![Some(InputValue::Array(vec![input_value_u32_one(); 3]))]);
output_ones(program)
}
@ -117,7 +117,7 @@ fn test_input_array_fail() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(input_value_u32_one())]);
program.set_main_inputs(vec![Some(input_value_u32_one())]);
fail_array(program);
}
@ -127,7 +127,7 @@ fn test_input_field_none() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![None]);
program.set_main_inputs(vec![None]);
fail_integer(program)
}

View File

@ -60,7 +60,7 @@ fn test_input_bool_field() {
let bytes = include_bytes!("input_bool.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Field("1field".to_string()))]);
program.set_main_inputs(vec![Some(InputValue::Field("1field".to_string()))]);
fail_boolean(program);
}
@ -70,7 +70,7 @@ fn test_input_bool_none() {
let bytes = include_bytes!("input_bool.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![None]);
program.set_main_inputs(vec![None]);
fail_boolean(program);
}

View File

@ -83,7 +83,7 @@ fn test_input_pass() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Field("1".into()))]);
program.set_main_inputs(vec![Some(InputValue::Field("1".into()))]);
let cs = TestConstraintSystem::<Fq>::new();
let expected = FqGadget::one(cs).unwrap();
@ -96,7 +96,7 @@ fn test_input_fail_bool() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
program.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
fail_field(program);
}
@ -105,7 +105,7 @@ fn test_input_fail_none() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![None]);
program.set_main_inputs(vec![None]);
fail_field(program);
}
@ -136,7 +136,7 @@ fn test_add() {
let bytes = include_bytes!("add.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
program.set_main_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]);
@ -172,7 +172,7 @@ fn test_sub() {
let bytes = include_bytes!("sub.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
program.set_main_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]);
@ -208,7 +208,7 @@ fn test_mul() {
let bytes = include_bytes!("mul.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
program.set_main_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]);
@ -244,7 +244,7 @@ fn test_div() {
let bytes = include_bytes!("div.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
program.set_main_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]);
@ -275,7 +275,7 @@ fn test_eq() {
let bytes = include_bytes!("eq.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
program.set_main_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
]);
@ -288,7 +288,7 @@ fn test_eq() {
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
program.set_main_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]);
@ -310,7 +310,7 @@ fn test_assert_eq_pass() {
let bytes = include_bytes!("assert_eq.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
program.set_main_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
]);
@ -341,7 +341,7 @@ fn test_assert_eq_fail() {
let bytes = include_bytes!("assert_eq.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![
program.set_main_inputs(vec![
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
]);
@ -372,7 +372,7 @@ fn test_ternary() {
let mut program_2 = program_1.clone();
// true -> field 1
program_1.set_inputs(vec![
program_1.set_main_inputs(vec![
Some(InputValue::Boolean(true)),
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),
@ -381,7 +381,7 @@ fn test_ternary() {
output_expected_allocated(program_1, g1);
// false -> field 2
program_2.set_inputs(vec![
program_2.set_main_inputs(vec![
Some(InputValue::Boolean(false)),
Some(InputValue::Field(r1.to_string())),
Some(InputValue::Field(r2.to_string())),

View File

@ -84,7 +84,7 @@ fn test_input() {
let bytes = include_bytes!("input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Group(TEST_POINT_1.into()))]);
program.set_main_inputs(vec![Some(InputValue::Group(TEST_POINT_1.into()))]);
let mut cs = TestConstraintSystem::<Fq>::new();
let constant_point = EdwardsAffine::from_str(TEST_POINT_1).unwrap();
@ -163,7 +163,7 @@ fn test_ternary() {
let mut program_2 = program_1.clone();
// true -> point_1
program_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
program_1.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
let mut cs = TestConstraintSystem::<Fq>::new();
let point_1 = EdwardsAffine::from_str(TEST_POINT_1).unwrap();
@ -172,7 +172,7 @@ fn test_ternary() {
output_expected_allocated(program_1, expected_point_1);
// false -> point_2
program_2.set_inputs(vec![Some(InputValue::Boolean(false))]);
program_2.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
let mut cs = TestConstraintSystem::<Fq>::new();
let point_2 = EdwardsAffine::from_str(TEST_POINT_2).unwrap();

View File

@ -61,7 +61,7 @@ fn test_print_input() {
let bytes = include_bytes!("print_input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
program.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
let _output = get_output(program);
}

View File

@ -49,8 +49,7 @@ pub(crate) fn fail_enforce(program: EdwardsTestCompiler) {
fn new_compiler() -> EdwardsTestCompiler {
let program_name = "test".to_string();
let path = PathBuf::from("/test/src/main.leo");
let mut compiler = EdwardsTestCompiler::new(program_name);
compiler.set_path(path);
let mut compiler = EdwardsTestCompiler::new(program_name, path);
compiler
}

View File

@ -100,7 +100,7 @@ fn test_function_input() {
let bytes = include_bytes!("function_input.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(input_value_u32_one())]);
program.set_main_inputs(vec![Some(input_value_u32_one())]);
mut_fail(program);
}
@ -109,6 +109,6 @@ fn test_function_input_mut() {
let bytes = include_bytes!("function_input_mut.leo");
let mut program = parse_program(bytes).unwrap();
program.set_inputs(vec![Some(input_value_u32_one())]);
program.set_main_inputs(vec![Some(input_value_u32_one())]);
mut_success(program);
}

View File

@ -35,7 +35,7 @@ fn test_assert() {
// Check that an input value of 1 satisfies the constraint system
program_1_pass.set_inputs(vec![Some(InputValue::Integer(
program_1_pass.set_main_inputs(vec![Some(InputValue::Integer(
IntegerType::U32Type(U32Type {}),
1.to_string(),
))]);
@ -43,7 +43,7 @@ fn test_assert() {
// Check that an input value of 0 satisfies the constraint system
program_0_pass.set_inputs(vec![Some(InputValue::Integer(
program_0_pass.set_main_inputs(vec![Some(InputValue::Integer(
IntegerType::U32Type(U32Type {}),
0.to_string(),
))]);
@ -51,7 +51,7 @@ fn test_assert() {
// Check that an input value of 2 does not satisfy the constraint system
program_2_fail.set_inputs(vec![Some(InputValue::Integer(
program_2_fail.set_main_inputs(vec![Some(InputValue::Integer(
IntegerType::U32Type(U32Type {}),
2.to_string(),
))]);
@ -68,7 +68,7 @@ fn test_mutate() {
// Check that an input value of 1 satisfies the constraint system
program_1_true.set_inputs(vec![Some(InputValue::Integer(
program_1_true.set_main_inputs(vec![Some(InputValue::Integer(
IntegerType::U32Type(U32Type {}),
1.to_string(),
))]);
@ -76,7 +76,7 @@ fn test_mutate() {
// Check that an input value of 0 satisfies the constraint system
program_0_pass.set_inputs(vec![Some(InputValue::Integer(
program_0_pass.set_main_inputs(vec![Some(InputValue::Integer(
IntegerType::U32Type(U32Type {}),
0.to_string(),
))]);
@ -91,12 +91,12 @@ fn test_for_loop() {
// Check that an input value of true satisfies the constraint system
program_true_6.set_inputs(vec![Some(InputValue::Boolean(true))]);
program_true_6.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
output_number(program_true_6, 6u32);
// Check that an input value of false satisfies the constraint system
program_false_0.set_inputs(vec![Some(InputValue::Boolean(false))]);
program_false_0.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
output_zero(program_false_0);
}
@ -108,21 +108,21 @@ fn test_chain() {
let mut program_2_3 = program_1_1.clone();
// Check that an input of 1 outputs true
program_1_1.set_inputs(vec![Some(InputValue::Integer(
program_1_1.set_main_inputs(vec![Some(InputValue::Integer(
IntegerType::U32Type(U32Type {}),
1.to_string(),
))]);
output_number(program_1_1, 1u32);
// Check that an input of 0 outputs true
program_2_2.set_inputs(vec![Some(InputValue::Integer(
program_2_2.set_main_inputs(vec![Some(InputValue::Integer(
IntegerType::U32Type(U32Type {}),
2.to_string(),
))]);
output_number(program_2_2, 2u32);
// Check that an input of 0 outputs true
program_2_3.set_inputs(vec![Some(InputValue::Integer(
program_2_3.set_main_inputs(vec![Some(InputValue::Integer(
IntegerType::U32Type(U32Type {}),
5.to_string(),
))]);
@ -138,17 +138,17 @@ fn test_nested() {
// Check that an input value of true true satisfies the constraint system
program_true_true_3.set_inputs(vec![Some(InputValue::Boolean(true)); 2]);
program_true_true_3.set_main_inputs(vec![Some(InputValue::Boolean(true)); 2]);
output_number(program_true_true_3, 3u32);
// Check that an input value of true false satisfies the constraint system
program_true_false_1.set_inputs(vec![Some(InputValue::Boolean(true)), Some(InputValue::Boolean(false))]);
program_true_false_1.set_main_inputs(vec![Some(InputValue::Boolean(true)), Some(InputValue::Boolean(false))]);
output_number(program_true_false_1, 1u32);
// Check that an input value of false false satisfies the constraint system
program_false_false_0.set_inputs(vec![Some(InputValue::Boolean(false)), Some(InputValue::Boolean(false))]);
program_false_false_0.set_main_inputs(vec![Some(InputValue::Boolean(false)), Some(InputValue::Boolean(false))]);
output_number(program_false_false_0, 0u32);
}
@ -160,11 +160,11 @@ fn test_multiple_returns() {
// Check that an input value of true returns 1 and satisfies the constraint system
program_true_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
program_true_1.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
output_number(program_true_1, 1u32);
// Check that an input value of false returns 0 and satisfies the constraint system
program_false_0.set_inputs(vec![Some(InputValue::Boolean(false))]);
program_false_0.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
output_number(program_false_0, 0u32);
}

View File

@ -19,10 +19,10 @@ fn test_ternary_basic() {
let mut program_input_false = program_input_true.clone();
program_input_true.set_inputs(vec![Some(InputValue::Boolean(true))]);
program_input_true.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
output_one(program_input_true);
program_input_false.set_inputs(vec![Some(InputValue::Boolean(false))]);
program_input_false.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
output_zero(program_input_false);
}
@ -46,7 +46,7 @@ fn test_assertion_basic() {
let mut program_input_true = program.clone();
let mut cs_satisfied = TestConstraintSystem::<Fq>::new();
program_input_true.set_inputs(vec![Some(InputValue::Boolean(true))]);
program_input_true.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
let _output = program_input_true.compile_constraints(&mut cs_satisfied).unwrap();
assert!(cs_satisfied.is_satisfied());
@ -54,7 +54,7 @@ fn test_assertion_basic() {
let mut program_input_false = program.clone();
let mut cs_unsatisfied = TestConstraintSystem::<Fq>::new();
program_input_false.set_inputs(vec![Some(InputValue::Boolean(false))]);
program_input_false.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
let _output = program_input_false.compile_constraints(&mut cs_unsatisfied).unwrap();
assert!(!cs_unsatisfied.is_satisfied());

View File

@ -2,11 +2,12 @@ use crate::{
ast::Rule,
errors::SyntaxError as InputSyntaxError,
expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression},
sections::Header,
tables::Table,
types::{DataType, Type},
values::{NumberImplicitValue, NumberValue, Value},
};
use crate::sections::Header;
use pest::{
error::{Error, ErrorVariant},
Span,
@ -84,21 +85,40 @@ impl InputParserError {
}
pub fn input_section_header(header: Header) -> Self {
let message = format!("the section header {} does not belong in an input `.in` file", header);
let message = format!("the section header `{}` is not valid in an input `.in` file", header);
let span = header.span();
Self::new_from_span(message, span)
}
pub fn public_section(header: Header) -> Self {
let message = format!("the section header {} is not a public section", header);
let message = format!("the section header `{}` is not a public section", header);
let span = header.span();
Self::new_from_span(message, span)
}
pub fn private_section(header: Header) -> Self {
let message = format!("the section header {} is not a private section", header);
let message = format!("the section header `{}` is not a private section", header);
let span = header.span();
Self::new_from_span(message, span)
}
pub fn table(table: Table) -> Self {
let message = format!(
"the double bracket section `{}` is not valid in an input `.in` file",
table
);
Self::new_from_span(message, table.span)
}
pub fn section(header: Header) -> Self {
let message = format!(
"the section header `{}` must have a double bracket visibility in a state `.state` file",
header
);
let span = header.span();
Self::new_from_span(message, span)

View File

@ -18,6 +18,7 @@ impl From<Error<Rule>> for SyntaxError {
Rule::file => "a table or section".to_owned(),
Rule::identifier => "a variable name".to_owned(),
Rule::type_ => "a type".to_owned(),
Rule::header => "[[public]] or [[private]]".to_owned(),
rule => format!("{:?}", rule),
});

View File

@ -30,8 +30,6 @@ protected_name = {
// Declared in common/line_end.rs
LINE_END = { ";" ~ NEWLINE* }
/// Types
// Declared in types/type_.rs

View File

@ -2,6 +2,7 @@ use crate::ast::Rule;
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::private))]
@ -9,3 +10,9 @@ pub struct Private<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Private<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.span.as_str().to_string())
}
}

View File

@ -2,6 +2,7 @@ use crate::ast::Rule;
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::public))]
@ -9,3 +10,9 @@ pub struct Public<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Public<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.span.as_str().to_string())
}
}

View File

@ -2,6 +2,7 @@ use crate::{ast::Rule, sections::Section, tables::Visibility};
use pest::Span;
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::table))]
@ -11,3 +12,9 @@ pub struct Table<'ast> {
#[pest_ast(outer())]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Table<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[[{}]]", self.visibility)
}
}

View File

@ -4,6 +4,7 @@ use crate::{
};
use pest_ast::FromPest;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::visibility))]
@ -11,3 +12,12 @@ pub enum Visibility<'ast> {
Private(Private<'ast>),
Public(Public<'ast>),
}
impl<'ast> fmt::Display for Visibility<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Visibility::Private(private) => write!(f, "{}", private),
Visibility::Public(public) => write!(f, "{}", public),
}
}
}

View File

@ -11,6 +11,7 @@ use snarkos_algorithms::snark::KeypairAssembly;
use snarkos_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
use snarkos_models::gadgets::r1cs::ConstraintSystem;
use crate::files::StateFile;
use clap::ArgMatches;
use std::{convert::TryFrom, env::current_dir};
@ -41,9 +42,6 @@ impl CLI for BuildCommand {
let manifest = Manifest::try_from(&path)?;
let package_name = manifest.get_package_name();
// Load the inputs file at `package_name`
let inputs_string = InputsFile::new(&package_name).read_from(&path)?;
// Sanitize the package path to the root directory
let mut package_path = path.clone();
if package_path.is_file() {
@ -58,10 +56,9 @@ impl CLI for BuildCommand {
lib_file_path.push(LIB_FILE_NAME);
// Compile the library file but do not output
let _program = Compiler::<Fq, EdwardsGroupType>::new_from_path(
let _program = Compiler::<Fq, EdwardsGroupType>::parse_program_without_inputs(
package_name.clone(),
lib_file_path.clone(),
&inputs_string,
)?;
log::info!("Compiled library file {:?}", lib_file_path);
@ -77,11 +74,18 @@ impl CLI for BuildCommand {
main_file_path.push(SOURCE_DIRECTORY_NAME);
main_file_path.push(MAIN_FILE_NAME);
// Load the inputs file at `package_name.in`
let inputs_string = InputsFile::new(&package_name).read_from(&path)?;
// Load the state file at `package_name.in`
let state_string = StateFile::new(&package_name).read_from(&path)?;
// Load the program at `main_file_path`
let program = Compiler::<Fq, EdwardsGroupType>::new_from_path(
let program = Compiler::<Fq, EdwardsGroupType>::parse_program_with_inputs(
package_name.clone(),
main_file_path.clone(),
&inputs_string,
&state_string,
)?;
// Compute the current program checksum

View File

@ -3,14 +3,13 @@ use crate::{
cli_types::*,
directories::source::SOURCE_DIRECTORY_NAME,
errors::{CLIError, TestError},
files::{MainFile, Manifest, MAIN_FILE_NAME},
files::{InputsFile, MainFile, Manifest, StateFile, MAIN_FILE_NAME},
};
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
use crate::files::InputsFile;
use clap::ArgMatches;
use std::{convert::TryFrom, env::current_dir};
@ -41,9 +40,6 @@ impl CLI for TestCommand {
let manifest = Manifest::try_from(&path)?;
let package_name = manifest.get_package_name();
// Load the inputs file at `package_name`
let inputs_string = InputsFile::new(&package_name).read_from(&path)?;
// Sanitize the package path to the root directory
let mut package_path = path.clone();
if package_path.is_file() {
@ -60,11 +56,18 @@ impl CLI for TestCommand {
main_file_path.push(SOURCE_DIRECTORY_NAME);
main_file_path.push(MAIN_FILE_NAME);
// Load the inputs file at `package_name`
let inputs_string = InputsFile::new(&package_name).read_from(&path)?;
// Load the state file at `package_name.in`
let state_string = StateFile::new(&package_name).read_from(&path)?;
// Compute the current program checksum
let program = Compiler::<Fq, EdwardsGroupType>::new_from_path(
let program = Compiler::<Fq, EdwardsGroupType>::parse_program_with_inputs(
package_name.clone(),
main_file_path.clone(),
&inputs_string,
&state_string,
)?;
// Generate the program on the constraint system and verify correctness

View File

@ -53,6 +53,9 @@ pub enum CLIError {
#[error("{}", _0)]
SourceDirectoryError(SourceDirectoryError),
#[error("{}", _0)]
StateFileError(StateFileError),
#[error("{}", _0)]
TestError(TestError),
@ -172,6 +175,13 @@ impl From<SourceDirectoryError> for CLIError {
}
}
impl From<StateFileError> for CLIError {
fn from(error: StateFileError) -> Self {
log::error!("{}\n", error);
CLIError::StateFileError(error)
}
}
impl From<TestError> for CLIError {
fn from(error: TestError) -> Self {
log::error!("{}\n", error);

View File

@ -25,5 +25,8 @@ pub use self::proof::*;
pub mod proving_key;
pub use self::proving_key::*;
pub mod state;
pub use self::state::*;
pub mod verification_key;
pub use self::verification_key::*;

22
leo/errors/files/state.rs Normal file
View File

@ -0,0 +1,22 @@
use std::{io, path::PathBuf};
#[derive(Debug, Error)]
pub enum StateFileError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("creating: {}", _0)]
Creating(io::Error),
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[error("writing: {}", _0)]
Writing(io::Error),
}
impl From<std::io::Error> for StateFileError {
fn from(error: std::io::Error) -> Self {
StateFileError::Crate("std::io", format!("{}", error))
}
}

View File

@ -1,4 +1,4 @@
//! The `inputs.leo` file.
//! The `program.in` file.
use crate::{directories::inputs::INPUTS_DIRECTORY_NAME, errors::InputsFileError};
@ -28,7 +28,7 @@ impl InputsFile {
path.exists()
}
/// Reads the proof from the given file path if it exists.
/// Reads the inputs from the given file path if it exists.
pub fn read_from(&self, path: &PathBuf) -> Result<String, InputsFileError> {
let path = self.setup_file_path(path);

View File

@ -25,5 +25,8 @@ pub use self::proof::*;
pub mod proving_key;
pub use self::proving_key::*;
pub mod state;
pub use self::state::*;
pub mod verification_key;
pub use self::verification_key::*;

89
leo/files/state.rs Normal file
View File

@ -0,0 +1,89 @@
//! The `program.state` file.
use crate::{directories::inputs::INPUTS_DIRECTORY_NAME, errors::StateFileError};
use serde::Deserialize;
use std::{
fs::{self, File},
io::Write,
path::PathBuf,
};
pub static STATE_FILE_EXTENSION: &str = ".state";
#[derive(Deserialize)]
pub struct StateFile {
pub package_name: String,
}
impl StateFile {
pub fn new(package_name: &str) -> Self {
Self {
package_name: package_name.to_string(),
}
}
pub fn exists_at(&self, path: &PathBuf) -> bool {
let path = self.setup_file_path(path);
path.exists()
}
/// Reads the state inputs from the given file path if it exists.
pub fn read_from(&self, path: &PathBuf) -> Result<String, StateFileError> {
let path = self.setup_file_path(path);
let inputs = fs::read_to_string(&path).map_err(|_| StateFileError::FileReadError(path.clone()))?;
Ok(inputs)
}
/// Writes the standard input format to a file.
pub fn write_to(self, path: &PathBuf) -> Result<(), StateFileError> {
let path = self.setup_file_path(path);
let mut file = File::create(&path)?;
Ok(file.write_all(self.template().as_bytes())?)
}
fn template(&self) -> String {
format!(
r#"// The program state for {}/src/main.leo
[[public]]
[state]
leaf_index: u32 = 0;
root: u8[32] = [0u8; 32];
[[private]]
[record]
serial_number: u8[32] = [0u8; 32];
commitment: u8[32] = [0u8; 32];
owner: address = aleo1...;
value: u64 = 5;
payload: u8[32] = [0u8; 32]; // TBD
birth_program_id: u8[32] = [0u8; 32];
death_program_id: u8[32] = [0u8; 32];
serial_number_nonce: u8[32] = [0u8; 32];
commitment_randomness: u8[32] = [0u8; 32];
[state_leaf]
path: u8[32][2] = [ [0u8; 32], [0u8; 32] ];
memo: u8[32] = [0u8; 32];
network_id: u8 = 0;
leaf_randomness: u8[32] = [0u8; 32];
"#,
self.package_name
)
}
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
let mut path = path.to_owned();
if path.is_dir() {
if !path.ends_with(INPUTS_DIRECTORY_NAME) {
path.push(PathBuf::from(INPUTS_DIRECTORY_NAME));
}
path.push(PathBuf::from(format!("{}{}", self.package_name, STATE_FILE_EXTENSION)));
}
path
}
}

View File

@ -39,13 +39,24 @@ impl Inputs {
}
/// Parse all inputs included in a file and store them in `self`.
/// Currently parser does not care if file is `.in` or `.state`
pub fn parse(&mut self, file: File) -> Result<(), InputParserError> {
pub fn parse_inputs(&mut self, file: File) -> Result<(), InputParserError> {
for entry in file.entries.into_iter() {
match entry {
TableOrSection::Section(section) => {
self.inputs.parse(section)?;
}
TableOrSection::Table(table) => return Err(InputParserError::table(table)),
}
}
Ok(())
}
/// Parse all inputs included in a file and store them in `self`.
pub fn parse_state(&mut self, file: File) -> Result<(), InputParserError> {
for entry in file.entries.into_iter() {
match entry {
TableOrSection::Section(section) => return Err(InputParserError::section(section.header)),
TableOrSection::Table(table) => {
self.state.parse(table)?;
}