add function input keyword. support access to registers, record, state, state_leaf

This commit is contained in:
collin 2020-07-31 18:30:08 -07:00
parent 17e2adcdb4
commit ce2a92b9bf
22 changed files with 190 additions and 262 deletions

View File

@ -1,6 +1,6 @@
use crate::{
ast::Rule,
functions::{FunctionInput, Record, Registers, State, StateLeaf},
functions::{FunctionInput, InputKeyword},
};
use pest_ast::FromPest;
@ -9,9 +9,6 @@ use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::input))]
pub enum Input<'ast> {
InputKeyword(InputKeyword<'ast>),
FunctionInput(FunctionInput<'ast>),
Record(Record<'ast>),
Registers(Registers<'ast>),
State(State<'ast>),
StateLeaf(StateLeaf<'ast>),
}

View File

@ -0,0 +1,18 @@
use crate::{
ast::{span_into_string, Rule},
SpanDef,
};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::input_keyword))]
pub struct InputKeyword<'ast> {
#[pest_ast(outer(with(span_into_string)))]
pub keyword: String,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -4,14 +4,5 @@ pub use function_input::*;
pub mod input;
pub use input::*;
pub mod record;
pub use record::*;
pub mod registers;
pub use registers::*;
pub mod state;
pub use state::*;
pub mod state_leaf;
pub use state_leaf::*;
pub mod input_keyword;
pub use input_keyword::*;

View File

@ -1,13 +0,0 @@
use crate::{ast::Rule, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::record))]
pub struct Record<'ast> {
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -1,13 +0,0 @@
use crate::{ast::Rule, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::registers))]
pub struct Registers<'ast> {
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -1,13 +0,0 @@
use crate::{ast::Rule, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::state))]
pub struct State<'ast> {
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -1,13 +0,0 @@
use crate::{ast::Rule, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::state_leaf))]
pub struct StateLeaf<'ast> {
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}

View File

