impl basic function and import tests. fix import parsing

This commit is contained in:
collin 2020-05-20 15:51:57 -07:00
parent e07d43c287
commit 1a0d7235cd
20 changed files with 239 additions and 9 deletions

View File

@ -12,8 +12,8 @@ use snarkos_models::{
curves::{Field, Group, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
use std::env::current_dir;
use std::fs;
use std::path::Path;
impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgram<F, G, CS> {
pub fn enforce_import(
@ -22,9 +22,23 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
scope: String,
import: Import<F, G>,
) -> Result<(), ImportError> {
let path = current_dir().map_err(|error| ImportError::DirectoryError(error))?;
// Sanitize the package path to the imports directory
let mut package_path = path.clone();
if package_path.is_file() {
package_path.pop();
}
// Construct the path to the import file in the import directory
let mut main_file_path = package_path.clone();
main_file_path.push(import.path_string_full());
println!("Compiling import - {:?}", main_file_path);
// Resolve program file path
let unparsed_file = fs::read_to_string(Path::new(&import.path_string_full()))
.map_err(|_| ImportError::FileReadError(import.path_string_full()))?;
let unparsed_file = fs::read_to_string(main_file_path.clone())
.map_err(|_| ImportError::FileReadError(main_file_path))?;
let mut file = ast::parse(&unparsed_file).map_err(|_| ImportError::FileParsingError)?;
// generate ast from file

View File

@ -270,8 +270,6 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
let mut returns = vec![];
for (expression, ty) in expressions.into_iter().zip(return_types.into_iter()) {
let expected_types = vec![ty.clone()];
println!("expression {}", expression);
println!("expected types {:?}", expected_types);
let result = self.enforce_branch(
cs,
file_scope.clone(),

View File

@ -85,7 +85,7 @@ pub enum ExpressionError {
)]
UndefinedFunction(String),
#[error("Cannot evaluate function call")]
#[error("{}", _0)]
FunctionError(Box<FunctionError>),
#[error("Inline function call to {} did not return", _0)]

View File

@ -1,7 +1,13 @@
use std::io;
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum ImportError {
#[error("Cannot read from the provided file path - {}", _0)]
FileReadError(String),
#[error("Attempt to access current directory failed - {:?}", _0)]
DirectoryError(io::Error),
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[error("Syntax error. Cannot parse the file")]
FileParsingError,

View File

@ -221,7 +221,7 @@ import_source = @{(!"\"" ~ ANY)*}
import_symbol = { identifier ~ ("as" ~ identifier)? }
import_symbol_tuple = _{ import_symbol ~ ("," ~ NEWLINE* ~ import_symbol)* }
import = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ ("*" | ("{" ~ NEWLINE* ~ import_symbol_tuple ~ NEWLINE* ~ "}")) ~ LINE_END}
import = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ ("*" | ("{" ~ NEWLINE* ~ import_symbol_tuple ~ NEWLINE* ~ "}") | import_symbol) ~ LINE_END}
/// Program File

View File

@ -0,0 +1,5 @@
function empty() { }
function main() {
empty();
}

View File

@ -0,0 +1,97 @@
use crate::{compile_program, get_error, get_output, integer::u32::output_one};
use leo_compiler::{
compiler::Compiler,
errors::{CompilerError, ExpressionError, FunctionError, StatementError},
ConstrainedValue,
};
use snarkos_curves::{bls12_377::Fr, edwards_bls12::EdwardsProjective};
use snarkos_models::gadgets::utilities::boolean::Boolean;
const DIRECTORY_NAME: &str = "tests/function/";
pub(crate) fn output_empty(program: Compiler<Fr, EdwardsProjective>) {
let output = get_output(program);
assert_eq!(
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![]),
output
);
}
// (true, false)
pub(crate) fn output_multiple(program: Compiler<Fr, EdwardsProjective>) {
let output = get_output(program);
assert_eq!(
ConstrainedValue::<Fr, EdwardsProjective>::Return(vec![
ConstrainedValue::Boolean(Boolean::Constant(true)),
ConstrainedValue::Boolean(Boolean::Constant(false))
]),
output
)
}
fn fail_undefined_identifier(program: Compiler<Fr, EdwardsProjective>) {
match get_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(
StatementError::ExpressionError(ExpressionError::UndefinedIdentifier(_)),
)) => {}
error => panic!("Expected function undefined, got {}", error),
}
}
// Inline function call
#[test]
fn test_empty() {
let program = compile_program(DIRECTORY_NAME, "empty.leo").unwrap();
output_empty(program);
}
#[test]
fn test_return() {
let program = compile_program(DIRECTORY_NAME, "return.leo").unwrap();
output_one(program);
}
#[test]
fn test_undefined() {
let program = compile_program(DIRECTORY_NAME, "undefined.leo").unwrap();
fail_undefined_identifier(program);
}
// Function scope
#[test]
fn test_global_scope_fail() {
let program = compile_program(DIRECTORY_NAME, "scope_fail.leo").unwrap();
match get_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(
StatementError::ExpressionError(ExpressionError::FunctionError(value)),
)) => match *value {
FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::UndefinedIdentifier(_),
)) => {}
error => panic!("Expected function undefined, got {}", error),
},
error => panic!("Expected function undefined, got {}", error),
}
}
#[test]
fn test_value_unchanged() {
let program = compile_program(DIRECTORY_NAME, "value_unchanged.leo").unwrap();
output_one(program);
}
// Multiple returns
#[test]
fn test_multiple_returns() {
let program = compile_program(DIRECTORY_NAME, "multiple.leo").unwrap();
output_multiple(program);
}
#[test]
fn test_multiple_returns_main() {
let program = compile_program(DIRECTORY_NAME, "multiple_main.leo").unwrap();
output_multiple(program);
}

