mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-09-11 05:45:30 +03:00
impl basic function and import tests. fix import parsing
This commit is contained in:
parent
e07d43c287
commit
1a0d7235cd
@ -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
|
||||
|
@ -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(),
|
||||
|
@ -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)]
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
5
compiler/tests/function/empty.leo
Normal file
5
compiler/tests/function/empty.leo
Normal file
@ -0,0 +1,5 @@
|
||||
function empty() { }
|
||||
|
||||
function main() {
|
||||
empty();
|
||||
}
|
97
compiler/tests/function/mod.rs
Normal file
97
compiler/tests/function/mod.rs
Normal 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);
|
||||
}
|
8
compiler/tests/function/multiple.leo
Normal file
8
compiler/tests/function/multiple.leo
Normal file
@ -0,0 +1,8 @@
|
||||
function test() -> (bool, bool) {
|
||||
return true, false
|
||||
}
|
||||
|
||||
function main() -> (bool, bool) {
|
||||
let (a, b) = test();
|
||||
return a, b
|
||||
}
|
3
compiler/tests/function/multiple_main.leo
Normal file
3
compiler/tests/function/multiple_main.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() -> (bool, bool) {
|
||||
return true, false
|
||||
}
|
7
compiler/tests/function/return.leo
Normal file
7
compiler/tests/function/return.leo
Normal file
@ -0,0 +1,7 @@
|
||||
function one() -> u32 {
|
||||
return 1u32
|
||||
}
|
||||
|
||||
function main() -> u32 {
|
||||
return one()
|
||||
}
|
8
compiler/tests/function/scope_fail.leo
Normal file
8
compiler/tests/function/scope_fail.leo
Normal file
@ -0,0 +1,8 @@
|
||||
function foo() -> field {
|
||||
return myGlobal
|
||||
}
|
||||
|
||||
function main() -> field {
|
||||
let myGlobal = 42field;
|
||||
return foo()
|
||||
}
|
3
compiler/tests/function/undefined.leo
Normal file
3
compiler/tests/function/undefined.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() {
|
||||
my_function();
|
||||
}
|
19
compiler/tests/function/value_unchanged.leo
Normal file
19
compiler/tests/function/value_unchanged.leo
Normal 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
|
||||
}
|
5
compiler/tests/import/alias.leo
Normal file
5
compiler/tests/import/alias.leo
Normal file
@ -0,0 +1,5 @@
|
||||
from "tests/import/test_import" import foo as bar;
|
||||
|
||||
function main() -> u32 {
|
||||
return bar()
|
||||
}
|
5
compiler/tests/import/basic.leo
Normal file
5
compiler/tests/import/basic.leo
Normal file
@ -0,0 +1,5 @@
|
||||
from "tests/import/test_import" import foo;
|
||||
|
||||
function main() -> u32 {
|
||||
return foo()
|
||||
}
|
27
compiler/tests/import/mod.rs
Normal file
27
compiler/tests/import/mod.rs
Normal 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);
|
||||
}
|
9
compiler/tests/import/multiple.leo
Normal file
9
compiler/tests/import/multiple.leo
Normal 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()
|
||||
}
|
6
compiler/tests/import/star.leo
Normal file
6
compiler/tests/import/star.leo
Normal file
@ -0,0 +1,6 @@
|
||||
from "tests/import/test_import" import *;
|
||||
|
||||
function main() -> u32 {
|
||||
let p = Point { x: 1u32, y: 0u32 };
|
||||
return foo()
|
||||
}
|
8
compiler/tests/import/test_import.leo
Normal file
8
compiler/tests/import/test_import.leo
Normal file
@ -0,0 +1,8 @@
|
||||
circuit Point {
|
||||
x: u32
|
||||
y: u32
|
||||
}
|
||||
|
||||
function foo() -> u32 {
|
||||
return 1u32
|
||||
}
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user