Merge branch 'master' into fix/tuple-cond-select

This commit is contained in:
Collin Chin 2020-11-23 16:57:22 -05:00 committed by GitHub
commit 26151f33ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 191 additions and 139 deletions

View File

@ -14,14 +14,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_ast::LeoAst; use leo_ast::Ast;
use leo_grammar::Grammar; use leo_grammar::Grammar;
use criterion::{criterion_group, criterion_main, Criterion}; use criterion::{criterion_group, criterion_main, Criterion};
use std::{path::Path, time::Duration}; use std::{path::Path, time::Duration};
fn leo_ast<'ast>(ast: &Grammar<'ast>) -> LeoAst { fn ast<'ast>(ast: &Grammar<'ast>) -> Ast {
LeoAst::new("leo_tree", &ast) Ast::new("leo_tree", &ast)
} }
fn bench_big_if_else(c: &mut Criterion) { fn bench_big_if_else(c: &mut Criterion) {
@ -29,7 +29,7 @@ fn bench_big_if_else(c: &mut Criterion) {
let program_string = include_str!("./big_if_else.leo"); let program_string = include_str!("./big_if_else.leo");
let ast = Grammar::new(&filepath, program_string).unwrap(); let ast = Grammar::new(&filepath, program_string).unwrap();
c.bench_function("LeoAst::big_if_else", |b| b.iter(|| leo_ast(&ast))); c.bench_function("Ast::big_if_else", |b| b.iter(|| ast(&ast)));
} }
fn bench_big_ternary(c: &mut Criterion) { fn bench_big_ternary(c: &mut Criterion) {
@ -37,7 +37,7 @@ fn bench_big_ternary(c: &mut Criterion) {
let program_string = include_str!("./big_ternary.leo"); let program_string = include_str!("./big_ternary.leo");
let ast = Grammar::new(&filepath, program_string).unwrap(); let ast = Grammar::new(&filepath, program_string).unwrap();
c.bench_function("LeoAst::big_ternary", |b| b.iter(|| leo_ast(&ast))); c.bench_function("Ast::big_ternary", |b| b.iter(|| ast(&ast)));
} }
fn bench_big_circuit(c: &mut Criterion) { fn bench_big_circuit(c: &mut Criterion) {
@ -45,7 +45,7 @@ fn bench_big_circuit(c: &mut Criterion) {
let program_string = include_str!("./big_circuit.leo"); let program_string = include_str!("./big_circuit.leo");
let ast = Grammar::new(&filepath, program_string).unwrap(); let ast = Grammar::new(&filepath, program_string).unwrap();
c.bench_function("LeoAst::big_circuit", |b| b.iter(|| leo_ast(&ast))); c.bench_function("Ast::big_circuit", |b| b.iter(|| ast(&ast)));
} }
fn bench_long_expr(c: &mut Criterion) { fn bench_long_expr(c: &mut Criterion) {
@ -53,7 +53,7 @@ fn bench_long_expr(c: &mut Criterion) {
let program_string = include_str!("./long_expr.leo"); let program_string = include_str!("./long_expr.leo");
let ast = Grammar::new(&filepath, program_string).unwrap(); let ast = Grammar::new(&filepath, program_string).unwrap();
c.bench_function("LeoAst::long_expr", |b| b.iter(|| leo_ast(&ast))); c.bench_function("Ast::long_expr", |b| b.iter(|| ast(&ast)));
} }
fn bench_long_array(c: &mut Criterion) { fn bench_long_array(c: &mut Criterion) {
@ -61,7 +61,7 @@ fn bench_long_array(c: &mut Criterion) {
let program_string = include_str!("./long_array.leo"); let program_string = include_str!("./long_array.leo");
let ast = Grammar::new(&filepath, program_string).unwrap(); let ast = Grammar::new(&filepath, program_string).unwrap();
c.bench_function("LeoAst::long_array", |b| b.iter(|| leo_ast(&ast))); c.bench_function("Ast::long_array", |b| b.iter(|| ast(&ast)));
} }
fn bench_many_foos(c: &mut Criterion) { fn bench_many_foos(c: &mut Criterion) {
@ -69,7 +69,7 @@ fn bench_many_foos(c: &mut Criterion) {
let program_string = include_str!("./many_foos.leo"); let program_string = include_str!("./many_foos.leo");
let ast = Grammar::new(&filepath, program_string).unwrap(); let ast = Grammar::new(&filepath, program_string).unwrap();
c.bench_function("LeoAst::many_foos", |b| b.iter(|| leo_ast(&ast))); c.bench_function("Ast::many_foos", |b| b.iter(|| ast(&ast)));
} }
fn bench_many_assigns(c: &mut Criterion) { fn bench_many_assigns(c: &mut Criterion) {
@ -77,7 +77,7 @@ fn bench_many_assigns(c: &mut Criterion) {
let program_string = include_str!("./many_assigns.leo"); let program_string = include_str!("./many_assigns.leo");
let ast = Grammar::new(&filepath, program_string).unwrap(); let ast = Grammar::new(&filepath, program_string).unwrap();
c.bench_function("LeoAst::many_assigns", |b| b.iter(|| leo_ast(&ast))); c.bench_function("Ast::many_assigns", |b| b.iter(|| ast(&ast)));
} }
criterion_group!( criterion_group!(

View File

@ -16,9 +16,9 @@
//! The abstract syntax tree (ast) for a Leo program. //! The abstract syntax tree (ast) for a Leo program.
//! //!
//! This module contains the [`LeoAst`] type, a wrapper around the [`Program`] type. //! This module contains the [`Ast`] type, a wrapper around the [`Program`] type.
//! The [`LeoAst`] type is intended to be parsed and modified by different passes //! The [`Ast`] type is intended to be parsed and modified by different passes
//! of the Leo compiler. The Leo compiler can generate a set of R1CS constraints from any [`LeoAst`]. //! of the Leo compiler. The Leo compiler can generate a set of R1CS constraints from any [`Ast`].
pub mod annotation; pub mod annotation;
pub use self::annotation::*; pub use self::annotation::*;
@ -63,34 +63,34 @@ use leo_grammar::Grammar;
/// The abstract syntax tree (ast) for a Leo program. /// The abstract syntax tree (ast) for a Leo program.
/// ///
/// The [`LeoAst`] type represents a Leo program as a series of recursive data types. /// The [`Ast`] type represents a Leo program as a series of recursive data types.
/// These data types form a tree that begins from a [`Program`] type root. /// These data types form a tree that begins from a [`Program`] type root.
/// ///
/// A new [`LeoAst`] can be created from a [`Grammar`] generated by the pest parser in the `grammar` module. /// A new [`Ast`] can be created from a [`Grammar`] generated by the pest parser in the `grammar` module.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct LeoAst { pub struct Ast {
ast: Program, ast: Program,
} }
impl LeoAst { impl Ast {
/// Creates a new syntax tree from a given program name and abstract syntax tree. /// Creates a new ast from a given program name and grammar tree.
pub fn new<'ast>(program_name: &str, ast: &Grammar<'ast>) -> Self { pub fn new<'ast>(program_name: &str, ast: &Grammar<'ast>) -> Self {
Self { Self {
ast: Program::from(program_name, ast.as_repr()), ast: Program::from(program_name, ast.as_repr()),
} }
} }
/// Returns a reference to the inner program syntax tree representation. /// Returns a reference to the inner program ast representation.
pub fn into_repr(self) -> Program { pub fn into_repr(self) -> Program {
self.ast self.ast
} }
/// Serializes the syntax tree into a JSON string. /// Serializes the ast into a JSON string.
pub fn to_json_string(&self) -> Result<String, serde_json::Error> { pub fn to_json_string(&self) -> Result<String, serde_json::Error> {
Ok(serde_json::to_string_pretty(&self.ast)?) Ok(serde_json::to_string_pretty(&self.ast)?)
} }
/// Deserializes the JSON string into a syntax tree. /// Deserializes the JSON string into a ast.
pub fn from_json_string(json: &str) -> Result<Self, serde_json::Error> { pub fn from_json_string(json: &str) -> Result<Self, serde_json::Error> {
let ast: Program = serde_json::from_str(json)?; let ast: Program = serde_json::from_str(json)?;
Ok(Self { ast }) Ok(Self { ast })

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_ast::LeoAst; use leo_ast::Ast;
use leo_grammar::{Grammar, ParserError}; use leo_grammar::{Grammar, ParserError};
use std::{env, fs, path::Path}; use std::{env, fs, path::Path};
@ -27,10 +27,10 @@ fn to_leo_tree(filepath: &Path) -> Result<String, ParserError> {
let ast = Grammar::new(&program_filepath, &program_string)?; let ast = Grammar::new(&program_filepath, &program_string)?;
// Parse the pest ast and constructs a ast. // Parse the pest ast and constructs a ast.
let leo_ast = LeoAst::new("leo_tree", &ast); let leo_ast = Ast::new("leo_tree", &ast);
// Serializes the tree into JSON format. // Serializes the tree into JSON format.
let serialized_leo_ast = LeoAst::to_json_string(&leo_ast)?; let serialized_leo_ast = Ast::to_json_string(&leo_ast)?;
Ok(serialized_leo_ast) Ok(serialized_leo_ast)
} }

View File

@ -14,14 +14,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_ast::LeoAst; use leo_ast::Ast;
#[cfg(not(feature = "ci_skip"))] #[cfg(not(feature = "ci_skip"))]
use leo_ast::Program; use leo_ast::Program;
use leo_grammar::Grammar; use leo_grammar::Grammar;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
fn to_ast(program_filepath: &Path) -> LeoAst { fn to_ast(program_filepath: &Path) -> Ast {
// Loads the Leo code as a string from the given file path. // Loads the Leo code as a string from the given file path.
let program_string = Grammar::load_file(program_filepath).unwrap(); let program_string = Grammar::load_file(program_filepath).unwrap();
@ -29,14 +29,14 @@ fn to_ast(program_filepath: &Path) -> LeoAst {
let ast = Grammar::new(&program_filepath, &program_string).unwrap(); let ast = Grammar::new(&program_filepath, &program_string).unwrap();
// Parses the pest ast and constructs a Leo ast. // Parses the pest ast and constructs a Leo ast.
LeoAst::new("leo_tree", &ast) Ast::new("leo_tree", &ast)
} }
#[test] #[test]
#[cfg(not(feature = "ci_skip"))] #[cfg(not(feature = "ci_skip"))]
fn test_serialize() { fn test_serialize() {
// Construct a ast from the given test file. // Construct an ast from the given test file.
let leo_ast = { let ast = {
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
program_filepath.push("tests/serialization/main.leo"); program_filepath.push("tests/serialization/main.leo");
@ -44,20 +44,19 @@ fn test_serialize() {
}; };
// Serializes the ast into JSON format. // Serializes the ast into JSON format.
let serialized_leo_ast: Program = let serialized_ast: Program = serde_json::from_value(serde_json::to_value(ast.into_repr()).unwrap()).unwrap();
serde_json::from_value(serde_json::to_value(leo_ast.into_repr()).unwrap()).unwrap();
// Load the expected ast. // Load the expected ast.
let expected: Program = serde_json::from_str(include_str!("expected_leo_ast.json")).unwrap(); let expected: Program = serde_json::from_str(include_str!("expected_leo_ast.json")).unwrap();
assert_eq!(expected, serialized_leo_ast); assert_eq!(expected, serialized_ast);
} }
#[test] #[test]
#[cfg(not(feature = "ci_skip"))] #[cfg(not(feature = "ci_skip"))]
fn test_deserialize() { fn test_deserialize() {
// Load the expected ast. // Load the expected ast.
let expected_leo_ast = { let expected_ast = {
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
program_filepath.push("tests/serialization/main.leo"); program_filepath.push("tests/serialization/main.leo");
@ -66,15 +65,15 @@ fn test_deserialize() {
// Construct an ast by deserializing a ast JSON file. // Construct an ast by deserializing a ast JSON file.
let serialized_ast = include_str!("expected_leo_ast.json"); let serialized_ast = include_str!("expected_leo_ast.json");
let leo_ast = LeoAst::from_json_string(serialized_ast).unwrap(); let ast = Ast::from_json_string(serialized_ast).unwrap();
assert_eq!(expected_leo_ast, leo_ast); assert_eq!(expected_ast, ast);
} }
#[test] #[test]
fn test_serialize_deserialize_serialize() { fn test_serialize_deserialize_serialize() {
// Construct a ast from the given test file. // Construct an ast from the given test file.
let leo_ast = { let ast = {
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
program_filepath.push("tests/serialization/main.leo"); program_filepath.push("tests/serialization/main.leo");
@ -82,13 +81,13 @@ fn test_serialize_deserialize_serialize() {
}; };
// Serializes the ast into JSON format. // Serializes the ast into JSON format.
let serialized_leo_ast = leo_ast.to_json_string().unwrap(); let serialized_ast = ast.to_json_string().unwrap();
// Deserializes the serialized ast into a LeoAst. // Deserializes the serialized ast into an ast.
let leo_ast = LeoAst::from_json_string(&serialized_leo_ast).unwrap(); let ast = Ast::from_json_string(&serialized_ast).unwrap();
// Reserializes the ast into JSON format. // Reserializes the ast into JSON format.
let reserialized_leo_ast = leo_ast.to_json_string().unwrap(); let reserialized_ast = ast.to_json_string().unwrap();
assert_eq!(serialized_leo_ast, reserialized_leo_ast); assert_eq!(serialized_ast, reserialized_ast);
} }

View File

@ -23,7 +23,7 @@ use crate::{
OutputBytes, OutputBytes,
OutputFile, OutputFile,
}; };
use leo_ast::{Input, LeoAst, MainInput, Program}; use leo_ast::{Ast, Input, MainInput, Program};
use leo_grammar::Grammar; use leo_grammar::Grammar;
use leo_imports::ImportParser; use leo_imports::ImportParser;
use leo_input::LeoInputParser; use leo_input::LeoInputParser;
@ -184,7 +184,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
})?; })?;
// Construct the core ast from the pest ast. // Construct the core ast from the pest ast.
let core_ast = LeoAst::new(&self.package_name, &pest_ast); let core_ast = Ast::new(&self.package_name, &pest_ast);
// Store the main program file. // Store the main program file.
self.program = core_ast.into_repr(); self.program = core_ast.into_repr();
@ -244,7 +244,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
let package_name = &self.package_name; let package_name = &self.package_name;
// Construct the core ast from the pest ast. // Construct the core ast from the pest ast.
let core_ast = LeoAst::new(package_name, &ast); let core_ast = Ast::new(package_name, &ast);
// Store the main program file. // Store the main program file.
self.program = core_ast.into_repr(); self.program = core_ast.into_repr();

View File

@ -46,7 +46,7 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
let program_name = program.get_name(); let program_name = program.get_name();
let main_function_name = new_scope(&program_name, "main"); let main_function_name = new_scope(&program_name, "main");
resolved_program.store_definitions(program, imported_programs)?; resolved_program.store_definitions(&program, imported_programs)?;
let main = resolved_program.get(&main_function_name).ok_or(CompilerError::NoMain)?; let main = resolved_program.get(&main_function_name).ok_or(CompilerError::NoMain)?;
@ -72,7 +72,7 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
let tests = program.tests.clone(); let tests = program.tests.clone();
// Store definitions // Store definitions
resolved_program.store_definitions(program, imported_programs)?; resolved_program.store_definitions(&program, imported_programs)?;
// Get default input // Get default input
let default = input.pairs.get(&program_name); let default = input.pairs.get(&program_name);

View File

@ -28,7 +28,11 @@ use leo_imports::ImportParser;
use snarkos_models::curves::{Field, PrimeField}; use snarkos_models::curves::{Field, PrimeField};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> { impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn store_definitions(&mut self, program: Program, imported_programs: &ImportParser) -> Result<(), ImportError> { pub fn store_definitions(
&mut self,
program: &Program,
imported_programs: &ImportParser,
) -> Result<(), ImportError> {
let program_name = program.name.trim_end_matches(".leo"); let program_name = program.name.trim_end_matches(".leo");
// evaluate all import statements and store imported definitions // evaluate all import statements and store imported definitions
@ -39,15 +43,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
.collect::<Result<Vec<_>, ImportError>>()?; .collect::<Result<Vec<_>, ImportError>>()?;
// evaluate and store all circuit definitions // evaluate and store all circuit definitions
program.circuits.into_iter().for_each(|(identifier, circuit)| { program.circuits.iter().for_each(|(identifier, circuit)| {
let resolved_circuit_name = new_scope(program_name, &identifier.name); let resolved_circuit_name = new_scope(program_name, &identifier.name);
self.store(resolved_circuit_name, ConstrainedValue::CircuitDefinition(circuit)); self.store(
resolved_circuit_name,
ConstrainedValue::CircuitDefinition(circuit.clone()),
);
}); });
// evaluate and store all function definitions // evaluate and store all function definitions
program.functions.into_iter().for_each(|(function_name, function)| { program.functions.iter().for_each(|(function_name, function)| {
let resolved_function_name = new_scope(program_name, &function_name.name); let resolved_function_name = new_scope(program_name, &function_name.name);
self.store(resolved_function_name, ConstrainedValue::Function(None, function)); self.store(
resolved_function_name,
ConstrainedValue::Function(None, function.clone()),
);
}); });
Ok(()) Ok(())

View File

@ -138,7 +138,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Boolean operations // Boolean operations
Expression::Not(expression, span) => Ok(evaluate_not( Expression::Not(expression, span) => Ok(evaluate_not(
self.enforce_expression(cs, file_scope, function_scope, expected_type, *expression)?, self.enforce_operand(cs, file_scope, function_scope, expected_type, *expression, &span)?,
span, span,
)?), )?),
Expression::Or(left_right, span) => { Expression::Or(left_right, span) => {

View File

@ -47,7 +47,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
.ok_or_else(|| ImportError::unknown_package(import.package.name.clone()))?; .ok_or_else(|| ImportError::unknown_package(import.package.name.clone()))?;
// Parse imported program // Parse imported program
self.store_definitions(program.clone(), imported_programs)?; self.store_definitions(program, imported_programs)?;
// Store the imported symbol // Store the imported symbol
self.store_symbol(scope, &name, &symbol, program)?; self.store_symbol(scope, &name, &symbol, program)?;

View File

@ -93,6 +93,14 @@ fn test_not_false() {
assert_satisfied(program); assert_satisfied(program);
} }
#[test]
fn test_not_mutable() {
let bytes = include_bytes!("not_mutable.leo");
let program = parse_program(bytes).unwrap();
assert_satisfied(program);
}
#[test] #[test]
fn test_not_u32() { fn test_not_u32() {
let bytes = include_bytes!("not_u32.leo"); let bytes = include_bytes!("not_u32.leo");

View File

@ -0,0 +1,4 @@
function main () {
let mut b = false;
let a = !b;
}

View File

@ -175,6 +175,17 @@ fn test_return_array_tuple_pass() {
assert_satisfied(program); assert_satisfied(program);
} }
// Test return tuples
#[test]
fn test_return_tuple() {
let bytes = include_bytes!("return_tuple.leo");
let program = parse_program(bytes).unwrap();
assert_satisfied(program);
}
#[test] #[test]
fn test_return_tuple_conditional() { fn test_return_tuple_conditional() {
let bytes = include_bytes!("return_tuple_conditional.leo"); let bytes = include_bytes!("return_tuple_conditional.leo");

View File

@ -0,0 +1,11 @@
// Returns a tuple of tuples.
function tuples() -> ((u8, u8), u32) {
let a: (u8, u8) = (1, 2);
let b: u32 = 3;
return (a, b)
}
function main() {
let t = tuples();
}

View File

@ -18,7 +18,7 @@
//! //!
//! This module contains the [`Grammar`] type, a wrapper around the [`File`] type in this module. //! This module contains the [`Grammar`] type, a wrapper around the [`File`] type in this module.
//! The [`Grammar`] type is the datatype generated by the pest parser using grammar from `leo.pest`. //! The [`Grammar`] type is the datatype generated by the pest parser using grammar from `leo.pest`.
//! The [`Grammar`] type is intended to be parsed into a [`LeoAst`]. It should not be parsed by //! The [`Grammar`] type is intended to be parsed into a [`Ast`]. It should not be parsed by
//! any other pass of the compiler. //! any other pass of the compiler.
#[macro_use] #[macro_use]
@ -60,7 +60,7 @@ use std::{fs, path::Path};
/// These data types form a tree that begins from a [`File`] type root. /// These data types form a tree that begins from a [`File`] type root.
/// ///
/// A new [`Grammar`] type can be created from a `*.leo` file at a [`Path`]. /// A new [`Grammar`] type can be created from a `*.leo` file at a [`Path`].
/// A [`Grammar`] type can be used to create a new [`LeoAst`] type. /// A [`Grammar`] type can be used to create a new [`Ast`] type.
pub struct Grammar<'ast> { pub struct Grammar<'ast> {
ast: files::File<'ast>, ast: files::File<'ast>,
} }

View File

@ -105,7 +105,7 @@ dimension_single = {
// Declared in types/array_dimensions.rs // Declared in types/array_dimensions.rs
dimension_multiple = { "(" ~ number_positive ~ ("," ~ number_positive)* ~ ")"} dimension_multiple = { "(" ~ number_positive ~ ("," ~ number_positive)* ~ ")"}
type_tuple = { "(" ~ type_ ~ ("," ~ (type_tuple | type_))+ ~ ")" } type_tuple = { "(" ~ NEWLINE* ~ (type_ ~ ("," ~ NEWLINE* ~ type_)+ ~ ","?)? ~ NEWLINE* ~ ")" }
/// Values /// Values

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{verify_record_commitment, LocalDataVerificationError, StateLeafValues, StateValues}; use crate::{verify_record_commitment, LocalDataVerificationError, StateLeafValues, StateValues};
use leo_ast::Input as InputAst; use leo_ast::Input as AstInput;
use snarkos_algorithms::commitment_tree::CommitmentMerklePath; use snarkos_algorithms::commitment_tree::CommitmentMerklePath;
use snarkos_dpc::base_dpc::{ use snarkos_dpc::base_dpc::{
@ -30,31 +30,33 @@ use snarkos_utilities::{bytes::ToBytes, to_bytes, FromBytes};
use std::convert::TryFrom; use std::convert::TryFrom;
/// Returns `true` if the path to the local data commitment leaf is a valid path in the record
/// commitment merkle tree.
pub fn verify_local_data_commitment( pub fn verify_local_data_commitment(
system_parameters: &SystemParameters<Components>, system_parameters: &SystemParameters<Components>,
input_ast: &InputAst, ast_input: &AstInput,
) -> Result<bool, LocalDataVerificationError> { ) -> Result<bool, LocalDataVerificationError> {
// verify record commitment // verify record commitment.
let typed_record = input_ast.get_record(); let typed_record = ast_input.get_record();
let dpc_record_values = verify_record_commitment(system_parameters, typed_record)?; let dpc_record_values = verify_record_commitment(system_parameters, typed_record)?;
let record_commitment: Vec<u8> = dpc_record_values.commitment; let record_commitment: Vec<u8> = dpc_record_values.commitment;
let record_serial_number: Vec<u8> = dpc_record_values.serial_number; let record_serial_number: Vec<u8> = dpc_record_values.serial_number;
// parse typed state values // parse typed state values.
let typed_state = input_ast.get_state(); let typed_state = ast_input.get_state();
let state_values = StateValues::try_from(typed_state)?; let state_values = StateValues::try_from(typed_state)?;
let leaf_index: u32 = state_values.leaf_index; let leaf_index: u32 = state_values.leaf_index;
let root: Vec<u8> = state_values.root; let root: Vec<u8> = state_values.root;
// parse typed state leaf values // parse typed state leaf values.
let typed_state_leaf = input_ast.get_state_leaf(); let typed_state_leaf = ast_input.get_state_leaf();
let state_leaf_values = StateLeafValues::try_from(typed_state_leaf)?; let state_leaf_values = StateLeafValues::try_from(typed_state_leaf)?;
let path: Vec<u8> = state_leaf_values.path; let path: Vec<u8> = state_leaf_values.path;
let memo: Vec<u8> = state_leaf_values.memo; let memo: Vec<u8> = state_leaf_values.memo;
let network_id: u8 = state_leaf_values.network_id; let network_id: u8 = state_leaf_values.network_id;
let leaf_randomness: Vec<u8> = state_leaf_values.leaf_randomness; let leaf_randomness: Vec<u8> = state_leaf_values.leaf_randomness;
// Select local data commitment input bytes // Select local data commitment input bytes.
let is_death = leaf_index < (Components::NUM_INPUT_RECORDS as u32); let is_death = leaf_index < (Components::NUM_INPUT_RECORDS as u32);
let input_bytes = if is_death { let input_bytes = if is_death {
to_bytes![record_serial_number, record_commitment, memo, network_id]? to_bytes![record_serial_number, record_commitment, memo, network_id]?
@ -62,7 +64,7 @@ pub fn verify_local_data_commitment(
to_bytes![record_commitment, memo, network_id]? to_bytes![record_commitment, memo, network_id]?
}; };
// Construct local data commitment leaf // Construct local data commitment leaf.
let local_data_leaf_randomness = <LocalDataCommitment as CommitmentScheme>::Randomness::read(&leaf_randomness[..])?; let local_data_leaf_randomness = <LocalDataCommitment as CommitmentScheme>::Randomness::read(&leaf_randomness[..])?;
let local_data_commitment_leaf = LocalDataCommitment::commit( let local_data_commitment_leaf = LocalDataCommitment::commit(
&system_parameters.local_data_commitment, &system_parameters.local_data_commitment,
@ -70,10 +72,10 @@ pub fn verify_local_data_commitment(
&local_data_leaf_randomness, &local_data_leaf_randomness,
)?; )?;
// Construct record commitment merkle path // Construct record commitment merkle path.
let local_data_merkle_path = CommitmentMerklePath::<LocalDataCommitment, LocalDataCRH>::read(&path[..])?; let local_data_merkle_path = CommitmentMerklePath::<LocalDataCommitment, LocalDataCRH>::read(&path[..])?;
// Check record commitment merkle path is valid for the given local data commitment root // Check record commitment merkle path is valid for the given local data commitment root.
let local_data_commitment_root = <LocalDataCRH as CRH>::Output::read(&root[..])?; let local_data_commitment_root = <LocalDataCRH as CRH>::Output::read(&root[..])?;
let result = local_data_merkle_path.verify( let result = local_data_merkle_path.verify(
&system_parameters.local_data_crh, &system_parameters.local_data_crh,

View File

@ -14,8 +14,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{find_input, input_to_integer_string, input_to_u8_vec, StateLeafValuesError}; use crate::{find_input, input_to_bytes, input_to_integer_string, StateLeafValuesError};
use leo_ast::StateLeaf as StateLeafAst; use leo_ast::StateLeaf as AstStateLeaf;
use std::convert::TryFrom; use std::convert::TryFrom;
@ -24,6 +24,8 @@ static MEMO_PARAMETER_STRING: &str = "memo";
static NETWORK_ID_PARAMETER_STRING: &str = "network_id"; static NETWORK_ID_PARAMETER_STRING: &str = "network_id";
static LEAF_RANDOMNESS_PARAMETER_STRING: &str = "leaf_randomness"; static LEAF_RANDOMNESS_PARAMETER_STRING: &str = "leaf_randomness";
/// The serialized values included in the state leaf.
/// A new [`StateLeafValues`] type can be constructed from an [`AstStateLeaf`] type.
pub struct StateLeafValues { pub struct StateLeafValues {
pub path: Vec<u8>, pub path: Vec<u8>,
pub memo: Vec<u8>, pub memo: Vec<u8>,
@ -31,19 +33,19 @@ pub struct StateLeafValues {
pub leaf_randomness: Vec<u8>, pub leaf_randomness: Vec<u8>,
} }
impl TryFrom<&StateLeafAst> for StateLeafValues { impl TryFrom<&AstStateLeaf> for StateLeafValues {
type Error = StateLeafValuesError; type Error = StateLeafValuesError;
fn try_from(state_leaf: &StateLeafAst) -> Result<Self, Self::Error> { fn try_from(ast_state_leaf: &AstStateLeaf) -> Result<Self, Self::Error> {
let parameters = state_leaf.values(); let parameters = ast_state_leaf.values();
// Lookup path // Lookup path
let path_value = find_input(PATH_PARAMETER_STRING.to_owned(), &parameters)?; let path_value = find_input(PATH_PARAMETER_STRING.to_owned(), &parameters)?;
let path = input_to_u8_vec(path_value)?; let path = input_to_bytes(path_value)?;
// Lookup memo // Lookup memo
let memo_value = find_input(MEMO_PARAMETER_STRING.to_owned(), &parameters)?; let memo_value = find_input(MEMO_PARAMETER_STRING.to_owned(), &parameters)?;
let memo = input_to_u8_vec(memo_value)?; let memo = input_to_bytes(memo_value)?;
// Lookup network id // Lookup network id
let network_id_value = find_input(NETWORK_ID_PARAMETER_STRING.to_owned(), &parameters)?; let network_id_value = find_input(NETWORK_ID_PARAMETER_STRING.to_owned(), &parameters)?;
@ -51,7 +53,7 @@ impl TryFrom<&StateLeafAst> for StateLeafValues {
// Lookup leaf randomness // Lookup leaf randomness
let leaf_randomness_value = find_input(LEAF_RANDOMNESS_PARAMETER_STRING.to_owned(), &parameters)?; let leaf_randomness_value = find_input(LEAF_RANDOMNESS_PARAMETER_STRING.to_owned(), &parameters)?;
let leaf_randomness = input_to_u8_vec(leaf_randomness_value)?; let leaf_randomness = input_to_bytes(leaf_randomness_value)?;
Ok(Self { Ok(Self {
path, path,

View File

@ -14,24 +14,26 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{find_input, input_to_integer_string, input_to_u8_vec, StateValuesError}; use crate::{find_input, input_to_bytes, input_to_integer_string, StateValuesError};
use leo_ast::State as StateAst; use leo_ast::State as AstState;
use std::convert::TryFrom; use std::convert::TryFrom;
static LEAF_INDEX_PARAMETER_STRING: &str = "leaf_index"; static LEAF_INDEX_PARAMETER_STRING: &str = "leaf_index";
static ROOT_PARAMETER_STRING: &str = "root"; static ROOT_PARAMETER_STRING: &str = "root";
/// The serialized values included in the state.
/// A new [`StateValues`] type can be constructed from an [`AstState`] type.
pub struct StateValues { pub struct StateValues {
pub leaf_index: u32, pub leaf_index: u32,
pub root: Vec<u8>, pub root: Vec<u8>,
} }
impl TryFrom<&StateAst> for StateValues { impl TryFrom<&AstState> for StateValues {
type Error = StateValuesError; type Error = StateValuesError;
fn try_from(state: &StateAst) -> Result<Self, Self::Error> { fn try_from(ast_state: &AstState) -> Result<Self, Self::Error> {
let parameters = state.values(); let parameters = ast_state.values();
// Lookup leaf index // Lookup leaf index
let leaf_index_value = find_input(LEAF_INDEX_PARAMETER_STRING.to_owned(), &parameters)?; let leaf_index_value = find_input(LEAF_INDEX_PARAMETER_STRING.to_owned(), &parameters)?;
@ -39,7 +41,7 @@ impl TryFrom<&StateAst> for StateValues {
// Lookup root // Lookup root
let root_value = find_input(ROOT_PARAMETER_STRING.to_owned(), &parameters)?; let root_value = find_input(ROOT_PARAMETER_STRING.to_owned(), &parameters)?;
let root = input_to_u8_vec(root_value)?; let root = input_to_bytes(root_value)?;
Ok(Self { leaf_index, root }) Ok(Self { leaf_index, root })
} }

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{utilities::*, DPCRecordValuesError}; use crate::{utilities::*, DPCRecordValuesError};
use leo_ast::Record as RecordAst; use leo_ast::Record as AstRecord;
use snarkos_dpc::base_dpc::instantiated::Components; use snarkos_dpc::base_dpc::instantiated::Components;
use snarkos_objects::AccountAddress; use snarkos_objects::AccountAddress;
@ -33,6 +33,8 @@ static SERIAL_NUMBER_NONCE_PARAMETER_STRING: &str = "serial_number_nonce";
static COMMITMENT_PARAMETER_STRING: &str = "commitment"; static COMMITMENT_PARAMETER_STRING: &str = "commitment";
static COMMITMENT_RANDOMNESS_PARAMETER_STRING: &str = "commitment_randomness"; static COMMITMENT_RANDOMNESS_PARAMETER_STRING: &str = "commitment_randomness";
/// The serialized values included in the dpc record.
/// A new [`DPCRecordValues`] type can be constructed from an [`AstRecord`] type.
pub struct DPCRecordValues { pub struct DPCRecordValues {
pub serial_number: Vec<u8>, pub serial_number: Vec<u8>,
pub owner: AccountAddress<Components>, pub owner: AccountAddress<Components>,
@ -46,15 +48,15 @@ pub struct DPCRecordValues {
pub commitment_randomness: Vec<u8>, pub commitment_randomness: Vec<u8>,
} }
impl TryFrom<&RecordAst> for DPCRecordValues { impl TryFrom<&AstRecord> for DPCRecordValues {
type Error = DPCRecordValuesError; type Error = DPCRecordValuesError;
fn try_from(record: &RecordAst) -> Result<Self, Self::Error> { fn try_from(ast_record: &AstRecord) -> Result<Self, Self::Error> {
let parameters = record.values(); let parameters = ast_record.values();
// Lookup serial number // Lookup serial number
let serial_number_value = find_input(SERIAL_NUMBER_PARAMETER_STRING.to_owned(), &parameters)?; let serial_number_value = find_input(SERIAL_NUMBER_PARAMETER_STRING.to_owned(), &parameters)?;
let serial_number = input_to_u8_vec(serial_number_value)?; let serial_number = input_to_bytes(serial_number_value)?;
// Lookup record owner // Lookup record owner
let owner_value = find_input(OWNER_PARAMETER_STRING.to_owned(), &parameters)?; let owner_value = find_input(OWNER_PARAMETER_STRING.to_owned(), &parameters)?;
@ -70,27 +72,27 @@ impl TryFrom<&RecordAst> for DPCRecordValues {
// Lookup record payload // Lookup record payload
let payload_value = find_input(PAYLOAD_PARAMETER_STRING.to_owned(), &parameters)?; let payload_value = find_input(PAYLOAD_PARAMETER_STRING.to_owned(), &parameters)?;
let payload = input_to_u8_vec(payload_value)?; let payload = input_to_bytes(payload_value)?;
// Lookup record birth program id // Lookup record birth program id
let birth_program_id_value = find_input(BIRTH_PROGRAM_ID_PARAMETER_STRING.to_owned(), &parameters)?; let birth_program_id_value = find_input(BIRTH_PROGRAM_ID_PARAMETER_STRING.to_owned(), &parameters)?;
let birth_program_id = input_to_u8_vec(birth_program_id_value)?; let birth_program_id = input_to_bytes(birth_program_id_value)?;
// Lookup record death program id // Lookup record death program id
let death_program_id_value = find_input(DEATH_PROGRAM_ID_PARAMETER_STRING.to_owned(), &parameters)?; let death_program_id_value = find_input(DEATH_PROGRAM_ID_PARAMETER_STRING.to_owned(), &parameters)?;
let death_program_id = input_to_u8_vec(death_program_id_value)?; let death_program_id = input_to_bytes(death_program_id_value)?;
// Lookup record serial number nonce // Lookup record serial number nonce
let serial_number_nonce_value = find_input(SERIAL_NUMBER_NONCE_PARAMETER_STRING.to_owned(), &parameters)?; let serial_number_nonce_value = find_input(SERIAL_NUMBER_NONCE_PARAMETER_STRING.to_owned(), &parameters)?;
let serial_number_nonce = input_to_u8_vec(serial_number_nonce_value)?; let serial_number_nonce = input_to_bytes(serial_number_nonce_value)?;
// Lookup record commitment // Lookup record commitment
let commitment_value = find_input(COMMITMENT_PARAMETER_STRING.to_owned(), &parameters)?; let commitment_value = find_input(COMMITMENT_PARAMETER_STRING.to_owned(), &parameters)?;
let commitment = input_to_u8_vec(commitment_value)?; let commitment = input_to_bytes(commitment_value)?;
// Lookup record commitment randomness // Lookup record commitment randomness
let commitment_randomness_value = find_input(COMMITMENT_RANDOMNESS_PARAMETER_STRING.to_owned(), &parameters)?; let commitment_randomness_value = find_input(COMMITMENT_RANDOMNESS_PARAMETER_STRING.to_owned(), &parameters)?;
let commitment_randomness = input_to_u8_vec(commitment_randomness_value)?; let commitment_randomness = input_to_bytes(commitment_randomness_value)?;
Ok(Self { Ok(Self {
serial_number, serial_number,

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{DPCRecordValues, RecordVerificationError}; use crate::{DPCRecordValues, RecordVerificationError};
use leo_ast::Record as RecordAst; use leo_ast::Record as AstRecord;
use snarkos_dpc::base_dpc::{ use snarkos_dpc::base_dpc::{
instantiated::{Components, RecordCommitment}, instantiated::{Components, RecordCommitment},
@ -26,12 +26,14 @@ use snarkos_utilities::{bytes::ToBytes, to_bytes, FromBytes};
use std::convert::TryFrom; use std::convert::TryFrom;
/// Returns a serialized [`DPCRecordValues`] type if the record commitment is valid given the
/// system parameters.
pub fn verify_record_commitment( pub fn verify_record_commitment(
system_parameters: &SystemParameters<Components>, system_parameters: &SystemParameters<Components>,
record_ast: &RecordAst, ast_record: &AstRecord,
) -> Result<DPCRecordValues, RecordVerificationError> { ) -> Result<DPCRecordValues, RecordVerificationError> {
// generate a dpc record from the typed record // generate a dpc record from the typed record
let record = DPCRecordValues::try_from(record_ast)?; let record = DPCRecordValues::try_from(ast_record)?;
// verify record commitment // verify record commitment
let record_commitment_input = to_bytes![ let record_commitment_input = to_bytes![

View File

@ -19,6 +19,8 @@ use leo_ast::{InputValue, Parameter};
use std::collections::HashMap; use std::collections::HashMap;
/// Returns the input parameter with the given name.
/// If a parameter with the given name does not exist, then an error is returned.
pub fn find_input( pub fn find_input(
name: String, name: String,
parameters: &HashMap<Parameter, Option<InputValue>>, parameters: &HashMap<Parameter, Option<InputValue>>,
@ -36,6 +38,8 @@ pub fn find_input(
} }
} }
/// Returns the string of the integer input value.
/// If the input value is not an integer, then an error is returned.
pub fn input_to_integer_string(input: InputValue) -> Result<String, InputValueError> { pub fn input_to_integer_string(input: InputValue) -> Result<String, InputValueError> {
match input { match input {
InputValue::Integer(_type, string) => Ok(string), InputValue::Integer(_type, string) => Ok(string),
@ -43,7 +47,9 @@ pub fn input_to_integer_string(input: InputValue) -> Result<String, InputValueEr
} }
} }
pub fn input_to_u8_vec(input: InputValue) -> Result<Vec<u8>, InputValueError> { /// Returns the given input value as u8 bytes.
/// If the given input value cannot be serialized into bytes then an error is returned.
pub fn input_to_bytes(input: InputValue) -> Result<Vec<u8>, InputValueError> {
let input_array = match input { let input_array = match input {
InputValue::Array(values) => values, InputValue::Array(values) => values,
value => return Err(InputValueError::ExpectedBytes(value.to_string())), value => return Err(InputValueError::ExpectedBytes(value.to_string())),
@ -61,7 +67,9 @@ pub fn input_to_u8_vec(input: InputValue) -> Result<Vec<u8>, InputValueError> {
Ok(result_vec) Ok(result_vec)
} }
pub fn input_to_nested_u8_vec(input: InputValue) -> Result<Vec<Vec<u8>>, InputValueError> { /// Returns the given input value as an array of u8 bytes.
/// If the given input value cannot be serialized into an array of bytes then an error is returned.
pub fn input_to_nested_bytes(input: InputValue) -> Result<Vec<Vec<u8>>, InputValueError> {
let inner_arrays = match input { let inner_arrays = match input {
InputValue::Array(arrays) => arrays, InputValue::Array(arrays) => arrays,
value => return Err(InputValueError::ExpectedBytes(value.to_string())), value => return Err(InputValueError::ExpectedBytes(value.to_string())),
@ -70,7 +78,7 @@ pub fn input_to_nested_u8_vec(input: InputValue) -> Result<Vec<Vec<u8>>, InputVa
let mut result_vec = Vec::with_capacity(inner_arrays.len()); let mut result_vec = Vec::with_capacity(inner_arrays.len());
for input_array in inner_arrays { for input_array in inner_arrays {
let array = input_to_u8_vec(input_array)?; let array = input_to_bytes(input_array)?;
result_vec.push(array); result_vec.push(array);
} }

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{FunctionInputVariableType, SymbolTable, Type, TypeError}; use crate::{FunctionInputVariableType, SymbolTable, Type, TypeError};
use leo_ast::{FunctionInput, Identifier}; use leo_ast::{FunctionInput, Identifier, Span};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -46,6 +46,16 @@ impl FunctionInputType {
} }
} }
///
/// Return the `Span` of the current function input.
///
pub fn span(&self) -> &Span {
match self {
FunctionInputType::InputKeyword(identifier) => &identifier.span,
FunctionInputType::Variable(variable) => &variable.span,
}
}
/// ///
/// Return a new `FunctionInputType` from a given `FunctionInput`. /// Return a new `FunctionInputType` from a given `FunctionInput`.
/// ///

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Attribute, SymbolTable, Type, TypeError, UserDefinedType}; use crate::{Attribute, SymbolTable, Type, TypeError};
use leo_ast::{FunctionInputVariable, Identifier, Span}; use leo_ast::{FunctionInputVariable, Identifier, Span};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -90,18 +90,6 @@ impl FunctionInputVariableType {
span: unresolved_function_input.span, span: unresolved_function_input.span,
}) })
} }
///
/// Insert the current function input variable type into the given symbol table.
///
/// If the symbol table did not have this name present, `None` is returned.
///
pub fn insert(&self, table: &mut SymbolTable) -> Option<UserDefinedType> {
let key = self.identifier.name.clone();
let value = UserDefinedType::from(self.clone());
table.insert_name(key, value)
}
} }
impl PartialEq for FunctionInputVariableType { impl PartialEq for FunctionInputVariableType {

View File

@ -16,7 +16,7 @@
pub mod symbol_table; pub mod symbol_table;
use leo_ast::{Input, LeoAst}; use leo_ast::{Ast, Input};
use leo_grammar::Grammar; use leo_grammar::Grammar;
use leo_symbol_table::{SymbolTable, SymbolTableError}; use leo_symbol_table::{SymbolTable, SymbolTableError};
@ -27,7 +27,7 @@ const TEST_PROGRAM_PATH: &str = "";
/// A helper struct to test a `SymbolTable`. /// A helper struct to test a `SymbolTable`.
pub struct TestSymbolTable { pub struct TestSymbolTable {
ast: LeoAst, ast: Ast,
} }
impl TestSymbolTable { impl TestSymbolTable {
@ -41,11 +41,11 @@ impl TestSymbolTable {
// Get test file path. // Get test file path.
let file_path = PathBuf::from(TEST_PROGRAM_PATH); let file_path = PathBuf::from(TEST_PROGRAM_PATH);
// Get parser syntax tree // Get parser syntax tree.
let grammar = Grammar::new(&file_path, &*file_string).unwrap(); let grammar = Grammar::new(&file_path, &*file_string).unwrap();
// Get Leo syntax tree // Get Leo syntax tree.
let ast = LeoAst::new(TEST_PROGRAM_PATH, &grammar); let ast = Ast::new(TEST_PROGRAM_PATH, &grammar);
Self { ast } Self { ast }
} }

View File

@ -74,16 +74,4 @@ impl TypeAssertionError {
Self::new_from_span(message, membership.span()) Self::new_from_span(message, membership.span())
} }
///
/// Mismatched array type dimensions.
///
pub fn array_dimensions(dimensions1: &[usize], dimensions2: &[usize], span: &Span) -> Self {
let message = format!(
"Expected array with dimensions `{:?}`, found array with dimensions `{:?}`.",
dimensions1, dimensions2
);
Self::new_from_span(message, span)
}
} }

View File

@ -43,10 +43,10 @@ impl VariableTableError {
} }
/// ///
/// Attempted to lookup a variable name that does not exist in the table. /// Attempted to define two function inputs with the same name.
/// ///
pub fn undefined_variable_name(name: &str, span: &Span) -> Self { pub fn duplicate_function_input(name: &str, span: &Span) -> Self {
let message = format!("Cannot find variable `{}` in this scope.", name); let message = format!("Duplicate function input `{}`found in function signature.", name);
Self::new_from_span(message, span.clone()) Self::new_from_span(message, span.clone())
} }

View File

@ -50,11 +50,16 @@ impl VariableTable {
/// ///
pub fn insert_function_inputs(&mut self, function_inputs: &[FunctionInputType]) -> Result<(), VariableTableError> { pub fn insert_function_inputs(&mut self, function_inputs: &[FunctionInputType]) -> Result<(), VariableTableError> {
for input in function_inputs { for input in function_inputs {
let input_name = input.identifier().name.clone(); let input_name = &input.identifier().name;
let input_type = input.type_(); let input_type = input.type_();
let input_span = input.span();
// TODO (collinc97) throw an error for duplicate function input names. // Check for duplicate function input names.
self.insert(input_name, input_type); let duplicate = self.insert(input_name.clone(), input_type);
if duplicate.is_some() {
return Err(VariableTableError::duplicate_function_input(input_name, input_span));
}
} }
Ok(()) Ok(())
} }

View File

@ -23,7 +23,7 @@ pub mod variables;
use leo_grammar::Grammar; use leo_grammar::Grammar;
use leo_type_inference::TypeInference; use leo_type_inference::TypeInference;
use leo_ast::{Input, LeoAst, Program}; use leo_ast::{Ast, Input, Program};
use leo_imports::ImportParser; use leo_imports::ImportParser;
use leo_symbol_table::SymbolTable; use leo_symbol_table::SymbolTable;
use std::path::PathBuf; use std::path::PathBuf;
@ -49,7 +49,7 @@ impl TestTypeInference {
let ast = Grammar::new(&file_path, &*file_string).unwrap(); let ast = Grammar::new(&file_path, &*file_string).unwrap();
// Get typed syntax tree. // Get typed syntax tree.
let typed = LeoAst::new(TEST_PROGRAM_NAME, &ast); let typed = Ast::new(TEST_PROGRAM_NAME, &ast);
let program = typed.into_repr(); let program = typed.into_repr();
// Create empty import parser. // Create empty import parser.