@ -340,24 +340,12 @@ function_definition = { "function " ~ identifier ~ "(" ~ NEWLINE* ~ input_list ~
// Declared in functions/inputs/function_input.rs
function_input = { mutable? ~ identifier ~ ":" ~ type_ }
// Declared in functions/inputs/record.rs
record = { "record" }
// Declared in functions/inputs/registers.rs
registers = { "registers" }
// Declared in functions/inputs/state.rs
state = { "state" }
// Declared in functions/inputs/state_leaf.rs
state_leaf = { "state_leaf" }
// Declared in functions/inputs/input_keyword.rs
input_keyword = { "input" }
// Declared in functions/inputs/input.rs
input = {
record
| registers
| state_leaf
| state
input_keyword
| function_input
}
input_list = _{ (input ~ ("," ~ NEWLINE* ~ input)*)? }

View File

@ -7,7 +7,7 @@ use crate::{
GroupType,
};
use leo_types::{Expression, Function, Input, Span};
use leo_types::{Expression, Function, InputVariable, Span};
use snarkos_models::{
curves::{Field, PrimeField},
@ -40,9 +40,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Store input values as new variables in resolved program
for (input_model, input_expression) in function.inputs.clone().iter().zip(inputs.into_iter()) {
let (name, value) = match input_model {
Input::FunctionInput(input_model) => {
InputVariable::InputKeyword(identifier) => {
let input_value = self.enforce_function_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
input_expression,
)?;
(identifier.name.clone(), input_value)
}
InputVariable::FunctionInput(input_model) => {
// First evaluate input expression
let mut input_value = self.enforce_input(
let mut input_value = self.enforce_function_input(
cs,
scope.clone(),
caller_scope.clone(),
@ -57,54 +69,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
(input_model.identifier.name.clone(), input_value)
}
Input::Registers(identifier) => {
let input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
input_expression,
)?;
(identifier.name.clone(), input_value)
}
Input::Record(identifier) => {
let input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
input_expression,
)?;
(identifier.name.clone(), input_value)
}
Input::State(identifier) => {
let input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
input_expression,
)?;
(identifier.name.clone(), input_value)
}
Input::StateLeaf(identifier) => {
let input_value = self.enforce_input(
cs,
scope.clone(),
caller_scope.clone(),
function_name.clone(),
vec![],
input_expression,
)?;
(identifier.name.clone(), input_value)
}
};
// Store input as variable with {function_name}_{input_name}

View File

@ -10,7 +10,7 @@ use snarkos_models::{
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn enforce_input<CS: ConstraintSystem<F>>(
pub fn enforce_function_input<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
scope: String,

View File

@ -0,0 +1,71 @@
use crate::{errors::FunctionError, ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue, GroupType};
use leo_types::{Identifier, Inputs};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
pub const RECORD_VARIABLE_NAME: &str = "record";
pub const REGISTERS_VARIABLE_NAME: &str = "registers";
pub const STATE_VARIABLE_NAME: &str = "state";
pub const STATE_LEAF_VARIABLE_NAME: &str = "state_leaf";
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn allocate_input_keyword<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
identifier: Identifier,
input: &Inputs,
) -> Result<ConstrainedValue<F, G>, FunctionError> {
// Create an identifier for each input variable
let registers_name = Identifier {
name: REGISTERS_VARIABLE_NAME.to_string(),
span: identifier.span.clone(),
};
let record_name = Identifier {
name: RECORD_VARIABLE_NAME.to_string(),
span: identifier.span.clone(),
};
let state_name = Identifier {
name: STATE_VARIABLE_NAME.to_string(),
span: identifier.span.clone(),
};
let state_leaf_name = Identifier {
name: STATE_LEAF_VARIABLE_NAME.to_string(),
span: identifier.span.clone(),
};
// Fetch each input variable's definitions
let registers_values = input.get_registers().values();
let record_values = input.get_record().values();
let state_values = input.get_state().values();
let state_leaf_values = input.get_state_leaf().values();
// Allocate each input variable as a circuit expression
let mut sections = vec![];
sections.push((registers_name, registers_values));
sections.push((record_name, record_values));
sections.push((state_name, state_values));
sections.push((state_leaf_name, state_leaf_values));
let mut members = vec![];
for (name, values) in sections {
let member_name = name.clone();
let member_value = self.allocate_input_section(cs, name, values)?;
let member = ConstrainedCircuitMember(member_name, member_value);
members.push(member)
}
// Return input variable keyword as circuit expression
Ok(ConstrainedValue::CircuitExpression(identifier, members))
}
}

View File

@ -16,7 +16,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
) -> Result<ConstrainedValue<F, G>, FunctionError> {
let mut members = vec![];
// Store each section definition as a circuit member value
// Allocate each section definition as a circuit member value
for (parameter, option) in section.into_iter() {
let member_name = parameter.variable.clone();
let member_value = self.allocate_main_function_input(
@ -32,6 +33,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
}
// Return section as circuit expression
Ok(ConstrainedValue::CircuitExpression(identifier, members))
}
}

View File

@ -3,11 +3,14 @@
pub mod array;
pub use self::array::*;
pub mod input;
pub use self::input::*;
pub mod function_input;
pub use self::function_input::*;
pub mod main_input;
pub use self::main_input::*;
pub mod main_function_input;
pub use self::main_function_input::*;
pub mod section;
pub use self::section::*;
pub mod input_keyword;
pub use self::input_keyword::*;
pub mod input_section;
pub use self::input_section::*;

View File

@ -7,7 +7,7 @@ use crate::{
OutputBytes,
};
use leo_types::{Expression, Function, Input, Inputs};
use leo_types::{Expression, Function, InputVariable, Inputs};
use snarkos_models::{
curves::{Field, PrimeField},
@ -29,7 +29,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
let mut input_variables = vec![];
for input_model in function.inputs.clone().into_iter() {
let (identifier, value) = match input_model {
Input::FunctionInput(input_model) => {
InputVariable::InputKeyword(identifier) => {
let value = self.allocate_input_keyword(cs, identifier.clone(), &inputs)?;
(identifier, value)
}
InputVariable::FunctionInput(input_model) => {
let name = input_model.identifier.name.clone();
let input_option = inputs
.get(&name)
@ -44,30 +49,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
(input_model.identifier, input_value)
}
Input::Registers(identifier) => {
let section = inputs.get_registers().values();
let value = self.allocate_input_section(cs, identifier.clone(), section)?;
(identifier, value)
}
Input::Record(identifier) => {
let section = inputs.get_record().values();
let value = self.allocate_input_section(cs, identifier.clone(), section)?;
(identifier, value)
}
Input::State(identifier) => {
let section = inputs.get_state().values();
let value = self.allocate_input_section(cs, identifier.clone(), section)?;
(identifier, value)
}
Input::StateLeaf(identifier) => {
let section = inputs.get_state_leaf().values();
let value = self.allocate_input_section(cs, identifier.clone(), section)?;
(identifier, value)
}
};
// Store input as variable with {function_name}_{identifier_name}

View File

@ -1,5 +1,5 @@
use crate::{errors::OutputBytesError, ConstrainedValue, GroupType};
use leo_types::{Parameter, Registers, Span, REGISTERS_VARIABLE_NAME};
use crate::{errors::OutputBytesError, ConstrainedValue, GroupType, REGISTERS_VARIABLE_NAME};
use leo_types::{Parameter, Registers, Span};
use snarkos_models::curves::{Field, PrimeField};

View File

@ -39,9 +39,7 @@ impl OutputsFile {
pub fn write(&self, path: &PathBuf, bytes: &[u8]) -> Result<(), OutputsFileError> {
// create output file
let path = self.setup_file_path(path);
println!("setup {:?}", path);
let mut file = File::create(&path)?;
println!("created");
log::info!("Writing to output registers...");
Ok(file.write_all(bytes)?)

View File

@ -1,4 +1,4 @@
use crate::{Identifier, Input, Span, Statement, Type};
use crate::{Identifier, InputVariable, Span, Statement, Type};
use leo_ast::functions::Function as AstFunction;
use serde::{Deserialize, Serialize};
@ -7,7 +7,7 @@ use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Function {
pub function_name: Identifier,
pub inputs: Vec<Input>,
pub inputs: Vec<InputVariable>,
pub returns: Vec<Type>,
pub statements: Vec<Statement>,
pub span: Span,
@ -19,7 +19,7 @@ impl<'ast> From<AstFunction<'ast>> for Function {
let parameters = function_definition
.parameters
.into_iter()
.map(|parameter| Input::from(parameter))
.map(|parameter| InputVariable::from(parameter))
.collect();
let returns = function_definition
.returns

View File

@ -1,83 +0,0 @@
use crate::{FunctionInput, Identifier, Span};
use leo_ast::functions::inputs::Input as AstInput;
use serde::{Deserialize, Serialize};
use std::fmt;
pub const RECORD_VARIABLE_NAME: &str = "record";
pub const REGISTERS_VARIABLE_NAME: &str = "registers";
pub const STATE_VARIABLE_NAME: &str = "state";
pub const STATE_LEAF_VARIABLE_NAME: &str = "state_leaf";
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Input {
FunctionInput(FunctionInput),
Record(Identifier),
Registers(Identifier),
State(Identifier),
StateLeaf(Identifier),
}
impl<'ast> From<AstInput<'ast>> for Input {
fn from(input: AstInput<'ast>) -> Self {
match input {
AstInput::FunctionInput(function_input) => Input::FunctionInput(FunctionInput::from(function_input)),
AstInput::Record(record) => {
let id = Identifier {
name: RECORD_VARIABLE_NAME.to_string(),
span: Span::from(record.span),
};
Input::Record(id)
}
AstInput::Registers(registers) => {
let id = Identifier {
name: REGISTERS_VARIABLE_NAME.to_string(),
span: Span::from(registers.span),
};
Input::Registers(id)
}
AstInput::State(state) => {
let id = Identifier {
name: STATE_VARIABLE_NAME.to_string(),
span: Span::from(state.span),
};
Input::State(id)
}
AstInput::StateLeaf(state_leaf) => {
let id = Identifier {
name: STATE_LEAF_VARIABLE_NAME.to_string(),
span: Span::from(state_leaf.span),
};
Input::StateLeaf(id)
}
}
}
}
impl Input {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Input::FunctionInput(function_input) => write!(f, "{}", function_input),
Input::Record(id) => write!(f, "{}", id),
Input::Registers(id) => write!(f, "{}", id),
Input::State(id) => write!(f, "{}", id),
Input::StateLeaf(id) => write!(f, "{}", id),
}
}
}
impl fmt::Display for Input {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Debug for Input {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}

View File

@ -0,0 +1,50 @@
use crate::{FunctionInput, Identifier, Span};
use leo_ast::functions::inputs::Input as AstInput;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum InputVariable {
InputKeyword(Identifier),
FunctionInput(FunctionInput),
}
impl<'ast> From<AstInput<'ast>> for InputVariable {
fn from(input: AstInput<'ast>) -> Self {
match input {
AstInput::InputKeyword(input_keyword) => {
let id = Identifier {
name: input_keyword.keyword,
span: Span::from(input_keyword.span),
};
InputVariable::InputKeyword(id)
}
AstInput::FunctionInput(function_input) => {
InputVariable::FunctionInput(FunctionInput::from(function_input))
}
}
}
}
impl InputVariable {
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
InputVariable::InputKeyword(id) => write!(f, "{}", id),
InputVariable::FunctionInput(function_input) => write!(f, "{}", function_input),
}
}
}
impl fmt::Display for InputVariable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}
impl fmt::Debug for InputVariable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f)
}
}

View File

@ -1,5 +1,5 @@
pub mod function_input;
pub use function_input::*;
pub mod input;
pub use input::*;
pub mod input_variable;
pub use input_variable::*;

View File

@ -1,7 +1,7 @@
//! A typed Leo program consists of import, circuit, and function definitions.
//! Each defined type consists of typed statements and expressions.
use crate::{Circuit, Function, Identifier, Import, Input, TestFunction};
use crate::{Circuit, Function, Identifier, Import, InputVariable, TestFunction};
use leo_ast::files::File;
use serde::{Deserialize, Serialize};
@ -11,7 +11,7 @@ use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Program {
pub name: String,
pub expected_inputs: Vec<Input>,
pub expected_inputs: Vec<InputVariable>,
pub imports: Vec<Import>,
pub circuits: HashMap<Identifier, Circuit>,
pub functions: HashMap<Identifier, Function>,