View File

@ -0,0 +1,8 @@
function test() -> (bool, bool) {
return true, false
}
function main() -> (bool, bool) {
let (a, b) = test();
return a, b
}

View File

@ -0,0 +1,3 @@
function main() -> (bool, bool) {
return true, false
}

View File

@ -0,0 +1,7 @@
function one() -> u32 {
return 1u32
}
function main() -> u32 {
return one()
}

View File

@ -0,0 +1,8 @@
function foo() -> field {
return myGlobal
}
function main() -> field {
let myGlobal = 42field;
return foo()
}

View File

@ -0,0 +1,3 @@
function main() {
my_function();
}

View File

@ -0,0 +1,19 @@
// Functions inputs in leo are pass-by-value.
//
// Program execution:
// line 15: variable `a` is defined with value `1`.
// line 16: value `1` is copied and passed into function `bad_mutate()`.
// line 10: variable `x` is defined with value `1`.
// line 11: variable `x` is set to value `0`.
// line 18: program returns the value of `a`.
function bad_mutate(mut x: u32) {
x = 0; // <- does not change `a`
}
function main() -> u32 {
let a = 1;
bad_mutate(a);
return a // <- returns 1
}

View File

@ -0,0 +1,5 @@
from "tests/import/test_import" import foo as bar;
function main() -> u32 {
return bar()
}

View File

@ -0,0 +1,5 @@
from "tests/import/test_import" import foo;
function main() -> u32 {
return foo()
}

View File

@ -0,0 +1,27 @@
use crate::{compile_program, integer::u32::output_one};
const DIRECTORY_NAME: &str = "tests/import/";
#[test]
fn test_basic() {
let program = compile_program(DIRECTORY_NAME, "basic.leo").unwrap();
output_one(program);
}
#[test]
fn test_multiple() {
let program = compile_program(DIRECTORY_NAME, "multiple.leo").unwrap();
output_one(program);
}
#[test]
fn test_star() {
let program = compile_program(DIRECTORY_NAME, "star.leo").unwrap();
output_one(program);
}
#[test]
fn test_alias() {
let program = compile_program(DIRECTORY_NAME, "alias.leo").unwrap();
output_one(program);
}

View File

@ -0,0 +1,9 @@
from "tests/import/test_import" import {
Point,
foo
};
function main() -> u32 {
let p = Point { x: 1u32, y: 0u32 };
return foo()
}

View File

@ -0,0 +1,6 @@
from "tests/import/test_import" import *;
function main() -> u32 {
let p = Point { x: 1u32, y: 0u32 };
return foo()
}

View File

@ -0,0 +1,8 @@
circuit Point {
x: u32
y: u32
}
function foo() -> u32 {
return 1u32
}

View File

@ -2,7 +2,9 @@ pub mod array;
pub mod boolean;
pub mod circuit;
pub mod field_element;
pub mod function;
pub mod group_element;
pub mod import;
pub mod integer;
pub mod mutability;