mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-23 15:15:47 +03:00
merge master
This commit is contained in:
commit
fe79cfcf71
24
.github/workflows/ci.yml
vendored
24
.github/workflows/ci.yml
vendored
@ -15,14 +15,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Load snarkOS
|
||||
run: |
|
||||
mkdir ~/.ssh
|
||||
echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
eval $(ssh-agent -s)
|
||||
ssh-add -k ~/.ssh/id_rsa
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@ -53,14 +45,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Load snarkOS
|
||||
run: |
|
||||
mkdir ~/.ssh
|
||||
echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
eval $(ssh-agent -s)
|
||||
ssh-add -k ~/.ssh/id_rsa
|
||||
|
||||
- name: Install Rust (${{ matrix.rust }})
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@ -131,14 +115,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Load snarkOS
|
||||
run: |
|
||||
mkdir ~/.ssh
|
||||
echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
eval $(ssh-agent -s)
|
||||
ssh-add -k ~/.ssh/id_rsa
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
16
.github/workflows/release-tests.yml
vendored
16
.github/workflows/release-tests.yml
vendored
@ -15,14 +15,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Load snarkOS
|
||||
run: |
|
||||
mkdir ~/.ssh
|
||||
echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
eval $(ssh-agent -s)
|
||||
ssh-add -k ~/.ssh/id_rsa
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@ -54,14 +46,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Load snarkOS
|
||||
run: |
|
||||
mkdir ~/.ssh
|
||||
echo "${{ secrets.SNARKOS_DEPLOY_KEY }}" > ~/.ssh/id_rsa
|
||||
chmod 600 ~/.ssh/id_rsa
|
||||
eval $(ssh-agent -s)
|
||||
ssh-add -k ~/.ssh/id_rsa
|
||||
|
||||
- name: Install Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
69
Cargo.lock
generated
69
Cargo.lock
generated
@ -140,7 +140,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"clang-sys",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"env_logger 0.7.1",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
@ -381,16 +381,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0b1aacfaffdbff75be81c15a399b4bedf78aaefe840e8af1d299ac2ade885d2"
|
||||
checksum = "a50aab2529019abfabfa93f1e6c41ef392f91fbf179b347a7e96abb524884a08"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"regex",
|
||||
"terminal_size",
|
||||
"termios",
|
||||
"unicode-width",
|
||||
"winapi 0.3.9",
|
||||
"winapi-util",
|
||||
@ -667,7 +666,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"humantime 1.3.0",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime 2.0.1",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
@ -1000,6 +1012,12 @@ dependencies = [
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.13.7"
|
||||
@ -1295,6 +1313,7 @@ dependencies = [
|
||||
name = "leo-gadgets"
|
||||
version = "1.0.3"
|
||||
dependencies = [
|
||||
"criterion",
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
"snarkos-errors",
|
||||
@ -1339,7 +1358,7 @@ dependencies = [
|
||||
"console",
|
||||
"dirs",
|
||||
"dotenv",
|
||||
"env_logger",
|
||||
"env_logger 0.8.1",
|
||||
"from-pest",
|
||||
"lazy_static",
|
||||
"leo-compiler",
|
||||
@ -2307,9 +2326,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.116"
|
||||
version = "1.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"
|
||||
checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@ -2326,9 +2345,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.116"
|
||||
version = "1.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
|
||||
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.19",
|
||||
"quote 1.0.7",
|
||||
@ -2337,9 +2356,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.57"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
|
||||
checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@ -2704,15 +2723,6 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termios"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0fcee7b24a25675de40d5bb4de6e41b0df07bc9856295e7e2b3a3600c400c2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
@ -2724,18 +2734,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.20"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
|
||||
checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.20"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
|
||||
checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.19",
|
||||
"quote 1.0.7",
|
||||
@ -2822,9 +2832,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.6"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
|
||||
checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -2891,9 +2901,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.2.12"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82bb5079aa76438620837198db8a5c529fb9878c730bc2b28179b0241cf04c10"
|
||||
checksum = "4ef0a5e15477aa303afbfac3a44cba9b6430fdaad52423b1e6c0dbbe28c3eedd"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"chrono",
|
||||
@ -2905,6 +2915,7 @@ dependencies = [
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
"tracing-serde",
|
||||
|
@ -109,13 +109,13 @@ version = "2.0"
|
||||
version = "3.0.1"
|
||||
|
||||
[dependencies.console]
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
|
||||
[dependencies.dotenv]
|
||||
version = "0.15.0"
|
||||
|
||||
[dependencies.env_logger]
|
||||
version = "0.7"
|
||||
version = "0.8"
|
||||
|
||||
[dependencies.from-pest]
|
||||
version = "0.3.1"
|
||||
|
@ -14,24 +14,21 @@
|
||||
// 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/>.
|
||||
|
||||
use leo_ast::{errors::ParserError, files::File, LeoAst};
|
||||
use leo_ast::LeoAst;
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
|
||||
fn leo_ast<'ast>(filepath: &'ast PathBuf, program_string: &'ast str) {
|
||||
fn leo_ast<'ast>(filepath: &'ast Path, program_string: &'ast str) {
|
||||
let result = LeoAst::<'ast>::new(filepath, program_string).unwrap();
|
||||
black_box(result);
|
||||
}
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
let filepath = Path::new("./main.leo").to_path_buf();
|
||||
// let program_string = &LeoAst::load_file(&filepath).unwrap();
|
||||
let program_string = include_str!("./main.leo");
|
||||
|
||||
c.bench_function("LeoAst::new", |b| {
|
||||
b.iter(|| leo_ast(black_box(&filepath), black_box(program_string)))
|
||||
});
|
||||
c.bench_function("LeoAst::new", |b| b.iter(|| leo_ast(&filepath, program_string)));
|
||||
}
|
||||
|
||||
criterion_group!(benches, criterion_benchmark);
|
||||
|
@ -1,3 +1,26 @@
|
||||
function main() {
|
||||
return 1 + 1
|
||||
circuit PedersenHash {
|
||||
parameters: [group; 256],
|
||||
|
||||
// Instantiates a Pedersen hash circuit
|
||||
static function new(parameters: [group; 256]) -> Self {
|
||||
return Self { parameters: parameters }
|
||||
}
|
||||
|
||||
function hash(bits: [bool; 256]) -> group {
|
||||
let mut digest: group = 0;
|
||||
for i in 0..256 {
|
||||
if bits[i] {
|
||||
digest += self.parameters[i];
|
||||
}
|
||||
}
|
||||
return digest
|
||||
}
|
||||
}
|
||||
|
||||
// The 'pedersen-hash' main function.
|
||||
function main() -> group {
|
||||
const parameters = [1group; 256];
|
||||
const pedersen = PedersenHash::new(parameters);
|
||||
let hash_input: [bool; 256] = [true; 256];
|
||||
return pedersen.hash(hash_input)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
// 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/>.
|
||||
|
||||
use crate::{ast::Rule, expressions::TupleExpression, SpanDef};
|
||||
use crate::{ast::Rule, expressions::Expression, SpanDef};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
@ -23,7 +23,7 @@ use serde::Serialize;
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::access_call))]
|
||||
pub struct CallAccess<'ast> {
|
||||
pub expressions: TupleExpression<'ast>,
|
||||
pub expressions: Vec<Expression<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
|
@ -14,6 +14,8 @@
|
||||
// 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/>.
|
||||
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
pub mod access;
|
||||
pub use access::*;
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
// 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/>.
|
||||
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
pub mod annotations;
|
||||
pub use annotations::*;
|
||||
|
||||
|
@ -74,8 +74,8 @@ fn precedence_climber() -> PrecClimber<Rule> {
|
||||
])
|
||||
}
|
||||
|
||||
fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
|
||||
Box::new(match pair.as_rule() {
|
||||
fn parse_term(pair: Pair<Rule>) -> Expression {
|
||||
match pair.as_rule() {
|
||||
Rule::expression_term => {
|
||||
let clone = pair.clone();
|
||||
let next = clone.into_inner().next().unwrap();
|
||||
@ -87,14 +87,14 @@ fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
|
||||
Rule::expression_array_inline => {
|
||||
Expression::ArrayInline(ArrayInlineExpression::from_pest(&mut pair.into_inner()).unwrap())
|
||||
}
|
||||
Rule::expression_array_initializer => {
|
||||
Expression::ArrayInitializer(ArrayInitializerExpression::from_pest(&mut pair.into_inner()).unwrap())
|
||||
}
|
||||
Rule::expression_array_initializer => Expression::ArrayInitializer(Box::new(
|
||||
ArrayInitializerExpression::from_pest(&mut pair.into_inner()).unwrap(),
|
||||
)),
|
||||
Rule::expression_circuit_inline => {
|
||||
Expression::CircuitInline(CircuitInlineExpression::from_pest(&mut pair.into_inner()).unwrap())
|
||||
}
|
||||
Rule::expression_conditional => {
|
||||
Expression::Ternary(TernaryExpression::from_pest(&mut pair.into_inner()).unwrap())
|
||||
Expression::Ternary(Box::new(TernaryExpression::from_pest(&mut pair.into_inner()).unwrap()))
|
||||
}
|
||||
Rule::expression_unary => {
|
||||
// The following is necessary to match with the unary operator and its unary expression
|
||||
@ -107,11 +107,11 @@ fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
|
||||
rule => unreachable!("`expression_unary` should yield `operation_unary`, found {:#?}", rule),
|
||||
};
|
||||
let expression = parse_term(inner.next().unwrap());
|
||||
Expression::Unary(UnaryExpression {
|
||||
Expression::Unary(Box::new(UnaryExpression {
|
||||
operation,
|
||||
expression,
|
||||
span,
|
||||
})
|
||||
}))
|
||||
}
|
||||
Rule::expression_postfix => {
|
||||
Expression::Postfix(PostfixExpression::from_pest(&mut pair.into_inner()).unwrap())
|
||||
@ -128,19 +128,15 @@ fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
|
||||
"`parse_expression_term` should be invoked on `Rule::expression_term`, found {:#?}",
|
||||
rule
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn binary_expression<'ast>(
|
||||
lhs: Box<Expression<'ast>>,
|
||||
pair: Pair<'ast, Rule>,
|
||||
rhs: Box<Expression<'ast>>,
|
||||
) -> Box<Expression<'ast>> {
|
||||
fn binary_expression<'ast>(lhs: Expression<'ast>, pair: Pair<'ast, Rule>, rhs: Expression<'ast>) -> Expression<'ast> {
|
||||
let (start, _) = lhs.span().clone().split();
|
||||
let (_, end) = rhs.span().clone().split();
|
||||
let span = start.span(&end);
|
||||
|
||||
Box::new(match pair.as_rule() {
|
||||
match pair.as_rule() {
|
||||
Rule::operation_or => Expression::binary(BinaryOperation::Or, lhs, rhs, span),
|
||||
Rule::operation_and => Expression::binary(BinaryOperation::And, lhs, rhs, span),
|
||||
Rule::operation_eq => Expression::binary(BinaryOperation::Eq, lhs, rhs, span),
|
||||
@ -155,7 +151,7 @@ fn binary_expression<'ast>(
|
||||
Rule::operation_div => Expression::binary(BinaryOperation::Div, lhs, rhs, span),
|
||||
Rule::operation_pow => Expression::binary(BinaryOperation::Pow, lhs, rhs, span),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> FromPest<'ast> for Expression<'ast> {
|
||||
@ -163,13 +159,12 @@ impl<'ast> FromPest<'ast> for Expression<'ast> {
|
||||
type Rule = Rule;
|
||||
|
||||
fn from_pest(pest: &mut Pairs<'ast, Rule>) -> Result<Self, ConversionError<Void>> {
|
||||
let mut clone = pest.clone();
|
||||
let pair = clone.next().ok_or(::from_pest::ConversionError::NoMatch)?;
|
||||
let pair = pest.peek().ok_or(::from_pest::ConversionError::NoMatch)?;
|
||||
match pair.as_rule() {
|
||||
Rule::expression => {
|
||||
// Transfer iterated state to pest.
|
||||
*pest = clone;
|
||||
Ok(*PRECEDENCE_CLIMBER.climb(pair.into_inner(), parse_term, binary_expression))
|
||||
// advance the iterator
|
||||
pest.next();
|
||||
Ok(PRECEDENCE_CLIMBER.climb(pair.into_inner(), parse_term, binary_expression))
|
||||
}
|
||||
_ => Err(ConversionError::NoMatch),
|
||||
}
|
||||
|
@ -34,8 +34,16 @@ impl<'ast> fmt::Display for RangeOrExpression<'ast> {
|
||||
RangeOrExpression::Range(ref range) => write!(
|
||||
f,
|
||||
"{}..{}",
|
||||
range.from.as_ref().map(|v| format!("{}", v)).unwrap_or(format!("")),
|
||||
range.to.as_ref().map(|v| format!("{}", v)).unwrap_or(format!("")),
|
||||
range
|
||||
.from
|
||||
.as_ref()
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_else(|| "".to_string()),
|
||||
range
|
||||
.to
|
||||
.as_ref()
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_else(|| "".to_string()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -38,12 +38,7 @@ impl<'ast> fmt::Display for Variables<'ast> {
|
||||
write!(f, "{}", self.names[0])?;
|
||||
} else {
|
||||
// (a, mut b)
|
||||
let names = self
|
||||
.names
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
let names = self.names.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
|
||||
|
||||
write!(f, "({})", names)?;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
use crate::{ast::Rule, errors::SyntaxError};
|
||||
|
||||
use pest::error::Error;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ParserError {
|
||||
@ -38,21 +38,18 @@ pub enum ParserError {
|
||||
}
|
||||
|
||||
impl ParserError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
match self {
|
||||
ParserError::SyntaxError(error) => {
|
||||
let new_error: Error<Rule> = match error {
|
||||
SyntaxError::Error(error) => {
|
||||
let new_error = error.clone();
|
||||
new_error.with_path(path.to_str().unwrap())
|
||||
}
|
||||
};
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
if let ParserError::SyntaxError(error) = self {
|
||||
let new_error: Error<Rule> = match error {
|
||||
SyntaxError::Error(error) => {
|
||||
let new_error = error.clone();
|
||||
new_error.with_path(path.to_str().unwrap())
|
||||
}
|
||||
};
|
||||
|
||||
tracing::error!("{}", new_error);
|
||||
tracing::error!("{}", new_error);
|
||||
|
||||
*error = SyntaxError::Error(new_error);
|
||||
}
|
||||
_ => {}
|
||||
*error = SyntaxError::Error(new_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -65,6 +62,6 @@ impl From<Error<Rule>> for ParserError {
|
||||
|
||||
impl From<std::io::Error> for ParserError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
ParserError::Crate("std::io", format!("{}", error))
|
||||
ParserError::Crate("std::io", error.to_string())
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ use serde::Serialize;
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::expression_array_initializer))]
|
||||
pub struct ArrayInitializerExpression<'ast> {
|
||||
pub expression: Box<Expression<'ast>>,
|
||||
pub expression: Expression<'ast>,
|
||||
pub dimensions: ArrayDimensions<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
#[serde(with = "SpanDef")]
|
||||
|
@ -22,8 +22,8 @@ use serde::Serialize;
|
||||
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||
pub struct BinaryExpression<'ast> {
|
||||
pub operation: BinaryOperation,
|
||||
pub left: Box<Expression<'ast>>,
|
||||
pub right: Box<Expression<'ast>>,
|
||||
pub left: Expression<'ast>,
|
||||
pub right: Expression<'ast>,
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
@ -24,11 +24,11 @@ use std::fmt;
|
||||
pub enum Expression<'ast> {
|
||||
Value(Value<'ast>),
|
||||
Identifier(Identifier<'ast>),
|
||||
Unary(UnaryExpression<'ast>),
|
||||
Binary(BinaryExpression<'ast>),
|
||||
Ternary(TernaryExpression<'ast>),
|
||||
Unary(Box<UnaryExpression<'ast>>),
|
||||
Binary(Box<BinaryExpression<'ast>>),
|
||||
Ternary(Box<TernaryExpression<'ast>>),
|
||||
ArrayInline(ArrayInlineExpression<'ast>),
|
||||
ArrayInitializer(ArrayInitializerExpression<'ast>),
|
||||
ArrayInitializer(Box<ArrayInitializerExpression<'ast>>),
|
||||
CircuitInline(CircuitInlineExpression<'ast>),
|
||||
Postfix(PostfixExpression<'ast>),
|
||||
Tuple(TupleExpression<'ast>),
|
||||
@ -37,30 +37,30 @@ pub enum Expression<'ast> {
|
||||
impl<'ast> Expression<'ast> {
|
||||
pub fn binary(
|
||||
operation: BinaryOperation,
|
||||
left: Box<Expression<'ast>>,
|
||||
right: Box<Expression<'ast>>,
|
||||
left: Expression<'ast>,
|
||||
right: Expression<'ast>,
|
||||
span: Span<'ast>,
|
||||
) -> Self {
|
||||
Expression::Binary(BinaryExpression {
|
||||
Expression::Binary(Box::new(BinaryExpression {
|
||||
operation,
|
||||
left,
|
||||
right,
|
||||
span,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn ternary(
|
||||
first: Box<Expression<'ast>>,
|
||||
second: Box<Expression<'ast>>,
|
||||
third: Box<Expression<'ast>>,
|
||||
first: Expression<'ast>,
|
||||
second: Expression<'ast>,
|
||||
third: Expression<'ast>,
|
||||
span: Span<'ast>,
|
||||
) -> Self {
|
||||
Expression::Ternary(TernaryExpression {
|
||||
Expression::Ternary(Box::new(TernaryExpression {
|
||||
first,
|
||||
second,
|
||||
third,
|
||||
span,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn span(&self) -> &Span<'ast> {
|
||||
|
@ -23,9 +23,9 @@ use serde::Serialize;
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::expression_conditional))]
|
||||
pub struct TernaryExpression<'ast> {
|
||||
pub first: Box<Expression<'ast>>,
|
||||
pub second: Box<Expression<'ast>>,
|
||||
pub third: Box<Expression<'ast>>,
|
||||
pub first: Expression<'ast>,
|
||||
pub second: Expression<'ast>,
|
||||
pub third: Expression<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
|
@ -25,7 +25,7 @@ use std::fmt;
|
||||
#[pest_ast(rule(Rule::expression_unary))]
|
||||
pub struct UnaryExpression<'ast> {
|
||||
pub operation: UnaryOperation,
|
||||
pub expression: Box<Expression<'ast>>,
|
||||
pub expression: Expression<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
|
@ -14,6 +14,8 @@
|
||||
// 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/>.
|
||||
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
pub mod function_input;
|
||||
pub use function_input::*;
|
||||
|
||||
|
@ -226,7 +226,7 @@ dimension_single = {
|
||||
// Declared in types/array_dimensions.rs
|
||||
dimension_multiple = { "(" ~ number_positive ~ ("," ~ number_positive)* ~ ")"}
|
||||
|
||||
type_tuple = { "(" ~ NEWLINE* ~ type_ ~ ("," ~ NEWLINE* ~ type_)+ ~ ","? ~ NEWLINE* ~ ")" }
|
||||
type_tuple = { "(" ~ NEWLINE* ~ (type_ ~ ("," ~ NEWLINE* ~ type_)+ ~ ","?)? ~ NEWLINE* ~ ")" }
|
||||
|
||||
/// Values
|
||||
|
||||
@ -302,7 +302,7 @@ access_tuple = ${ "." ~ number_positive }
|
||||
access_assignee = { access_array | access_tuple | access_member }
|
||||
|
||||
// Declared in access/call_access.rs
|
||||
access_call = !{ expression_tuple }
|
||||
access_call = !{ "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
|
||||
|
||||
// Declared in access/member_access.rs
|
||||
access_member = ${ "." ~ identifier }
|
||||
@ -351,7 +351,7 @@ expression_term = {
|
||||
expression = { expression_term ~ (operation_binary ~ expression_term)* }
|
||||
|
||||
// Declared in expressions/expression_tuple.rs
|
||||
expression_tuple = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
|
||||
expression_tuple = { "(" ~ (expression ~ ("," ~ expression)+)? ~ ")" }
|
||||
|
||||
// Declared in expressions/array_initializer_expression.rs
|
||||
expression_array_initializer = { "[" ~ expression ~ ";" ~ array_dimensions ~ "]" }
|
||||
|
@ -21,7 +21,7 @@ extern crate pest_derive;
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
mod ast;
|
||||
pub mod ast;
|
||||
|
||||
pub mod access;
|
||||
pub mod annotations;
|
||||
@ -45,7 +45,7 @@ pub(crate) mod span;
|
||||
pub(crate) use span::*;
|
||||
|
||||
use from_pest::FromPest;
|
||||
use std::{fs, path::PathBuf};
|
||||
use std::{fs, path::Path};
|
||||
|
||||
pub struct LeoAst<'ast> {
|
||||
ast: files::File<'ast>,
|
||||
@ -53,7 +53,7 @@ pub struct LeoAst<'ast> {
|
||||
|
||||
impl<'ast> LeoAst<'ast> {
|
||||
/// Creates a new abstract syntax tree given the file path.
|
||||
pub fn new(file_path: &'ast PathBuf, program_string: &'ast str) -> Result<Self, ParserError> {
|
||||
pub fn new(file_path: &'ast Path, program_string: &'ast str) -> Result<Self, ParserError> {
|
||||
// TODO (howardwu): Turn this check back on after fixing the testing module.
|
||||
// assert_eq!(program_string, fs::read_to_string(file_path).map_err(|_| ParserError::FileReadError(file_path.clone()))?);
|
||||
|
||||
@ -71,8 +71,8 @@ impl<'ast> LeoAst<'ast> {
|
||||
// TODO (howardwu): Remove this in favor of a dedicated file loader to verify checksums
|
||||
// and maintain a global cache of program strings during the compilation process.
|
||||
/// Loads the Leo code as a string from the given file path.
|
||||
pub fn load_file(file_path: &'ast PathBuf) -> Result<String, ParserError> {
|
||||
Ok(fs::read_to_string(file_path).map_err(|_| ParserError::FileReadError(file_path.clone()))?)
|
||||
pub fn load_file(file_path: &'ast Path) -> Result<String, ParserError> {
|
||||
Ok(fs::read_to_string(file_path).map_err(|_| ParserError::FileReadError(file_path.to_owned()))?)
|
||||
}
|
||||
|
||||
/// Returns a reference to the inner abstract syntax tree representation.
|
||||
|
@ -39,11 +39,11 @@ pub struct ConditionalStatement<'ast> {
|
||||
|
||||
impl<'ast> fmt::Display for ConditionalStatement<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "if ({}) {{\n", self.condition)?;
|
||||
write!(f, "\t{:#?}\n", self.statements)?;
|
||||
writeln!(f, "if ({}) {{", self.condition)?;
|
||||
writeln!(f, "\t{:#?}", self.statements)?;
|
||||
self.next
|
||||
.as_ref()
|
||||
.map(|n_or_e| write!(f, "}} {}", n_or_e))
|
||||
.unwrap_or(write!(f, "}}"))
|
||||
.unwrap_or_else(|| write!(f, "}}"))
|
||||
}
|
||||
}
|
||||
|
39
ast/tests/expression.rs
Normal file
39
ast/tests/expression.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use leo_ast::ast::{LanguageParser, Rule};
|
||||
|
||||
use pest::*;
|
||||
|
||||
#[test]
|
||||
fn redundant_parens() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "(true)",
|
||||
rule: Rule::expression,
|
||||
tokens: [
|
||||
expression(0, 6, [
|
||||
expression_term(0, 6, [expression(1, 5, [expression_term(1, 5, [value(1, 5, [value_boolean(1, 5, [])])])])])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_redundant_parens() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "(((true)))",
|
||||
rule: Rule::expression,
|
||||
tokens: [
|
||||
expression(0, 10, [
|
||||
expression_term(0, 10, [
|
||||
expression(1, 9, [expression_term(1, 9, [
|
||||
expression(2, 8, [expression_term(2, 8, [
|
||||
expression(3, 7, [expression_term(3, 7, [
|
||||
value(3, 7, [value_boolean(3, 7, [])])
|
||||
])])
|
||||
])])
|
||||
])])
|
||||
])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
115
ast/tests/function.rs
Normal file
115
ast/tests/function.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use leo_ast::ast::{LanguageParser, Rule};
|
||||
|
||||
use pest::*;
|
||||
|
||||
#[test]
|
||||
fn call_wo_args() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "x()",
|
||||
rule: Rule::expression_postfix,
|
||||
tokens: [
|
||||
expression_postfix(0, 3, [
|
||||
keyword_or_identifier(0, 1, [self_keyword_or_identifier(0, 1, [identifier(0, 1, [])])]),
|
||||
access(1, 3, [access_call(1, 3, [])])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_with_arg() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "x(true)",
|
||||
rule: Rule::expression_postfix,
|
||||
tokens: [
|
||||
expression_postfix(0, 7, [
|
||||
keyword_or_identifier(0, 1, [self_keyword_or_identifier(0, 1, [identifier(0, 1, [])])]),
|
||||
access(1, 7, [access_call(1, 7, [
|
||||
expression(2, 6, [expression_term(2, 6, [value(2, 6, [value_boolean(2, 6, [])])])])
|
||||
])])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_with_2_args() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "x(true, false)",
|
||||
rule: Rule::expression_postfix,
|
||||
tokens: [
|
||||
expression_postfix(0, 14, [
|
||||
keyword_or_identifier(0, 1, [self_keyword_or_identifier(0, 1, [identifier(0, 1, [])])]),
|
||||
access(1, 14, [access_call(1, 14, [
|
||||
expression(2, 6, [expression_term(2, 6, [value(2, 6, [value_boolean(2, 6, [])])])]),
|
||||
expression(8, 13, [expression_term(8, 13, [value(8, 13, [value_boolean(8, 13, [])])])])
|
||||
])])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_def() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "function x() {}",
|
||||
rule: Rule::function,
|
||||
tokens: [
|
||||
function(0, 15, [identifier(9, 10, [])])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returning_unit_type() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "function x() -> () {}",
|
||||
rule: Rule::function,
|
||||
tokens: [
|
||||
function(0, 21, [identifier(9, 10, []), type_(16, 18, [type_tuple(16, 18, [])])])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returning_unit_value() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "function x() { return () }",
|
||||
rule: Rule::function,
|
||||
tokens: [
|
||||
function(0, 26, [identifier(9, 10, []), statement(15, 25, [
|
||||
statement_return(15, 25, [expression(22, 25, [expression_term(22, 24, [expression_tuple(22, 24, [])])])])
|
||||
])])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn id_def() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "function id(x: u8) -> u8 { return x }",
|
||||
rule: Rule::function,
|
||||
tokens: [
|
||||
function(0, 37, [
|
||||
identifier(9, 11, []),
|
||||
input(12, 17, [
|
||||
function_input(12, 17, [
|
||||
identifier(12, 13, []),
|
||||
type_(15, 17, [type_data(15, 17, [type_integer(15, 17, [type_integer_unsigned(15, 17, [type_u8(15, 17, [])])])])])
|
||||
])
|
||||
]),
|
||||
type_(22, 24, [type_data(22, 24, [type_integer(22, 24, [type_integer_unsigned(22, 24, [type_u8(22, 24, [])])])])]),
|
||||
statement(27, 36, [statement_return(27, 36, [
|
||||
expression(34, 36, [expression_term(34, 35, [identifier(34, 35, [])])])
|
||||
])])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
@ -14,4 +14,7 @@
|
||||
// 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/>.
|
||||
|
||||
mod expression;
|
||||
mod function;
|
||||
mod serialization;
|
||||
mod tuple;
|
||||
|
@ -14,13 +14,12 @@
|
||||
// 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/>.
|
||||
|
||||
use leo_ast::LeoAst;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "ci_skip"))]
|
||||
fn test_serialize() {
|
||||
use leo_ast::LeoAst;
|
||||
use std::path::PathBuf;
|
||||
|
||||
let mut program_filepath = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
program_filepath.push("tests/serialization/main.leo");
|
||||
|
||||
|
91
ast/tests/tuple.rs
Normal file
91
ast/tests/tuple.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use leo_ast::ast::{LanguageParser, Rule};
|
||||
|
||||
use pest::*;
|
||||
|
||||
#[test]
|
||||
fn implicitly_typed() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "(true, false)",
|
||||
rule: Rule::expression_tuple,
|
||||
tokens: [
|
||||
expression_tuple(0, 13, [
|
||||
expression(1, 5, [expression_term(1, 5, [value(1, 5, [value_boolean(1, 5, [])])])]),
|
||||
expression(7, 12, [expression_term(7, 12, [value(7, 12, [value_boolean(7, 12, [])])])])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicitly_typed() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "let tup: (bool, bool) = (true, false);",
|
||||
rule: Rule::statement_definition,
|
||||
tokens: [
|
||||
statement_definition(0, 38, [
|
||||
declare(0, 4, [let_(0, 4, [])]),
|
||||
variables(4, 21, [
|
||||
variable_name(4, 7, [identifier(4, 7, [])]),
|
||||
type_(9, 21, [type_tuple(9, 21, [
|
||||
type_(10, 14, [type_data(10, 14, [type_boolean(10, 14, [])])]),
|
||||
type_(16, 20, [type_data(16, 20, [type_boolean(16, 20, [])])]),
|
||||
])])
|
||||
]),
|
||||
expression(24, 37, [expression_term(24, 37, [expression_tuple(24, 37, [
|
||||
expression(25, 29, [expression_term(25, 29, [value(25, 29, [value_boolean(25, 29, [])])])]),
|
||||
expression(31, 36, [expression_term(31, 36, [value(31, 36, [value_boolean(31, 36, [])])])]),
|
||||
])])]),
|
||||
LINE_END(37, 38, [])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn access() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "x.0",
|
||||
rule: Rule::expression_postfix,
|
||||
tokens: [
|
||||
expression_postfix(0, 3, [
|
||||
keyword_or_identifier(0, 1, [self_keyword_or_identifier(0, 1, [identifier(0, 1, [])])]),
|
||||
access(1, 3, [access_tuple(1, 3, [number_positive(2, 3, [])])])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn implicit_unit() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "()",
|
||||
rule: Rule::expression_tuple,
|
||||
tokens: [
|
||||
expression_tuple(0, 2, [])
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_unit() {
|
||||
parses_to! {
|
||||
parser: LanguageParser,
|
||||
input: "let x: () = ();",
|
||||
rule: Rule::statement_definition,
|
||||
tokens: [
|
||||
statement_definition(0, 15, [
|
||||
declare(0, 4, [let_(0, 4, [])]),
|
||||
variables(4, 9, [
|
||||
variable_name(4, 5, [identifier(4, 5, [])]),
|
||||
type_(7, 9, [type_tuple(7, 9, [])])
|
||||
]),
|
||||
expression(12, 14, [expression_term(12, 14, [expression_tuple(12, 14, [])])]),
|
||||
LINE_END(14, 15, [])
|
||||
])
|
||||
]
|
||||
}
|
||||
}
|
@ -40,7 +40,11 @@ use snarkos_models::{
|
||||
};
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{fs, marker::PhantomData, path::PathBuf};
|
||||
use std::{
|
||||
fs,
|
||||
marker::PhantomData,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
|
||||
@ -73,17 +77,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
pub fn parse_input(
|
||||
&mut self,
|
||||
input_string: &str,
|
||||
input_path: PathBuf,
|
||||
input_path: &Path,
|
||||
state_string: &str,
|
||||
state_path: PathBuf,
|
||||
state_path: &Path,
|
||||
) -> Result<(), CompilerError> {
|
||||
let input_syntax_tree = LeoInputParser::parse_file(&input_string).map_err(|mut e| {
|
||||
e.set_path(input_path.clone());
|
||||
e.set_path(input_path);
|
||||
|
||||
e
|
||||
})?;
|
||||
let state_syntax_tree = LeoInputParser::parse_file(&state_string).map_err(|mut e| {
|
||||
e.set_path(state_path.clone());
|
||||
e.set_path(state_path);
|
||||
|
||||
e
|
||||
})?;
|
||||
@ -123,9 +127,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
main_file_path: PathBuf,
|
||||
output_directory: PathBuf,
|
||||
input_string: &str,
|
||||
input_path: PathBuf,
|
||||
input_path: &Path,
|
||||
state_string: &str,
|
||||
state_path: PathBuf,
|
||||
state_path: &Path,
|
||||
) -> Result<Self, CompilerError> {
|
||||
let mut compiler = Self::new(package_name, main_file_path, output_directory);
|
||||
|
||||
@ -137,6 +141,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
}
|
||||
|
||||
/// Parses the Leo program file, constructs a syntax tree, and generates a program.
|
||||
#[allow(deprecated)]
|
||||
pub(crate) fn parse_program(&mut self) -> Result<(), CompilerError> {
|
||||
// Use the parser to construct the abstract syntax tree.
|
||||
let program_string = LeoAst::load_file(&self.main_file_path)?;
|
||||
@ -150,16 +155,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
pub fn parse_program_from_string(&mut self, program_string: &str) -> Result<(), CompilerError> {
|
||||
// Use the given bytes to construct the abstract syntax tree.
|
||||
let ast = LeoAst::new(&self.main_file_path, &program_string).map_err(|mut e| {
|
||||
e.set_path(self.main_file_path.clone());
|
||||
e.set_path(&self.main_file_path);
|
||||
|
||||
e
|
||||
})?;
|
||||
|
||||
// Derive the package name.
|
||||
let package_name = self.package_name.clone();
|
||||
let package_name = &self.package_name;
|
||||
|
||||
// Use the typed parser to construct the typed syntax tree.
|
||||
let typed_tree = LeoTypedAst::new(&package_name, &ast);
|
||||
let typed_tree = LeoTypedAst::new(package_name, &ast);
|
||||
|
||||
self.program = typed_tree.into_repr();
|
||||
self.imported_programs = ImportParser::parse(&self.program)?;
|
||||
@ -209,7 +214,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
|
||||
generate_constraints::<F, G, CS>(cs, self.program, self.program_input, &self.imported_programs).map_err(
|
||||
|mut error| {
|
||||
error.set_path(path);
|
||||
error.set_path(&path);
|
||||
|
||||
error
|
||||
},
|
||||
@ -235,7 +240,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
let path = self.main_file_path;
|
||||
generate_constraints::<_, G, _>(cs, self.program, self.program_input, &self.imported_programs).map_err(
|
||||
|mut error| {
|
||||
error.set_path(path);
|
||||
error.set_path(&path);
|
||||
error
|
||||
},
|
||||
)
|
||||
|
@ -28,11 +28,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn evaluate_console_assert<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
indicator: Option<Boolean>,
|
||||
expression: Expression,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<(), ConsoleError> {
|
||||
let expected_type = Some(Type::Boolean);
|
||||
let expression_string = expression.to_string();
|
||||
@ -53,12 +53,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Unwrap assertion value and handle errors
|
||||
let result_option = match assert_expression {
|
||||
ConstrainedValue::Boolean(boolean) => boolean.get_value(),
|
||||
_ => return Err(ConsoleError::assertion_must_be_boolean(expression_string, span.clone())),
|
||||
_ => {
|
||||
return Err(ConsoleError::assertion_must_be_boolean(
|
||||
expression_string,
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
};
|
||||
let result_bool = result_option.ok_or(ConsoleError::assertion_depends_on_input(span.clone()))?;
|
||||
let result_bool = result_option.ok_or_else(|| ConsoleError::assertion_depends_on_input(span.to_owned()))?;
|
||||
|
||||
if !result_bool {
|
||||
return Err(ConsoleError::assertion_failed(expression_string, span));
|
||||
return Err(ConsoleError::assertion_failed(expression_string, span.to_owned()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -28,14 +28,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn evaluate_console_function_call<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
indicator: Option<Boolean>,
|
||||
console: ConsoleFunctionCall,
|
||||
) -> Result<(), ConsoleError> {
|
||||
match console.function {
|
||||
ConsoleFunction::Assert(expression) => {
|
||||
self.evaluate_console_assert(cs, file_scope, function_scope, indicator, expression, console.span)?;
|
||||
self.evaluate_console_assert(cs, file_scope, function_scope, indicator, expression, &console.span)?;
|
||||
}
|
||||
ConsoleFunction::Debug(string) => {
|
||||
let string = self.format(cs, file_scope, function_scope, string)?;
|
||||
|
@ -28,8 +28,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn format<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
formatted: FormattedString,
|
||||
) -> Result<String, ConsoleError> {
|
||||
// Check that containers and parameters match
|
||||
@ -37,29 +37,23 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
return Err(ConsoleError::length(
|
||||
formatted.containers.len(),
|
||||
formatted.parameters.len(),
|
||||
formatted.span.clone(),
|
||||
formatted.span,
|
||||
));
|
||||
}
|
||||
|
||||
// Trim starting double quote `"`
|
||||
let mut string = formatted.string.as_str();
|
||||
string = string.trim_start_matches("\"");
|
||||
string = string.trim_start_matches('\"');
|
||||
|
||||
// Trim everything after the ending double quote `"`
|
||||
let parts: Vec<&str> = string.split("\"").collect();
|
||||
string = parts[0];
|
||||
let string = string.split('\"').next().unwrap();
|
||||
|
||||
// Insert the parameter for each container `{}`
|
||||
let mut result = string.to_string();
|
||||
|
||||
for parameter in formatted.parameters.into_iter() {
|
||||
let parameter_value = self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
None,
|
||||
parameter.expression,
|
||||
)?;
|
||||
let parameter_value =
|
||||
self.enforce_expression(cs, file_scope, function_scope, None, parameter.expression)?;
|
||||
|
||||
result = result.replacen("{}", ¶meter_value.to_string(), 1);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::{ConstraintSystem, TestConstraintSystem},
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
||||
cs: &mut CS,
|
||||
@ -44,7 +44,7 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
|
||||
) -> Result<OutputBytes, CompilerError> {
|
||||
let mut resolved_program = ConstrainedProgram::<F, G>::new();
|
||||
let program_name = program.get_name();
|
||||
let main_function_name = new_scope(program_name.clone(), "main".into());
|
||||
let main_function_name = new_scope(&program_name, "main");
|
||||
|
||||
resolved_program.store_definitions(program, imported_programs)?;
|
||||
|
||||
@ -54,7 +54,7 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
|
||||
|
||||
match main.clone() {
|
||||
ConstrainedValue::Function(_circuit_identifier, function) => {
|
||||
let result = resolved_program.enforce_main_function(cs, program_name, function, input)?;
|
||||
let result = resolved_program.enforce_main_function(cs, &program_name, function, input)?;
|
||||
Ok(result)
|
||||
}
|
||||
_ => Err(CompilerError::NoMainFunction),
|
||||
@ -65,8 +65,8 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
|
||||
program: Program,
|
||||
input: InputPairs,
|
||||
imported_programs: &ImportParser,
|
||||
main_file_path: &PathBuf,
|
||||
output_directory: &PathBuf,
|
||||
main_file_path: &Path,
|
||||
output_directory: &Path,
|
||||
) -> Result<(u32, u32), CompilerError> {
|
||||
let mut resolved_program = ConstrainedProgram::<F, G>::new();
|
||||
let program_name = program.get_name();
|
||||
@ -87,7 +87,7 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
|
||||
|
||||
for (test_name, test) in tests.into_iter() {
|
||||
let cs = &mut TestConstraintSystem::<F>::new();
|
||||
let full_test_name = format!("{}::{}", program_name.clone(), test_name.to_string());
|
||||
let full_test_name = format!("{}::{}", program_name.clone(), test_name);
|
||||
let mut output_file_name = program_name.clone();
|
||||
|
||||
// get input file name from annotation or use test_name
|
||||
@ -118,9 +118,9 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
|
||||
input.parse_state(state_ast)?;
|
||||
|
||||
// run test function on new program with input
|
||||
let result = resolved_program.clone().enforce_main_function(
|
||||
let result = resolved_program.enforce_main_function(
|
||||
cs,
|
||||
program_name.clone(),
|
||||
&program_name,
|
||||
test.function,
|
||||
input, // pass program input into every test
|
||||
);
|
||||
@ -147,7 +147,7 @@ pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
|
||||
(false, _) => {
|
||||
// Set file location of error
|
||||
let mut error = result.unwrap_err();
|
||||
error.set_path(main_file_path.clone());
|
||||
error.set_path(main_file_path);
|
||||
|
||||
tracing::error!("{} failed due to error\n\n{}\n", full_test_name, error);
|
||||
|
||||
|
@ -28,17 +28,17 @@ use snarkos_models::curves::{Field, PrimeField};
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn store_definition(
|
||||
&mut self,
|
||||
function_scope: String,
|
||||
function_scope: &str,
|
||||
mutable: bool,
|
||||
identifier: Identifier,
|
||||
mut value: ConstrainedValue<F, G>,
|
||||
) -> () {
|
||||
) {
|
||||
// Store with given mutability
|
||||
if mutable {
|
||||
value = ConstrainedValue::Mutable(Box::new(value));
|
||||
}
|
||||
|
||||
let variable_program_identifier = new_scope(function_scope, identifier.name);
|
||||
let variable_program_identifier = new_scope(function_scope, &identifier.name);
|
||||
|
||||
self.store(variable_program_identifier, value);
|
||||
}
|
||||
|
@ -35,18 +35,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
program
|
||||
.imports
|
||||
.iter()
|
||||
.map(|import| self.store_import(program_name.to_owned(), import, imported_programs))
|
||||
.map(|import| self.store_import(&program_name, import, imported_programs))
|
||||
.collect::<Result<Vec<_>, ImportError>>()?;
|
||||
|
||||
// evaluate and store all circuit definitions
|
||||
program.circuits.into_iter().for_each(|(identifier, circuit)| {
|
||||
let resolved_circuit_name = new_scope(program_name.to_owned(), identifier.to_string());
|
||||
let resolved_circuit_name = new_scope(program_name, &identifier.name);
|
||||
self.store(resolved_circuit_name, ConstrainedValue::CircuitDefinition(circuit));
|
||||
});
|
||||
|
||||
// evaluate and store all function definitions
|
||||
program.functions.into_iter().for_each(|(function_name, function)| {
|
||||
let resolved_function_name = new_scope(program_name.to_owned(), function_name.to_string());
|
||||
let resolved_function_name = new_scope(program_name, &function_name.name);
|
||||
self.store(resolved_function_name, ConstrainedValue::Function(None, function));
|
||||
});
|
||||
|
||||
|
@ -23,7 +23,7 @@ use leo_state::LocalDataVerificationError;
|
||||
use bincode::Error as SerdeError;
|
||||
use leo_dynamic_check::DynamicCheckError;
|
||||
use leo_static_check::StaticCheckError;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CompilerError {
|
||||
@ -77,7 +77,7 @@ pub enum CompilerError {
|
||||
}
|
||||
|
||||
impl CompilerError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
CompilerError::InputParserError(error) => error.set_path(path),
|
||||
CompilerError::FunctionError(error) => error.set_path(path),
|
||||
|
@ -17,7 +17,7 @@
|
||||
use crate::errors::ExpressionError;
|
||||
use leo_typed::{Error as FormattedError, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ConsoleError {
|
||||
@ -29,7 +29,7 @@ pub enum ConsoleError {
|
||||
}
|
||||
|
||||
impl ConsoleError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
ConsoleError::Expression(error) => error.set_path(path),
|
||||
ConsoleError::Error(error) => error.set_path(path),
|
||||
@ -50,7 +50,8 @@ impl ConsoleError {
|
||||
}
|
||||
|
||||
pub fn assertion_depends_on_input(span: Span) -> Self {
|
||||
let message = format!("console.assert() failed to evaluate. This error is caused by empty input file values");
|
||||
let message =
|
||||
"console.assert() failed to evaluate. This error is caused by empty input file values".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use leo_core::LeoCoreError;
|
||||
use leo_typed::{Error as FormattedError, Identifier, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ExpressionError {
|
||||
@ -52,7 +52,7 @@ pub enum ExpressionError {
|
||||
}
|
||||
|
||||
impl ExpressionError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
ExpressionError::AddressError(error) => error.set_path(path),
|
||||
ExpressionError::BooleanError(error) => error.set_path(path),
|
||||
@ -146,7 +146,7 @@ impl ExpressionError {
|
||||
}
|
||||
|
||||
pub fn self_keyword(span: Span) -> Self {
|
||||
let message = format!("cannot call keyword `Self` outside of a circuit function");
|
||||
let message = "cannot call keyword `Self` outside of a circuit function".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use crate::errors::{
|
||||
};
|
||||
use leo_typed::{Error as FormattedError, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FunctionError {
|
||||
@ -63,7 +63,7 @@ pub enum FunctionError {
|
||||
}
|
||||
|
||||
impl FunctionError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
FunctionError::AddressError(error) => error.set_path(path),
|
||||
FunctionError::BooleanError(error) => error.set_path(path),
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use leo_typed::{Error as FormattedError, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum OutputBytesError {
|
||||
@ -25,7 +25,7 @@ pub enum OutputBytesError {
|
||||
}
|
||||
|
||||
impl OutputBytesError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
OutputBytesError::Error(error) => error.set_path(path),
|
||||
}
|
||||
@ -36,7 +36,7 @@ impl OutputBytesError {
|
||||
}
|
||||
|
||||
pub fn not_enough_registers(span: Span) -> Self {
|
||||
let message = format!("number of input registers must be greater than or equal to output registers");
|
||||
let message = "number of input registers must be greater than or equal to output registers".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
@ -36,6 +36,6 @@ pub enum OutputFileError {
|
||||
|
||||
impl From<std::io::Error> for OutputFileError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
OutputFileError::Crate("std::io", format!("{}", error))
|
||||
OutputFileError::Crate("std::io", error.to_string())
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
use crate::errors::{AddressError, BooleanError, ConsoleError, ExpressionError, IntegerError, ValueError};
|
||||
use leo_typed::{Error as FormattedError, Span, Type};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum StatementError {
|
||||
@ -44,7 +44,7 @@ pub enum StatementError {
|
||||
}
|
||||
|
||||
impl StatementError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
StatementError::AddressError(error) => error.set_path(path),
|
||||
StatementError::BooleanError(error) => error.set_path(path),
|
||||
@ -67,13 +67,13 @@ impl StatementError {
|
||||
}
|
||||
|
||||
pub fn array_assign_index(span: Span) -> Self {
|
||||
let message = format!("Cannot assign single index to array of values");
|
||||
let message = "Cannot assign single index to array of values".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn array_assign_range(span: Span) -> Self {
|
||||
let message = format!("Cannot assign range of array values to single value");
|
||||
let message = "Cannot assign range of array values to single value".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
@ -145,7 +145,7 @@ impl StatementError {
|
||||
}
|
||||
|
||||
pub fn tuple_assign_index(span: Span) -> Self {
|
||||
let message = format!("Cannot assign single index to tuple of values");
|
||||
let message = "Cannot assign single index to tuple of values".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
use leo_typed::{Error as FormattedError, Span};
|
||||
|
||||
use snarkos_errors::{gadgets::SynthesisError, objects::account::AccountError};
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AddressError {
|
||||
@ -26,7 +26,7 @@ pub enum AddressError {
|
||||
}
|
||||
|
||||
impl AddressError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
AddressError::Error(error) => error.set_path(path),
|
||||
}
|
||||
@ -64,7 +64,7 @@ impl AddressError {
|
||||
}
|
||||
|
||||
pub fn missing_address(span: Span) -> Self {
|
||||
let message = format!("expected address input not found");
|
||||
let message = "expected address input not found".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
use leo_typed::{Error as FormattedError, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum BooleanError {
|
||||
@ -26,7 +26,7 @@ pub enum BooleanError {
|
||||
}
|
||||
|
||||
impl BooleanError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
BooleanError::Error(error) => error.set_path(path),
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
use leo_typed::{Error as FormattedError, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum FieldError {
|
||||
@ -26,7 +26,7 @@ pub enum FieldError {
|
||||
}
|
||||
|
||||
impl FieldError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
FieldError::Error(error) => error.set_path(path),
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
use leo_typed::{Error as FormattedError, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GroupError {
|
||||
@ -26,7 +26,7 @@ pub enum GroupError {
|
||||
}
|
||||
|
||||
impl GroupError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
GroupError::Error(error) => error.set_path(path),
|
||||
}
|
||||
@ -88,13 +88,13 @@ impl GroupError {
|
||||
}
|
||||
|
||||
pub fn x_recover(span: Span) -> Self {
|
||||
let message = format!("could not recover group element from x coordinate");
|
||||
let message = "could not recover group element from x coordinate".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn y_recover(span: Span) -> Self {
|
||||
let message = format!("could not recover group element from y coordinate");
|
||||
let message = "could not recover group element from y coordinate".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ use leo_gadgets::errors::SignedIntegerError;
|
||||
use leo_typed::{error::Error as FormattedError, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum IntegerError {
|
||||
@ -27,7 +27,7 @@ pub enum IntegerError {
|
||||
}
|
||||
|
||||
impl IntegerError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
IntegerError::Error(error) => error.set_path(path),
|
||||
}
|
||||
@ -68,7 +68,7 @@ impl IntegerError {
|
||||
}
|
||||
|
||||
pub fn negate_operation(span: Span) -> Self {
|
||||
let message = format!("integer negation can only be enforced on signed integers");
|
||||
let message = "integer negation can only be enforced on signed integers".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
@ -83,9 +83,9 @@ impl IntegerError {
|
||||
}
|
||||
|
||||
pub fn invalid_index(span: Span) -> Self {
|
||||
let message = format!(
|
||||
let message =
|
||||
"index must be a constant value unsigned integer. allocated indices produce a circuit of unknown size"
|
||||
);
|
||||
.to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
use crate::errors::{AddressError, BooleanError, FieldError, GroupError, IntegerError};
|
||||
use leo_typed::{Error as FormattedError, Span};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ValueError {
|
||||
@ -41,7 +41,7 @@ pub enum ValueError {
|
||||
}
|
||||
|
||||
impl ValueError {
|
||||
pub fn set_path(&mut self, path: PathBuf) {
|
||||
pub fn set_path(&mut self, path: &Path) {
|
||||
match self {
|
||||
ValueError::AddressError(error) => error.set_path(path),
|
||||
ValueError::BooleanError(error) => error.set_path(path),
|
||||
@ -63,7 +63,7 @@ impl ValueError {
|
||||
}
|
||||
|
||||
pub fn implicit_group(span: Span) -> Self {
|
||||
let message = format!("group coordinates should be in (x, y)group format");
|
||||
let message = "group coordinates should be in (x, y)group format".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub fn enforce_add<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
match (left, right) {
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
@ -41,16 +41,16 @@ pub fn enforce_add<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
Ok(ConstrainedValue::Group(point_1.add(cs, &point_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span)?;
|
||||
enforce_add(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span)?;
|
||||
enforce_add(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||
format!("{} + {}", val_1, val_2),
|
||||
span,
|
||||
span.to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub fn enforce_div<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
match (left, right) {
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
@ -38,18 +38,16 @@ pub fn enforce_div<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
Ok(ConstrainedValue::Field(field_1.div(cs, &field_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span)?;
|
||||
enforce_div(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span)?;
|
||||
enforce_div(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
format!("{} / {}", val_1, val_2,),
|
||||
span,
|
||||
));
|
||||
}
|
||||
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||
format!("{} / {}", val_1, val_2,),
|
||||
span.to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub fn enforce_mul<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
match (left, right) {
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
@ -38,18 +38,16 @@ pub fn enforce_mul<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
Ok(ConstrainedValue::Field(field_1.mul(cs, &field_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span)?;
|
||||
enforce_mul(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span)?;
|
||||
enforce_mul(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
format!("{} * {}", val_1, val_2),
|
||||
span,
|
||||
));
|
||||
}
|
||||
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||
format!("{} * {}", val_1, val_2),
|
||||
span.to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -27,12 +27,15 @@ use snarkos_models::{
|
||||
pub fn enforce_negate<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
||||
cs: &mut CS,
|
||||
value: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
match value {
|
||||
ConstrainedValue::Integer(integer) => Ok(ConstrainedValue::Integer(integer.negate(cs, span)?)),
|
||||
ConstrainedValue::Field(field) => Ok(ConstrainedValue::Field(field.negate(cs, span)?)),
|
||||
ConstrainedValue::Group(group) => Ok(ConstrainedValue::Group(group.negate(cs, span)?)),
|
||||
value => Err(ExpressionError::incompatible_types(format!("-{}", value), span)),
|
||||
value => Err(ExpressionError::incompatible_types(
|
||||
format!("-{}", value),
|
||||
span.to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -28,23 +28,23 @@ pub fn enforce_pow<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
match (left, right) {
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
Ok(ConstrainedValue::Integer(num_1.pow(cs, num_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span)?;
|
||||
enforce_pow(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span)?;
|
||||
enforce_pow(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||
format!("{} ** {}", val_1, val_2,),
|
||||
span,
|
||||
span.to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ pub fn enforce_sub<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
match (left, right) {
|
||||
(ConstrainedValue::Integer(num_1), ConstrainedValue::Integer(num_2)) => {
|
||||
@ -41,16 +41,16 @@ pub fn enforce_sub<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
Ok(ConstrainedValue::Group(point_1.sub(cs, &point_2, span)?))
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, &span)?;
|
||||
enforce_sub(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, &span)?;
|
||||
enforce_sub(cs, val_1, val_2, span)
|
||||
}
|
||||
(val_1, val_2) => Err(ExpressionError::incompatible_types(
|
||||
format!("{} - {}", val_1, val_2),
|
||||
span,
|
||||
span.to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
@ -25,40 +25,30 @@ use snarkos_models::{
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_array_access<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
array: Box<Expression>,
|
||||
array: Expression,
|
||||
index: RangeOrExpression,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let array = match self.enforce_operand(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type,
|
||||
*array,
|
||||
span.clone(),
|
||||
)? {
|
||||
let array = match self.enforce_operand(cs, file_scope, function_scope, expected_type, array, span)? {
|
||||
ConstrainedValue::Array(array) => array,
|
||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span)),
|
||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
||||
};
|
||||
|
||||
match index {
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_resolved = match from {
|
||||
Some(from_index) => {
|
||||
self.enforce_index(cs, file_scope.clone(), function_scope.clone(), from_index, span.clone())?
|
||||
}
|
||||
Some(from_index) => self.enforce_index(cs, file_scope, function_scope, from_index, span)?,
|
||||
None => 0usize, // Array slice starts at index 0
|
||||
};
|
||||
let to_resolved = match to {
|
||||
Some(to_index) => {
|
||||
self.enforce_index(cs, file_scope.clone(), function_scope.clone(), to_index, span.clone())?
|
||||
}
|
||||
Some(to_index) => self.enforce_index(cs, file_scope, function_scope, to_index, span)?,
|
||||
None => array.len(), // Array slice ends at array length
|
||||
};
|
||||
Ok(ConstrainedValue::Array(array[from_resolved..to_resolved].to_owned()))
|
||||
|
@ -34,10 +34,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_array<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
mut expected_type: Option<Type>,
|
||||
array: Vec<Box<SpreadOrExpression>>,
|
||||
array: Vec<SpreadOrExpression>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// Check explicit array type dimension if given
|
||||
@ -47,12 +47,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
match type_ {
|
||||
Type::Array(ref type_, ref dimensions) => {
|
||||
let number = match dimensions.first() {
|
||||
Some(number) => number.clone(),
|
||||
Some(number) => *number,
|
||||
None => return Err(ExpressionError::unexpected_array(type_.to_string(), span)),
|
||||
};
|
||||
|
||||
expected_dimensions.push(number);
|
||||
expected_type = Some(type_.outer_dimension(dimensions).clone());
|
||||
expected_type = Some(type_.outer_dimension(dimensions));
|
||||
}
|
||||
ref type_ => {
|
||||
return Err(ExpressionError::unexpected_array(type_.to_string(), span));
|
||||
@ -62,10 +62,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
let mut result = vec![];
|
||||
for element in array.into_iter() {
|
||||
match *element {
|
||||
match element {
|
||||
SpreadOrExpression::Spread(spread) => match spread {
|
||||
Expression::Identifier(identifier) => {
|
||||
let array_name = new_scope(function_scope.clone(), identifier.to_string());
|
||||
let array_name = new_scope(&function_scope, &identifier.name);
|
||||
match self.get(&array_name) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Array(array) => result.extend(array.clone()),
|
||||
@ -79,8 +79,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
SpreadOrExpression::Expression(expression) => {
|
||||
result.push(self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type.clone(),
|
||||
expression,
|
||||
)?);
|
||||
@ -89,14 +89,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
|
||||
// Check expected_dimensions if given
|
||||
if !expected_dimensions.is_empty() {
|
||||
if expected_dimensions[expected_dimensions.len() - 1] != result.len() {
|
||||
return Err(ExpressionError::invalid_length(
|
||||
expected_dimensions[expected_dimensions.len() - 1],
|
||||
result.len(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
if !expected_dimensions.is_empty() && expected_dimensions[expected_dimensions.len() - 1] != result.len() {
|
||||
return Err(ExpressionError::invalid_length(
|
||||
expected_dimensions[expected_dimensions.len() - 1],
|
||||
result.len(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::Array(result))
|
||||
|
@ -28,22 +28,15 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub(crate) fn enforce_index<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
index: Expression,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<usize, ExpressionError> {
|
||||
let expected_type = Some(Type::IntegerType(IntegerType::U32));
|
||||
match self.enforce_operand(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type,
|
||||
index,
|
||||
span.clone(),
|
||||
)? {
|
||||
ConstrainedValue::Integer(number) => Ok(number.to_usize(span.clone())?),
|
||||
value => Err(ExpressionError::invalid_index(value.to_string(), span)),
|
||||
match self.enforce_operand(cs, file_scope, function_scope, expected_type, index, &span)? {
|
||||
ConstrainedValue::Integer(number) => Ok(number.to_usize(span)?),
|
||||
value => Err(ExpressionError::invalid_index(value.to_string(), span.to_owned())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,33 +24,24 @@ use snarkos_models::{
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
type ConstrainedValuePair<T, U> = (ConstrainedValue<T, U>, ConstrainedValue<T, U>);
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_binary_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
left: Expression,
|
||||
right: Expression,
|
||||
span: Span,
|
||||
) -> Result<(ConstrainedValue<F, G>, ConstrainedValue<F, G>), ExpressionError> {
|
||||
let mut resolved_left = self.enforce_operand(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type.clone(),
|
||||
left,
|
||||
span.clone(),
|
||||
)?;
|
||||
let mut resolved_right = self.enforce_operand(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type.clone(),
|
||||
right,
|
||||
span.clone(),
|
||||
)?;
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValuePair<F, G>, ExpressionError> {
|
||||
let mut resolved_left =
|
||||
self.enforce_operand(cs, file_scope, function_scope, expected_type.clone(), left, span)?;
|
||||
let mut resolved_right =
|
||||
self.enforce_operand(cs, file_scope, function_scope, expected_type.clone(), right, span)?;
|
||||
|
||||
resolved_left.resolve_types(&mut resolved_right, expected_type, span)?;
|
||||
|
||||
|
@ -31,11 +31,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_operand<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
expression: Expression,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let mut branch = self.enforce_expression(cs, file_scope, function_scope, expected_type.clone(), expression)?;
|
||||
|
||||
|
@ -29,43 +29,38 @@ use snarkos_models::{
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
static SELF_KEYWORD: &'static str = "self";
|
||||
static SELF_KEYWORD: &str = "self";
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_circuit_access<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
circuit_identifier: Box<Expression>,
|
||||
circuit_identifier: Expression,
|
||||
circuit_member: Identifier,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// access a circuit member using the `self` keyword
|
||||
if let Expression::Identifier(ref identifier) = *circuit_identifier {
|
||||
if let Expression::Identifier(ref identifier) = circuit_identifier {
|
||||
if identifier.is_self() {
|
||||
let self_file_scope = new_scope(file_scope.clone(), identifier.name.to_string());
|
||||
let self_function_scope = new_scope(self_file_scope.clone(), identifier.name.to_string());
|
||||
let self_file_scope = new_scope(&file_scope, &identifier.name);
|
||||
let self_function_scope = new_scope(&self_file_scope, &identifier.name);
|
||||
|
||||
let member_value =
|
||||
self.evaluate_identifier(self_file_scope, self_function_scope, None, circuit_member.clone())?;
|
||||
self.evaluate_identifier(&self_file_scope, &self_function_scope, None, circuit_member)?;
|
||||
|
||||
return Ok(member_value);
|
||||
}
|
||||
}
|
||||
|
||||
let (circuit_name, members) = match self.enforce_operand(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type,
|
||||
*circuit_identifier.clone(),
|
||||
span.clone(),
|
||||
)? {
|
||||
ConstrainedValue::CircuitExpression(name, members) => (name, members),
|
||||
value => return Err(ExpressionError::undefined_circuit(value.to_string(), span)),
|
||||
};
|
||||
let (circuit_name, members) =
|
||||
match self.enforce_operand(cs, file_scope, function_scope, expected_type, circuit_identifier, &span)? {
|
||||
ConstrainedValue::CircuitExpression(name, members) => (name, members),
|
||||
value => return Err(ExpressionError::undefined_circuit(value.to_string(), span)),
|
||||
};
|
||||
|
||||
let matched_member = members.clone().into_iter().find(|member| member.0 == circuit_member);
|
||||
|
||||
@ -75,9 +70,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
ConstrainedValue::Function(ref _circuit_identifier, ref _function) => {
|
||||
// Pass circuit members into function call by value
|
||||
for stored_member in members {
|
||||
let circuit_scope = new_scope(file_scope.clone(), circuit_name.to_string());
|
||||
let self_keyword = new_scope(circuit_scope, SELF_KEYWORD.to_string());
|
||||
let variable = new_scope(self_keyword, stored_member.0.to_string());
|
||||
let circuit_scope = new_scope(&file_scope, &circuit_name.name);
|
||||
let self_keyword = new_scope(&circuit_scope, SELF_KEYWORD);
|
||||
let variable = new_scope(&self_keyword, &stored_member.0.name);
|
||||
|
||||
self.store(variable, stored_member.1.clone());
|
||||
}
|
||||
|
@ -33,29 +33,30 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_circuit<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
identifier: Identifier,
|
||||
members: Vec<CircuitVariableDefinition>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// Circuit definitions are located at the minimum file scope
|
||||
let scopes: Vec<&str> = file_scope.split("_").collect();
|
||||
let mut program_identifier = new_scope(scopes[0].to_string(), identifier.to_string());
|
||||
let minimum_scope = file_scope.split('_').next().unwrap();
|
||||
let identifier_string = identifier.to_string();
|
||||
let mut program_identifier = new_scope(minimum_scope, &identifier_string);
|
||||
|
||||
if identifier.is_self() {
|
||||
program_identifier = file_scope.clone();
|
||||
program_identifier = file_scope.to_string();
|
||||
}
|
||||
|
||||
let circuit = match self.get(&program_identifier) {
|
||||
Some(value) => value.clone().extract_circuit(span.clone())?,
|
||||
Some(value) => value.clone().extract_circuit(&span)?,
|
||||
None => return Err(ExpressionError::undefined_circuit(identifier.to_string(), span)),
|
||||
};
|
||||
|
||||
let circuit_identifier = circuit.circuit_name.clone();
|
||||
let mut resolved_members = vec![];
|
||||
let mut resolved_members = Vec::with_capacity(circuit.members.len());
|
||||
|
||||
for member in circuit.members.clone().into_iter() {
|
||||
for member in circuit.members.into_iter() {
|
||||
match member {
|
||||
CircuitMember::CircuitVariable(is_mutable, identifier, type_) => {
|
||||
let matched_variable = members
|
||||
@ -67,8 +68,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Resolve and enforce circuit variable
|
||||
let mut variable_value = self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
Some(type_.clone()),
|
||||
variable.expression,
|
||||
)?;
|
||||
@ -98,7 +99,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::CircuitExpression(
|
||||
circuit_identifier.clone(),
|
||||
circuit_identifier,
|
||||
resolved_members,
|
||||
))
|
||||
}
|
||||
|
@ -25,39 +25,34 @@ use snarkos_models::{
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_circuit_static_access<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
circuit_identifier: Box<Expression>,
|
||||
circuit_identifier: Expression,
|
||||
circuit_member: Identifier,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// Get defined circuit
|
||||
let circuit = match *circuit_identifier.clone() {
|
||||
let circuit = match circuit_identifier {
|
||||
Expression::Identifier(identifier) => {
|
||||
// Use the "Self" keyword to access a static circuit function
|
||||
if identifier.is_self() {
|
||||
let circuit = self
|
||||
.get(&file_scope)
|
||||
.ok_or(ExpressionError::self_keyword(identifier.span.clone()))?;
|
||||
.ok_or_else(|| ExpressionError::self_keyword(identifier.span))?;
|
||||
|
||||
circuit.to_owned()
|
||||
} else {
|
||||
self.evaluate_identifier(file_scope.clone(), function_scope.clone(), expected_type, identifier)?
|
||||
self.evaluate_identifier(&file_scope, &function_scope, expected_type, identifier)?
|
||||
}
|
||||
}
|
||||
expression => self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type,
|
||||
expression,
|
||||
)?,
|
||||
expression => self.enforce_expression(cs, file_scope, function_scope, expected_type, expression)?,
|
||||
}
|
||||
.extract_circuit(span.clone())?;
|
||||
.extract_circuit(&span)?;
|
||||
|
||||
// Find static circuit function
|
||||
let matched_function = circuit.members.into_iter().find(|member| match member {
|
||||
|
@ -26,45 +26,27 @@ use snarkos_models::{
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
/// Enforce ternary conditional expression
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_conditional_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
conditional: Expression,
|
||||
first: Expression,
|
||||
second: Expression,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let conditional_value = match self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
Some(Type::Boolean),
|
||||
conditional,
|
||||
)? {
|
||||
ConstrainedValue::Boolean(resolved) => resolved,
|
||||
value => return Err(ExpressionError::conditional_boolean(value.to_string(), span)),
|
||||
};
|
||||
let conditional_value =
|
||||
match self.enforce_expression(cs, file_scope, function_scope, Some(Type::Boolean), conditional)? {
|
||||
ConstrainedValue::Boolean(resolved) => resolved,
|
||||
value => return Err(ExpressionError::conditional_boolean(value.to_string(), span.to_owned())),
|
||||
};
|
||||
|
||||
let first_value = self.enforce_operand(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type.clone(),
|
||||
first,
|
||||
span.clone(),
|
||||
)?;
|
||||
let first_value = self.enforce_operand(cs, file_scope, function_scope, expected_type.clone(), first, span)?;
|
||||
|
||||
let second_value = self.enforce_operand(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type,
|
||||
second,
|
||||
span.clone(),
|
||||
)?;
|
||||
let second_value = self.enforce_operand(cs, file_scope, function_scope, expected_type, second, span)?;
|
||||
|
||||
let unique_namespace = cs.ns(|| {
|
||||
format!(
|
||||
@ -74,6 +56,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
});
|
||||
|
||||
ConstrainedValue::conditionally_select(unique_namespace, &conditional_value, &first_value, &second_value)
|
||||
.map_err(|e| ExpressionError::cannot_enforce(format!("conditional select"), e, span))
|
||||
.map_err(|e| ExpressionError::cannot_enforce("conditional select".to_string(), e, span.to_owned()))
|
||||
}
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub(crate) fn enforce_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
expression: Expression,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
@ -51,86 +51,86 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
|
||||
// Values
|
||||
Expression::Address(address, span) => Ok(ConstrainedValue::Address(Address::constant(address, span)?)),
|
||||
Expression::Boolean(boolean, span) => Ok(ConstrainedValue::Boolean(new_bool_constant(boolean, span)?)),
|
||||
Expression::Field(field, span) => Ok(ConstrainedValue::Field(FieldType::constant(field, span)?)),
|
||||
Expression::Group(group_element) => Ok(ConstrainedValue::Group(G::constant(group_element)?)),
|
||||
Expression::Implicit(value, span) => Ok(enforce_number_implicit(expected_type, value, span)?),
|
||||
Expression::Integer(type_, integer, span) => {
|
||||
Ok(ConstrainedValue::Integer(Integer::new_constant(&type_, integer, span)?))
|
||||
}
|
||||
Expression::Address(address, span) => Ok(ConstrainedValue::Address(Address::constant(address, &span)?)),
|
||||
Expression::Boolean(boolean, span) => Ok(ConstrainedValue::Boolean(new_bool_constant(boolean, &span)?)),
|
||||
Expression::Field(field, span) => Ok(ConstrainedValue::Field(FieldType::constant(field, &span)?)),
|
||||
Expression::Group(group_element) => Ok(ConstrainedValue::Group(G::constant(*group_element)?)),
|
||||
Expression::Implicit(value, span) => Ok(enforce_number_implicit(expected_type, value, &span)?),
|
||||
Expression::Integer(type_, integer, span) => Ok(ConstrainedValue::Integer(Integer::new_constant(
|
||||
&type_, integer, &span,
|
||||
)?)),
|
||||
|
||||
// Binary operations
|
||||
Expression::Negate(expression, span) => {
|
||||
let resolved_value =
|
||||
self.enforce_expression(cs, file_scope, function_scope, expected_type, *expression)?;
|
||||
|
||||
enforce_negate(cs, resolved_value, span)
|
||||
enforce_negate(cs, resolved_value, &span)
|
||||
}
|
||||
Expression::Add(left, right, span) => {
|
||||
Expression::Add(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
enforce_add(cs, resolved_left, resolved_right, span)
|
||||
enforce_add(cs, resolved_left, resolved_right, &span)
|
||||
}
|
||||
Expression::Sub(left, right, span) => {
|
||||
Expression::Sub(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
enforce_sub(cs, resolved_left, resolved_right, span)
|
||||
enforce_sub(cs, resolved_left, resolved_right, &span)
|
||||
}
|
||||
Expression::Mul(left, right, span) => {
|
||||
Expression::Mul(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
enforce_mul(cs, resolved_left, resolved_right, span)
|
||||
enforce_mul(cs, resolved_left, resolved_right, &span)
|
||||
}
|
||||
Expression::Div(left, right, span) => {
|
||||
Expression::Div(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
enforce_div(cs, resolved_left, resolved_right, span)
|
||||
enforce_div(cs, resolved_left, resolved_right, &span)
|
||||
}
|
||||
Expression::Pow(left, right, span) => {
|
||||
Expression::Pow(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
enforce_pow(cs, resolved_left, resolved_right, span)
|
||||
enforce_pow(cs, resolved_left, resolved_right, &span)
|
||||
}
|
||||
|
||||
// Boolean operations
|
||||
@ -138,124 +138,130 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
self.enforce_expression(cs, file_scope, function_scope, expected_type, *expression)?,
|
||||
span,
|
||||
)?),
|
||||
Expression::Or(left, right, span) => {
|
||||
Expression::Or(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
Ok(enforce_or(cs, resolved_left, resolved_right, span)?)
|
||||
Ok(enforce_or(cs, resolved_left, resolved_right, &span)?)
|
||||
}
|
||||
Expression::And(left, right, span) => {
|
||||
Expression::And(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
Ok(enforce_and(cs, resolved_left, resolved_right, span)?)
|
||||
Ok(enforce_and(cs, resolved_left, resolved_right, &span)?)
|
||||
}
|
||||
Expression::Eq(left, right, span) => {
|
||||
Expression::Eq(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
None,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
Ok(evaluate_eq(cs, resolved_left, resolved_right, span)?)
|
||||
Ok(evaluate_eq(cs, resolved_left, resolved_right, &span)?)
|
||||
}
|
||||
Expression::Ge(left, right, span) => {
|
||||
Expression::Ge(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
None,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
Ok(evaluate_ge(cs, resolved_left, resolved_right, span)?)
|
||||
Ok(evaluate_ge(cs, resolved_left, resolved_right, &span)?)
|
||||
}
|
||||
Expression::Gt(left, right, span) => {
|
||||
Expression::Gt(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
None,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
Ok(evaluate_gt(cs, resolved_left, resolved_right, span)?)
|
||||
Ok(evaluate_gt(cs, resolved_left, resolved_right, &span)?)
|
||||
}
|
||||
Expression::Le(left, right, span) => {
|
||||
Expression::Le(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
None,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
Ok(evaluate_le(cs, resolved_left, resolved_right, span)?)
|
||||
Ok(evaluate_le(cs, resolved_left, resolved_right, &span)?)
|
||||
}
|
||||
Expression::Lt(left, right, span) => {
|
||||
Expression::Lt(left_right, span) => {
|
||||
let (resolved_left, resolved_right) = self.enforce_binary_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
None,
|
||||
*left,
|
||||
*right,
|
||||
span.clone(),
|
||||
left_right.0,
|
||||
left_right.1,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
Ok(evaluate_lt(cs, resolved_left, resolved_right, span)?)
|
||||
Ok(evaluate_lt(cs, resolved_left, resolved_right, &span)?)
|
||||
}
|
||||
|
||||
// Conditionals
|
||||
Expression::IfElse(conditional, first, second, span) => self.enforce_conditional_expression(
|
||||
Expression::IfElse(triplet, span) => self.enforce_conditional_expression(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
*conditional,
|
||||
*first,
|
||||
*second,
|
||||
span,
|
||||
triplet.0,
|
||||
triplet.1,
|
||||
triplet.2,
|
||||
&span,
|
||||
),
|
||||
|
||||
// Arrays
|
||||
Expression::Array(array, span) => {
|
||||
self.enforce_array(cs, file_scope, function_scope, expected_type, array, span)
|
||||
}
|
||||
Expression::ArrayAccess(array, index, span) => {
|
||||
self.enforce_array_access(cs, file_scope, function_scope, expected_type, array, *index, span)
|
||||
}
|
||||
Expression::ArrayAccess(array_w_index, span) => self.enforce_array_access(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
array_w_index.0,
|
||||
array_w_index.1,
|
||||
&span,
|
||||
),
|
||||
|
||||
// Tuples
|
||||
Expression::Tuple(tuple, span) => {
|
||||
self.enforce_tuple(cs, file_scope, function_scope, expected_type, tuple, span)
|
||||
}
|
||||
Expression::TupleAccess(tuple, index, span) => {
|
||||
self.enforce_tuple_access(cs, file_scope, function_scope, expected_type, tuple, index, span)
|
||||
self.enforce_tuple_access(cs, file_scope, function_scope, expected_type, *tuple, index, &span)
|
||||
}
|
||||
|
||||
// Circuits
|
||||
@ -267,7 +273,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
circuit_variable,
|
||||
*circuit_variable,
|
||||
circuit_member,
|
||||
span,
|
||||
),
|
||||
@ -277,7 +283,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
circuit_identifier,
|
||||
*circuit_identifier,
|
||||
circuit_member,
|
||||
span,
|
||||
),
|
||||
@ -288,7 +294,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
function,
|
||||
*function,
|
||||
arguments,
|
||||
span,
|
||||
),
|
||||
|
@ -25,21 +25,21 @@ use snarkos_models::{
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
/// Call a default core circuit function with arguments
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_core_circuit_call_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
core_circuit: String,
|
||||
arguments: Vec<Expression>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// Get the value of each core function argument
|
||||
let mut argument_values = vec![];
|
||||
let mut argument_values = Vec::with_capacity(arguments.len());
|
||||
for argument in arguments.into_iter() {
|
||||
let argument_value =
|
||||
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), None, argument)?;
|
||||
let argument_value = self.enforce_expression(cs, file_scope, function_scope, None, argument)?;
|
||||
let core_function_argument = argument_value.to_value();
|
||||
|
||||
argument_values.push(core_function_argument);
|
||||
@ -49,10 +49,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let res = call_core_circuit(cs, core_circuit, argument_values, span.clone())?;
|
||||
|
||||
// Convert the core function returns into constrained values
|
||||
let returns = res
|
||||
.into_iter()
|
||||
.map(|value| ConstrainedValue::from(value))
|
||||
.collect::<Vec<_>>();
|
||||
let returns = res.into_iter().map(ConstrainedValue::from).collect::<Vec<_>>();
|
||||
|
||||
let return_value = if returns.len() == 1 {
|
||||
// The function has a single return
|
||||
@ -64,7 +61,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
// Check that function returns expected type
|
||||
if let Some(expected) = expected_type {
|
||||
let actual = return_value.to_type(span.clone())?;
|
||||
let actual = return_value.to_type(&span)?;
|
||||
if expected.ne(&actual) {
|
||||
return Err(ExpressionError::FunctionError(Box::new(
|
||||
FunctionError::return_argument_type(expected.to_string(), actual.to_string(), span),
|
||||
@ -72,6 +69,6 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(return_value);
|
||||
Ok(return_value)
|
||||
}
|
||||
}
|
||||
|
@ -25,59 +25,62 @@ use snarkos_models::{
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_function_call_expression<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
function: Box<Expression>,
|
||||
function: Expression,
|
||||
arguments: Vec<Expression>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let (declared_circuit_reference, function_value) = match *function.clone() {
|
||||
let (declared_circuit_reference, function_value) = match function {
|
||||
Expression::CircuitMemberAccess(circuit_identifier, circuit_member, span) => {
|
||||
// Call a circuit function that can mutate self.
|
||||
|
||||
// Save a reference to the circuit we are mutating.
|
||||
let circuit_id_string = format!("{}", circuit_identifier);
|
||||
let declared_circuit_reference = new_scope(function_scope.clone(), circuit_id_string);
|
||||
let circuit_id_string = circuit_identifier.to_string();
|
||||
let declared_circuit_reference = new_scope(function_scope, &circuit_id_string);
|
||||
|
||||
(
|
||||
declared_circuit_reference,
|
||||
self.enforce_circuit_access(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
expected_type,
|
||||
circuit_identifier,
|
||||
*circuit_identifier,
|
||||
circuit_member,
|
||||
span,
|
||||
)?,
|
||||
)
|
||||
}
|
||||
function => (
|
||||
function_scope.clone(),
|
||||
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), expected_type, function)?,
|
||||
function_scope.to_string(),
|
||||
self.enforce_expression(cs, file_scope, function_scope, expected_type, function)?,
|
||||
),
|
||||
};
|
||||
|
||||
let (outer_scope, function_call) = function_value.extract_function(file_scope.clone(), span.clone())?;
|
||||
let (outer_scope, function_call) = function_value.extract_function(file_scope, &span)?;
|
||||
|
||||
let name_unique = format!(
|
||||
"function call {} {}:{}",
|
||||
function_call.get_name(),
|
||||
span.line,
|
||||
span.start,
|
||||
);
|
||||
let name_unique = || {
|
||||
format!(
|
||||
"function call {} {}:{}",
|
||||
function_call.get_name(),
|
||||
span.line,
|
||||
span.start,
|
||||
)
|
||||
};
|
||||
|
||||
self.enforce_function(
|
||||
&mut cs.ns(|| name_unique),
|
||||
outer_scope,
|
||||
&mut cs.ns(name_unique),
|
||||
&outer_scope,
|
||||
function_scope,
|
||||
function_call,
|
||||
arguments,
|
||||
declared_circuit_reference,
|
||||
&declared_circuit_reference,
|
||||
)
|
||||
.map_err(|error| ExpressionError::from(Box::new(error)))
|
||||
}
|
||||
|
@ -31,14 +31,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
/// Enforce a variable expression by getting the resolved value
|
||||
pub fn evaluate_identifier(
|
||||
&mut self,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
unresolved_identifier: Identifier,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
// Evaluate the identifier name in the current function scope
|
||||
let variable_name = new_scope(function_scope.clone(), unresolved_identifier.to_string());
|
||||
let identifier_name = new_scope(file_scope, unresolved_identifier.to_string());
|
||||
let variable_name = new_scope(function_scope, &unresolved_identifier.name);
|
||||
let identifier_name = new_scope(file_scope, &unresolved_identifier.name);
|
||||
|
||||
let mut result_value = if let Some(value) = self.get(&variable_name) {
|
||||
// Reassigning variable to another variable
|
||||
@ -51,14 +51,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
value.clone()
|
||||
} else if expected_type.is_some() && expected_type.unwrap() == Type::Address {
|
||||
// If we expect an address type, try to return an address
|
||||
let address = Address::constant(unresolved_identifier.name, unresolved_identifier.span)?;
|
||||
let address = Address::constant(unresolved_identifier.name, &unresolved_identifier.span)?;
|
||||
|
||||
return Ok(ConstrainedValue::Address(address));
|
||||
} else {
|
||||
return Err(ExpressionError::undefined_identifier(unresolved_identifier));
|
||||
};
|
||||
|
||||
result_value.resolve_type(expected_type, unresolved_identifier.span.clone())?;
|
||||
result_value.resolve_type(expected_type, &unresolved_identifier.span)?;
|
||||
|
||||
Ok(result_value)
|
||||
}
|
||||
|
@ -28,17 +28,20 @@ pub fn enforce_and<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, BooleanError> {
|
||||
let name = format!("{} && {}", left, right);
|
||||
|
||||
if let (ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) = (left, right) {
|
||||
let name_unique = format!("{} {}:{}", name, span.line, span.start);
|
||||
let result = Boolean::and(cs.ns(|| name_unique), &left_bool, &right_bool)
|
||||
.map_err(|e| BooleanError::cannot_enforce(format!("&&"), e, span))?;
|
||||
let result = Boolean::and(
|
||||
cs.ns(|| format!("{} {}:{}", name, span.line, span.start)),
|
||||
&left_bool,
|
||||
&right_bool,
|
||||
)
|
||||
.map_err(|e| BooleanError::cannot_enforce("&&".to_string(), e, span.to_owned()))?;
|
||||
|
||||
return Ok(ConstrainedValue::Boolean(result));
|
||||
}
|
||||
|
||||
Err(BooleanError::cannot_evaluate(name, span))
|
||||
Err(BooleanError::cannot_evaluate(name, span.to_owned()))
|
||||
}
|
||||
|
@ -28,17 +28,20 @@ pub fn enforce_or<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, BooleanError> {
|
||||
let name = format!("{} || {}", left, right);
|
||||
|
||||
if let (ConstrainedValue::Boolean(left_bool), ConstrainedValue::Boolean(right_bool)) = (left, right) {
|
||||
let name_unique = format!("{} {}:{}", name, span.line, span.start);
|
||||
let result = Boolean::or(cs.ns(|| name_unique), &left_bool, &right_bool)
|
||||
.map_err(|e| BooleanError::cannot_enforce(format!("||"), e, span))?;
|
||||
let result = Boolean::or(
|
||||
cs.ns(|| format!("{} {}:{}", name, span.line, span.start)),
|
||||
&left_bool,
|
||||
&right_bool,
|
||||
)
|
||||
.map_err(|e| BooleanError::cannot_enforce("||".to_string(), e, span.to_owned()))?;
|
||||
|
||||
return Ok(ConstrainedValue::Boolean(result));
|
||||
}
|
||||
|
||||
Err(BooleanError::cannot_evaluate(name, span))
|
||||
Err(BooleanError::cannot_evaluate(name, span.to_owned()))
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ pub fn evaluate_eq<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let namespace_string = format!("evaluate {} == {} {}:{}", left, right, span.line, span.start);
|
||||
let constraint_result = match (left, right) {
|
||||
@ -58,14 +58,9 @@ pub fn evaluate_eq<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
(ConstrainedValue::Array(arr_1), ConstrainedValue::Array(arr_2)) => {
|
||||
let mut current = ConstrainedValue::Boolean(Boolean::constant(true));
|
||||
for (i, (left, right)) in arr_1.into_iter().zip(arr_2.into_iter()).enumerate() {
|
||||
let next = evaluate_eq(&mut cs.ns(|| format!("array[{}]", i)), left, right, span.clone())?;
|
||||
let next = evaluate_eq(&mut cs.ns(|| format!("array[{}]", i)), left, right, span)?;
|
||||
|
||||
current = enforce_and(
|
||||
&mut cs.ns(|| format!("array result {}", i)),
|
||||
current,
|
||||
next,
|
||||
span.clone(),
|
||||
)?;
|
||||
current = enforce_and(&mut cs.ns(|| format!("array result {}", i)), current, next, span)?;
|
||||
}
|
||||
return Ok(current);
|
||||
}
|
||||
@ -73,36 +68,31 @@ pub fn evaluate_eq<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
let mut current = ConstrainedValue::Boolean(Boolean::constant(true));
|
||||
|
||||
for (i, (left, right)) in tuple_1.into_iter().zip(tuple_2.into_iter()).enumerate() {
|
||||
let next = evaluate_eq(&mut cs.ns(|| format!("tuple_index {}", i)), left, right, span.clone())?;
|
||||
let next = evaluate_eq(&mut cs.ns(|| format!("tuple_index {}", i)), left, right, span)?;
|
||||
|
||||
current = enforce_and(
|
||||
&mut cs.ns(|| format!("array result {}", i)),
|
||||
current,
|
||||
next,
|
||||
span.clone(),
|
||||
)?;
|
||||
current = enforce_and(&mut cs.ns(|| format!("array result {}", i)), current, next, span)?;
|
||||
}
|
||||
return Ok(current);
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let mut unique_namespace = cs.ns(|| namespace_string);
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span)?;
|
||||
return evaluate_eq(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let mut unique_namespace = cs.ns(|| namespace_string);
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span)?;
|
||||
return evaluate_eq(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
format!("{} == {}", val_1, val_2,),
|
||||
span,
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate(format!("=="), span))?;
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate("==".to_string(), span.to_owned()))?;
|
||||
|
||||
Ok(ConstrainedValue::Boolean(boolean))
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ pub fn evaluate_ge<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let mut unique_namespace = cs.ns(|| format!("evaluate {} >= {} {}:{}", left, right, span.line, span.start));
|
||||
let constraint_result = match (left, right) {
|
||||
@ -37,22 +37,22 @@ pub fn evaluate_ge<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
num_1.greater_than_or_equal(unique_namespace, &num_2)
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span)?;
|
||||
return evaluate_ge(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span)?;
|
||||
return evaluate_ge(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
format!("{} >= {}", val_1, val_2),
|
||||
span,
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate(format!(">="), span))?;
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate(">=".to_string(), span.to_owned()))?;
|
||||
|
||||
Ok(ConstrainedValue::Boolean(boolean))
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ pub fn evaluate_gt<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let mut unique_namespace = cs.ns(|| format!("evaluate {} > {} {}:{}", left, right, span.line, span.start));
|
||||
let constraint_result = match (left, right) {
|
||||
@ -37,22 +37,22 @@ pub fn evaluate_gt<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
num_1.greater_than(unique_namespace, &num_2)
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span)?;
|
||||
return evaluate_gt(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span)?;
|
||||
return evaluate_gt(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
format!("{} > {}", val_1, val_2),
|
||||
span,
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate(format!(">"), span))?;
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate(">".to_string(), span.to_owned()))?;
|
||||
|
||||
Ok(ConstrainedValue::Boolean(boolean))
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ pub fn evaluate_le<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let mut unique_namespace = cs.ns(|| format!("evaluate {} <= {} {}:{}", left, right, span.line, span.start));
|
||||
let constraint_result = match (left, right) {
|
||||
@ -37,22 +37,22 @@ pub fn evaluate_le<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
num_1.less_than_or_equal(unique_namespace, &num_2)
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span)?;
|
||||
return evaluate_le(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span)?;
|
||||
return evaluate_le(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
format!("{} <= {}", val_1, val_2),
|
||||
span,
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate(format!("<="), span))?;
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate("<=".to_string(), span.to_owned()))?;
|
||||
|
||||
Ok(ConstrainedValue::Boolean(boolean))
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ pub fn evaluate_lt<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
cs: &mut CS,
|
||||
left: ConstrainedValue<F, G>,
|
||||
right: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let mut unique_namespace = cs.ns(|| format!("evaluate {} < {} {}:{}", left, right, span.line, span.start));
|
||||
let constraint_result = match (left, right) {
|
||||
@ -37,22 +37,22 @@ pub fn evaluate_lt<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<
|
||||
num_1.less_than(unique_namespace, &num_2)
|
||||
}
|
||||
(ConstrainedValue::Unresolved(string), val_2) => {
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span.clone())?;
|
||||
let val_1 = ConstrainedValue::from_other(string, &val_2, span)?;
|
||||
return evaluate_lt(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, ConstrainedValue::Unresolved(string)) => {
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span.clone())?;
|
||||
let val_2 = ConstrainedValue::from_other(string, &val_1, span)?;
|
||||
return evaluate_lt(&mut unique_namespace, val_1, val_2, span);
|
||||
}
|
||||
(val_1, val_2) => {
|
||||
return Err(ExpressionError::incompatible_types(
|
||||
format!("{} < {}", val_1, val_2),
|
||||
span,
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate(format!("<"), span))?;
|
||||
let boolean = constraint_result.map_err(|_| ExpressionError::cannot_evaluate("<".to_string(), span.to_owned()))?;
|
||||
|
||||
Ok(ConstrainedValue::Boolean(boolean))
|
||||
}
|
||||
|
@ -25,30 +25,24 @@ use snarkos_models::{
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_tuple_access<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
tuple: Box<Expression>,
|
||||
tuple: Expression,
|
||||
index: usize,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
|
||||
let tuple = match self.enforce_operand(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
expected_type,
|
||||
*tuple,
|
||||
span.clone(),
|
||||
)? {
|
||||
let tuple = match self.enforce_operand(cs, file_scope, function_scope, expected_type, tuple, &span)? {
|
||||
ConstrainedValue::Tuple(tuple) => tuple,
|
||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.clone())),
|
||||
value => return Err(ExpressionError::undefined_array(value.to_string(), span.to_owned())),
|
||||
};
|
||||
|
||||
if index > tuple.len() - 1 {
|
||||
return Err(ExpressionError::index_out_of_bounds(index, span));
|
||||
return Err(ExpressionError::index_out_of_bounds(index, span.to_owned()));
|
||||
}
|
||||
|
||||
Ok(tuple[index].to_owned())
|
||||
|
@ -29,8 +29,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_tuple<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expected_type: Option<Type>,
|
||||
tuple: Vec<Expression>,
|
||||
span: Span,
|
||||
@ -38,22 +38,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Check explicit tuple type dimension if given
|
||||
let mut expected_types = vec![];
|
||||
|
||||
if expected_type.is_some() {
|
||||
match expected_type.unwrap() {
|
||||
Type::Tuple(ref types) => {
|
||||
expected_types = types.clone();
|
||||
}
|
||||
ref type_ => {
|
||||
return Err(ExpressionError::unexpected_tuple(
|
||||
type_.to_string(),
|
||||
format!("{:?}", tuple),
|
||||
span,
|
||||
));
|
||||
}
|
||||
match expected_type {
|
||||
Some(Type::Tuple(ref types)) => {
|
||||
expected_types = types.clone();
|
||||
}
|
||||
Some(ref type_) => {
|
||||
return Err(ExpressionError::unexpected_tuple(
|
||||
type_.to_string(),
|
||||
format!("{:?}", tuple),
|
||||
span,
|
||||
));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
let mut result = vec![];
|
||||
let mut result = Vec::with_capacity(tuple.len());
|
||||
for (i, expression) in tuple.into_iter().enumerate() {
|
||||
let type_ = if expected_types.is_empty() {
|
||||
None
|
||||
@ -61,7 +60,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
Some(expected_types[i].clone())
|
||||
};
|
||||
|
||||
result.push(self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), type_, expression)?);
|
||||
result.push(self.enforce_expression(cs, file_scope, function_scope, type_, expression)?);
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::Tuple(result))
|
||||
|
@ -30,10 +30,10 @@ use snarkos_models::{
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
pub fn check_arguments_length(expected: usize, actual: usize, span: Span) -> Result<(), FunctionError> {
|
||||
pub fn check_arguments_length(expected: usize, actual: usize, span: &Span) -> Result<(), FunctionError> {
|
||||
// Make sure we are given the correct number of arguments
|
||||
if expected != actual {
|
||||
Err(FunctionError::arguments_length(expected, actual, span))
|
||||
Err(FunctionError::arguments_length(expected, actual, span.to_owned()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@ -43,39 +43,33 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub(crate) fn enforce_function<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
caller_scope: String,
|
||||
scope: &str,
|
||||
caller_scope: &str,
|
||||
function: Function,
|
||||
input: Vec<Expression>,
|
||||
declared_circuit_reference: String,
|
||||
declared_circuit_reference: &str,
|
||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||
let function_name = new_scope(scope.clone(), function.get_name());
|
||||
let function_name = new_scope(scope, function.get_name());
|
||||
|
||||
// Make sure we are given the correct number of input variables
|
||||
check_arguments_length(function.input.len(), input.len(), function.span.clone())?;
|
||||
check_arguments_length(function.input.len(), input.len(), &function.span)?;
|
||||
|
||||
// Store input values as new variables in resolved program
|
||||
for (input_model, input_expression) in function.input.clone().iter().zip(input.into_iter()) {
|
||||
for (input_model, input_expression) in function.input.iter().zip(input.into_iter()) {
|
||||
let (name, value) = match input_model {
|
||||
FunctionInput::InputKeyword(identifier) => {
|
||||
let input_value = self.enforce_function_input(
|
||||
cs,
|
||||
scope.clone(),
|
||||
caller_scope.clone(),
|
||||
function_name.clone(),
|
||||
None,
|
||||
input_expression,
|
||||
)?;
|
||||
let input_value =
|
||||
self.enforce_function_input(cs, scope, caller_scope, &function_name, None, input_expression)?;
|
||||
|
||||
(identifier.name.clone(), input_value)
|
||||
(&identifier.name, input_value)
|
||||
}
|
||||
FunctionInput::Variable(input_model) => {
|
||||
// First evaluate input expression
|
||||
let mut input_value = self.enforce_function_input(
|
||||
cs,
|
||||
scope.clone(),
|
||||
caller_scope.clone(),
|
||||
function_name.clone(),
|
||||
scope,
|
||||
caller_scope,
|
||||
&function_name,
|
||||
Some(input_model.type_.clone()),
|
||||
input_expression,
|
||||
)?;
|
||||
@ -84,12 +78,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
input_value = ConstrainedValue::Mutable(Box::new(input_value))
|
||||
}
|
||||
|
||||
(input_model.identifier.name.clone(), input_value)
|
||||
(&input_model.identifier.name, input_value)
|
||||
}
|
||||
};
|
||||
|
||||
// Store input as variable with {function_name}_{input_name}
|
||||
let input_program_identifier = new_scope(function_name.clone(), name);
|
||||
let input_program_identifier = new_scope(&function_name, &name);
|
||||
self.store(input_program_identifier, value);
|
||||
}
|
||||
|
||||
@ -99,12 +93,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
for statement in function.statements.iter() {
|
||||
let mut result = self.enforce_statement(
|
||||
cs,
|
||||
scope.clone(),
|
||||
function_name.clone(),
|
||||
scope,
|
||||
&function_name,
|
||||
None,
|
||||
statement.clone(),
|
||||
function.output.clone(),
|
||||
declared_circuit_reference.clone(),
|
||||
declared_circuit_reference,
|
||||
)?;
|
||||
|
||||
results.append(&mut result);
|
||||
@ -113,7 +107,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Conditionally select a result based on returned indicators
|
||||
let mut return_values = ConstrainedValue::Tuple(vec![]);
|
||||
|
||||
Self::conditionally_select_result(cs, &mut return_values, results, function.span.clone())?;
|
||||
Self::conditionally_select_result(cs, &mut return_values, results, &function.span)?;
|
||||
|
||||
if let ConstrainedValue::Tuple(ref returns) = return_values {
|
||||
let return_types = match function.output {
|
||||
|
@ -34,11 +34,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn allocate_array<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
name: String,
|
||||
name: &str,
|
||||
array_type: Type,
|
||||
array_dimensions: Vec<usize>,
|
||||
input_value: Option<InputValue>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||
let expected_length = array_dimensions[0];
|
||||
let mut array_value = vec![];
|
||||
@ -47,34 +47,33 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
Some(InputValue::Array(arr)) => {
|
||||
// Allocate each value in the current row
|
||||
for (i, value) in arr.into_iter().enumerate() {
|
||||
let value_name = new_scope(name.clone(), i.to_string());
|
||||
let value_name = new_scope(&name, &i.to_string());
|
||||
let value_type = array_type.outer_dimension(&array_dimensions);
|
||||
|
||||
array_value.push(self.allocate_main_function_input(
|
||||
cs,
|
||||
value_type,
|
||||
value_name,
|
||||
&value_name,
|
||||
Some(value),
|
||||
span.clone(),
|
||||
span,
|
||||
)?)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Allocate all row values as none
|
||||
for i in 0..expected_length {
|
||||
let value_name = new_scope(name.clone(), i.to_string());
|
||||
let value_name = new_scope(&name, &i.to_string());
|
||||
let value_type = array_type.outer_dimension(&array_dimensions);
|
||||
|
||||
array_value.push(self.allocate_main_function_input(
|
||||
cs,
|
||||
value_type,
|
||||
value_name,
|
||||
None,
|
||||
span.clone(),
|
||||
)?);
|
||||
array_value.push(self.allocate_main_function_input(cs, value_type, &value_name, None, span)?);
|
||||
}
|
||||
}
|
||||
_ => return Err(FunctionError::invalid_array(input_value.unwrap().to_string(), span)),
|
||||
_ => {
|
||||
return Err(FunctionError::invalid_array(
|
||||
input_value.unwrap().to_string(),
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::Array(array_value))
|
||||
|
@ -29,9 +29,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_function_input<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
caller_scope: String,
|
||||
function_name: String,
|
||||
scope: &str,
|
||||
caller_scope: &str,
|
||||
function_name: &str,
|
||||
expected_type: Option<Type>,
|
||||
input: Expression,
|
||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||
|
@ -62,14 +62,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
// Allocate each input variable as a circuit expression
|
||||
|
||||
let mut sections = vec![];
|
||||
let mut sections = Vec::with_capacity(4);
|
||||
|
||||
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![];
|
||||
let mut members = Vec::with_capacity(sections.len());
|
||||
|
||||
for (name, values) in sections {
|
||||
let member_name = name.clone();
|
||||
|
@ -30,7 +30,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
identifier: Identifier,
|
||||
section: HashMap<Parameter, Option<InputValue>>,
|
||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||
let mut members = vec![];
|
||||
let mut members = Vec::with_capacity(section.len());
|
||||
|
||||
// Allocate each section definition as a circuit member value
|
||||
|
||||
@ -39,9 +39,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let member_value = self.allocate_main_function_input(
|
||||
cs,
|
||||
parameter.type_,
|
||||
parameter.variable.name,
|
||||
¶meter.variable.name,
|
||||
option,
|
||||
parameter.span,
|
||||
¶meter.span,
|
||||
)?;
|
||||
let member = ConstrainedCircuitMember(member_name, member_value);
|
||||
|
||||
|
@ -42,9 +42,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
type_: Type,
|
||||
name: String,
|
||||
name: &str,
|
||||
input_option: Option<InputValue>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||
match type_ {
|
||||
Type::Address => Ok(Address::from_input(cs, name, input_option, span)?),
|
||||
@ -59,7 +59,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
span,
|
||||
)?)),
|
||||
Type::Array(type_, dimensions) => self.allocate_array(cs, name, *type_, dimensions, input_option, span),
|
||||
Type::Tuple(types) => self.allocate_tuple(cs, name, types, input_option, span),
|
||||
Type::Tuple(types) => self.allocate_tuple(cs, &name, types, input_option, span),
|
||||
_ => unimplemented!("main function input not implemented for type"),
|
||||
}
|
||||
}
|
||||
|
@ -34,10 +34,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn allocate_tuple<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
name: String,
|
||||
name: &str,
|
||||
types: Vec<Type>,
|
||||
input_value: Option<InputValue>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, FunctionError> {
|
||||
let mut tuple_values = vec![];
|
||||
|
||||
@ -45,26 +45,25 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
Some(InputValue::Tuple(values)) => {
|
||||
// Allocate each value in the tuple
|
||||
for (i, (value, type_)) in values.into_iter().zip(types.into_iter()).enumerate() {
|
||||
let value_name = new_scope(name.clone(), i.to_string());
|
||||
let value_name = new_scope(name, &i.to_string());
|
||||
|
||||
tuple_values.push(self.allocate_main_function_input(
|
||||
cs,
|
||||
type_,
|
||||
value_name,
|
||||
Some(value),
|
||||
span.clone(),
|
||||
)?)
|
||||
tuple_values.push(self.allocate_main_function_input(cs, type_, &value_name, Some(value), span)?)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Allocate all tuple values as none
|
||||
for (i, type_) in types.into_iter().enumerate() {
|
||||
let value_name = new_scope(name.clone(), i.to_string());
|
||||
let value_name = new_scope(name, &i.to_string());
|
||||
|
||||
tuple_values.push(self.allocate_main_function_input(cs, type_, value_name, None, span.clone())?);
|
||||
tuple_values.push(self.allocate_main_function_input(cs, type_, &value_name, None, span)?);
|
||||
}
|
||||
}
|
||||
_ => return Err(FunctionError::invalid_tuple(input_value.unwrap().to_string(), span)),
|
||||
_ => {
|
||||
return Err(FunctionError::invalid_tuple(
|
||||
input_value.unwrap().to_string(),
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ConstrainedValue::Tuple(tuple_values))
|
||||
|
@ -34,15 +34,15 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_main_function<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
scope: String,
|
||||
scope: &str,
|
||||
function: Function,
|
||||
input: Input,
|
||||
) -> Result<OutputBytes, FunctionError> {
|
||||
let function_name = new_scope(scope.clone(), function.get_name());
|
||||
let function_name = new_scope(scope, function.get_name());
|
||||
let registers = input.get_registers();
|
||||
|
||||
// Iterate over main function input variables and allocate new values
|
||||
let mut input_variables = vec![];
|
||||
let mut input_variables = Vec::with_capacity(function.input.len());
|
||||
for input_model in function.input.clone().into_iter() {
|
||||
let (identifier, value) = match input_model {
|
||||
FunctionInput::InputKeyword(identifier) => {
|
||||
@ -54,21 +54,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let name = input_model.identifier.name.clone();
|
||||
let input_option = input
|
||||
.get(&name)
|
||||
.ok_or(FunctionError::input_not_found(name.clone(), function.span.clone()))?;
|
||||
let input_value = self.allocate_main_function_input(
|
||||
cs,
|
||||
input_model.type_,
|
||||
name.clone(),
|
||||
input_option,
|
||||
function.span.clone(),
|
||||
)?;
|
||||
.ok_or_else(|| FunctionError::input_not_found(name.clone(), function.span.clone()))?;
|
||||
let input_value =
|
||||
self.allocate_main_function_input(cs, input_model.type_, &name, input_option, &function.span)?;
|
||||
|
||||
(input_model.identifier, input_value)
|
||||
}
|
||||
};
|
||||
|
||||
// Store input as variable with {function_name}_{identifier_name}
|
||||
let input_name = new_scope(function_name.clone(), identifier.name.clone());
|
||||
let input_name = new_scope(&function_name, &identifier.name);
|
||||
|
||||
// Store a new variable for every allocated main function input
|
||||
self.store(input_name, value);
|
||||
@ -77,7 +72,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
|
||||
let span = function.span.clone();
|
||||
let result_value = self.enforce_function(cs, scope, function_name, function, input_variables, "".to_owned())?;
|
||||
let result_value = self.enforce_function(cs, scope, &function_name, function, input_variables, "")?;
|
||||
let output_bytes = OutputBytes::new_from_constrained_value(registers, result_value, span)?;
|
||||
|
||||
Ok(output_bytes)
|
||||
|
@ -34,17 +34,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
cs: &mut CS,
|
||||
return_value: &mut ConstrainedValue<F, G>,
|
||||
results: Vec<(Option<Boolean>, ConstrainedValue<F, G>)>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
// if there are no results, continue
|
||||
if results.len() == 0 {
|
||||
if results.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// If all indicators are none, then there are no branch conditions in the function.
|
||||
// We simply return the last result.
|
||||
|
||||
if let None = results.iter().find(|(indicator, _res)| indicator.is_some()) {
|
||||
if results.iter().all(|(indicator, _res)| indicator.is_none()) {
|
||||
let result = &results[results.len() - 1].1;
|
||||
|
||||
*return_value = result.clone();
|
||||
@ -61,12 +61,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
let name_unique = format!("select {} {}:{}", result, span.line, span.start);
|
||||
let selected_value =
|
||||
ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &result, return_value)
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(result.to_string(), return_value.to_string(), span.clone())
|
||||
})?;
|
||||
let selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| format!("select {} {}:{}", result, span.line, span.start)),
|
||||
&condition,
|
||||
&result,
|
||||
return_value,
|
||||
)
|
||||
.map_err(|_| StatementError::select_fail(result.to_string(), return_value.to_string(), span.to_owned()))?;
|
||||
|
||||
*return_value = selected_value;
|
||||
}
|
||||
|
67
compiler/src/import/parser/import_parser.rs
Normal file
67
compiler/src/import/parser/import_parser.rs
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright (C) 2019-2020 Aleo Systems Inc.
|
||||
// This file is part of the Leo library.
|
||||
|
||||
// The Leo library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// The Leo library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// 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/>.
|
||||
|
||||
use crate::errors::ImportError;
|
||||
use leo_typed::{Package, Program};
|
||||
|
||||
use std::{collections::HashMap, env::current_dir};
|
||||
|
||||
/// Parses all relevant import files for a program.
|
||||
/// Stores compiled program structs.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ImportParser {
|
||||
imports: HashMap<String, Program>,
|
||||
core_packages: Vec<Package>,
|
||||
}
|
||||
|
||||
impl ImportParser {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub(crate) fn insert_import(&mut self, file_name: String, program: Program) {
|
||||
// todo: handle conflicting versions for duplicate imports here
|
||||
let _res = self.imports.insert(file_name, program);
|
||||
}
|
||||
|
||||
pub(crate) fn insert_core_package(&mut self, package: &Package) {
|
||||
let _res = self.core_packages.push(package.clone());
|
||||
}
|
||||
|
||||
pub fn get_import(&self, file_name: &str) -> Option<&Program> {
|
||||
self.imports.get(file_name)
|
||||
}
|
||||
|
||||
pub fn core_packages(&self) -> &Vec<Package> {
|
||||
&self.core_packages
|
||||
}
|
||||
|
||||
pub fn parse(program: &Program) -> Result<Self, ImportError> {
|
||||
let mut imports = Self::new();
|
||||
|
||||
// Find all imports relative to current directory
|
||||
let path = current_dir().map_err(ImportError::current_directory_error)?;
|
||||
|
||||
// Parse each imported file
|
||||
program
|
||||
.imports
|
||||
.iter()
|
||||
.map(|import| imports.parse_package(path.clone(), &import.package))
|
||||
.collect::<Result<Vec<()>, ImportError>>()?;
|
||||
|
||||
Ok(imports)
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ use leo_core::{CorePackageList, LeoCoreError};
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub(crate) fn store_core_package(&mut self, scope: String, package: Package) -> Result<(), LeoCoreError> {
|
||||
pub(crate) fn store_core_package(&mut self, scope: &str, package: Package) -> Result<(), LeoCoreError> {
|
||||
// Create list of imported core packages.
|
||||
let list = CorePackageList::from_package_access(package.access)?;
|
||||
|
||||
@ -29,10 +29,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let symbol_list = list.to_symbols()?;
|
||||
|
||||
for (symbol, circuit) in symbol_list.symbols() {
|
||||
let symbol_name = new_scope(scope.clone(), symbol);
|
||||
let symbol_name = new_scope(scope, symbol);
|
||||
|
||||
// store packages
|
||||
self.store(symbol_name, ConstrainedValue::CircuitDefinition(circuit))
|
||||
self.store(symbol_name, ConstrainedValue::CircuitDefinition(circuit.to_owned()))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -24,15 +24,15 @@ use snarkos_models::curves::{Field, PrimeField};
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub(crate) fn store_import(
|
||||
&mut self,
|
||||
scope: String,
|
||||
scope: &str,
|
||||
import: &ImportStatement,
|
||||
imported_programs: &ImportParser,
|
||||
) -> Result<(), ImportError> {
|
||||
// Fetch core packages
|
||||
// Fetch core packages.
|
||||
let core_package = imported_programs.get_core_package(&import.package);
|
||||
|
||||
if let Some(package) = core_package {
|
||||
self.store_core_package(scope.clone(), package.clone())?;
|
||||
self.store_core_package(scope, package.clone())?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@ -44,13 +44,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Find imported program
|
||||
let program = imported_programs
|
||||
.get_import(&name)
|
||||
.ok_or(ImportError::unknown_package(import.package.name.clone()))?;
|
||||
.ok_or_else(|| ImportError::unknown_package(import.package.name.clone()))?;
|
||||
|
||||
// Parse imported program
|
||||
self.store_definitions(program.clone(), imported_programs)?;
|
||||
|
||||
// Store the imported symbol
|
||||
self.store_symbol(scope.clone(), name, &symbol, program)?;
|
||||
self.store_symbol(scope, &name, &symbol, program)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -22,8 +22,8 @@ use snarkos_models::curves::{Field, PrimeField};
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub(crate) fn store_symbol(
|
||||
&mut self,
|
||||
scope: String,
|
||||
program_name: String,
|
||||
scope: &str,
|
||||
program_name: &str,
|
||||
symbol: &ImportSymbol,
|
||||
program: &Program,
|
||||
) -> Result<(), ImportError> {
|
||||
@ -31,9 +31,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
if symbol.is_star() {
|
||||
// evaluate and store all circuit definitions
|
||||
program.circuits.iter().for_each(|(identifier, circuit)| {
|
||||
let name = new_scope(scope.clone(), identifier.to_string());
|
||||
let name = new_scope(scope, &identifier.name);
|
||||
let value = ConstrainedValue::Import(
|
||||
program_name.clone(),
|
||||
program_name.to_owned(),
|
||||
Box::new(ConstrainedValue::CircuitDefinition(circuit.clone())),
|
||||
);
|
||||
|
||||
@ -42,9 +42,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
// evaluate and store all function definitions
|
||||
program.functions.iter().for_each(|(identifier, function)| {
|
||||
let name = new_scope(scope.clone(), identifier.to_string());
|
||||
let name = new_scope(scope, &identifier.name);
|
||||
let value = ConstrainedValue::Import(
|
||||
program_name.clone(),
|
||||
program_name.to_owned(),
|
||||
Box::new(ConstrainedValue::Function(None, function.clone())),
|
||||
);
|
||||
|
||||
@ -59,7 +59,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
let value = match matched_circuit {
|
||||
Some((_circuit_name, circuit)) => ConstrainedValue::Import(
|
||||
program_name.clone(),
|
||||
program_name.to_owned(),
|
||||
Box::new(ConstrainedValue::CircuitDefinition(circuit.clone())),
|
||||
),
|
||||
None => {
|
||||
@ -71,17 +71,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
match matched_function {
|
||||
Some((_function_name, function)) => ConstrainedValue::Import(
|
||||
program_name.clone(),
|
||||
program_name.to_owned(),
|
||||
Box::new(ConstrainedValue::Function(None, function.clone())),
|
||||
),
|
||||
None => return Err(ImportError::unknown_symbol(symbol.to_owned(), program_name)),
|
||||
None => return Err(ImportError::unknown_symbol(symbol.to_owned(), program_name.to_owned())),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// take the alias if it is present
|
||||
let id = symbol.alias.clone().unwrap_or(symbol.symbol.clone());
|
||||
let name = new_scope(scope, id.to_string());
|
||||
let id = symbol.alias.clone().unwrap_or_else(|| symbol.symbol.clone());
|
||||
let name = new_scope(scope, &id.name);
|
||||
|
||||
// store imported circuit under imported name
|
||||
self.store(name, value);
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
//! Module containing structs and types that make up a Leo program.
|
||||
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate thiserror;
|
||||
|
||||
|
@ -71,8 +71,7 @@ impl OutputBytes {
|
||||
string.push_str(&format);
|
||||
}
|
||||
|
||||
let mut bytes: Vec<u8> = vec![];
|
||||
bytes.extend_from_slice(string.as_bytes());
|
||||
let bytes = string.into_bytes();
|
||||
|
||||
Ok(Self(bytes))
|
||||
}
|
||||
|
@ -19,9 +19,10 @@
|
||||
use crate::errors::OutputFileError;
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs::{self, File},
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
path::Path,
|
||||
};
|
||||
|
||||
pub static OUTPUTS_DIRECTORY_NAME: &str = "outputs/";
|
||||
@ -38,21 +39,21 @@ impl OutputFile {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exists_at(&self, path: &PathBuf) -> bool {
|
||||
pub fn exists_at(&self, path: &Path) -> bool {
|
||||
let path = self.setup_file_path(path);
|
||||
path.exists()
|
||||
}
|
||||
|
||||
/// Reads the output register variables from the given file path if it exists.
|
||||
pub fn read_from(&self, path: &PathBuf) -> Result<String, OutputFileError> {
|
||||
pub fn read_from(&self, path: &Path) -> Result<String, OutputFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
|
||||
let output = fs::read_to_string(&path).map_err(|_| OutputFileError::FileReadError(path.clone()))?;
|
||||
let output = fs::read_to_string(&path).map_err(|_| OutputFileError::FileReadError(path.into_owned()))?;
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
/// Writes output to a file.
|
||||
pub fn write(&self, path: &PathBuf, bytes: &[u8]) -> Result<(), OutputFileError> {
|
||||
pub fn write(&self, path: &Path, bytes: &[u8]) -> Result<(), OutputFileError> {
|
||||
// create output file
|
||||
let path = self.setup_file_path(path);
|
||||
let mut file = File::create(&path)?;
|
||||
@ -62,23 +63,24 @@ impl OutputFile {
|
||||
|
||||
/// Removes the output file at the given path if it exists. Returns `true` on success,
|
||||
/// `false` if the file doesn't exist, and `Error` if the file system fails during operation.
|
||||
pub fn remove(&self, path: &PathBuf) -> Result<bool, OutputFileError> {
|
||||
pub fn remove(&self, path: &Path) -> Result<bool, OutputFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
if !path.exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
fs::remove_file(&path).map_err(|_| OutputFileError::FileRemovalError(path.clone()))?;
|
||||
fs::remove_file(&path).map_err(|_| OutputFileError::FileRemovalError(path.into_owned()))?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
|
||||
let mut path = path.to_owned();
|
||||
fn setup_file_path<'a>(&self, path: &'a Path) -> Cow<'a, Path> {
|
||||
let mut path = Cow::from(path);
|
||||
if path.is_dir() {
|
||||
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(OUTPUTS_DIRECTORY_NAME));
|
||||
path.to_mut().push(OUTPUTS_DIRECTORY_NAME);
|
||||
}
|
||||
path.push(PathBuf::from(format!("{}{}", self.package_name, OUTPUT_FILE_EXTENSION)));
|
||||
path.to_mut()
|
||||
.push(format!("{}{}", self.package_name, OUTPUT_FILE_EXTENSION));
|
||||
}
|
||||
path
|
||||
}
|
||||
|
@ -22,35 +22,40 @@ use snarkos_models::curves::{Field, PrimeField};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ConstrainedProgram<F: Field + PrimeField, G: GroupType<F>> {
|
||||
pub identifiers: HashMap<String, ConstrainedValue<F, G>>,
|
||||
}
|
||||
|
||||
pub fn new_scope(outer: String, inner: String) -> String {
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> Default for ConstrainedProgram<F, G> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
identifiers: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_scope(outer: &str, inner: &str) -> String {
|
||||
format!("{}_{}", outer, inner)
|
||||
}
|
||||
|
||||
pub fn is_in_scope(current_scope: &String, desired_scope: &String) -> bool {
|
||||
pub fn is_in_scope(current_scope: &str, desired_scope: &str) -> bool {
|
||||
current_scope.ends_with(desired_scope)
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
identifiers: HashMap::new(),
|
||||
}
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub(crate) fn store(&mut self, name: String, value: ConstrainedValue<F, G>) {
|
||||
self.identifiers.insert(name, value);
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, name: &String) -> Option<&ConstrainedValue<F, G>> {
|
||||
pub(crate) fn get(&self, name: &str) -> Option<&ConstrainedValue<F, G>> {
|
||||
self.identifiers.get(name)
|
||||
}
|
||||
|
||||
pub(crate) fn get_mut(&mut self, name: &String) -> Option<&mut ConstrainedValue<F, G>> {
|
||||
pub(crate) fn get_mut(&mut self, name: &str) -> Option<&mut ConstrainedValue<F, G>> {
|
||||
self.identifiers.get_mut(name)
|
||||
}
|
||||
}
|
||||
|
@ -28,65 +28,57 @@ use snarkos_models::{
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn assign_array<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
indicator: Option<Boolean>,
|
||||
name: String,
|
||||
name: &str,
|
||||
range_or_expression: RangeOrExpression,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
|
||||
// Resolve index so we know if we are assigning to a single value or a range of values
|
||||
match range_or_expression {
|
||||
RangeOrExpression::Expression(index) => {
|
||||
let index = self.enforce_index(cs, file_scope.clone(), function_scope.clone(), index, span.clone())?;
|
||||
let index = self.enforce_index(cs, file_scope, function_scope, index, span)?;
|
||||
|
||||
// Modify the single value of the array in place
|
||||
match self.get_mutable_assignee(name, span.clone())? {
|
||||
match self.get_mutable_assignee(name, &span)? {
|
||||
ConstrainedValue::Array(old) => {
|
||||
new_value.resolve_type(Some(old[index].to_type(span.clone())?), span.clone())?;
|
||||
new_value.resolve_type(Some(old[index].to_type(&span)?), &span)?;
|
||||
|
||||
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
|
||||
let selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| name_unique),
|
||||
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
||||
&condition,
|
||||
&new_value,
|
||||
&old[index],
|
||||
)
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(new_value.to_string(), old[index].to_string(), span)
|
||||
StatementError::select_fail(new_value.to_string(), old[index].to_string(), span.to_owned())
|
||||
})?;
|
||||
|
||||
old[index] = selected_value;
|
||||
}
|
||||
_ => return Err(StatementError::array_assign_index(span)),
|
||||
_ => return Err(StatementError::array_assign_index(span.to_owned())),
|
||||
}
|
||||
}
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_index = match from {
|
||||
Some(integer) => {
|
||||
self.enforce_index(cs, file_scope.clone(), function_scope.clone(), integer, span.clone())?
|
||||
}
|
||||
Some(integer) => self.enforce_index(cs, file_scope, function_scope, integer, span)?,
|
||||
None => 0usize,
|
||||
};
|
||||
let to_index_option = match to {
|
||||
Some(integer) => Some(self.enforce_index(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
integer,
|
||||
span.clone(),
|
||||
)?),
|
||||
Some(integer) => Some(self.enforce_index(cs, file_scope, function_scope, integer, span)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
// Modify the range of values of the array
|
||||
let old_array = self.get_mutable_assignee(name, span.clone())?;
|
||||
let old_array = self.get_mutable_assignee(name, &span)?;
|
||||
let new_array = match (old_array.clone(), new_value) {
|
||||
(ConstrainedValue::Array(mut mutable), ConstrainedValue::Array(new)) => {
|
||||
let to_index = to_index_option.unwrap_or(mutable.len());
|
||||
@ -94,12 +86,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
mutable.splice(from_index..to_index, new.iter().cloned());
|
||||
ConstrainedValue::Array(mutable)
|
||||
}
|
||||
_ => return Err(StatementError::array_assign_range(span)),
|
||||
_ => return Err(StatementError::array_assign_range(span.to_owned())),
|
||||
};
|
||||
let name_unique = format!("select {} {}:{}", new_array, span.line, span.start);
|
||||
let selected_array =
|
||||
ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &new_array, old_array)
|
||||
.map_err(|_| StatementError::select_fail(new_array.to_string(), old_array.to_string(), span))?;
|
||||
let selected_array = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| format!("select {} {}:{}", new_array, span.line, span.start)),
|
||||
&condition,
|
||||
&new_array,
|
||||
old_array,
|
||||
)
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(new_array.to_string(), old_array.to_string(), span.to_owned())
|
||||
})?;
|
||||
|
||||
*old_array = selected_array;
|
||||
}
|
||||
|
@ -35,35 +35,38 @@ use snarkos_models::{
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_assign_statement<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
declared_circuit_reference: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
declared_circuit_reference: &str,
|
||||
indicator: Option<Boolean>,
|
||||
assignee: Assignee,
|
||||
expression: Expression,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
// Get the name of the variable we are assigning to
|
||||
let variable_name = resolve_assignee(function_scope.clone(), assignee.clone());
|
||||
let variable_name = resolve_assignee(function_scope.to_string(), assignee.clone());
|
||||
|
||||
// Evaluate new value
|
||||
let mut new_value =
|
||||
self.enforce_expression(cs, file_scope.clone(), function_scope.clone(), None, expression)?;
|
||||
let mut new_value = self.enforce_expression(cs, file_scope, function_scope, None, expression)?;
|
||||
|
||||
// Mutate the old value into the new value
|
||||
if assignee.accesses.is_empty() {
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
let old_value = self.get_mutable_assignee(variable_name.clone(), span.clone())?;
|
||||
let old_value = self.get_mutable_assignee(&variable_name, span)?;
|
||||
|
||||
new_value.resolve_type(Some(old_value.to_type(span.clone())?), span.clone())?;
|
||||
new_value.resolve_type(Some(old_value.to_type(&span)?), span)?;
|
||||
|
||||
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
|
||||
let selected_value =
|
||||
ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &new_value, old_value)
|
||||
.map_err(|_| StatementError::select_fail(new_value.to_string(), old_value.to_string(), span))?;
|
||||
let selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
||||
&condition,
|
||||
&new_value,
|
||||
old_value,
|
||||
)
|
||||
.map_err(|_| StatementError::select_fail(new_value.to_string(), old_value.to_string(), span.to_owned()))?;
|
||||
|
||||
*old_value = selected_value;
|
||||
|
||||
@ -75,18 +78,19 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
file_scope,
|
||||
function_scope,
|
||||
indicator,
|
||||
variable_name,
|
||||
&variable_name,
|
||||
range_or_expression,
|
||||
new_value,
|
||||
span,
|
||||
),
|
||||
AssigneeAccess::Tuple(index) => self.assign_tuple(cs, indicator, variable_name, index, new_value, span),
|
||||
AssigneeAccess::Tuple(index) => {
|
||||
self.assign_tuple(cs, indicator, &variable_name, index, new_value, span)
|
||||
}
|
||||
AssigneeAccess::Member(identifier) => {
|
||||
// Mutate a circuit variable using the self keyword.
|
||||
if assignee.identifier.is_self() {
|
||||
let self_circuit_variable_name =
|
||||
new_scope(assignee.identifier.name.clone(), identifier.name.clone());
|
||||
let self_variable_name = new_scope(file_scope, self_circuit_variable_name);
|
||||
let self_circuit_variable_name = new_scope(&assignee.identifier.name, &identifier.name);
|
||||
let self_variable_name = new_scope(file_scope, &self_circuit_variable_name);
|
||||
let value = self.mutate_circuit_variable(
|
||||
cs,
|
||||
indicator,
|
||||
@ -99,7 +103,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
self.store(self_variable_name, value);
|
||||
} else {
|
||||
let _value =
|
||||
self.mutate_circuit_variable(cs, indicator, variable_name, identifier, new_value, span)?;
|
||||
self.mutate_circuit_variable(cs, indicator, &variable_name, identifier, new_value, span)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -22,22 +22,22 @@ use leo_typed::{Assignee, Span};
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
|
||||
pub fn resolve_assignee(scope: String, assignee: Assignee) -> String {
|
||||
new_scope(scope, assignee.identifier().to_string())
|
||||
new_scope(&scope, &assignee.identifier().to_string())
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn get_mutable_assignee(
|
||||
&mut self,
|
||||
name: String,
|
||||
span: Span,
|
||||
name: &str,
|
||||
span: &Span,
|
||||
) -> Result<&mut ConstrainedValue<F, G>, StatementError> {
|
||||
// Check that assignee exists and is mutable
|
||||
Ok(match self.get_mut(&name) {
|
||||
Ok(match self.get_mut(name) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Mutable(mutable_value) => mutable_value,
|
||||
_ => return Err(StatementError::immutable_assign(name, span)),
|
||||
_ => return Err(StatementError::immutable_assign(name.to_owned(), span.to_owned())),
|
||||
},
|
||||
None => return Err(StatementError::undefined_variable(name, span)),
|
||||
None => return Err(StatementError::undefined_variable(name.to_owned(), span.to_owned())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -32,18 +32,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
indicator: Option<Boolean>,
|
||||
circuit_name: String,
|
||||
circuit_name: &str,
|
||||
variable_name: Identifier,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
|
||||
// Get the mutable circuit by name
|
||||
match self.get_mutable_assignee(circuit_name, span.clone())? {
|
||||
match self.get_mutable_assignee(circuit_name, span)? {
|
||||
ConstrainedValue::CircuitExpression(_variable, members) => {
|
||||
// Modify the circuit variable in place
|
||||
let matched_variable = members.into_iter().find(|member| member.0 == variable_name);
|
||||
let matched_variable = members.iter_mut().find(|member| member.0 == variable_name);
|
||||
|
||||
match matched_variable {
|
||||
Some(member) => match &member.1 {
|
||||
@ -51,29 +51,35 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Throw an error if we try to mutate a circuit function
|
||||
Err(StatementError::immutable_circuit_function(
|
||||
function.identifier.to_string(),
|
||||
span,
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
ConstrainedValue::Static(_circuit_function) => {
|
||||
// Throw an error if we try to mutate a static circuit function
|
||||
Err(StatementError::immutable_circuit_function("static".into(), span))
|
||||
Err(StatementError::immutable_circuit_function(
|
||||
"static".into(),
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
ConstrainedValue::Mutable(value) => {
|
||||
// Mutate the circuit variable's value in place
|
||||
|
||||
// Check that the new value type == old value type
|
||||
new_value.resolve_type(Some(value.to_type(span.clone())?), span.clone())?;
|
||||
new_value.resolve_type(Some(value.to_type(span)?), span)?;
|
||||
|
||||
// Conditionally select the value if this branch is executed.
|
||||
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
|
||||
let mut selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| name_unique),
|
||||
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
||||
&condition,
|
||||
&new_value,
|
||||
&member.1,
|
||||
)
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(new_value.to_string(), member.1.to_string(), span)
|
||||
StatementError::select_fail(
|
||||
new_value.to_string(),
|
||||
member.1.to_string(),
|
||||
span.to_owned(),
|
||||
)
|
||||
})?;
|
||||
|
||||
// Make sure the new value is still mutable
|
||||
@ -81,24 +87,30 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
member.1 = selected_value.to_owned();
|
||||
|
||||
Ok(selected_value.to_owned())
|
||||
Ok(selected_value)
|
||||
}
|
||||
_ => {
|
||||
// Throw an error if we try to mutate an immutable circuit variable
|
||||
Err(StatementError::immutable_circuit_variable(variable_name.name, span))
|
||||
Err(StatementError::immutable_circuit_variable(
|
||||
variable_name.name,
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// Throw an error if the circuit variable does not exist in the circuit
|
||||
Err(StatementError::undefined_circuit_variable(
|
||||
variable_name.to_string(),
|
||||
span,
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Throw an error if the circuit definition does not exist in the file
|
||||
_ => Err(StatementError::undefined_circuit(variable_name.to_string(), span)),
|
||||
_ => Err(StatementError::undefined_circuit(
|
||||
variable_name.to_string(),
|
||||
span.to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,28 +32,31 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
indicator: Option<Boolean>,
|
||||
name: String,
|
||||
name: &str,
|
||||
index: usize,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
|
||||
// Modify the single value of the tuple in place
|
||||
match self.get_mutable_assignee(name, span.clone())? {
|
||||
match self.get_mutable_assignee(name, &span)? {
|
||||
ConstrainedValue::Tuple(old) => {
|
||||
new_value.resolve_type(Some(old[index].to_type(span.clone())?), span.clone())?;
|
||||
new_value.resolve_type(Some(old[index].to_type(&span)?), &span)?;
|
||||
|
||||
let name_unique = format!("select {} {}:{}", new_value, span.line, span.start);
|
||||
let selected_value =
|
||||
ConstrainedValue::conditionally_select(cs.ns(|| name_unique), &condition, &new_value, &old[index])
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(new_value.to_string(), old[index].to_string(), span)
|
||||
})?;
|
||||
let selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
||||
&condition,
|
||||
&new_value,
|
||||
&old[index],
|
||||
)
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(new_value.to_string(), old[index].to_string(), span.to_owned())
|
||||
})?;
|
||||
|
||||
old[index] = selected_value;
|
||||
}
|
||||
_ => return Err(StatementError::tuple_assign_index(span)),
|
||||
_ => return Err(StatementError::tuple_assign_index(span.to_owned())),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
//! Enforces a branch of a conditional or iteration statement in a compiled Leo program.
|
||||
|
||||
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use crate::{program::ConstrainedProgram, GroupType, IndicatorAndConstrainedValue, StatementResult};
|
||||
use leo_typed::{Statement, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
@ -28,23 +28,23 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn evaluate_branch<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
indicator: Option<Boolean>,
|
||||
statements: Vec<Statement>,
|
||||
return_type: Option<Type>,
|
||||
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
|
||||
let mut results = vec![];
|
||||
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
||||
let mut results = Vec::with_capacity(statements.len());
|
||||
// Evaluate statements. Only allow a single return argument to be returned.
|
||||
for statement in statements.iter() {
|
||||
for statement in statements.into_iter() {
|
||||
let mut value = self.enforce_statement(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
indicator.clone(),
|
||||
statement.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
indicator,
|
||||
statement,
|
||||
return_type.clone(),
|
||||
"".to_owned(),
|
||||
"",
|
||||
)?;
|
||||
|
||||
results.append(&mut value);
|
||||
|
@ -16,7 +16,14 @@
|
||||
|
||||
//! Methods to enforce constraints on statements in a compiled Leo program.
|
||||
|
||||
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use crate::{
|
||||
errors::StatementError,
|
||||
program::ConstrainedProgram,
|
||||
value::ConstrainedValue,
|
||||
GroupType,
|
||||
IndicatorAndConstrainedValue,
|
||||
StatementResult,
|
||||
};
|
||||
use leo_typed::{ConditionalNestedOrEndStatement, ConditionalStatement, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
@ -28,7 +35,7 @@ fn indicator_to_string(indicator: &Boolean) -> String {
|
||||
indicator
|
||||
.get_value()
|
||||
.map(|b| b.to_string())
|
||||
.unwrap_or(format!("[input]"))
|
||||
.unwrap_or_else(|| "[input]".to_string())
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
@ -36,16 +43,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
/// Due to R1CS constraints, we must evaluate every branch to properly construct the circuit.
|
||||
/// At program execution, we will pass an `indicator` bit down to all child statements within each branch.
|
||||
/// The `indicator` bit will select that branch while keeping the constraint system satisfied.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_conditional_statement<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
indicator: Option<Boolean>,
|
||||
statement: ConditionalStatement,
|
||||
return_type: Option<Type>,
|
||||
span: Span,
|
||||
) -> Result<Vec<(Option<Boolean>, ConstrainedValue<F, G>)>, StatementError> {
|
||||
span: &Span,
|
||||
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
||||
let statement_string = statement.to_string();
|
||||
|
||||
// Inherit the indicator from a previous conditional statement or assume that we are the outer parent
|
||||
@ -54,13 +62,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Evaluate the conditional boolean as the inner indicator
|
||||
let inner_indicator = match self.enforce_expression(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
Some(Type::Boolean),
|
||||
statement.condition.clone(),
|
||||
)? {
|
||||
ConstrainedValue::Boolean(resolved) => resolved,
|
||||
value => return Err(StatementError::conditional_boolean(value.to_string(), span)),
|
||||
value => return Err(StatementError::conditional_boolean(value.to_string(), span.to_owned())),
|
||||
};
|
||||
|
||||
// If outer_indicator && inner_indicator, then select branch 1
|
||||
@ -75,15 +83,15 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
&outer_indicator,
|
||||
&inner_indicator,
|
||||
)
|
||||
.map_err(|_| StatementError::indicator_calculation(branch_1_name, span.clone()))?;
|
||||
.map_err(|_| StatementError::indicator_calculation(branch_1_name, span.to_owned()))?;
|
||||
|
||||
let mut results = vec![];
|
||||
|
||||
// Evaluate branch 1
|
||||
let mut branch_1_result = self.evaluate_branch(
|
||||
cs,
|
||||
file_scope.clone(),
|
||||
function_scope.clone(),
|
||||
file_scope,
|
||||
function_scope,
|
||||
Some(branch_1_indicator),
|
||||
statement.statements,
|
||||
return_type.clone(),
|
||||
@ -103,7 +111,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
&outer_indicator,
|
||||
&inner_indicator,
|
||||
)
|
||||
.map_err(|_| StatementError::indicator_calculation(branch_2_name, span.clone()))?;
|
||||
.map_err(|_| StatementError::indicator_calculation(branch_2_name, span.to_owned()))?;
|
||||
|
||||
// Evaluate branch 2
|
||||
let mut branch_2_result = match statement.next {
|
||||
|
@ -28,14 +28,17 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
fn enforce_single_definition<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
function_scope: String,
|
||||
function_scope: &str,
|
||||
is_constant: bool,
|
||||
variable_name: VariableName,
|
||||
mut value: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
if is_constant && variable_name.mutable {
|
||||
return Err(StatementError::immutable_assign(variable_name.to_string(), span));
|
||||
return Err(StatementError::immutable_assign(
|
||||
variable_name.to_string(),
|
||||
span.to_owned(),
|
||||
));
|
||||
} else {
|
||||
value.allocate_value(cs, span)?
|
||||
}
|
||||
@ -48,36 +51,37 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
fn enforce_multiple_definition<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
function_scope: String,
|
||||
function_scope: &str,
|
||||
is_constant: bool,
|
||||
variables: Variables,
|
||||
values: Vec<ConstrainedValue<F, G>>,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
if values.len() != variables.names.len() {
|
||||
return Err(StatementError::invalid_number_of_definitions(
|
||||
values.len(),
|
||||
variables.names.len(),
|
||||
span,
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
for (variable, value) in variables.names.into_iter().zip(values.into_iter()) {
|
||||
self.enforce_single_definition(cs, function_scope.clone(), is_constant, variable, value, span.clone())?;
|
||||
self.enforce_single_definition(cs, function_scope, is_constant, variable, value, span)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn enforce_definition_statement<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
declare: Declare,
|
||||
variables: Variables,
|
||||
expression: Expression,
|
||||
span: Span,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let num_variables = variables.names.len();
|
||||
let is_constant = match declare {
|
||||
@ -102,7 +106,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let values = match expression {
|
||||
// ConstrainedValue::Return(values) => values,
|
||||
ConstrainedValue::Tuple(values) => values,
|
||||
value => return Err(StatementError::multiple_definition(value.to_string(), span.clone())),
|
||||
value => return Err(StatementError::multiple_definition(value.to_string(), span.to_owned())),
|
||||
};
|
||||
|
||||
self.enforce_multiple_definition(cs, function_scope, is_constant, variables, values, span)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user