commit
3a2e9407b7
129 changed files with 2976 additions and 2234 deletions
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file.
|
|||
## [Unreleased]
|
||||
https://github.com/Zokrates/ZoKrates/compare/latest...develop
|
||||
|
||||
## [0.7.2] - 2021-05-18
|
||||
|
||||
### Release
|
||||
- https://github.com/Zokrates/ZoKrates/releases/tag/0.7.2
|
||||
|
||||
### Changes
|
||||
- Isolate branch panics: only panic in a branch if it's being logically executed (#865, @schaeff)
|
||||
- Support the use of constants in struct and function declarations (#864, @dark64)
|
||||
- Relax ordering of symbol declarations (#863, @dark64)
|
||||
- Update `one_liner.sh` script to support arm64 architecture (#861, @dark64)
|
||||
- Fix crash when updating a constant struct member to another constant (#855, @schaeff)
|
||||
- Fix treatment of uint subtraction involving constants (bug) (#852, @schaeff)
|
||||
- Add uint to abi docs (#848, @schaeff)
|
||||
- Remove side effects on complex types (bug) (#847, @schaeff)
|
||||
- Fix crash on struct member type mismatch (#846, @schaeff)
|
||||
- Fix nested struct access crash (#845, @schaeff)
|
||||
- Make error formatting consistent (#843, @schaeff)
|
||||
|
||||
## [0.7.1] - 2021-04-30
|
||||
|
||||
### Release
|
||||
|
|
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -2269,7 +2269,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zokrates_cli"
|
||||
version = "0.7.0"
|
||||
version = "0.7.2"
|
||||
dependencies = [
|
||||
"assert_cli",
|
||||
"bincode",
|
||||
|
@ -2294,7 +2294,7 @@ version = "0.1.0"
|
|||
|
||||
[[package]]
|
||||
name = "zokrates_core"
|
||||
version = "0.6.0"
|
||||
version = "0.6.2"
|
||||
dependencies = [
|
||||
"ark-bls12-377",
|
||||
"ark-bn254",
|
||||
|
@ -2335,7 +2335,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zokrates_core_test"
|
||||
version = "0.2.0"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"zokrates_test",
|
||||
"zokrates_test_derive",
|
||||
|
@ -2381,7 +2381,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zokrates_parser"
|
||||
version = "0.2.0"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"glob 0.2.11",
|
||||
"pest",
|
||||
|
@ -2390,7 +2390,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zokrates_pest_ast"
|
||||
version = "0.2.0"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"from-pest",
|
||||
"glob 0.2.11",
|
||||
|
@ -2402,7 +2402,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zokrates_stdlib"
|
||||
version = "0.2.0"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"fs_extra",
|
||||
"zokrates_test",
|
||||
|
@ -2411,7 +2411,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zokrates_test"
|
||||
version = "0.1.5"
|
||||
version = "0.1.6"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
<img src="http://www.redaktion.tu-berlin.de/fileadmin/fg308/icons/projekte/logos/ZoKrates_logo.svg" width="100%" height="180">
|
||||
<img src="zokrates_logo.svg" width="100%" height="180">
|
||||
|
||||
# ZoKrates
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ get_architecture() {
|
|||
fi
|
||||
;;
|
||||
|
||||
aarch64)
|
||||
aarch64 | arm64)
|
||||
_cputype=aarch64
|
||||
;;
|
||||
|
||||
|
|
|
@ -26,6 +26,23 @@ An if-expression allows you to branch your code depending on a boolean condition
|
|||
{{#include ../../../zokrates_cli/examples/book/if_else.zok}}
|
||||
```
|
||||
|
||||
There are two important caveats when it comes to conditional expressions. Before we go into them, let's define two concepts:
|
||||
- for an execution of the program, *an executed branch* is a branch which has to be paid for when executing the program, generating proofs, etc.
|
||||
- for an execution of the program, *a logically executed branch* is a branch which is "chosen" by the condition of an if-expression. This is the more intuitive notion of execution, and there is only one for each if-expression.
|
||||
|
||||
Now the two caveats:
|
||||
- **Both branches are always executed**. No short-circuiting happens based on the value of the condition. Therefore, the complexity of a program in terms of the number of constraints it compiles down to is the *sum* of the cost of all branches.
|
||||
```zokrates
|
||||
{{#include ../../../zokrates_cli/examples/book/if_else_expensive.zok}}
|
||||
```
|
||||
- **An unsatisfied constraint inside any branch will make the whole execution fail, even if this branch is not logically executed**. Also, the compiler itself inserts assertions which can fail. This can lead to unexpected results:
|
||||
```zokrates
|
||||
{{#include ../../../zokrates_cli/examples/book/if_else_panic.zok}}
|
||||
```
|
||||
The experimental flag `--branch-isolation` can be activated in the CLI in order to restrict any unsatisfied constraint to make the execution fail only if it is in a logically executed branch. This way, the execution of the program above will always succeed.
|
||||
|
||||
>The reason for these caveats is that the program is compiled down to an arithmetic circuit. This construct does not support jumping to a branch depending on a condition as you could do on traditional architectures. Instead, all branches are inlined as if they were printed on a circuit board. The `branch-isolation` feature comes with overhead for each assertion in each branch, and this overhead compounds when deeply nesting conditionals.
|
||||
|
||||
### For loops
|
||||
|
||||
For loops are available with the following syntax:
|
||||
|
|
|
@ -26,7 +26,7 @@ In this example, the ABI specification is:
|
|||
"members":[
|
||||
{
|
||||
"name":"a",
|
||||
"type":"field"
|
||||
"type":"u8"
|
||||
},
|
||||
{
|
||||
"name":"b",
|
||||
|
@ -75,7 +75,7 @@ When executing a program, arguments can be passed as a JSON object of the follow
|
|||
```json
|
||||
[
|
||||
{
|
||||
"a":"42",
|
||||
"a":"0x2a",
|
||||
"b":{
|
||||
"a":"42"
|
||||
}
|
||||
|
@ -89,5 +89,6 @@ When executing a program, arguments can be passed as a JSON object of the follow
|
|||
```
|
||||
|
||||
Note the following:
|
||||
- Field elements are passed as JSON strings in order to support arbitrary large numbers.
|
||||
- Field elements are passed as JSON strings in order to support arbitrary large numbers
|
||||
- Unsigned integers are passed as JSON strings containing their hexadecimal representation
|
||||
- Structs are passed as JSON objects, ignoring the struct name
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_cli"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>", "Thibaut Schaeffer <thibaut@schaeff.fr>"]
|
||||
repository = "https://github.com/JacobEberhardt/ZoKrates.git"
|
||||
edition = "2018"
|
||||
|
|
|
@ -3,7 +3,7 @@ struct Bar {
|
|||
}
|
||||
|
||||
struct Foo {
|
||||
field a
|
||||
u8 a
|
||||
Bar b
|
||||
}
|
||||
|
||||
|
|
12
zokrates_cli/examples/book/if_else_expensive.zok
Normal file
12
zokrates_cli/examples/book/if_else_expensive.zok
Normal file
|
@ -0,0 +1,12 @@
|
|||
def cheap(field x) -> field:
|
||||
return x + 1
|
||||
|
||||
def expensive(field x) -> field:
|
||||
return x**1000
|
||||
|
||||
def main(field x) -> field:
|
||||
return if x == 1 then\
|
||||
cheap(x)\// executed
|
||||
else\
|
||||
expensive(x)\// also executed
|
||||
fi
|
6
zokrates_cli/examples/book/if_else_panic.zok
Normal file
6
zokrates_cli/examples/book/if_else_panic.zok
Normal file
|
@ -0,0 +1,6 @@
|
|||
def main(field x) -> field:
|
||||
return if x == 0 then\
|
||||
0\
|
||||
else\
|
||||
1/x\// executed even for x := 0, which leads to the execution failing
|
||||
fi
|
|
@ -0,0 +1,10 @@
|
|||
def throwing_bound<N>(u32 x) -> u32:
|
||||
assert(x == N)
|
||||
return 1
|
||||
|
||||
// this should compile: the conditional, even though it can throw, has a constant compile-time value `1`
|
||||
// the value of the blocks should be propagated out, so that `if x == 0 then 1 else 1 fi` can be determined to be `1`
|
||||
def main(u32 x):
|
||||
for u32 i in 0..if x == 0 then throwing_bound::<0>(x) else throwing_bound::<1>(x) fi do
|
||||
endfor
|
||||
return
|
|
@ -0,0 +1,4 @@
|
|||
const field SIZE = 2
|
||||
|
||||
def main(field[SIZE] n):
|
||||
return
|
|
@ -0,0 +1,4 @@
|
|||
const u8 SIZE = 0x02
|
||||
|
||||
def main(field[SIZE] n):
|
||||
return
|
|
@ -0,0 +1,7 @@
|
|||
const u32 N = 42
|
||||
|
||||
def foo<N>(field[N] a) -> bool:
|
||||
return true
|
||||
|
||||
def main():
|
||||
return
|
|
@ -0,0 +1,17 @@
|
|||
struct Foo {
|
||||
field[2] values
|
||||
}
|
||||
|
||||
struct Bar {
|
||||
Foo foo
|
||||
field bar
|
||||
}
|
||||
|
||||
def main():
|
||||
Bar s = Bar {
|
||||
foo: Foo { values: [1] },
|
||||
bar: 0,
|
||||
}
|
||||
field b = s.bar
|
||||
|
||||
return
|
|
@ -0,0 +1,17 @@
|
|||
struct Foo {
|
||||
u8[2] values
|
||||
}
|
||||
|
||||
struct Bar {
|
||||
Foo foo
|
||||
u8 bar
|
||||
}
|
||||
|
||||
def main():
|
||||
Bar s = Bar {
|
||||
foo: Foo { values: [1] }, // notice the size mismatch here
|
||||
bar: 0,
|
||||
}
|
||||
u8 b = s.bar
|
||||
|
||||
return
|
|
@ -4,7 +4,7 @@ def bound(field x) -> u32:
|
|||
def main(field a) -> field:
|
||||
field x = 7
|
||||
x = x + 1
|
||||
for u32 i in 0..bound(x) do
|
||||
for u32 i in 0..bound(x) + bound(x + 1) do
|
||||
// x = x + a
|
||||
x = x + a
|
||||
endfor
|
||||
|
|
11
zokrates_cli/examples/structs/nested_access.zok
Normal file
11
zokrates_cli/examples/structs/nested_access.zok
Normal file
|
@ -0,0 +1,11 @@
|
|||
struct Foo {
|
||||
field a
|
||||
}
|
||||
|
||||
struct Bar {
|
||||
Foo foo
|
||||
}
|
||||
|
||||
def main(Bar b):
|
||||
field a = b.foo.a
|
||||
return
|
|
@ -56,6 +56,10 @@ pub fn subcommand() -> App<'static, 'static> {
|
|||
.long("allow-unconstrained-variables")
|
||||
.help("Allow unconstrained variables by inserting dummy constraints")
|
||||
.required(false)
|
||||
).arg(Arg::with_name("isolate-branches")
|
||||
.long("isolate-branches")
|
||||
.help("Isolate the execution of branches: a panic in a branch only makes the program panic if this branch is being logically executed")
|
||||
.required(false)
|
||||
).arg(Arg::with_name("ztf")
|
||||
.long("ztf")
|
||||
.help("Write human readable output (ztf)")
|
||||
|
@ -124,6 +128,7 @@ fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
|
|||
|
||||
let config = CompileConfig {
|
||||
allow_unconstrained_variables: sub_matches.is_present("allow-unconstrained-variables"),
|
||||
isolate_branches: sub_matches.is_present("isolate-branches"),
|
||||
};
|
||||
|
||||
let resolver = FileSystemResolver::with_stdlib_root(stdlib_path);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_core"
|
||||
version = "0.6.1"
|
||||
version = "0.6.2"
|
||||
edition = "2018"
|
||||
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>"]
|
||||
repository = "https://github.com/JacobEberhardt/ZoKrates"
|
||||
|
|
|
@ -1,66 +1,71 @@
|
|||
use crate::absy;
|
||||
use crate::imports;
|
||||
|
||||
use crate::absy::SymbolDefinition;
|
||||
use num_bigint::BigUint;
|
||||
use std::path::Path;
|
||||
use zokrates_pest_ast as pest;
|
||||
|
||||
impl<'ast> From<pest::File<'ast>> for absy::Module<'ast> {
|
||||
fn from(prog: pest::File<'ast>) -> absy::Module<'ast> {
|
||||
absy::Module::with_symbols(
|
||||
prog.structs
|
||||
.into_iter()
|
||||
.map(absy::SymbolDeclarationNode::from)
|
||||
.chain(
|
||||
prog.constants
|
||||
.into_iter()
|
||||
.map(absy::SymbolDeclarationNode::from),
|
||||
)
|
||||
.chain(
|
||||
prog.functions
|
||||
.into_iter()
|
||||
.map(absy::SymbolDeclarationNode::from),
|
||||
),
|
||||
)
|
||||
.imports(
|
||||
prog.imports
|
||||
.into_iter()
|
||||
.map(absy::ImportDirective::from)
|
||||
.flatten(),
|
||||
)
|
||||
fn from(file: pest::File<'ast>) -> absy::Module<'ast> {
|
||||
absy::Module::with_symbols(file.declarations.into_iter().flat_map(|d| match d {
|
||||
pest::SymbolDeclaration::Import(i) => import_directive_to_symbol_vec(i),
|
||||
pest::SymbolDeclaration::Constant(c) => vec![c.into()],
|
||||
pest::SymbolDeclaration::Struct(s) => vec![s.into()],
|
||||
pest::SymbolDeclaration::Function(f) => vec![f.into()],
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<pest::ImportDirective<'ast>> for absy::ImportDirective<'ast> {
|
||||
fn from(import: pest::ImportDirective<'ast>) -> absy::ImportDirective<'ast> {
|
||||
use crate::absy::NodeValue;
|
||||
fn import_directive_to_symbol_vec(
|
||||
import: pest::ImportDirective,
|
||||
) -> Vec<absy::SymbolDeclarationNode> {
|
||||
use crate::absy::NodeValue;
|
||||
|
||||
match import {
|
||||
pest::ImportDirective::Main(import) => absy::ImportDirective::Main(
|
||||
imports::Import::new(None, std::path::Path::new(import.source.span.as_str()))
|
||||
.alias(import.alias.map(|a| a.span.as_str()))
|
||||
.span(import.span),
|
||||
),
|
||||
pest::ImportDirective::From(import) => absy::ImportDirective::From(
|
||||
import
|
||||
.symbols
|
||||
.iter()
|
||||
.map(|symbol| {
|
||||
imports::Import::new(
|
||||
Some(symbol.symbol.span.as_str()),
|
||||
std::path::Path::new(import.source.span.as_str()),
|
||||
)
|
||||
.alias(
|
||||
symbol
|
||||
.alias
|
||||
.as_ref()
|
||||
.map(|a| a.span.as_str())
|
||||
.or_else(|| Some(symbol.symbol.span.as_str())),
|
||||
)
|
||||
.span(symbol.span.clone())
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
match import {
|
||||
pest::ImportDirective::Main(import) => {
|
||||
let span = import.span;
|
||||
let source = Path::new(import.source.span.as_str());
|
||||
let id = "main";
|
||||
let alias = import.alias.map(|a| a.span.as_str());
|
||||
|
||||
let import = absy::CanonicalImport {
|
||||
source,
|
||||
id: absy::SymbolIdentifier::from(id).alias(alias),
|
||||
}
|
||||
.span(span.clone());
|
||||
|
||||
vec![absy::SymbolDeclaration {
|
||||
id: alias.unwrap_or(id),
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Import(import)),
|
||||
}
|
||||
.span(span.clone())]
|
||||
}
|
||||
pest::ImportDirective::From(import) => {
|
||||
let span = import.span;
|
||||
let source = Path::new(import.source.span.as_str());
|
||||
import
|
||||
.symbols
|
||||
.into_iter()
|
||||
.map(|symbol| {
|
||||
let alias = symbol
|
||||
.alias
|
||||
.as_ref()
|
||||
.map(|a| a.span.as_str())
|
||||
.unwrap_or_else(|| symbol.id.span.as_str());
|
||||
|
||||
let import = absy::CanonicalImport {
|
||||
source,
|
||||
id: absy::SymbolIdentifier::from(symbol.id.span.as_str())
|
||||
.alias(Some(alias)),
|
||||
}
|
||||
.span(span.clone());
|
||||
|
||||
absy::SymbolDeclaration {
|
||||
id: alias,
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Import(import)),
|
||||
}
|
||||
.span(span.clone())
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +89,7 @@ impl<'ast> From<pest::StructDefinition<'ast>> for absy::SymbolDeclarationNode<'a
|
|||
|
||||
absy::SymbolDeclaration {
|
||||
id,
|
||||
symbol: absy::Symbol::Here(SymbolDefinition::Struct(ty)),
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Struct(ty)),
|
||||
}
|
||||
.span(span)
|
||||
}
|
||||
|
@ -119,14 +124,14 @@ impl<'ast> From<pest::ConstantDefinition<'ast>> for absy::SymbolDeclarationNode<
|
|||
|
||||
absy::SymbolDeclaration {
|
||||
id,
|
||||
symbol: absy::Symbol::Here(SymbolDefinition::Constant(ty)),
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Constant(ty)),
|
||||
}
|
||||
.span(span)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<pest::Function<'ast>> for absy::SymbolDeclarationNode<'ast> {
|
||||
fn from(function: pest::Function<'ast>) -> absy::SymbolDeclarationNode<'ast> {
|
||||
impl<'ast> From<pest::FunctionDefinition<'ast>> for absy::SymbolDeclarationNode<'ast> {
|
||||
fn from(function: pest::FunctionDefinition<'ast>) -> absy::SymbolDeclarationNode<'ast> {
|
||||
use crate::absy::NodeValue;
|
||||
|
||||
let span = function.span;
|
||||
|
@ -175,7 +180,7 @@ impl<'ast> From<pest::Function<'ast>> for absy::SymbolDeclarationNode<'ast> {
|
|||
|
||||
absy::SymbolDeclaration {
|
||||
id,
|
||||
symbol: absy::Symbol::Here(SymbolDefinition::Function(function)),
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Function(function)),
|
||||
}
|
||||
.span(span)
|
||||
}
|
||||
|
@ -781,7 +786,7 @@ mod tests {
|
|||
let expected: absy::Module = absy::Module {
|
||||
symbols: vec![absy::SymbolDeclaration {
|
||||
id: &source[4..8],
|
||||
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Function(
|
||||
absy::Function {
|
||||
arguments: vec![],
|
||||
statements: vec![absy::Statement::Return(
|
||||
|
@ -801,7 +806,6 @@ mod tests {
|
|||
)),
|
||||
}
|
||||
.into()],
|
||||
imports: vec![],
|
||||
};
|
||||
assert_eq!(absy::Module::from(ast), expected);
|
||||
}
|
||||
|
@ -813,7 +817,7 @@ mod tests {
|
|||
let expected: absy::Module = absy::Module {
|
||||
symbols: vec![absy::SymbolDeclaration {
|
||||
id: &source[4..8],
|
||||
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Function(
|
||||
absy::Function {
|
||||
arguments: vec![],
|
||||
statements: vec![absy::Statement::Return(
|
||||
|
@ -831,7 +835,6 @@ mod tests {
|
|||
)),
|
||||
}
|
||||
.into()],
|
||||
imports: vec![],
|
||||
};
|
||||
assert_eq!(absy::Module::from(ast), expected);
|
||||
}
|
||||
|
@ -844,7 +847,7 @@ mod tests {
|
|||
let expected: absy::Module = absy::Module {
|
||||
symbols: vec![absy::SymbolDeclaration {
|
||||
id: &source[4..8],
|
||||
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Function(
|
||||
absy::Function {
|
||||
arguments: vec![
|
||||
absy::Parameter::private(
|
||||
|
@ -884,7 +887,6 @@ mod tests {
|
|||
)),
|
||||
}
|
||||
.into()],
|
||||
imports: vec![],
|
||||
};
|
||||
|
||||
assert_eq!(absy::Module::from(ast), expected);
|
||||
|
@ -898,7 +900,7 @@ mod tests {
|
|||
absy::Module {
|
||||
symbols: vec![absy::SymbolDeclaration {
|
||||
id: "main",
|
||||
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Function(
|
||||
absy::Function {
|
||||
arguments: vec![absy::Parameter::private(
|
||||
absy::Variable::new("a", ty.clone().mock()).into(),
|
||||
|
@ -917,7 +919,6 @@ mod tests {
|
|||
)),
|
||||
}
|
||||
.into()],
|
||||
imports: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -972,7 +973,7 @@ mod tests {
|
|||
absy::Module {
|
||||
symbols: vec![absy::SymbolDeclaration {
|
||||
id: "main",
|
||||
symbol: absy::Symbol::Here(SymbolDefinition::Function(
|
||||
symbol: absy::Symbol::Here(absy::SymbolDefinition::Function(
|
||||
absy::Function {
|
||||
arguments: vec![],
|
||||
statements: vec![absy::Statement::Return(
|
||||
|
@ -988,7 +989,6 @@ mod tests {
|
|||
)),
|
||||
}
|
||||
.into()],
|
||||
imports: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,6 @@ pub use crate::absy::variable::{Variable, VariableNode};
|
|||
use crate::embed::FlatEmbed;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::imports::ImportDirective;
|
||||
use crate::imports::ImportNode;
|
||||
use std::fmt;
|
||||
|
||||
use num_bigint::BigUint;
|
||||
|
@ -44,61 +42,134 @@ pub struct Program<'ast> {
|
|||
pub main: OwnedModuleId,
|
||||
}
|
||||
|
||||
/// A declaration of a `FunctionSymbol`, be it from an import or a function definition
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct SymbolIdentifier<'ast> {
|
||||
pub id: Identifier<'ast>,
|
||||
pub alias: Option<Identifier<'ast>>,
|
||||
}
|
||||
|
||||
impl<'ast> From<Identifier<'ast>> for SymbolIdentifier<'ast> {
|
||||
fn from(id: &'ast str) -> Self {
|
||||
SymbolIdentifier { id, alias: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> SymbolIdentifier<'ast> {
|
||||
pub fn alias(mut self, alias: Option<Identifier<'ast>>) -> Self {
|
||||
self.alias = alias;
|
||||
self
|
||||
}
|
||||
pub fn get_alias(&self) -> Identifier<'ast> {
|
||||
self.alias.unwrap_or(self.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for SymbolIdentifier<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}{}",
|
||||
self.id,
|
||||
self.alias.map(|a| format!(" as {}", a)).unwrap_or_default()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct CanonicalImport<'ast> {
|
||||
pub source: &'ast Path,
|
||||
pub id: SymbolIdentifier<'ast>,
|
||||
}
|
||||
|
||||
pub type CanonicalImportNode<'ast> = Node<CanonicalImport<'ast>>;
|
||||
|
||||
impl<'ast> fmt::Display for CanonicalImport<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "from \"{}\" import {}", self.source.display(), self.id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct SymbolImport<'ast> {
|
||||
pub module_id: OwnedModuleId,
|
||||
pub symbol_id: Identifier<'ast>,
|
||||
}
|
||||
|
||||
pub type SymbolImportNode<'ast> = Node<SymbolImport<'ast>>;
|
||||
|
||||
impl<'ast> SymbolImport<'ast> {
|
||||
pub fn with_id_in_module<S: Into<Identifier<'ast>>, U: Into<OwnedModuleId>>(
|
||||
symbol_id: S,
|
||||
module_id: U,
|
||||
) -> Self {
|
||||
SymbolImport {
|
||||
symbol_id: symbol_id.into(),
|
||||
module_id: module_id.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for SymbolImport<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"from \"{}\" import {}",
|
||||
self.module_id.display(),
|
||||
self.symbol_id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A declaration of a symbol
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct SymbolDeclaration<'ast> {
|
||||
pub id: Identifier<'ast>,
|
||||
pub symbol: Symbol<'ast>,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(PartialEq, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum SymbolDefinition<'ast> {
|
||||
Import(CanonicalImportNode<'ast>),
|
||||
Struct(StructDefinitionNode<'ast>),
|
||||
Constant(ConstantDefinitionNode<'ast>),
|
||||
Function(FunctionNode<'ast>),
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for SymbolDefinition<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
SymbolDefinition::Struct(s) => write!(f, "Struct({:?})", s),
|
||||
SymbolDefinition::Constant(c) => write!(f, "Constant({:?})", c),
|
||||
SymbolDefinition::Function(func) => write!(f, "Function({:?})", func),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Symbol<'ast> {
|
||||
Here(SymbolDefinition<'ast>),
|
||||
There(SymbolImportNode<'ast>),
|
||||
Flat(FlatEmbed),
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for Symbol<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Symbol::Here(k) => write!(f, "Here({:?})", k),
|
||||
Symbol::There(i) => write!(f, "There({:?})", i),
|
||||
Symbol::Flat(flat) => write!(f, "Flat({:?})", flat),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for SymbolDeclaration<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.symbol {
|
||||
Symbol::Here(ref kind) => match kind {
|
||||
SymbolDefinition::Struct(t) => write!(f, "struct {} {}", self.id, t),
|
||||
SymbolDefinition::Constant(c) => write!(
|
||||
match &self.symbol {
|
||||
Symbol::Here(ref symbol) => match symbol {
|
||||
SymbolDefinition::Import(ref i) => write!(
|
||||
f,
|
||||
"from \"{}\" import {}",
|
||||
i.value.source.display(),
|
||||
i.value.id
|
||||
),
|
||||
SymbolDefinition::Struct(ref t) => write!(f, "struct {} {}", self.id, t),
|
||||
SymbolDefinition::Constant(ref c) => write!(
|
||||
f,
|
||||
"const {} {} = {}",
|
||||
c.value.ty, self.id, c.value.expression
|
||||
),
|
||||
SymbolDefinition::Function(func) => write!(f, "def {}{}", self.id, func),
|
||||
SymbolDefinition::Function(ref func) => {
|
||||
write!(f, "def {}{}", self.id, func)
|
||||
}
|
||||
},
|
||||
Symbol::There(ref import) => write!(f, "import {} as {}", import, self.id),
|
||||
Symbol::There(ref i) => write!(
|
||||
f,
|
||||
"from \"{}\" import {} as {}",
|
||||
i.value.module_id.display(),
|
||||
i.value.symbol_id,
|
||||
self.id
|
||||
),
|
||||
Symbol::Flat(ref flat_fun) => {
|
||||
write!(f, "def {}{}:\n\t// hidden", self.id, flat_fun.signature())
|
||||
}
|
||||
|
@ -109,25 +180,18 @@ impl<'ast> fmt::Display for SymbolDeclaration<'ast> {
|
|||
pub type SymbolDeclarationNode<'ast> = Node<SymbolDeclaration<'ast>>;
|
||||
|
||||
/// A module as a collection of `FunctionDeclaration`s
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Module<'ast> {
|
||||
/// Symbols of the module
|
||||
pub symbols: Declarations<'ast>,
|
||||
pub imports: Vec<ImportNode<'ast>>, // we still use `imports` as they are not directly converted into `FunctionDeclaration`s after the importer is done, `imports` is empty
|
||||
}
|
||||
|
||||
impl<'ast> Module<'ast> {
|
||||
pub fn with_symbols<I: IntoIterator<Item = SymbolDeclarationNode<'ast>>>(i: I) -> Self {
|
||||
Module {
|
||||
symbols: i.into_iter().collect(),
|
||||
imports: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn imports<I: IntoIterator<Item = ImportNode<'ast>>>(mut self, i: I) -> Self {
|
||||
self.imports = i.into_iter().collect();
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub type UnresolvedTypeNode<'ast> = Node<UnresolvedType<'ast>>;
|
||||
|
@ -169,7 +233,7 @@ impl<'ast> fmt::Display for StructDefinitionField<'ast> {
|
|||
|
||||
type StructDefinitionFieldNode<'ast> = Node<StructDefinitionField<'ast>>;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ConstantDefinition<'ast> {
|
||||
pub ty: UnresolvedTypeNode<'ast>,
|
||||
pub expression: ExpressionNode<'ast>,
|
||||
|
@ -183,92 +247,21 @@ impl<'ast> fmt::Display for ConstantDefinition<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for ConstantDefinition<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"ConstantDefinition({:?}, {:?})",
|
||||
self.ty, self.expression
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// An import
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct SymbolImport<'ast> {
|
||||
/// the id of the symbol in the target module. Note: there may be many candidates as imports statements do not specify the signature. In that case they must all be functions however.
|
||||
pub symbol_id: Identifier<'ast>,
|
||||
/// the id of the module to import from
|
||||
pub module_id: OwnedModuleId,
|
||||
}
|
||||
|
||||
type SymbolImportNode<'ast> = Node<SymbolImport<'ast>>;
|
||||
|
||||
impl<'ast> SymbolImport<'ast> {
|
||||
pub fn with_id_in_module<S: Into<Identifier<'ast>>, U: Into<OwnedModuleId>>(
|
||||
symbol_id: S,
|
||||
module_id: U,
|
||||
) -> Self {
|
||||
SymbolImport {
|
||||
symbol_id: symbol_id.into(),
|
||||
module_id: module_id.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for SymbolImport<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} from {}",
|
||||
self.symbol_id,
|
||||
self.module_id.display().to_string()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Module<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut res = vec![];
|
||||
res.extend(
|
||||
self.imports
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
res.extend(
|
||||
self.symbols
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
let res = self
|
||||
.symbols
|
||||
.iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>();
|
||||
write!(f, "{}", res.join("\n"))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for Module<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"module(\n\timports:\n\t\t{}\n\tsymbols:\n\t\t{}\n)",
|
||||
self.imports
|
||||
.iter()
|
||||
.map(|x| format!("{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\t\t"),
|
||||
self.symbols
|
||||
.iter()
|
||||
.map(|x| format!("{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\t\t")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub type ConstantGenericNode<'ast> = Node<Identifier<'ast>>;
|
||||
|
||||
/// A function defined locally
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Function<'ast> {
|
||||
/// Arguments of the function
|
||||
pub arguments: Vec<ParameterNode<'ast>>,
|
||||
|
@ -312,23 +305,8 @@ impl<'ast> fmt::Display for Function<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for Function<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Function(arguments: {:?}, ...):\n{}",
|
||||
self.arguments,
|
||||
self.statements
|
||||
.iter()
|
||||
.map(|x| format!("\t{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that we can assign to
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Assignee<'ast> {
|
||||
Identifier(Identifier<'ast>),
|
||||
Select(Box<AssigneeNode<'ast>>, Box<RangeOrExpression<'ast>>),
|
||||
|
@ -337,16 +315,6 @@ pub enum Assignee<'ast> {
|
|||
|
||||
pub type AssigneeNode<'ast> = Node<Assignee<'ast>>;
|
||||
|
||||
impl<'ast> fmt::Debug for Assignee<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Assignee::Identifier(ref s) => write!(f, "Identifier({:?})", s),
|
||||
Assignee::Select(ref a, ref e) => write!(f, "Select({:?}[{:?}])", a, e),
|
||||
Assignee::Member(ref s, ref m) => write!(f, "Member({:?}.{:?})", s, m),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Assignee<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
@ -359,7 +327,7 @@ impl<'ast> fmt::Display for Assignee<'ast> {
|
|||
|
||||
/// A statement in a `Function`
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Statement<'ast> {
|
||||
Return(ExpressionListNode<'ast>),
|
||||
Declaration(VariableNode<'ast>),
|
||||
|
@ -403,31 +371,8 @@ impl<'ast> fmt::Display for Statement<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for Statement<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Statement::Return(ref expr) => write!(f, "Return({:?})", expr),
|
||||
Statement::Declaration(ref var) => write!(f, "Declaration({:?})", var),
|
||||
Statement::Definition(ref lhs, ref rhs) => {
|
||||
write!(f, "Definition({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
Statement::Assertion(ref e) => write!(f, "Assertion({:?})", e),
|
||||
Statement::For(ref var, ref start, ref stop, ref list) => {
|
||||
writeln!(f, "for {:?} in {:?}..{:?} do", var, start, stop)?;
|
||||
for l in list {
|
||||
writeln!(f, "\t\t{:?}", l)?;
|
||||
}
|
||||
write!(f, "\tendfor")
|
||||
}
|
||||
Statement::MultipleDefinition(ref lhs, ref rhs) => {
|
||||
write!(f, "MultipleDefinition({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An element of an inline array, can be a spread `...a` or an expression `a`
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum SpreadOrExpression<'ast> {
|
||||
Spread(SpreadNode<'ast>),
|
||||
Expression(ExpressionNode<'ast>),
|
||||
|
@ -448,17 +393,8 @@ impl<'ast> fmt::Display for SpreadOrExpression<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for SpreadOrExpression<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
SpreadOrExpression::Spread(ref s) => write!(f, "{:?}", s),
|
||||
SpreadOrExpression::Expression(ref e) => write!(f, "{:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The index in an array selector. Can be a range or an expression.
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum RangeOrExpression<'ast> {
|
||||
Range(RangeNode<'ast>),
|
||||
Expression(ExpressionNode<'ast>),
|
||||
|
@ -473,13 +409,10 @@ impl<'ast> fmt::Display for RangeOrExpression<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for RangeOrExpression<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
RangeOrExpression::Range(ref s) => write!(f, "{:?}", s),
|
||||
RangeOrExpression::Expression(ref e) => write!(f, "{:?}", e),
|
||||
}
|
||||
}
|
||||
/// A spread
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Spread<'ast> {
|
||||
pub expression: ExpressionNode<'ast>,
|
||||
}
|
||||
|
||||
pub type SpreadNode<'ast> = Node<Spread<'ast>>;
|
||||
|
@ -490,20 +423,8 @@ impl<'ast> fmt::Display for Spread<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for Spread<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Spread({:?})", self.expression)
|
||||
}
|
||||
}
|
||||
|
||||
/// A spread
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Spread<'ast> {
|
||||
pub expression: ExpressionNode<'ast>,
|
||||
}
|
||||
|
||||
/// A range
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Range<'ast> {
|
||||
pub from: Option<ExpressionNode<'ast>>,
|
||||
pub to: Option<ExpressionNode<'ast>>,
|
||||
|
@ -528,14 +449,8 @@ impl<'ast> fmt::Display for Range<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for Range<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Range({:?}, {:?})", self.from, self.to)
|
||||
}
|
||||
}
|
||||
|
||||
/// An expression
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Expression<'ast> {
|
||||
IntConstant(BigUint),
|
||||
FieldConstant(BigUint),
|
||||
|
@ -672,73 +587,8 @@ impl<'ast> fmt::Display for Expression<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for Expression<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Expression::U8Constant(ref i) => write!(f, "U8({:x})", i),
|
||||
Expression::U16Constant(ref i) => write!(f, "U16({:x})", i),
|
||||
Expression::U32Constant(ref i) => write!(f, "U32({:x})", i),
|
||||
Expression::U64Constant(ref i) => write!(f, "U64({:x})", i),
|
||||
Expression::FieldConstant(ref i) => write!(f, "Field({:?})", i),
|
||||
Expression::IntConstant(ref i) => write!(f, "Int({:?})", i),
|
||||
Expression::Identifier(ref var) => write!(f, "Ide({})", var),
|
||||
Expression::Add(ref lhs, ref rhs) => write!(f, "Add({:?}, {:?})", lhs, rhs),
|
||||
Expression::Sub(ref lhs, ref rhs) => write!(f, "Sub({:?}, {:?})", lhs, rhs),
|
||||
Expression::Mult(ref lhs, ref rhs) => write!(f, "Mult({:?}, {:?})", lhs, rhs),
|
||||
Expression::Div(ref lhs, ref rhs) => write!(f, "Div({:?}, {:?})", lhs, rhs),
|
||||
Expression::Rem(ref lhs, ref rhs) => write!(f, "Rem({:?}, {:?})", lhs, rhs),
|
||||
Expression::Pow(ref lhs, ref rhs) => write!(f, "Pow({:?}, {:?})", lhs, rhs),
|
||||
Expression::Neg(ref e) => write!(f, "Neg({:?})", e),
|
||||
Expression::Pos(ref e) => write!(f, "Pos({:?})", e),
|
||||
Expression::BooleanConstant(b) => write!(f, "{}", b),
|
||||
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(
|
||||
f,
|
||||
"IfElse({:?}, {:?}, {:?})",
|
||||
condition, consequent, alternative
|
||||
),
|
||||
Expression::FunctionCall(ref g, ref i, ref p) => {
|
||||
write!(f, "FunctionCall({:?}, {:?}, (", g, i)?;
|
||||
f.debug_list().entries(p.iter()).finish()?;
|
||||
write!(f, ")")
|
||||
}
|
||||
Expression::Lt(ref lhs, ref rhs) => write!(f, "Lt({:?}, {:?})", lhs, rhs),
|
||||
Expression::Le(ref lhs, ref rhs) => write!(f, "Le({:?}, {:?})", lhs, rhs),
|
||||
Expression::Eq(ref lhs, ref rhs) => write!(f, "Eq({:?}, {:?})", lhs, rhs),
|
||||
Expression::Ge(ref lhs, ref rhs) => write!(f, "Ge({:?}, {:?})", lhs, rhs),
|
||||
Expression::Gt(ref lhs, ref rhs) => write!(f, "Gt({:?}, {:?})", lhs, rhs),
|
||||
Expression::And(ref lhs, ref rhs) => write!(f, "And({:?}, {:?})", lhs, rhs),
|
||||
Expression::Not(ref exp) => write!(f, "Not({:?})", exp),
|
||||
Expression::InlineArray(ref exprs) => {
|
||||
write!(f, "InlineArray([")?;
|
||||
f.debug_list().entries(exprs.iter()).finish()?;
|
||||
write!(f, "]")
|
||||
}
|
||||
Expression::ArrayInitializer(ref e, ref count) => {
|
||||
write!(f, "ArrayInitializer({:?}, {:?})", e, count)
|
||||
}
|
||||
Expression::InlineStruct(ref id, ref members) => {
|
||||
write!(f, "InlineStruct({:?}, [", id)?;
|
||||
f.debug_list().entries(members.iter()).finish()?;
|
||||
write!(f, "]")
|
||||
}
|
||||
Expression::Select(ref array, ref index) => {
|
||||
write!(f, "Select({:?}, {:?})", array, index)
|
||||
}
|
||||
Expression::Member(ref struc, ref id) => write!(f, "Member({:?}, {:?})", struc, id),
|
||||
Expression::Or(ref lhs, ref rhs) => write!(f, "Or({:?}, {:?})", lhs, rhs),
|
||||
Expression::BitXor(ref lhs, ref rhs) => write!(f, "BitXor({:?}, {:?})", lhs, rhs),
|
||||
Expression::BitAnd(ref lhs, ref rhs) => write!(f, "BitAnd({:?}, {:?})", lhs, rhs),
|
||||
Expression::BitOr(ref lhs, ref rhs) => write!(f, "BitOr({:?}, {:?})", lhs, rhs),
|
||||
Expression::LeftShift(ref lhs, ref rhs) => write!(f, "LeftShift({:?}, {:?})", lhs, rhs),
|
||||
Expression::RightShift(ref lhs, ref rhs) => {
|
||||
write!(f, "RightShift({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of expressions, used in return statements
|
||||
#[derive(Clone, PartialEq, Default)]
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct ExpressionList<'ast> {
|
||||
pub expressions: Vec<ExpressionNode<'ast>>,
|
||||
}
|
||||
|
@ -756,9 +606,3 @@ impl<'ast> fmt::Display for ExpressionList<'ast> {
|
|||
write!(f, "")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for ExpressionList<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "ExpressionList({:?})", self.expressions)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,6 @@ impl<V: NodeValue> From<V> for Node<V> {
|
|||
|
||||
use crate::absy::types::UnresolvedType;
|
||||
use crate::absy::*;
|
||||
use crate::imports::*;
|
||||
|
||||
impl<'ast> NodeValue for Expression<'ast> {}
|
||||
impl<'ast> NodeValue for ExpressionList<'ast> {}
|
||||
|
@ -87,10 +86,10 @@ impl<'ast> NodeValue for StructDefinitionField<'ast> {}
|
|||
impl<'ast> NodeValue for ConstantDefinition<'ast> {}
|
||||
impl<'ast> NodeValue for Function<'ast> {}
|
||||
impl<'ast> NodeValue for Module<'ast> {}
|
||||
impl<'ast> NodeValue for CanonicalImport<'ast> {}
|
||||
impl<'ast> NodeValue for SymbolImport<'ast> {}
|
||||
impl<'ast> NodeValue for Variable<'ast> {}
|
||||
impl<'ast> NodeValue for Parameter<'ast> {}
|
||||
impl<'ast> NodeValue for Import<'ast> {}
|
||||
impl<'ast> NodeValue for Spread<'ast> {}
|
||||
impl<'ast> NodeValue for Range<'ast> {}
|
||||
impl<'ast> NodeValue for Identifier<'ast> {}
|
||||
|
|
|
@ -140,19 +140,32 @@ impl From<static_analysis::Error> for CompileErrorInner {
|
|||
impl fmt::Display for CompileErrorInner {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
CompileErrorInner::ParserError(ref e) => write!(f, "{}", e),
|
||||
CompileErrorInner::MacroError(ref e) => write!(f, "{}", e),
|
||||
CompileErrorInner::SemanticError(ref e) => write!(f, "{}", e),
|
||||
CompileErrorInner::ReadError(ref e) => write!(f, "{}", e),
|
||||
CompileErrorInner::ImportError(ref e) => write!(f, "{}", e),
|
||||
CompileErrorInner::AnalysisError(ref e) => write!(f, "{}", e),
|
||||
CompileErrorInner::ParserError(ref e) => write!(f, "\n\t{}", e),
|
||||
CompileErrorInner::MacroError(ref e) => write!(f, "\n\t{}", e),
|
||||
CompileErrorInner::SemanticError(ref e) => {
|
||||
let location = e
|
||||
.pos()
|
||||
.map(|p| format!("{}", p.0))
|
||||
.unwrap_or_else(|| "".to_string());
|
||||
write!(f, "{}\n\t{}", location, e.message())
|
||||
}
|
||||
CompileErrorInner::ReadError(ref e) => write!(f, "\n\t{}", e),
|
||||
CompileErrorInner::ImportError(ref e) => {
|
||||
let location = e
|
||||
.pos()
|
||||
.map(|p| format!("{}", p.0))
|
||||
.unwrap_or_else(|| "".to_string());
|
||||
write!(f, "{}\n\t{}", location, e.message())
|
||||
}
|
||||
CompileErrorInner::AnalysisError(ref e) => write!(f, "\n\t{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct CompileConfig {
|
||||
pub allow_unconstrained_variables: bool,
|
||||
pub isolate_branches: bool,
|
||||
}
|
||||
|
||||
type FilePath = PathBuf;
|
||||
|
@ -283,7 +296,7 @@ mod test {
|
|||
assert!(res.unwrap_err().0[0]
|
||||
.value()
|
||||
.to_string()
|
||||
.contains(&"Can't resolve import without a resolver"));
|
||||
.contains(&"Cannot resolve import without a resolver"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -70,7 +70,11 @@ impl fmt::Display for FlatVariable {
|
|||
|
||||
impl fmt::Debug for FlatVariable {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "FlatVariable(id: {})", self.id)
|
||||
match self.id {
|
||||
0 => write!(f, "~one"),
|
||||
i if i > 0 => write!(f, "_{}", i - 1),
|
||||
i => write!(f, "~out_{}", -(i + 1)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -370,6 +370,56 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
));
|
||||
}
|
||||
|
||||
fn make_conditional(
|
||||
&mut self,
|
||||
statements: Vec<FlatStatement<T>>,
|
||||
condition: FlatExpression<T>,
|
||||
) -> Vec<FlatStatement<T>> {
|
||||
statements
|
||||
.into_iter()
|
||||
.flat_map(|s| match s {
|
||||
FlatStatement::Condition(left, right) => {
|
||||
let mut output = vec![];
|
||||
|
||||
// we transform (a == b) into (c => (a == b)) which is (!c || (a == b))
|
||||
|
||||
// let's introduce new variables to make sure everything is linear
|
||||
let name_left = self.define(left, &mut output);
|
||||
let name_right = self.define(right, &mut output);
|
||||
|
||||
// let's introduce an expression which is 1 iff `a == b`
|
||||
let y = FlatExpression::Add(
|
||||
box FlatExpression::Sub(box name_left.into(), box name_right.into()),
|
||||
box T::one().into(),
|
||||
);
|
||||
// let's introduce !c
|
||||
let x = FlatExpression::Sub(box T::one().into(), box condition.clone());
|
||||
|
||||
assert!(x.is_linear() && y.is_linear());
|
||||
let name_x_or_y = self.use_sym();
|
||||
output.push(FlatStatement::Directive(FlatDirective {
|
||||
solver: Solver::Or,
|
||||
outputs: vec![name_x_or_y],
|
||||
inputs: vec![x.clone(), y.clone()],
|
||||
}));
|
||||
output.push(FlatStatement::Condition(
|
||||
FlatExpression::Add(
|
||||
box x.clone(),
|
||||
box FlatExpression::Sub(box y.clone(), box name_x_or_y.into()),
|
||||
),
|
||||
FlatExpression::Mult(box x.clone(), box y.clone()),
|
||||
));
|
||||
output.push(FlatStatement::Condition(
|
||||
name_x_or_y.into(),
|
||||
T::one().into(),
|
||||
));
|
||||
output
|
||||
}
|
||||
s => vec![s],
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Flatten an if/else expression
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -389,13 +439,39 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
) -> FlatUExpression<T> {
|
||||
let condition = self.flatten_boolean_expression(statements_flattened, condition);
|
||||
|
||||
let consequence = consequence.flatten(self, statements_flattened);
|
||||
|
||||
let alternative = alternative.flatten(self, statements_flattened);
|
||||
|
||||
let condition_id = self.use_sym();
|
||||
statements_flattened.push(FlatStatement::Definition(condition_id, condition));
|
||||
|
||||
let (consequence, alternative) = if self.config.isolate_branches {
|
||||
let mut consequence_statements = vec![];
|
||||
|
||||
let consequence = consequence.flatten(self, &mut consequence_statements);
|
||||
|
||||
let mut alternative_statements = vec![];
|
||||
|
||||
let alternative = alternative.flatten(self, &mut alternative_statements);
|
||||
|
||||
let consequence_statements =
|
||||
self.make_conditional(consequence_statements, condition_id.into());
|
||||
let alternative_statements = self.make_conditional(
|
||||
alternative_statements,
|
||||
FlatExpression::Sub(
|
||||
box FlatExpression::Number(T::one()),
|
||||
box condition_id.into(),
|
||||
),
|
||||
);
|
||||
|
||||
statements_flattened.extend(consequence_statements);
|
||||
statements_flattened.extend(alternative_statements);
|
||||
|
||||
(consequence, alternative)
|
||||
} else {
|
||||
(
|
||||
consequence.flatten(self, statements_flattened),
|
||||
alternative.flatten(self, statements_flattened),
|
||||
)
|
||||
};
|
||||
|
||||
let consequence = consequence.flat();
|
||||
let alternative = alternative.flat();
|
||||
|
||||
|
@ -1396,9 +1472,10 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
}
|
||||
UExpressionInner::Sub(box left, box right) => {
|
||||
// see uint optimizer for the reasoning here
|
||||
let aux = FlatExpression::Number(
|
||||
T::from(2).pow(right.metadata.clone().unwrap().bitwidth() as usize),
|
||||
);
|
||||
let offset = FlatExpression::Number(T::from(2).pow(std::cmp::max(
|
||||
right.metadata.clone().unwrap().bitwidth() as usize,
|
||||
target_bitwidth as usize,
|
||||
)));
|
||||
|
||||
let left_flattened = self
|
||||
.flatten_uint_expression(statements_flattened, left)
|
||||
|
@ -1422,7 +1499,7 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
};
|
||||
|
||||
FlatUExpression::with_field(FlatExpression::Add(
|
||||
box aux,
|
||||
box offset,
|
||||
box FlatExpression::Sub(box new_left, box new_right),
|
||||
))
|
||||
}
|
||||
|
@ -2106,8 +2183,37 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
|||
expressions: flat_expressions,
|
||||
}));
|
||||
}
|
||||
ZirStatement::Declaration(_) => {
|
||||
// declarations have already been checked
|
||||
ZirStatement::IfElse(condition, consequence, alternative) => {
|
||||
let condition = self.flatten_boolean_expression(statements_flattened, condition);
|
||||
|
||||
if self.config.isolate_branches {
|
||||
let mut consequence_statements = vec![];
|
||||
let mut alternative_statements = vec![];
|
||||
|
||||
consequence
|
||||
.into_iter()
|
||||
.for_each(|s| self.flatten_statement(&mut consequence_statements, s));
|
||||
alternative
|
||||
.into_iter()
|
||||
.for_each(|s| self.flatten_statement(&mut alternative_statements, s));
|
||||
|
||||
let consequence_statements =
|
||||
self.make_conditional(consequence_statements, condition.clone());
|
||||
let alternative_statements = self.make_conditional(
|
||||
alternative_statements,
|
||||
FlatExpression::Sub(box FlatExpression::Number(T::one()), box condition),
|
||||
);
|
||||
|
||||
statements_flattened.extend(consequence_statements);
|
||||
statements_flattened.extend(alternative_statements);
|
||||
} else {
|
||||
consequence
|
||||
.into_iter()
|
||||
.for_each(|s| self.flatten_statement(statements_flattened, s));
|
||||
alternative
|
||||
.into_iter()
|
||||
.for_each(|s| self.flatten_statement(statements_flattened, s));
|
||||
}
|
||||
}
|
||||
ZirStatement::Definition(assignee, expr) => {
|
||||
// define n variables with n the number of primitive types for v_type
|
||||
|
|
|
@ -32,6 +32,14 @@ impl Error {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn pos(&self) -> &Option<(Position, Position)> {
|
||||
&self.pos
|
||||
}
|
||||
|
||||
pub fn message(&self) -> &str {
|
||||
&self.message
|
||||
}
|
||||
|
||||
fn with_pos(self, pos: Option<(Position, Position)>) -> Error {
|
||||
Error { pos, ..self }
|
||||
}
|
||||
|
@ -56,94 +64,6 @@ impl From<io::Error> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub enum ImportDirective<'ast> {
|
||||
Main(ImportNode<'ast>),
|
||||
From(Vec<ImportNode<'ast>>),
|
||||
}
|
||||
|
||||
impl<'ast> IntoIterator for ImportDirective<'ast> {
|
||||
type Item = ImportNode<'ast>;
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
let vec = match self {
|
||||
ImportDirective::Main(v) => vec![v],
|
||||
ImportDirective::From(v) => v,
|
||||
};
|
||||
vec.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
type ImportPath<'ast> = &'ast Path;
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub struct Import<'ast> {
|
||||
source: ImportPath<'ast>,
|
||||
symbol: Option<Identifier<'ast>>,
|
||||
alias: Option<Identifier<'ast>>,
|
||||
}
|
||||
|
||||
pub type ImportNode<'ast> = Node<Import<'ast>>;
|
||||
|
||||
impl<'ast> Import<'ast> {
|
||||
pub fn new(symbol: Option<Identifier<'ast>>, source: ImportPath<'ast>) -> Import<'ast> {
|
||||
Import {
|
||||
symbol,
|
||||
source,
|
||||
alias: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_alias(&self) -> &Option<Identifier<'ast>> {
|
||||
&self.alias
|
||||
}
|
||||
|
||||
pub fn new_with_alias(
|
||||
symbol: Option<Identifier<'ast>>,
|
||||
source: ImportPath<'ast>,
|
||||
alias: Identifier<'ast>,
|
||||
) -> Import<'ast> {
|
||||
Import {
|
||||
symbol,
|
||||
source,
|
||||
alias: Some(alias),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alias(mut self, alias: Option<Identifier<'ast>>) -> Self {
|
||||
self.alias = alias;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_source(&self) -> &ImportPath<'ast> {
|
||||
&self.source
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Import<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.alias {
|
||||
Some(ref alias) => write!(f, "import {} as {}", self.source.display(), alias),
|
||||
None => write!(f, "import {}", self.source.display()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for Import<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.alias {
|
||||
Some(ref alias) => write!(
|
||||
f,
|
||||
"import(source: {}, alias: {})",
|
||||
self.source.display(),
|
||||
alias
|
||||
),
|
||||
None => write!(f, "import(source: {})", self.source.display()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Importer;
|
||||
|
||||
impl Importer {
|
||||
|
@ -154,255 +74,157 @@ impl Importer {
|
|||
modules: &mut HashMap<OwnedModuleId, Module<'ast>>,
|
||||
arena: &'ast Arena<String>,
|
||||
) -> Result<Module<'ast>, CompileErrors> {
|
||||
let mut symbols: Vec<_> = vec![];
|
||||
let symbols: Vec<_> = destination
|
||||
.symbols
|
||||
.into_iter()
|
||||
.map(|s| match s.value.symbol {
|
||||
Symbol::Here(SymbolDefinition::Import(import)) => {
|
||||
Importer::resolve::<T, E>(import, &location, resolver, modules, arena)
|
||||
}
|
||||
_ => Ok(s),
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
for import in destination.imports {
|
||||
let pos = import.pos();
|
||||
let import = import.value;
|
||||
let alias = import.alias;
|
||||
// handle the case of special bellman and packing imports
|
||||
if import.source.starts_with("EMBED") {
|
||||
match import.source.to_str().unwrap() {
|
||||
#[cfg(feature = "bellman")]
|
||||
"EMBED/sha256round" => {
|
||||
if T::id() != Bn128Field::id() {
|
||||
return Err(CompileErrorInner::ImportError(
|
||||
Error::new(format!(
|
||||
"Embed sha256round cannot be used with curve {}",
|
||||
T::name()
|
||||
))
|
||||
.with_pos(Some(pos)),
|
||||
)
|
||||
.in_file(&location)
|
||||
.into());
|
||||
} else {
|
||||
let alias = alias.unwrap_or("sha256round");
|
||||
Ok(Module::with_symbols(symbols))
|
||||
}
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::Sha256Round),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
}
|
||||
"EMBED/unpack" => {
|
||||
let alias = alias.unwrap_or("unpack");
|
||||
fn resolve<'ast, T: Field, E: Into<Error>>(
|
||||
import: CanonicalImportNode<'ast>,
|
||||
location: &Path,
|
||||
resolver: Option<&dyn Resolver<E>>,
|
||||
modules: &mut HashMap<OwnedModuleId, Module<'ast>>,
|
||||
arena: &'ast Arena<String>,
|
||||
) -> Result<SymbolDeclarationNode<'ast>, CompileErrors> {
|
||||
let pos = import.pos();
|
||||
let module_id = import.value.source;
|
||||
let symbol = import.value.id;
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::Unpack),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
"EMBED/u64_to_bits" => {
|
||||
let alias = alias.unwrap_or("u64_to_bits");
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::U64ToBits),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
"EMBED/u32_to_bits" => {
|
||||
let alias = alias.unwrap_or("u32_to_bits");
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::U32ToBits),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
"EMBED/u16_to_bits" => {
|
||||
let alias = alias.unwrap_or("u16_to_bits");
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::U16ToBits),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
"EMBED/u8_to_bits" => {
|
||||
let alias = alias.unwrap_or("u8_to_bits");
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::U8ToBits),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
"EMBED/u64_from_bits" => {
|
||||
let alias = alias.unwrap_or("u64_from_bits");
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::U64FromBits),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
"EMBED/u32_from_bits" => {
|
||||
let alias = alias.unwrap_or("u32_from_bits");
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::U32FromBits),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
"EMBED/u16_from_bits" => {
|
||||
let alias = alias.unwrap_or("u16_from_bits");
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::U16FromBits),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
"EMBED/u8_from_bits" => {
|
||||
let alias = alias.unwrap_or("u8_from_bits");
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::Flat(FlatEmbed::U8FromBits),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
s => {
|
||||
let symbol_declaration = match module_id.to_str().unwrap() {
|
||||
"EMBED" => match symbol.id {
|
||||
#[cfg(feature = "bellman")]
|
||||
"sha256round" => {
|
||||
if T::id() != Bn128Field::id() {
|
||||
return Err(CompileErrorInner::ImportError(
|
||||
Error::new(format!("Embed {} not found", s)).with_pos(Some(pos)),
|
||||
Error::new(format!(
|
||||
"Embed sha256round cannot be used with curve {}",
|
||||
T::name()
|
||||
))
|
||||
.with_pos(Some(pos)),
|
||||
)
|
||||
.in_file(&location)
|
||||
.in_file(location)
|
||||
.into());
|
||||
} else {
|
||||
SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::Sha256Round),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// to resolve imports, we need a resolver
|
||||
match resolver {
|
||||
Some(res) => match res.resolve(location.clone(), import.source.to_path_buf()) {
|
||||
Ok((source, new_location)) => {
|
||||
// generate an alias from the imported path if none was given explicitely
|
||||
let alias = import.alias.unwrap_or(
|
||||
std::path::Path::new(import.source)
|
||||
.file_stem()
|
||||
.ok_or_else(|| {
|
||||
CompileErrors::from(
|
||||
CompileErrorInner::ImportError(Error::new(format!(
|
||||
"Could not determine alias for import {}",
|
||||
import.source.display()
|
||||
)))
|
||||
.in_file(&location),
|
||||
)
|
||||
})?
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
match modules.get(&new_location) {
|
||||
Some(_) => {}
|
||||
None => {
|
||||
let source = arena.alloc(source);
|
||||
|
||||
let compiled = compile_module::<T, E>(
|
||||
source,
|
||||
new_location.clone(),
|
||||
resolver,
|
||||
modules,
|
||||
&arena,
|
||||
)?;
|
||||
|
||||
assert!(modules
|
||||
.insert(new_location.clone(), compiled)
|
||||
.is_none());
|
||||
}
|
||||
};
|
||||
|
||||
symbols.push(
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::There(
|
||||
SymbolImport::with_id_in_module(
|
||||
import.symbol.unwrap_or("main"),
|
||||
new_location.display().to_string(),
|
||||
)
|
||||
.start_end(pos.0, pos.1),
|
||||
),
|
||||
}
|
||||
.start_end(pos.0, pos.1),
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(CompileErrorInner::ImportError(
|
||||
err.into().with_pos(Some(pos)),
|
||||
)
|
||||
.in_file(&location)
|
||||
.into());
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(CompileErrorInner::from(Error::new(
|
||||
"Can't resolve import without a resolver",
|
||||
))
|
||||
.in_file(&location)
|
||||
.into());
|
||||
}
|
||||
"unpack" => SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::Unpack),
|
||||
},
|
||||
"u64_to_bits" => SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::U64ToBits),
|
||||
},
|
||||
"u32_to_bits" => SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::U32ToBits),
|
||||
},
|
||||
"u16_to_bits" => SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::U16ToBits),
|
||||
},
|
||||
"u8_to_bits" => SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::U8ToBits),
|
||||
},
|
||||
"u64_from_bits" => SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::U64FromBits),
|
||||
},
|
||||
"u32_from_bits" => SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::U32FromBits),
|
||||
},
|
||||
"u16_from_bits" => SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::U16FromBits),
|
||||
},
|
||||
"u8_from_bits" => SymbolDeclaration {
|
||||
id: symbol.get_alias(),
|
||||
symbol: Symbol::Flat(FlatEmbed::U8FromBits),
|
||||
},
|
||||
s => {
|
||||
return Err(CompileErrorInner::ImportError(
|
||||
Error::new(format!("Embed {} not found", s)).with_pos(Some(pos)),
|
||||
)
|
||||
.in_file(location)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => match resolver {
|
||||
Some(res) => match res.resolve(location.to_path_buf(), module_id.to_path_buf()) {
|
||||
Ok((source, new_location)) => {
|
||||
let alias = symbol.alias.unwrap_or(
|
||||
module_id
|
||||
.file_stem()
|
||||
.ok_or_else(|| {
|
||||
CompileErrors::from(
|
||||
CompileErrorInner::ImportError(Error::new(format!(
|
||||
"Could not determine alias for import {}",
|
||||
module_id.display()
|
||||
)))
|
||||
.in_file(location),
|
||||
)
|
||||
})?
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
symbols.extend(destination.symbols);
|
||||
match modules.get(&new_location) {
|
||||
Some(_) => {}
|
||||
None => {
|
||||
let source = arena.alloc(source);
|
||||
let compiled = compile_module::<T, E>(
|
||||
source,
|
||||
new_location.clone(),
|
||||
resolver,
|
||||
modules,
|
||||
&arena,
|
||||
)?;
|
||||
|
||||
Ok(Module {
|
||||
imports: vec![],
|
||||
symbols,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn create_with_no_alias() {
|
||||
assert_eq!(
|
||||
Import::new(None, Path::new("./foo/bar/baz.zok")),
|
||||
Import {
|
||||
symbol: None,
|
||||
source: Path::new("./foo/bar/baz.zok"),
|
||||
alias: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_with_alias() {
|
||||
assert_eq!(
|
||||
Import::new_with_alias(None, Path::new("./foo/bar/baz.zok"), &"myalias"),
|
||||
Import {
|
||||
symbol: None,
|
||||
source: Path::new("./foo/bar/baz.zok"),
|
||||
alias: Some("myalias"),
|
||||
}
|
||||
);
|
||||
assert!(modules.insert(new_location.clone(), compiled).is_none());
|
||||
}
|
||||
};
|
||||
|
||||
SymbolDeclaration {
|
||||
id: &alias,
|
||||
symbol: Symbol::There(
|
||||
SymbolImport::with_id_in_module(symbol.id, new_location)
|
||||
.start_end(pos.0, pos.1),
|
||||
),
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(
|
||||
CompileErrorInner::ImportError(err.into().with_pos(Some(pos)))
|
||||
.in_file(location)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(CompileErrorInner::from(Error::new(
|
||||
"Cannot resolve import without a resolver",
|
||||
))
|
||||
.in_file(location)
|
||||
.into());
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Ok(symbol_declaration.start_end(pos.0, pos.1))
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,7 +19,7 @@ impl BoundsChecker {
|
|||
let array = self.fold_array_expression(array)?;
|
||||
let index = self.fold_uint_expression(index)?;
|
||||
|
||||
match (array.get_array_type().size.as_inner(), index.as_inner()) {
|
||||
match (array.ty().size.as_inner(), index.as_inner()) {
|
||||
(UExpressionInner::Value(size), UExpressionInner::Value(index)) => {
|
||||
if index >= size {
|
||||
return Err(format!(
|
||||
|
@ -52,11 +52,7 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for BoundsChecker {
|
|||
let from = self.fold_uint_expression(from)?;
|
||||
let to = self.fold_uint_expression(to)?;
|
||||
|
||||
match (
|
||||
array.get_array_type().size.as_inner(),
|
||||
from.as_inner(),
|
||||
to.as_inner(),
|
||||
) {
|
||||
match (array.ty().size.as_inner(), from.as_inner(), to.as_inner()) {
|
||||
(
|
||||
UExpressionInner::Value(size),
|
||||
UExpressionInner::Value(from),
|
||||
|
|
102
zokrates_core/src/static_analysis/branch_isolator.rs
Normal file
102
zokrates_core/src/static_analysis/branch_isolator.rs
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Isolate branches means making sure that any branch is enclosed in a block.
|
||||
// This is important, because we want any statement resulting from inlining any branch to be isolated from the coller, so that its panics can be conditional to the branch being logically run
|
||||
|
||||
// `if c then a else b fi` becomes `if c then { a } else { b } fi`, and down the line any statements resulting from trating `a` and `b` can be safely kept inside the respective blocks.
|
||||
|
||||
use crate::typed_absy::folder::*;
|
||||
use crate::typed_absy::*;
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub struct Isolator;
|
||||
|
||||
impl Isolator {
|
||||
pub fn isolate<T: Field>(p: TypedProgram<T>) -> TypedProgram<T> {
|
||||
let mut isolator = Isolator;
|
||||
isolator.fold_program(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Folder<'ast, T> for Isolator {
|
||||
fn fold_field_expression(
|
||||
&mut self,
|
||||
e: FieldElementExpression<'ast, T>,
|
||||
) -> FieldElementExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementExpression::IfElse(box condition, box consequence, box alternative) => {
|
||||
FieldElementExpression::IfElse(
|
||||
box self.fold_boolean_expression(condition),
|
||||
box FieldElementExpression::block(vec![], consequence.fold(self)),
|
||||
box FieldElementExpression::block(vec![], alternative.fold(self)),
|
||||
)
|
||||
}
|
||||
e => fold_field_expression(self, e),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_boolean_expression(
|
||||
&mut self,
|
||||
e: BooleanExpression<'ast, T>,
|
||||
) -> BooleanExpression<'ast, T> {
|
||||
match e {
|
||||
BooleanExpression::IfElse(box condition, box consequence, box alternative) => {
|
||||
BooleanExpression::IfElse(
|
||||
box self.fold_boolean_expression(condition),
|
||||
box BooleanExpression::block(vec![], consequence.fold(self)),
|
||||
box BooleanExpression::block(vec![], alternative.fold(self)),
|
||||
)
|
||||
}
|
||||
e => fold_boolean_expression(self, e),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_uint_expression_inner(
|
||||
&mut self,
|
||||
bitwidth: UBitwidth,
|
||||
e: UExpressionInner<'ast, T>,
|
||||
) -> UExpressionInner<'ast, T> {
|
||||
match e {
|
||||
UExpressionInner::IfElse(box condition, box consequence, box alternative) => {
|
||||
UExpressionInner::IfElse(
|
||||
box self.fold_boolean_expression(condition),
|
||||
box UExpression::block(vec![], consequence.fold(self)),
|
||||
box UExpression::block(vec![], alternative.fold(self)),
|
||||
)
|
||||
}
|
||||
e => fold_uint_expression_inner(self, bitwidth, e),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_array_expression_inner(
|
||||
&mut self,
|
||||
array_ty: &ArrayType<'ast, T>,
|
||||
e: ArrayExpressionInner<'ast, T>,
|
||||
) -> ArrayExpressionInner<'ast, T> {
|
||||
match e {
|
||||
ArrayExpressionInner::IfElse(box condition, box consequence, box alternative) => {
|
||||
ArrayExpressionInner::IfElse(
|
||||
box self.fold_boolean_expression(condition),
|
||||
box ArrayExpression::block(vec![], consequence.fold(self)),
|
||||
box ArrayExpression::block(vec![], alternative.fold(self)),
|
||||
)
|
||||
}
|
||||
e => fold_array_expression_inner(self, array_ty, e),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_struct_expression_inner(
|
||||
&mut self,
|
||||
struct_ty: &StructType<'ast, T>,
|
||||
e: StructExpressionInner<'ast, T>,
|
||||
) -> StructExpressionInner<'ast, T> {
|
||||
match e {
|
||||
StructExpressionInner::IfElse(box condition, box consequence, box alternative) => {
|
||||
StructExpressionInner::IfElse(
|
||||
box self.fold_boolean_expression(condition),
|
||||
box StructExpression::block(vec![], consequence.fold(self)),
|
||||
box StructExpression::block(vec![], alternative.fold(self)),
|
||||
)
|
||||
}
|
||||
e => fold_struct_expression_inner(self, struct_ty, e),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +1,37 @@
|
|||
use crate::static_analysis::propagation::Propagator;
|
||||
use crate::typed_absy::folder::*;
|
||||
use crate::typed_absy::result_folder::ResultFolder;
|
||||
use crate::typed_absy::types::{Constant, DeclarationStructType, GStructMember};
|
||||
use crate::typed_absy::*;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub struct ConstantInliner<'ast, T: Field> {
|
||||
pub struct ConstantInliner<'ast, 'a, T: Field> {
|
||||
modules: TypedModules<'ast, T>,
|
||||
location: OwnedTypedModuleId,
|
||||
propagator: Propagator<'ast, 'a, T>,
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> ConstantInliner<'ast, T> {
|
||||
pub fn new(modules: TypedModules<'ast, T>, location: OwnedTypedModuleId) -> Self {
|
||||
ConstantInliner { modules, location }
|
||||
impl<'ast, 'a, T: Field> ConstantInliner<'ast, 'a, T> {
|
||||
pub fn new(
|
||||
modules: TypedModules<'ast, T>,
|
||||
location: OwnedTypedModuleId,
|
||||
propagator: Propagator<'ast, 'a, T>,
|
||||
) -> Self {
|
||||
ConstantInliner {
|
||||
modules,
|
||||
location,
|
||||
propagator,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inline(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
|
||||
let mut inliner = ConstantInliner::new(p.modules.clone(), p.main.clone());
|
||||
let mut constants = HashMap::new();
|
||||
let mut inliner = ConstantInliner::new(
|
||||
p.modules.clone(),
|
||||
p.main.clone(),
|
||||
Propagator::with_constants(&mut constants),
|
||||
);
|
||||
inliner.fold_program(p)
|
||||
}
|
||||
|
||||
|
@ -51,12 +68,18 @@ impl<'ast, T: Field> ConstantInliner<'ast, T> {
|
|||
let _ = self.change_location(location);
|
||||
symbol
|
||||
}
|
||||
TypedConstantSymbol::Here(tc) => self.fold_constant(tc),
|
||||
TypedConstantSymbol::Here(tc) => {
|
||||
let tc: TypedConstant<T> = self.fold_constant(tc);
|
||||
TypedConstant {
|
||||
expression: self.propagator.fold_expression(tc.expression).unwrap(),
|
||||
..tc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Folder<'ast, T> for ConstantInliner<'ast, T> {
|
||||
impl<'ast, 'a, T: Field> Folder<'ast, T> for ConstantInliner<'ast, 'a, T> {
|
||||
fn fold_program(&mut self, p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
|
||||
TypedProgram {
|
||||
modules: p
|
||||
|
@ -71,6 +94,62 @@ impl<'ast, T: Field> Folder<'ast, T> for ConstantInliner<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_declaration_type(&mut self, t: DeclarationType<'ast>) -> DeclarationType<'ast> {
|
||||
match t {
|
||||
DeclarationType::Array(ref array_ty) => match array_ty.size {
|
||||
Constant::Identifier(name, _) => {
|
||||
let tc = self.get_constant(&name.into()).unwrap();
|
||||
let expression: UExpression<'ast, T> = tc.expression.try_into().unwrap();
|
||||
match expression.inner {
|
||||
UExpressionInner::Value(v) => DeclarationType::array((
|
||||
self.fold_declaration_type(*array_ty.ty.clone()),
|
||||
Constant::Concrete(v as u32),
|
||||
)),
|
||||
_ => unreachable!("expected u32 value"),
|
||||
}
|
||||
}
|
||||
_ => t,
|
||||
},
|
||||
DeclarationType::Struct(struct_ty) => DeclarationType::struc(DeclarationStructType {
|
||||
members: struct_ty
|
||||
.members
|
||||
.into_iter()
|
||||
.map(|m| GStructMember::new(m.id, self.fold_declaration_type(*m.ty)))
|
||||
.collect(),
|
||||
..struct_ty
|
||||
}),
|
||||
_ => t,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_type(&mut self, t: Type<'ast, T>) -> Type<'ast, T> {
|
||||
use self::GType::*;
|
||||
match t {
|
||||
Array(ref array_type) => match &array_type.size.inner {
|
||||
UExpressionInner::Identifier(v) => match self.get_constant(v) {
|
||||
Some(tc) => {
|
||||
let expression: UExpression<'ast, T> = tc.expression.try_into().unwrap();
|
||||
Type::array(GArrayType::new(
|
||||
self.fold_type(*array_type.ty.clone()),
|
||||
expression,
|
||||
))
|
||||
}
|
||||
None => t,
|
||||
},
|
||||
_ => t,
|
||||
},
|
||||
Struct(struct_type) => Type::struc(GStructType {
|
||||
members: struct_type
|
||||
.members
|
||||
.into_iter()
|
||||
.map(|m| GStructMember::new(m.id, self.fold_type(*m.ty)))
|
||||
.collect(),
|
||||
..struct_type
|
||||
}),
|
||||
_ => t,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_constant_symbol(
|
||||
&mut self,
|
||||
s: TypedConstantSymbol<'ast, T>,
|
||||
|
@ -636,11 +715,9 @@ mod tests {
|
|||
|
||||
let expected_main = TypedFunction {
|
||||
arguments: vec![],
|
||||
statements: vec![TypedStatement::Return(vec![FieldElementExpression::Add(
|
||||
box FieldElementExpression::Number(Bn128Field::from(1)),
|
||||
box FieldElementExpression::Number(Bn128Field::from(1)),
|
||||
)
|
||||
.into()])],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::Number(Bn128Field::from(2)).into(),
|
||||
])],
|
||||
signature: DeclarationSignature::new()
|
||||
.inputs(vec![])
|
||||
.outputs(vec![DeclarationType::FieldElement]),
|
||||
|
@ -675,9 +752,8 @@ mod tests {
|
|||
const_b_id,
|
||||
TypedConstantSymbol::Here(TypedConstant::new(
|
||||
GType::FieldElement,
|
||||
TypedExpression::FieldElement(FieldElementExpression::Add(
|
||||
box FieldElementExpression::Number(Bn128Field::from(1)),
|
||||
box FieldElementExpression::Number(Bn128Field::from(1)),
|
||||
TypedExpression::FieldElement(FieldElementExpression::Number(
|
||||
Bn128Field::from(2),
|
||||
)),
|
||||
)),
|
||||
),
|
||||
|
|
|
@ -6,6 +6,7 @@ use zokrates_field::Field;
|
|||
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Flattener<T: Field> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
@ -50,9 +51,7 @@ fn flatten_identifier_rec<'ast>(
|
|||
|
||||
impl<'ast, T: Field> Flattener<T> {
|
||||
pub fn flatten(p: typed_absy::TypedProgram<T>) -> zir::ZirProgram<T> {
|
||||
let mut f = Flattener {
|
||||
phantom: PhantomData,
|
||||
};
|
||||
let mut f = Flattener::default();
|
||||
f.fold_program(p)
|
||||
}
|
||||
|
||||
|
@ -141,53 +140,72 @@ impl<'ast, T: Field> Flattener<T> {
|
|||
|
||||
fn fold_statement(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
s: typed_absy::TypedStatement<'ast, T>,
|
||||
) -> Vec<zir::ZirStatement<'ast, T>> {
|
||||
fold_statement(self, s)
|
||||
) {
|
||||
fold_statement(self, statements_buffer, s)
|
||||
}
|
||||
|
||||
fn fold_expression_or_spread(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::TypedExpressionOrSpread<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
match e {
|
||||
typed_absy::TypedExpressionOrSpread::Expression(e) => self.fold_expression(e),
|
||||
typed_absy::TypedExpressionOrSpread::Spread(s) => self.fold_array_expression(s.array),
|
||||
typed_absy::TypedExpressionOrSpread::Expression(e) => {
|
||||
self.fold_expression(statements_buffer, e)
|
||||
}
|
||||
typed_absy::TypedExpressionOrSpread::Spread(s) => {
|
||||
self.fold_array_expression(statements_buffer, s.array)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_expression(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::TypedExpression<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
match e {
|
||||
typed_absy::TypedExpression::FieldElement(e) => {
|
||||
vec![self.fold_field_expression(e).into()]
|
||||
vec![self.fold_field_expression(statements_buffer, e).into()]
|
||||
}
|
||||
typed_absy::TypedExpression::Boolean(e) => {
|
||||
vec![self.fold_boolean_expression(statements_buffer, e).into()]
|
||||
}
|
||||
typed_absy::TypedExpression::Uint(e) => {
|
||||
vec![self.fold_uint_expression(statements_buffer, e).into()]
|
||||
}
|
||||
typed_absy::TypedExpression::Array(e) => {
|
||||
self.fold_array_expression(statements_buffer, e)
|
||||
}
|
||||
typed_absy::TypedExpression::Struct(e) => {
|
||||
self.fold_struct_expression(statements_buffer, e)
|
||||
}
|
||||
typed_absy::TypedExpression::Boolean(e) => vec![self.fold_boolean_expression(e).into()],
|
||||
typed_absy::TypedExpression::Uint(e) => vec![self.fold_uint_expression(e).into()],
|
||||
typed_absy::TypedExpression::Array(e) => self.fold_array_expression(e),
|
||||
typed_absy::TypedExpression::Struct(e) => self.fold_struct_expression(e),
|
||||
typed_absy::TypedExpression::Int(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_array_expression(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::ArrayExpression<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
fold_array_expression(self, e)
|
||||
fold_array_expression(self, statements_buffer, e)
|
||||
}
|
||||
|
||||
fn fold_struct_expression(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
|
||||
e: typed_absy::StructExpression<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
fold_struct_expression(self, e)
|
||||
fold_struct_expression(self, statements_buffer, e)
|
||||
}
|
||||
|
||||
fn fold_expression_list(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
es: typed_absy::TypedExpressionList<'ast, T>,
|
||||
) -> zir::ZirExpressionList<'ast, T> {
|
||||
match es {
|
||||
|
@ -197,7 +215,7 @@ impl<'ast, T: Field> Flattener<T> {
|
|||
generics,
|
||||
arguments
|
||||
.into_iter()
|
||||
.flat_map(|a| self.fold_expression(a))
|
||||
.flat_map(|a| self.fold_expression(statements_buffer, a))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
@ -207,74 +225,80 @@ impl<'ast, T: Field> Flattener<T> {
|
|||
|
||||
fn fold_field_expression(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::FieldElementExpression<'ast, T>,
|
||||
) -> zir::FieldElementExpression<'ast, T> {
|
||||
fold_field_expression(self, e)
|
||||
fold_field_expression(self, statements_buffer, e)
|
||||
}
|
||||
fn fold_boolean_expression(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::BooleanExpression<'ast, T>,
|
||||
) -> zir::BooleanExpression<'ast, T> {
|
||||
fold_boolean_expression(self, e)
|
||||
fold_boolean_expression(self, statements_buffer, e)
|
||||
}
|
||||
fn fold_uint_expression(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::UExpression<'ast, T>,
|
||||
) -> zir::UExpression<'ast, T> {
|
||||
fold_uint_expression(self, e)
|
||||
fold_uint_expression(self, statements_buffer, e)
|
||||
}
|
||||
|
||||
fn fold_uint_expression_inner(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
bitwidth: UBitwidth,
|
||||
e: typed_absy::UExpressionInner<'ast, T>,
|
||||
) -> zir::UExpressionInner<'ast, T> {
|
||||
fold_uint_expression_inner(self, bitwidth, e)
|
||||
fold_uint_expression_inner(self, statements_buffer, bitwidth, e)
|
||||
}
|
||||
|
||||
fn fold_array_expression_inner(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
ty: &typed_absy::types::ConcreteType,
|
||||
size: usize,
|
||||
e: typed_absy::ArrayExpressionInner<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
fold_array_expression_inner(self, ty, size, e)
|
||||
fold_array_expression_inner(self, statements_buffer, ty, size, e)
|
||||
}
|
||||
fn fold_struct_expression_inner(
|
||||
&mut self,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
ty: &typed_absy::types::ConcreteStructType,
|
||||
e: typed_absy::StructExpressionInner<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
fold_struct_expression_inner(self, ty, e)
|
||||
fold_struct_expression_inner(self, statements_buffer, ty, e)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_statement<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
s: typed_absy::TypedStatement<'ast, T>,
|
||||
) -> Vec<zir::ZirStatement<'ast, T>> {
|
||||
match s {
|
||||
) {
|
||||
let res = match s {
|
||||
typed_absy::TypedStatement::Return(expressions) => vec![zir::ZirStatement::Return(
|
||||
expressions
|
||||
.into_iter()
|
||||
.flat_map(|e| f.fold_expression(e))
|
||||
.flat_map(|e| f.fold_expression(statements_buffer, e))
|
||||
.collect(),
|
||||
)],
|
||||
typed_absy::TypedStatement::Definition(a, e) => {
|
||||
let a = f.fold_assignee(a);
|
||||
let e = f.fold_expression(e);
|
||||
let e = f.fold_expression(statements_buffer, e);
|
||||
assert_eq!(a.len(), e.len());
|
||||
a.into_iter()
|
||||
.zip(e.into_iter())
|
||||
.map(|(a, e)| zir::ZirStatement::Definition(a, e))
|
||||
.collect()
|
||||
}
|
||||
typed_absy::TypedStatement::Declaration(v) => {
|
||||
let v = f.fold_variable(v);
|
||||
v.into_iter().map(zir::ZirStatement::Declaration).collect()
|
||||
typed_absy::TypedStatement::Declaration(..) => {
|
||||
unreachable!()
|
||||
}
|
||||
typed_absy::TypedStatement::Assertion(e) => {
|
||||
let e = f.fold_boolean_expression(e);
|
||||
let e = f.fold_boolean_expression(statements_buffer, e);
|
||||
vec![zir::ZirStatement::Assertion(e)]
|
||||
}
|
||||
typed_absy::TypedStatement::For(..) => unreachable!(),
|
||||
|
@ -284,21 +308,31 @@ pub fn fold_statement<'ast, T: Field>(
|
|||
.into_iter()
|
||||
.flat_map(|v| f.fold_assignee(v))
|
||||
.collect(),
|
||||
f.fold_expression_list(elist),
|
||||
f.fold_expression_list(statements_buffer, elist),
|
||||
)]
|
||||
}
|
||||
typed_absy::TypedStatement::PushCallLog(..) => vec![],
|
||||
typed_absy::TypedStatement::PopCallLog => vec![],
|
||||
}
|
||||
};
|
||||
|
||||
statements_buffer.extend(res);
|
||||
}
|
||||
|
||||
pub fn fold_array_expression_inner<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
ty: &typed_absy::types::ConcreteType,
|
||||
size: usize,
|
||||
array: typed_absy::ArrayExpressionInner<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
match array {
|
||||
typed_absy::ArrayExpressionInner::Block(block) => {
|
||||
block
|
||||
.statements
|
||||
.into_iter()
|
||||
.for_each(|s| f.fold_statement(statements_buffer, s));
|
||||
f.fold_array_expression(statements_buffer, *block.value)
|
||||
}
|
||||
typed_absy::ArrayExpressionInner::Identifier(id) => {
|
||||
let variables = flatten_identifier_rec(
|
||||
f.fold_name(id),
|
||||
|
@ -318,7 +352,7 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
typed_absy::ArrayExpressionInner::Value(exprs) => {
|
||||
let exprs: Vec<_> = exprs
|
||||
.into_iter()
|
||||
.flat_map(|e| f.fold_expression_or_spread(e))
|
||||
.flat_map(|e| f.fold_expression_or_spread(statements_buffer, e))
|
||||
.collect();
|
||||
|
||||
assert_eq!(exprs.len(), size * ty.get_primitive_count());
|
||||
|
@ -331,12 +365,21 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
box consequence,
|
||||
box alternative,
|
||||
) => {
|
||||
let condition = f.fold_boolean_expression(condition);
|
||||
let consequence = f.fold_array_expression(consequence);
|
||||
let alternative = f.fold_array_expression(alternative);
|
||||
let mut consequence_statements = vec![];
|
||||
let mut alternative_statements = vec![];
|
||||
|
||||
let condition = f.fold_boolean_expression(statements_buffer, condition);
|
||||
let consequence = f.fold_array_expression(&mut consequence_statements, consequence);
|
||||
let alternative = f.fold_array_expression(&mut alternative_statements, alternative);
|
||||
|
||||
assert_eq!(consequence.len(), alternative.len());
|
||||
|
||||
statements_buffer.push(zir::ZirStatement::IfElse(
|
||||
condition.clone(),
|
||||
consequence_statements,
|
||||
alternative_statements,
|
||||
));
|
||||
|
||||
use crate::zir::IfElse;
|
||||
|
||||
consequence
|
||||
|
@ -359,7 +402,7 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
typed_absy::ArrayExpressionInner::Member(box s, id) => {
|
||||
let members = s.ty().clone();
|
||||
|
||||
let s = f.fold_struct_expression(s);
|
||||
let s = f.fold_struct_expression(statements_buffer, s);
|
||||
|
||||
let offset: usize = members
|
||||
.iter()
|
||||
|
@ -377,8 +420,8 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
s[offset..offset + size].to_vec()
|
||||
}
|
||||
typed_absy::ArrayExpressionInner::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_uint_expression(index);
|
||||
let array = f.fold_array_expression(statements_buffer, array);
|
||||
let index = f.fold_uint_expression(statements_buffer, index);
|
||||
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => {
|
||||
|
@ -391,9 +434,9 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
}
|
||||
}
|
||||
typed_absy::ArrayExpressionInner::Slice(box array, box from, box to) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let from = f.fold_uint_expression(from);
|
||||
let to = f.fold_uint_expression(to);
|
||||
let array = f.fold_array_expression(statements_buffer, array);
|
||||
let from = f.fold_uint_expression(statements_buffer, from);
|
||||
let to = f.fold_uint_expression(statements_buffer, to);
|
||||
|
||||
match (from.into_inner(), to.into_inner()) {
|
||||
(zir::UExpressionInner::Value(from), zir::UExpressionInner::Value(to)) => {
|
||||
|
@ -408,8 +451,8 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
}
|
||||
}
|
||||
typed_absy::ArrayExpressionInner::Repeat(box e, box count) => {
|
||||
let e = f.fold_expression(e);
|
||||
let count = f.fold_uint_expression(count);
|
||||
let e = f.fold_expression(statements_buffer, e);
|
||||
let count = f.fold_uint_expression(statements_buffer, count);
|
||||
|
||||
match count.into_inner() {
|
||||
zir::UExpressionInner::Value(count) => {
|
||||
|
@ -423,10 +466,18 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
|
||||
pub fn fold_struct_expression_inner<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
ty: &typed_absy::types::ConcreteStructType,
|
||||
struc: typed_absy::StructExpressionInner<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
match struc {
|
||||
typed_absy::StructExpressionInner::Block(block) => {
|
||||
block
|
||||
.statements
|
||||
.into_iter()
|
||||
.for_each(|s| f.fold_statement(statements_buffer, s));
|
||||
f.fold_struct_expression(statements_buffer, *block.value)
|
||||
}
|
||||
typed_absy::StructExpressionInner::Identifier(id) => {
|
||||
let variables = flatten_identifier_rec(
|
||||
f.fold_name(id),
|
||||
|
@ -445,7 +496,7 @@ pub fn fold_struct_expression_inner<'ast, T: Field>(
|
|||
}
|
||||
typed_absy::StructExpressionInner::Value(exprs) => exprs
|
||||
.into_iter()
|
||||
.flat_map(|e| f.fold_expression(e))
|
||||
.flat_map(|e| f.fold_expression(statements_buffer, e))
|
||||
.collect(),
|
||||
typed_absy::StructExpressionInner::FunctionCall(..) => unreachable!(),
|
||||
typed_absy::StructExpressionInner::IfElse(
|
||||
|
@ -453,13 +504,22 @@ pub fn fold_struct_expression_inner<'ast, T: Field>(
|
|||
box consequence,
|
||||
box alternative,
|
||||
) => {
|
||||
let condition = f.fold_boolean_expression(condition);
|
||||
let consequence = f.fold_struct_expression(consequence);
|
||||
let alternative = f.fold_struct_expression(alternative);
|
||||
let mut consequence_statements = vec![];
|
||||
let mut alternative_statements = vec![];
|
||||
|
||||
let condition = f.fold_boolean_expression(statements_buffer, condition);
|
||||
let consequence = f.fold_struct_expression(&mut consequence_statements, consequence);
|
||||
let alternative = f.fold_struct_expression(&mut alternative_statements, alternative);
|
||||
|
||||
assert_eq!(consequence.len(), alternative.len());
|
||||
|
||||
use crate::zir::IfElse;
|
||||
statements_buffer.push(zir::ZirStatement::IfElse(
|
||||
condition.clone(),
|
||||
consequence_statements,
|
||||
alternative_statements,
|
||||
));
|
||||
|
||||
use zir::IfElse;
|
||||
|
||||
consequence
|
||||
.into_iter()
|
||||
|
@ -479,22 +539,19 @@ pub fn fold_struct_expression_inner<'ast, T: Field>(
|
|||
.collect()
|
||||
}
|
||||
typed_absy::StructExpressionInner::Member(box s, id) => {
|
||||
let members = s.ty().clone();
|
||||
// get the concrete struct type, which must be available now
|
||||
let struct_ty: typed_absy::types::ConcreteStructType =
|
||||
s.ty().clone().try_into().unwrap();
|
||||
|
||||
let s = f.fold_struct_expression(s);
|
||||
|
||||
let offset: usize = members
|
||||
// get the offset at which this member starts
|
||||
let offset: usize = struct_ty
|
||||
.iter()
|
||||
.take_while(|member| member.id != id)
|
||||
.map(|member| {
|
||||
typed_absy::types::ConcreteType::try_from(*member.ty.clone())
|
||||
.unwrap()
|
||||
.get_primitive_count()
|
||||
})
|
||||
.map(|member| member.ty.get_primitive_count())
|
||||
.sum();
|
||||
|
||||
// we also need the size of this member
|
||||
let size = ty
|
||||
// get the size of this member
|
||||
let size = struct_ty
|
||||
.iter()
|
||||
.find(|member| member.id == id)
|
||||
.cloned()
|
||||
|
@ -502,11 +559,15 @@ pub fn fold_struct_expression_inner<'ast, T: Field>(
|
|||
.ty
|
||||
.get_primitive_count();
|
||||
|
||||
// flatten the full struct
|
||||
let s = f.fold_struct_expression(statements_buffer, s);
|
||||
|
||||
// extract the member
|
||||
s[offset..offset + size].to_vec()
|
||||
}
|
||||
typed_absy::StructExpressionInner::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_uint_expression(index);
|
||||
let array = f.fold_array_expression(statements_buffer, array);
|
||||
let index = f.fold_uint_expression(statements_buffer, index);
|
||||
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => {
|
||||
|
@ -523,6 +584,7 @@ pub fn fold_struct_expression_inner<'ast, T: Field>(
|
|||
|
||||
pub fn fold_field_expression<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::FieldElementExpression<'ast, T>,
|
||||
) -> zir::FieldElementExpression<'ast, T> {
|
||||
match e {
|
||||
|
@ -538,50 +600,66 @@ pub fn fold_field_expression<'ast, T: Field>(
|
|||
)
|
||||
}
|
||||
typed_absy::FieldElementExpression::Add(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_field_expression(statements_buffer, e2);
|
||||
zir::FieldElementExpression::Add(box e1, box e2)
|
||||
}
|
||||
typed_absy::FieldElementExpression::Sub(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_field_expression(statements_buffer, e2);
|
||||
zir::FieldElementExpression::Sub(box e1, box e2)
|
||||
}
|
||||
typed_absy::FieldElementExpression::Mult(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_field_expression(statements_buffer, e2);
|
||||
zir::FieldElementExpression::Mult(box e1, box e2)
|
||||
}
|
||||
typed_absy::FieldElementExpression::Div(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_field_expression(statements_buffer, e2);
|
||||
zir::FieldElementExpression::Div(box e1, box e2)
|
||||
}
|
||||
typed_absy::FieldElementExpression::Pow(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_uint_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_uint_expression(statements_buffer, e2);
|
||||
zir::FieldElementExpression::Pow(box e1, box e2)
|
||||
}
|
||||
typed_absy::FieldElementExpression::Neg(box e) => {
|
||||
let e = f.fold_field_expression(e);
|
||||
let e = f.fold_field_expression(statements_buffer, e);
|
||||
|
||||
zir::FieldElementExpression::Sub(
|
||||
box zir::FieldElementExpression::Number(T::zero()),
|
||||
box e,
|
||||
)
|
||||
}
|
||||
typed_absy::FieldElementExpression::Pos(box e) => f.fold_field_expression(e),
|
||||
typed_absy::FieldElementExpression::IfElse(box cond, box cons, box alt) => {
|
||||
let cond = f.fold_boolean_expression(cond);
|
||||
let cons = f.fold_field_expression(cons);
|
||||
let alt = f.fold_field_expression(alt);
|
||||
zir::FieldElementExpression::IfElse(box cond, box cons, box alt)
|
||||
typed_absy::FieldElementExpression::Pos(box e) => {
|
||||
f.fold_field_expression(statements_buffer, e)
|
||||
}
|
||||
typed_absy::FieldElementExpression::IfElse(
|
||||
box condition,
|
||||
box consequence,
|
||||
box alternative,
|
||||
) => {
|
||||
let mut consequence_statements = vec![];
|
||||
let mut alternative_statements = vec![];
|
||||
|
||||
let condition = f.fold_boolean_expression(statements_buffer, condition);
|
||||
let consequence = f.fold_field_expression(&mut consequence_statements, consequence);
|
||||
let alternative = f.fold_field_expression(&mut alternative_statements, alternative);
|
||||
|
||||
statements_buffer.push(zir::ZirStatement::IfElse(
|
||||
condition.clone(),
|
||||
consequence_statements,
|
||||
alternative_statements,
|
||||
));
|
||||
|
||||
zir::FieldElementExpression::IfElse(box condition, box consequence, box alternative)
|
||||
}
|
||||
typed_absy::FieldElementExpression::FunctionCall(..) => unreachable!(""),
|
||||
typed_absy::FieldElementExpression::Member(box s, id) => {
|
||||
let members = s.ty().clone();
|
||||
|
||||
let s = f.fold_struct_expression(s);
|
||||
let s = f.fold_struct_expression(statements_buffer, s);
|
||||
|
||||
let offset: usize = members
|
||||
.iter()
|
||||
|
@ -596,23 +674,38 @@ pub fn fold_field_expression<'ast, T: Field>(
|
|||
s[offset].clone().try_into().unwrap()
|
||||
}
|
||||
typed_absy::FieldElementExpression::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let array = f.fold_array_expression(statements_buffer, array);
|
||||
|
||||
let index = f.fold_uint_expression(index);
|
||||
let index = f.fold_uint_expression(statements_buffer, index);
|
||||
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => array[i as usize].clone().try_into().unwrap(),
|
||||
_ => unreachable!(""),
|
||||
}
|
||||
}
|
||||
typed_absy::FieldElementExpression::Block(block) => {
|
||||
block
|
||||
.statements
|
||||
.into_iter()
|
||||
.for_each(|s| f.fold_statement(statements_buffer, s));
|
||||
f.fold_field_expression(statements_buffer, *block.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_boolean_expression<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::BooleanExpression<'ast, T>,
|
||||
) -> zir::BooleanExpression<'ast, T> {
|
||||
match e {
|
||||
typed_absy::BooleanExpression::Block(block) => {
|
||||
block
|
||||
.statements
|
||||
.into_iter()
|
||||
.for_each(|s| f.fold_statement(statements_buffer, s));
|
||||
f.fold_boolean_expression(statements_buffer, *block.value)
|
||||
}
|
||||
typed_absy::BooleanExpression::Value(v) => zir::BooleanExpression::Value(v),
|
||||
typed_absy::BooleanExpression::Identifier(id) => zir::BooleanExpression::Identifier(
|
||||
flatten_identifier_rec(f.fold_name(id), &typed_absy::types::ConcreteType::Boolean)[0]
|
||||
|
@ -620,18 +713,18 @@ pub fn fold_boolean_expression<'ast, T: Field>(
|
|||
.clone(),
|
||||
),
|
||||
typed_absy::BooleanExpression::FieldEq(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_field_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::FieldEq(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::BoolEq(box e1, box e2) => {
|
||||
let e1 = f.fold_boolean_expression(e1);
|
||||
let e2 = f.fold_boolean_expression(e2);
|
||||
let e1 = f.fold_boolean_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_boolean_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::BoolEq(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::ArrayEq(box e1, box e2) => {
|
||||
let e1 = f.fold_array_expression(e1);
|
||||
let e2 = f.fold_array_expression(e2);
|
||||
let e1 = f.fold_array_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_array_expression(statements_buffer, e2);
|
||||
|
||||
assert_eq!(e1.len(), e2.len());
|
||||
|
||||
|
@ -658,8 +751,8 @@ pub fn fold_boolean_expression<'ast, T: Field>(
|
|||
)
|
||||
}
|
||||
typed_absy::BooleanExpression::StructEq(box e1, box e2) => {
|
||||
let e1 = f.fold_struct_expression(e1);
|
||||
let e2 = f.fold_struct_expression(e2);
|
||||
let e1 = f.fold_struct_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_struct_expression(statements_buffer, e2);
|
||||
|
||||
assert_eq!(e1.len(), e2.len());
|
||||
|
||||
|
@ -686,76 +779,86 @@ pub fn fold_boolean_expression<'ast, T: Field>(
|
|||
)
|
||||
}
|
||||
typed_absy::BooleanExpression::UintEq(box e1, box e2) => {
|
||||
let e1 = f.fold_uint_expression(e1);
|
||||
let e2 = f.fold_uint_expression(e2);
|
||||
let e1 = f.fold_uint_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_uint_expression(statements_buffer, e2);
|
||||
|
||||
zir::BooleanExpression::UintEq(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::FieldLt(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_field_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::FieldLt(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::FieldLe(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_field_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::FieldLe(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::FieldGt(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_field_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::FieldGt(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::FieldGe(box e1, box e2) => {
|
||||
let e1 = f.fold_field_expression(e1);
|
||||
let e2 = f.fold_field_expression(e2);
|
||||
let e1 = f.fold_field_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_field_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::FieldGe(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::UintLt(box e1, box e2) => {
|
||||
let e1 = f.fold_uint_expression(e1);
|
||||
let e2 = f.fold_uint_expression(e2);
|
||||
let e1 = f.fold_uint_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_uint_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::UintLt(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::UintLe(box e1, box e2) => {
|
||||
let e1 = f.fold_uint_expression(e1);
|
||||
let e2 = f.fold_uint_expression(e2);
|
||||
let e1 = f.fold_uint_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_uint_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::UintLe(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::UintGt(box e1, box e2) => {
|
||||
let e1 = f.fold_uint_expression(e1);
|
||||
let e2 = f.fold_uint_expression(e2);
|
||||
let e1 = f.fold_uint_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_uint_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::UintGt(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::UintGe(box e1, box e2) => {
|
||||
let e1 = f.fold_uint_expression(e1);
|
||||
let e2 = f.fold_uint_expression(e2);
|
||||
let e1 = f.fold_uint_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_uint_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::UintGe(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::Or(box e1, box e2) => {
|
||||
let e1 = f.fold_boolean_expression(e1);
|
||||
let e2 = f.fold_boolean_expression(e2);
|
||||
let e1 = f.fold_boolean_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_boolean_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::Or(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::And(box e1, box e2) => {
|
||||
let e1 = f.fold_boolean_expression(e1);
|
||||
let e2 = f.fold_boolean_expression(e2);
|
||||
let e1 = f.fold_boolean_expression(statements_buffer, e1);
|
||||
let e2 = f.fold_boolean_expression(statements_buffer, e2);
|
||||
zir::BooleanExpression::And(box e1, box e2)
|
||||
}
|
||||
typed_absy::BooleanExpression::Not(box e) => {
|
||||
let e = f.fold_boolean_expression(e);
|
||||
let e = f.fold_boolean_expression(statements_buffer, e);
|
||||
zir::BooleanExpression::Not(box e)
|
||||
}
|
||||
typed_absy::BooleanExpression::IfElse(box cond, box cons, box alt) => {
|
||||
let cond = f.fold_boolean_expression(cond);
|
||||
let cons = f.fold_boolean_expression(cons);
|
||||
let alt = f.fold_boolean_expression(alt);
|
||||
zir::BooleanExpression::IfElse(box cond, box cons, box alt)
|
||||
typed_absy::BooleanExpression::IfElse(box condition, box consequence, box alternative) => {
|
||||
let mut consequence_statements = vec![];
|
||||
let mut alternative_statements = vec![];
|
||||
|
||||
let condition = f.fold_boolean_expression(statements_buffer, condition);
|
||||
let consequence = f.fold_boolean_expression(&mut consequence_statements, consequence);
|
||||
let alternative = f.fold_boolean_expression(&mut alternative_statements, alternative);
|
||||
|
||||
statements_buffer.push(zir::ZirStatement::IfElse(
|
||||
condition.clone(),
|
||||
consequence_statements,
|
||||
alternative_statements,
|
||||
));
|
||||
|
||||
zir::BooleanExpression::IfElse(box condition, box consequence, box alternative)
|
||||
}
|
||||
typed_absy::BooleanExpression::FunctionCall(..) => unreachable!(),
|
||||
typed_absy::BooleanExpression::Member(box s, id) => {
|
||||
let members = s.ty().clone();
|
||||
|
||||
let s = f.fold_struct_expression(s);
|
||||
let s = f.fold_struct_expression(statements_buffer, s);
|
||||
|
||||
let offset: usize = members
|
||||
.iter()
|
||||
|
@ -770,8 +873,8 @@ pub fn fold_boolean_expression<'ast, T: Field>(
|
|||
s[offset].clone().try_into().unwrap()
|
||||
}
|
||||
typed_absy::BooleanExpression::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_uint_expression(index);
|
||||
let array = f.fold_array_expression(statements_buffer, array);
|
||||
let index = f.fold_uint_expression(statements_buffer, index);
|
||||
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => array[i as usize].clone().try_into().unwrap(),
|
||||
|
@ -783,18 +886,28 @@ pub fn fold_boolean_expression<'ast, T: Field>(
|
|||
|
||||
pub fn fold_uint_expression<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::UExpression<'ast, T>,
|
||||
) -> zir::UExpression<'ast, T> {
|
||||
f.fold_uint_expression_inner(e.bitwidth, e.inner)
|
||||
f.fold_uint_expression_inner(statements_buffer, e.bitwidth, e.inner)
|
||||
.annotate(e.bitwidth.to_usize())
|
||||
}
|
||||
|
||||
pub fn fold_uint_expression_inner<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
bitwidth: UBitwidth,
|
||||
e: typed_absy::UExpressionInner<'ast, T>,
|
||||
) -> zir::UExpressionInner<'ast, T> {
|
||||
match e {
|
||||
typed_absy::UExpressionInner::Block(block) => {
|
||||
block
|
||||
.statements
|
||||
.into_iter()
|
||||
.for_each(|s| f.fold_statement(statements_buffer, s));
|
||||
f.fold_uint_expression(statements_buffer, *block.value)
|
||||
.into_inner()
|
||||
}
|
||||
typed_absy::UExpressionInner::Value(v) => zir::UExpressionInner::Value(v),
|
||||
typed_absy::UExpressionInner::Identifier(id) => zir::UExpressionInner::Identifier(
|
||||
flatten_identifier_rec(
|
||||
|
@ -805,56 +918,56 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
|
|||
.clone(),
|
||||
),
|
||||
typed_absy::UExpressionInner::Add(box left, box right) => {
|
||||
let left = f.fold_uint_expression(left);
|
||||
let right = f.fold_uint_expression(right);
|
||||
let left = f.fold_uint_expression(statements_buffer, left);
|
||||
let right = f.fold_uint_expression(statements_buffer, right);
|
||||
|
||||
zir::UExpressionInner::Add(box left, box right)
|
||||
}
|
||||
typed_absy::UExpressionInner::Sub(box left, box right) => {
|
||||
let left = f.fold_uint_expression(left);
|
||||
let right = f.fold_uint_expression(right);
|
||||
let left = f.fold_uint_expression(statements_buffer, left);
|
||||
let right = f.fold_uint_expression(statements_buffer, right);
|
||||
|
||||
zir::UExpressionInner::Sub(box left, box right)
|
||||
}
|
||||
typed_absy::UExpressionInner::FloorSub(..) => unreachable!(),
|
||||
typed_absy::UExpressionInner::Mult(box left, box right) => {
|
||||
let left = f.fold_uint_expression(left);
|
||||
let right = f.fold_uint_expression(right);
|
||||
let left = f.fold_uint_expression(statements_buffer, left);
|
||||
let right = f.fold_uint_expression(statements_buffer, right);
|
||||
|
||||
zir::UExpressionInner::Mult(box left, box right)
|
||||
}
|
||||
typed_absy::UExpressionInner::Div(box left, box right) => {
|
||||
let left = f.fold_uint_expression(left);
|
||||
let right = f.fold_uint_expression(right);
|
||||
let left = f.fold_uint_expression(statements_buffer, left);
|
||||
let right = f.fold_uint_expression(statements_buffer, right);
|
||||
|
||||
zir::UExpressionInner::Div(box left, box right)
|
||||
}
|
||||
typed_absy::UExpressionInner::Rem(box left, box right) => {
|
||||
let left = f.fold_uint_expression(left);
|
||||
let right = f.fold_uint_expression(right);
|
||||
let left = f.fold_uint_expression(statements_buffer, left);
|
||||
let right = f.fold_uint_expression(statements_buffer, right);
|
||||
|
||||
zir::UExpressionInner::Rem(box left, box right)
|
||||
}
|
||||
typed_absy::UExpressionInner::Xor(box left, box right) => {
|
||||
let left = f.fold_uint_expression(left);
|
||||
let right = f.fold_uint_expression(right);
|
||||
let left = f.fold_uint_expression(statements_buffer, left);
|
||||
let right = f.fold_uint_expression(statements_buffer, right);
|
||||
|
||||
zir::UExpressionInner::Xor(box left, box right)
|
||||
}
|
||||
typed_absy::UExpressionInner::And(box left, box right) => {
|
||||
let left = f.fold_uint_expression(left);
|
||||
let right = f.fold_uint_expression(right);
|
||||
let left = f.fold_uint_expression(statements_buffer, left);
|
||||
let right = f.fold_uint_expression(statements_buffer, right);
|
||||
|
||||
zir::UExpressionInner::And(box left, box right)
|
||||
}
|
||||
typed_absy::UExpressionInner::Or(box left, box right) => {
|
||||
let left = f.fold_uint_expression(left);
|
||||
let right = f.fold_uint_expression(right);
|
||||
let left = f.fold_uint_expression(statements_buffer, left);
|
||||
let right = f.fold_uint_expression(statements_buffer, right);
|
||||
|
||||
zir::UExpressionInner::Or(box left, box right)
|
||||
}
|
||||
typed_absy::UExpressionInner::LeftShift(box e, box by) => {
|
||||
let e = f.fold_uint_expression(e);
|
||||
let e = f.fold_uint_expression(statements_buffer, e);
|
||||
|
||||
let by = match by.as_inner() {
|
||||
typed_absy::UExpressionInner::Value(by) => by,
|
||||
|
@ -864,7 +977,7 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
|
|||
zir::UExpressionInner::LeftShift(box e, *by as u32)
|
||||
}
|
||||
typed_absy::UExpressionInner::RightShift(box e, box by) => {
|
||||
let e = f.fold_uint_expression(e);
|
||||
let e = f.fold_uint_expression(statements_buffer, e);
|
||||
|
||||
let by = match by.as_inner() {
|
||||
typed_absy::UExpressionInner::Value(by) => by,
|
||||
|
@ -874,19 +987,22 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
|
|||
zir::UExpressionInner::RightShift(box e, *by as u32)
|
||||
}
|
||||
typed_absy::UExpressionInner::Not(box e) => {
|
||||
let e = f.fold_uint_expression(e);
|
||||
let e = f.fold_uint_expression(statements_buffer, e);
|
||||
|
||||
zir::UExpressionInner::Not(box e)
|
||||
}
|
||||
typed_absy::UExpressionInner::Neg(box e) => {
|
||||
let bitwidth = e.bitwidth();
|
||||
|
||||
f.fold_uint_expression(typed_absy::UExpressionInner::Value(0).annotate(bitwidth) - e)
|
||||
.into_inner()
|
||||
f.fold_uint_expression(
|
||||
statements_buffer,
|
||||
typed_absy::UExpressionInner::Value(0).annotate(bitwidth) - e,
|
||||
)
|
||||
.into_inner()
|
||||
}
|
||||
|
||||
typed_absy::UExpressionInner::Pos(box e) => {
|
||||
let e = f.fold_uint_expression(e);
|
||||
let e = f.fold_uint_expression(statements_buffer, e);
|
||||
|
||||
e.into_inner()
|
||||
}
|
||||
|
@ -894,8 +1010,8 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
|
|||
unreachable!("function calls should have been removed")
|
||||
}
|
||||
typed_absy::UExpressionInner::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_uint_expression(index);
|
||||
let array = f.fold_array_expression(statements_buffer, array);
|
||||
let index = f.fold_uint_expression(statements_buffer, index);
|
||||
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => {
|
||||
|
@ -908,7 +1024,7 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
|
|||
typed_absy::UExpressionInner::Member(box s, id) => {
|
||||
let members = s.ty().clone();
|
||||
|
||||
let s = f.fold_struct_expression(s);
|
||||
let s = f.fold_struct_expression(statements_buffer, s);
|
||||
|
||||
let offset: usize = members
|
||||
.iter()
|
||||
|
@ -924,11 +1040,21 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
|
|||
|
||||
res.into_inner()
|
||||
}
|
||||
typed_absy::UExpressionInner::IfElse(box cond, box cons, box alt) => {
|
||||
let cond = f.fold_boolean_expression(cond);
|
||||
let cons = f.fold_uint_expression(cons);
|
||||
let alt = f.fold_uint_expression(alt);
|
||||
zir::UExpressionInner::IfElse(box cond, box cons, box alt)
|
||||
typed_absy::UExpressionInner::IfElse(box condition, box consequence, box alternative) => {
|
||||
let mut consequence_statements = vec![];
|
||||
let mut alternative_statements = vec![];
|
||||
|
||||
let condition = f.fold_boolean_expression(statements_buffer, condition);
|
||||
let consequence = f.fold_uint_expression(&mut consequence_statements, consequence);
|
||||
let alternative = f.fold_uint_expression(&mut alternative_statements, alternative);
|
||||
|
||||
statements_buffer.push(zir::ZirStatement::IfElse(
|
||||
condition.clone(),
|
||||
consequence_statements,
|
||||
alternative_statements,
|
||||
));
|
||||
|
||||
zir::UExpressionInner::IfElse(box condition, box consequence, box alternative)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -937,17 +1063,19 @@ pub fn fold_function<'ast, T: Field>(
|
|||
f: &mut Flattener<T>,
|
||||
fun: typed_absy::TypedFunction<'ast, T>,
|
||||
) -> zir::ZirFunction<'ast, T> {
|
||||
let mut main_statements_buffer = vec![];
|
||||
|
||||
fun.statements
|
||||
.into_iter()
|
||||
.for_each(|s| f.fold_statement(&mut main_statements_buffer, s));
|
||||
|
||||
zir::ZirFunction {
|
||||
arguments: fun
|
||||
.arguments
|
||||
.into_iter()
|
||||
.flat_map(|a| f.fold_declaration_parameter(a))
|
||||
.collect(),
|
||||
statements: fun
|
||||
.statements
|
||||
.into_iter()
|
||||
.flat_map(|s| f.fold_statement(s))
|
||||
.collect(),
|
||||
statements: main_statements_buffer,
|
||||
signature: typed_absy::types::ConcreteSignature::try_from(
|
||||
typed_absy::types::Signature::<T>::try_from(fun.signature).unwrap(),
|
||||
)
|
||||
|
@ -958,6 +1086,7 @@ pub fn fold_function<'ast, T: Field>(
|
|||
|
||||
pub fn fold_array_expression<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::ArrayExpression<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
let size = match e.size().into_inner() {
|
||||
|
@ -965,6 +1094,7 @@ pub fn fold_array_expression<'ast, T: Field>(
|
|||
_ => unreachable!(),
|
||||
} as usize;
|
||||
f.fold_array_expression_inner(
|
||||
statements_buffer,
|
||||
&typed_absy::types::ConcreteType::try_from(e.inner_type().clone()).unwrap(),
|
||||
size,
|
||||
e.into_inner(),
|
||||
|
@ -973,9 +1103,11 @@ pub fn fold_array_expression<'ast, T: Field>(
|
|||
|
||||
pub fn fold_struct_expression<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
statements_buffer: &mut Vec<zir::ZirStatement<'ast, T>>,
|
||||
e: typed_absy::StructExpression<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
f.fold_struct_expression_inner(
|
||||
statements_buffer,
|
||||
&typed_absy::types::ConcreteStructType::try_from(e.ty().clone()).unwrap(),
|
||||
e.into_inner(),
|
||||
)
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
//! @date 2018
|
||||
|
||||
mod bounds_checker;
|
||||
mod branch_isolator;
|
||||
mod constant_inliner;
|
||||
mod flat_propagation;
|
||||
mod flatten_complex_types;
|
||||
mod propagation;
|
||||
mod redefinition;
|
||||
mod reducer;
|
||||
mod shift_checker;
|
||||
mod uint_optimizer;
|
||||
|
@ -18,9 +18,9 @@ mod variable_read_remover;
|
|||
mod variable_write_remover;
|
||||
|
||||
use self::bounds_checker::BoundsChecker;
|
||||
use self::branch_isolator::Isolator;
|
||||
use self::flatten_complex_types::Flattener;
|
||||
use self::propagation::Propagator;
|
||||
use self::redefinition::RedefinitionOptimizer;
|
||||
use self::reducer::reduce_program;
|
||||
use self::shift_checker::ShiftChecker;
|
||||
use self::uint_optimizer::UintOptimizer;
|
||||
|
@ -77,6 +77,8 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
|
|||
pub fn analyse(self) -> Result<(ZirProgram<'ast, T>, Abi), Error> {
|
||||
// inline user-defined constants
|
||||
let r = ConstantInliner::inline(self);
|
||||
// isolate branches
|
||||
let r = Isolator::isolate(r);
|
||||
// reduce the program to a single function
|
||||
let r = reduce_program(r).map_err(Error::from)?;
|
||||
// generate abi
|
||||
|
@ -84,8 +86,6 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
|
|||
|
||||
// propagate
|
||||
let r = Propagator::propagate(r).map_err(Error::from)?;
|
||||
// optimize redefinitions
|
||||
let r = RedefinitionOptimizer::optimize(r);
|
||||
// remove assignment to variable index
|
||||
let r = VariableWriteRemover::apply(r);
|
||||
// remove variable access to complex types
|
||||
|
|
|
@ -152,13 +152,16 @@ fn is_constant<T: Field>(e: &TypedExpression<T>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
||||
fn remove_spreads_aux<T: Field>(e: TypedExpressionOrSpread<T>) -> Vec<TypedExpression<T>> {
|
||||
// in the constant map, we only want canonical constants: [0; 3] -> [0, 0, 0], [...[1], 2] -> [1, 2], etc
|
||||
fn to_canonical_constant<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
||||
fn to_canonical_constant_aux<T: Field>(
|
||||
e: TypedExpressionOrSpread<T>,
|
||||
) -> Vec<TypedExpression<T>> {
|
||||
match e {
|
||||
TypedExpressionOrSpread::Expression(e) => vec![e],
|
||||
TypedExpressionOrSpread::Spread(s) => match s.array.into_inner() {
|
||||
ArrayExpressionInner::Value(v) => {
|
||||
v.into_iter().flat_map(remove_spreads_aux).collect()
|
||||
v.into_iter().flat_map(to_canonical_constant_aux).collect()
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
|
@ -167,12 +170,12 @@ fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
|||
|
||||
match e {
|
||||
TypedExpression::Array(a) => {
|
||||
let array_ty = a.get_array_type();
|
||||
let array_ty = a.ty();
|
||||
|
||||
match a.into_inner() {
|
||||
ArrayExpressionInner::Value(v) => ArrayExpressionInner::Value(
|
||||
v.into_iter()
|
||||
.flat_map(remove_spreads_aux)
|
||||
.flat_map(to_canonical_constant_aux)
|
||||
.map(|e| e.into())
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
|
@ -197,7 +200,7 @@ fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
|||
|
||||
ArrayExpressionInner::Value(
|
||||
v.into_iter()
|
||||
.flat_map(remove_spreads_aux)
|
||||
.flat_map(to_canonical_constant_aux)
|
||||
.map(|e| e.into())
|
||||
.enumerate()
|
||||
.filter(|(index, _)| index >= &from && index < &to)
|
||||
|
@ -214,7 +217,7 @@ fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
|||
_ => unreachable!("should be a uint value"),
|
||||
};
|
||||
|
||||
let e = remove_spreads(e);
|
||||
let e = to_canonical_constant(e);
|
||||
|
||||
ArrayExpressionInner::Value(
|
||||
vec![TypedExpressionOrSpread::Expression(e); count].into(),
|
||||
|
@ -225,6 +228,18 @@ fn remove_spreads<T: Field>(e: TypedExpression<T>) -> TypedExpression<T> {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
TypedExpression::Struct(s) => {
|
||||
let struct_ty = s.ty().clone();
|
||||
|
||||
match s.into_inner() {
|
||||
StructExpressionInner::Value(expressions) => StructExpressionInner::Value(
|
||||
expressions.into_iter().map(to_canonical_constant).collect(),
|
||||
)
|
||||
.annotate(struct_ty)
|
||||
.into(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
e => e,
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +315,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
|
|||
if is_constant(&expr) {
|
||||
match assignee {
|
||||
TypedAssignee::Identifier(var) => {
|
||||
let expr = remove_spreads(expr);
|
||||
let expr = to_canonical_constant(expr);
|
||||
|
||||
assert!(self.constants.insert(var.id, expr).is_none());
|
||||
|
||||
|
@ -308,7 +323,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
|
|||
}
|
||||
assignee => match self.try_get_constant_mut(&assignee) {
|
||||
Ok((_, c)) => {
|
||||
*c = remove_spreads(expr);
|
||||
*c = to_canonical_constant(expr);
|
||||
Ok(vec![])
|
||||
}
|
||||
Err(v) => match self.constants.remove(&v.id) {
|
||||
|
@ -374,7 +389,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
|
|||
|
||||
let argument = arguments.pop().unwrap();
|
||||
|
||||
let argument = remove_spreads(argument);
|
||||
let argument = to_canonical_constant(argument);
|
||||
|
||||
match ArrayExpression::try_from(argument)
|
||||
.unwrap()
|
||||
|
@ -1409,6 +1424,22 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> {
|
|||
)),
|
||||
}
|
||||
}
|
||||
StructExpressionInner::Value(v) => {
|
||||
let v = v.into_iter().zip(ty.iter()).map(|(v, member)|
|
||||
match self.fold_expression(v) {
|
||||
Ok(v) => match (ConcreteType::try_from(v.get_type().clone()), ConcreteType::try_from(*member.ty.clone())) {
|
||||
(Ok(t1), Ok(t2)) => if t1 == t2 { Ok(v) } else { Err(Error::Type(format!(
|
||||
"Struct member `{}` in struct `{}/{}` expected to have type `{}`, found type `{}`",
|
||||
member.id, ty.canonical_location.clone().module.display(), ty.canonical_location.clone().name, t2, t1
|
||||
))) },
|
||||
_ => Ok(v)
|
||||
}
|
||||
e => e
|
||||
}
|
||||
).collect::<Result<_, _>>()?;
|
||||
|
||||
Ok(StructExpressionInner::Value(v))
|
||||
}
|
||||
e => fold_struct_expression_inner(self, ty, e),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
use crate::typed_absy::folder::*;
|
||||
use crate::typed_absy::*;
|
||||
use std::collections::HashMap;
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub struct RedefinitionOptimizer<'ast> {
|
||||
identifiers: HashMap<Identifier<'ast>, Identifier<'ast>>,
|
||||
}
|
||||
|
||||
impl<'ast> RedefinitionOptimizer<'ast> {
|
||||
fn new() -> Self {
|
||||
RedefinitionOptimizer {
|
||||
identifiers: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optimize<T: Field>(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
|
||||
RedefinitionOptimizer::new().fold_program(p)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_id<'ast, T: Field>(e: &TypedExpression<'ast, T>) -> Option<Identifier<'ast>> {
|
||||
match e {
|
||||
TypedExpression::FieldElement(FieldElementExpression::Identifier(id)) => Some(id.clone()),
|
||||
TypedExpression::Boolean(BooleanExpression::Identifier(id)) => Some(id.clone()),
|
||||
TypedExpression::Array(a) => match a.as_inner() {
|
||||
ArrayExpressionInner::Identifier(id) => Some(id.clone()),
|
||||
_ => None,
|
||||
},
|
||||
TypedExpression::Struct(a) => match a.as_inner() {
|
||||
StructExpressionInner::Identifier(id) => Some(id.clone()),
|
||||
_ => None,
|
||||
},
|
||||
TypedExpression::Uint(a) => match a.as_inner() {
|
||||
UExpressionInner::Identifier(id) => Some(id.clone()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Folder<'ast, T> for RedefinitionOptimizer<'ast> {
|
||||
fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> {
|
||||
self.identifiers = HashMap::new();
|
||||
fold_function(self, f)
|
||||
}
|
||||
|
||||
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
|
||||
match s {
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(var), expr) => {
|
||||
let expr = self.fold_expression(expr);
|
||||
|
||||
match try_id(&expr) {
|
||||
Some(id) => {
|
||||
let target = self.identifiers.get(&id).unwrap_or(&id).clone();
|
||||
|
||||
self.identifiers.insert(var.id, target);
|
||||
vec![]
|
||||
}
|
||||
None => vec![TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(var),
|
||||
expr,
|
||||
)],
|
||||
}
|
||||
}
|
||||
s => fold_statement(self, s),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_name(&mut self, s: Identifier<'ast>) -> Identifier<'ast> {
|
||||
self.identifiers.get(&s).cloned().unwrap_or(s)
|
||||
}
|
||||
}
|
|
@ -22,11 +22,11 @@ use crate::typed_absy::Folder;
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::typed_absy::{
|
||||
ArrayExpression, ArrayExpressionInner, ArrayType, BooleanExpression, CoreIdentifier,
|
||||
DeclarationFunctionKey, FieldElementExpression, FunctionCall, Identifier, StructExpression,
|
||||
StructExpressionInner, Type, Typed, TypedExpression, TypedExpressionList, TypedFunction,
|
||||
TypedFunctionSymbol, TypedModule, TypedProgram, TypedStatement, UExpression, UExpressionInner,
|
||||
Variable,
|
||||
ArrayExpression, ArrayExpressionInner, ArrayType, BlockExpression, BooleanExpression,
|
||||
CoreIdentifier, DeclarationFunctionKey, FieldElementExpression, FunctionCall, Identifier,
|
||||
StructExpression, StructExpressionInner, StructType, Type, TypedExpression,
|
||||
TypedExpressionList, TypedFunction, TypedFunctionSymbol, TypedModule, TypedProgram,
|
||||
TypedStatement, UBitwidth, UExpression, UExpressionInner, Variable,
|
||||
};
|
||||
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
@ -197,7 +197,7 @@ impl<'ast, 'a, T: Field> Reducer<'ast, 'a, T> {
|
|||
key: DeclarationFunctionKey<'ast>,
|
||||
generics: Vec<Option<UExpression<'ast, T>>>,
|
||||
arguments: Vec<TypedExpression<'ast, T>>,
|
||||
output_types: Vec<Type<'ast, T>>,
|
||||
output_type: Type<'ast, T>,
|
||||
) -> Result<E, Error>
|
||||
where
|
||||
E: FunctionCall<'ast, T> + TryFrom<TypedExpression<'ast, T>, Error = ()> + std::fmt::Debug,
|
||||
|
@ -216,16 +216,16 @@ impl<'ast, 'a, T: Field> Reducer<'ast, 'a, T> {
|
|||
key.clone(),
|
||||
generics,
|
||||
arguments,
|
||||
output_types,
|
||||
vec![output_type.clone()],
|
||||
&self.program,
|
||||
&mut self.versions,
|
||||
);
|
||||
|
||||
match res {
|
||||
Ok(Output::Complete((statements, expressions))) => {
|
||||
Ok(Output::Complete((statements, mut expressions))) => {
|
||||
self.complete &= true;
|
||||
self.statement_buffer.extend(statements);
|
||||
Ok(expressions[0].clone().try_into().unwrap())
|
||||
Ok(expressions.pop().unwrap().try_into().unwrap())
|
||||
}
|
||||
Ok(Output::Incomplete((statements, expressions), delta_for_loop_versions)) => {
|
||||
self.complete = false;
|
||||
|
@ -248,7 +248,7 @@ impl<'ast, 'a, T: Field> Reducer<'ast, 'a, T> {
|
|||
output_types.pop().unwrap(),
|
||||
))
|
||||
}
|
||||
Err(InlineError::Flat(embed, generics, arguments, output_types)) => {
|
||||
Err(InlineError::Flat(embed, generics, arguments, mut output_types)) => {
|
||||
let identifier = Identifier::from(CoreIdentifier::Call(0)).version(
|
||||
*self
|
||||
.versions
|
||||
|
@ -256,7 +256,7 @@ impl<'ast, 'a, T: Field> Reducer<'ast, 'a, T> {
|
|||
.and_modify(|e| *e += 1) // if it was already declared, we increment
|
||||
.or_insert(0),
|
||||
);
|
||||
let var = Variable::with_id_and_type(identifier, output_types[0].clone());
|
||||
let var = Variable::with_id_and_type(identifier, output_types.pop().unwrap());
|
||||
|
||||
let v = vec![var.clone().into()];
|
||||
|
||||
|
@ -274,6 +274,29 @@ impl<'ast, 'a, T: Field> Reducer<'ast, 'a, T> {
|
|||
impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
|
||||
type Error = Error;
|
||||
|
||||
fn fold_block_expression<E: ResultFold<'ast, T>>(
|
||||
&mut self,
|
||||
b: BlockExpression<'ast, T, E>,
|
||||
) -> Result<BlockExpression<'ast, T, E>, Self::Error> {
|
||||
// backup the statements and continue with a fresh state
|
||||
let statement_buffer = std::mem::take(&mut self.statement_buffer);
|
||||
|
||||
let block = fold_block_expression(self, b)?;
|
||||
|
||||
// put the original statements back and extract the statements created by visiting the block
|
||||
let extra_statements = std::mem::replace(&mut self.statement_buffer, statement_buffer);
|
||||
|
||||
// return the visited block, augmented with the statements created while visiting it
|
||||
Ok(BlockExpression {
|
||||
statements: block
|
||||
.statements
|
||||
.into_iter()
|
||||
.chain(extra_statements)
|
||||
.collect(),
|
||||
..block
|
||||
})
|
||||
}
|
||||
|
||||
fn fold_statement(
|
||||
&mut self,
|
||||
s: TypedStatement<'ast, T>,
|
||||
|
@ -435,24 +458,27 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
|
|||
) -> Result<BooleanExpression<'ast, T>, Self::Error> {
|
||||
match e {
|
||||
BooleanExpression::FunctionCall(key, generics, arguments) => {
|
||||
self.fold_function_call(key, generics, arguments, vec![Type::Boolean])
|
||||
self.fold_function_call(key, generics, arguments, Type::Boolean)
|
||||
}
|
||||
e => fold_boolean_expression(self, e),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_uint_expression(
|
||||
fn fold_uint_expression_inner(
|
||||
&mut self,
|
||||
e: UExpression<'ast, T>,
|
||||
) -> Result<UExpression<'ast, T>, Self::Error> {
|
||||
match e.as_inner() {
|
||||
UExpressionInner::FunctionCall(key, generics, arguments) => self.fold_function_call(
|
||||
key.clone(),
|
||||
generics.clone(),
|
||||
arguments.clone(),
|
||||
vec![e.get_type()],
|
||||
),
|
||||
_ => fold_uint_expression(self, e),
|
||||
bitwidth: UBitwidth,
|
||||
e: UExpressionInner<'ast, T>,
|
||||
) -> Result<UExpressionInner<'ast, T>, Self::Error> {
|
||||
match e {
|
||||
UExpressionInner::FunctionCall(key, generics, arguments) => self
|
||||
.fold_function_call::<UExpression<'ast, T>>(
|
||||
key,
|
||||
generics,
|
||||
arguments,
|
||||
Type::Uint(bitwidth),
|
||||
)
|
||||
.map(|e| e.into_inner()),
|
||||
e => fold_uint_expression_inner(self, bitwidth, e),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,7 +488,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
|
|||
) -> Result<FieldElementExpression<'ast, T>, Self::Error> {
|
||||
match e {
|
||||
FieldElementExpression::FunctionCall(key, generic, arguments) => {
|
||||
self.fold_function_call(key, generic, arguments, vec![Type::FieldElement])
|
||||
self.fold_function_call(key, generic, arguments, Type::FieldElement)
|
||||
}
|
||||
e => fold_field_expression(self, e),
|
||||
}
|
||||
|
@ -470,7 +496,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
|
|||
|
||||
fn fold_array_expression_inner(
|
||||
&mut self,
|
||||
ty: &ArrayType<'ast, T>,
|
||||
array_ty: &ArrayType<'ast, T>,
|
||||
e: ArrayExpressionInner<'ast, T>,
|
||||
) -> Result<ArrayExpressionInner<'ast, T>, Self::Error> {
|
||||
match e {
|
||||
|
@ -479,7 +505,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
|
|||
key.clone(),
|
||||
generics,
|
||||
arguments.clone(),
|
||||
vec![Type::array(ty.clone())],
|
||||
Type::array(array_ty.clone()),
|
||||
)
|
||||
.map(|e| e.into_inner()),
|
||||
ArrayExpressionInner::Slice(box array, box from, box to) => {
|
||||
|
@ -497,23 +523,25 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Reducer<'ast, 'a, T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
_ => fold_array_expression_inner(self, &ty, e),
|
||||
_ => fold_array_expression_inner(self, &array_ty, e),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_struct_expression(
|
||||
fn fold_struct_expression_inner(
|
||||
&mut self,
|
||||
e: StructExpression<'ast, T>,
|
||||
) -> Result<StructExpression<'ast, T>, Self::Error> {
|
||||
match e.as_inner() {
|
||||
struct_ty: &StructType<'ast, T>,
|
||||
e: StructExpressionInner<'ast, T>,
|
||||
) -> Result<StructExpressionInner<'ast, T>, Self::Error> {
|
||||
match e {
|
||||
StructExpressionInner::FunctionCall(key, generics, arguments) => self
|
||||
.fold_function_call(
|
||||
key.clone(),
|
||||
generics.clone(),
|
||||
arguments.clone(),
|
||||
vec![e.get_type()],
|
||||
),
|
||||
_ => fold_struct_expression(self, e),
|
||||
.fold_function_call::<StructExpression<'ast, T>>(
|
||||
key,
|
||||
generics,
|
||||
arguments,
|
||||
Type::Struct(struct_ty.clone()),
|
||||
)
|
||||
.map(|e| e.into_inner()),
|
||||
_ => fold_struct_expression_inner(self, struct_ty, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -405,78 +405,79 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> {
|
|||
})
|
||||
.collect(),
|
||||
)],
|
||||
ZirStatement::MultipleDefinition(lhs, rhs) => match rhs {
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments) => match embed {
|
||||
FlatEmbed::U64FromBits => {
|
||||
assert_eq!(lhs.len(), 1);
|
||||
self.register(
|
||||
lhs[0].clone(),
|
||||
UMetadata {
|
||||
max: T::from(2).pow(64) - T::from(1),
|
||||
should_reduce: ShouldReduce::False,
|
||||
},
|
||||
);
|
||||
ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments),
|
||||
) => match embed {
|
||||
FlatEmbed::U64FromBits => {
|
||||
assert_eq!(lhs.len(), 1);
|
||||
self.register(
|
||||
lhs[0].clone(),
|
||||
UMetadata {
|
||||
max: T::from(2).pow(64) - T::from(1),
|
||||
should_reduce: ShouldReduce::False,
|
||||
},
|
||||
);
|
||||
|
||||
vec![ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments),
|
||||
)]
|
||||
}
|
||||
FlatEmbed::U32FromBits => {
|
||||
assert_eq!(lhs.len(), 1);
|
||||
self.register(
|
||||
lhs[0].clone(),
|
||||
UMetadata {
|
||||
max: T::from(2).pow(32) - T::from(1),
|
||||
should_reduce: ShouldReduce::False,
|
||||
},
|
||||
);
|
||||
|
||||
vec![ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments),
|
||||
)]
|
||||
}
|
||||
FlatEmbed::U16FromBits => {
|
||||
assert_eq!(lhs.len(), 1);
|
||||
self.register(
|
||||
lhs[0].clone(),
|
||||
UMetadata {
|
||||
max: T::from(2).pow(16) - T::from(1),
|
||||
should_reduce: ShouldReduce::False,
|
||||
},
|
||||
);
|
||||
vec![ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments),
|
||||
)]
|
||||
}
|
||||
FlatEmbed::U8FromBits => {
|
||||
assert_eq!(lhs.len(), 1);
|
||||
self.register(
|
||||
lhs[0].clone(),
|
||||
UMetadata {
|
||||
max: T::from(2).pow(8) - T::from(1),
|
||||
should_reduce: ShouldReduce::False,
|
||||
},
|
||||
);
|
||||
vec![ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments),
|
||||
)]
|
||||
}
|
||||
_ => vec![ZirStatement::MultipleDefinition(
|
||||
vec![ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(
|
||||
embed,
|
||||
generics,
|
||||
arguments
|
||||
.into_iter()
|
||||
.map(|e| self.fold_expression(e))
|
||||
.collect(),
|
||||
),
|
||||
)],
|
||||
},
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments),
|
||||
)]
|
||||
}
|
||||
FlatEmbed::U32FromBits => {
|
||||
assert_eq!(lhs.len(), 1);
|
||||
self.register(
|
||||
lhs[0].clone(),
|
||||
UMetadata {
|
||||
max: T::from(2).pow(32) - T::from(1),
|
||||
should_reduce: ShouldReduce::False,
|
||||
},
|
||||
);
|
||||
|
||||
vec![ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments),
|
||||
)]
|
||||
}
|
||||
FlatEmbed::U16FromBits => {
|
||||
assert_eq!(lhs.len(), 1);
|
||||
self.register(
|
||||
lhs[0].clone(),
|
||||
UMetadata {
|
||||
max: T::from(2).pow(16) - T::from(1),
|
||||
should_reduce: ShouldReduce::False,
|
||||
},
|
||||
);
|
||||
vec![ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments),
|
||||
)]
|
||||
}
|
||||
FlatEmbed::U8FromBits => {
|
||||
assert_eq!(lhs.len(), 1);
|
||||
self.register(
|
||||
lhs[0].clone(),
|
||||
UMetadata {
|
||||
max: T::from(2).pow(8) - T::from(1),
|
||||
should_reduce: ShouldReduce::False,
|
||||
},
|
||||
);
|
||||
vec![ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(embed, generics, arguments),
|
||||
)]
|
||||
}
|
||||
_ => vec![ZirStatement::MultipleDefinition(
|
||||
lhs,
|
||||
ZirExpressionList::EmbedCall(
|
||||
embed,
|
||||
generics,
|
||||
arguments
|
||||
.into_iter()
|
||||
.map(|e| self.fold_expression(e))
|
||||
.collect(),
|
||||
),
|
||||
)],
|
||||
},
|
||||
ZirStatement::Assertion(BooleanExpression::UintEq(box left, box right)) => {
|
||||
let left = self.fold_uint_expression(left);
|
||||
|
|
|
@ -4,6 +4,40 @@ use crate::typed_absy::types::{ArrayType, StructMember, StructType};
|
|||
use crate::typed_absy::*;
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub trait Fold<'ast, T: Field>: Sized {
|
||||
fn fold<F: Folder<'ast, T>>(self, f: &mut F) -> Self;
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Fold<'ast, T> for FieldElementExpression<'ast, T> {
|
||||
fn fold<F: Folder<'ast, T>>(self, f: &mut F) -> Self {
|
||||
f.fold_field_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Fold<'ast, T> for BooleanExpression<'ast, T> {
|
||||
fn fold<F: Folder<'ast, T>>(self, f: &mut F) -> Self {
|
||||
f.fold_boolean_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Fold<'ast, T> for UExpression<'ast, T> {
|
||||
fn fold<F: Folder<'ast, T>>(self, f: &mut F) -> Self {
|
||||
f.fold_uint_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Fold<'ast, T> for StructExpression<'ast, T> {
|
||||
fn fold<F: Folder<'ast, T>>(self, f: &mut F) -> Self {
|
||||
f.fold_struct_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Fold<'ast, T> for ArrayExpression<'ast, T> {
|
||||
fn fold<F: Folder<'ast, T>>(self, f: &mut F) -> Self {
|
||||
f.fold_array_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Folder<'ast, T: Field>: Sized {
|
||||
fn fold_program(&mut self, p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
|
||||
fold_program(self, p)
|
||||
|
@ -31,10 +65,21 @@ pub trait Folder<'ast, T: Field>: Sized {
|
|||
fold_function_symbol(self, s)
|
||||
}
|
||||
|
||||
fn fold_declaration_function_key(
|
||||
&mut self,
|
||||
key: DeclarationFunctionKey<'ast>,
|
||||
) -> DeclarationFunctionKey<'ast> {
|
||||
fold_declaration_function_key(self, key)
|
||||
}
|
||||
|
||||
fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> {
|
||||
fold_function(self, f)
|
||||
}
|
||||
|
||||
fn fold_signature(&mut self, s: DeclarationSignature<'ast>) -> DeclarationSignature<'ast> {
|
||||
fold_signature(self, s)
|
||||
}
|
||||
|
||||
fn fold_parameter(&mut self, p: DeclarationParameter<'ast>) -> DeclarationParameter<'ast> {
|
||||
DeclarationParameter {
|
||||
id: self.fold_declaration_variable(p.id),
|
||||
|
@ -137,6 +182,13 @@ pub trait Folder<'ast, T: Field>: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_block_expression<E: Fold<'ast, T>>(
|
||||
&mut self,
|
||||
block: BlockExpression<'ast, T, E>,
|
||||
) -> BlockExpression<'ast, T, E> {
|
||||
fold_block_expression(self, block)
|
||||
}
|
||||
|
||||
fn fold_array_expression(&mut self, e: ArrayExpression<'ast, T>) -> ArrayExpression<'ast, T> {
|
||||
fold_array_expression(self, e)
|
||||
}
|
||||
|
@ -190,6 +242,7 @@ pub trait Folder<'ast, T: Field>: Sized {
|
|||
) -> ArrayExpressionInner<'ast, T> {
|
||||
fold_array_expression_inner(self, ty, e)
|
||||
}
|
||||
|
||||
fn fold_struct_expression_inner(
|
||||
&mut self,
|
||||
ty: &StructType<'ast, T>,
|
||||
|
@ -212,7 +265,12 @@ pub fn fold_module<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
functions: m
|
||||
.functions
|
||||
.into_iter()
|
||||
.map(|(key, fun)| (key, f.fold_function_symbol(fun)))
|
||||
.map(|(key, fun)| {
|
||||
(
|
||||
f.fold_declaration_function_key(key),
|
||||
f.fold_function_symbol(fun),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
@ -257,6 +315,9 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
e: ArrayExpressionInner<'ast, T>,
|
||||
) -> ArrayExpressionInner<'ast, T> {
|
||||
match e {
|
||||
ArrayExpressionInner::Block(block) => {
|
||||
ArrayExpressionInner::Block(f.fold_block_expression(block))
|
||||
}
|
||||
ArrayExpressionInner::Identifier(id) => ArrayExpressionInner::Identifier(f.fold_name(id)),
|
||||
ArrayExpressionInner::Value(exprs) => ArrayExpressionInner::Value(
|
||||
exprs
|
||||
|
@ -308,6 +369,9 @@ pub fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
e: StructExpressionInner<'ast, T>,
|
||||
) -> StructExpressionInner<'ast, T> {
|
||||
match e {
|
||||
StructExpressionInner::Block(block) => {
|
||||
StructExpressionInner::Block(f.fold_block_expression(block))
|
||||
}
|
||||
StructExpressionInner::Identifier(id) => StructExpressionInner::Identifier(f.fold_name(id)),
|
||||
StructExpressionInner::Value(exprs) => {
|
||||
StructExpressionInner::Value(exprs.into_iter().map(|e| f.fold_expression(e)).collect())
|
||||
|
@ -344,6 +408,9 @@ pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
e: FieldElementExpression<'ast, T>,
|
||||
) -> FieldElementExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementExpression::Block(block) => {
|
||||
FieldElementExpression::Block(f.fold_block_expression(block))
|
||||
}
|
||||
FieldElementExpression::Number(n) => FieldElementExpression::Number(n),
|
||||
FieldElementExpression::Identifier(id) => {
|
||||
FieldElementExpression::Identifier(f.fold_name(id))
|
||||
|
@ -421,6 +488,7 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
e: BooleanExpression<'ast, T>,
|
||||
) -> BooleanExpression<'ast, T> {
|
||||
match e {
|
||||
BooleanExpression::Block(block) => BooleanExpression::Block(f.fold_block_expression(block)),
|
||||
BooleanExpression::Value(v) => BooleanExpression::Value(v),
|
||||
BooleanExpression::Identifier(id) => BooleanExpression::Identifier(f.fold_name(id)),
|
||||
BooleanExpression::FieldEq(box e1, box e2) => {
|
||||
|
@ -544,6 +612,7 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
e: UExpressionInner<'ast, T>,
|
||||
) -> UExpressionInner<'ast, T> {
|
||||
match e {
|
||||
UExpressionInner::Block(block) => UExpressionInner::Block(f.fold_block_expression(block)),
|
||||
UExpressionInner::Value(v) => UExpressionInner::Value(v),
|
||||
UExpressionInner::Identifier(id) => UExpressionInner::Identifier(f.fold_name(id)),
|
||||
UExpressionInner::Add(box left, box right) => {
|
||||
|
@ -653,6 +722,30 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fold_block_expression<'ast, T: Field, E: Fold<'ast, T>, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
block: BlockExpression<'ast, T, E>,
|
||||
) -> BlockExpression<'ast, T, E> {
|
||||
BlockExpression {
|
||||
statements: block
|
||||
.statements
|
||||
.into_iter()
|
||||
.flat_map(|s| f.fold_statement(s))
|
||||
.collect(),
|
||||
value: box block.value.fold(f),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_declaration_function_key<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
key: DeclarationFunctionKey<'ast>,
|
||||
) -> DeclarationFunctionKey<'ast> {
|
||||
DeclarationFunctionKey {
|
||||
signature: f.fold_signature(key.signature),
|
||||
..key
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_function<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
fun: TypedFunction<'ast, T>,
|
||||
|
@ -668,7 +761,26 @@ pub fn fold_function<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
.into_iter()
|
||||
.flat_map(|s| f.fold_statement(s))
|
||||
.collect(),
|
||||
..fun
|
||||
signature: f.fold_signature(fun.signature),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_signature<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
s: DeclarationSignature<'ast>,
|
||||
) -> DeclarationSignature<'ast> {
|
||||
DeclarationSignature {
|
||||
generics: s.generics,
|
||||
inputs: s
|
||||
.inputs
|
||||
.into_iter()
|
||||
.map(|o| f.fold_declaration_type(o))
|
||||
.collect(),
|
||||
outputs: s
|
||||
.outputs
|
||||
.into_iter()
|
||||
.map(|o| f.fold_declaration_type(o))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -721,9 +833,10 @@ pub fn fold_struct_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
f: &mut F,
|
||||
e: StructExpression<'ast, T>,
|
||||
) -> StructExpression<'ast, T> {
|
||||
let ty = f.fold_struct_type(e.ty);
|
||||
StructExpression {
|
||||
inner: f.fold_struct_expression_inner(&e.ty, e.inner),
|
||||
..e
|
||||
inner: f.fold_struct_expression_inner(&ty, e.inner),
|
||||
ty,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -481,7 +481,7 @@ impl<'ast, T: Field> ArrayExpression<'ast, T> {
|
|||
array: Self,
|
||||
target_inner_ty: Type<'ast, T>,
|
||||
) -> Result<Self, TypedExpression<'ast, T>> {
|
||||
let array_ty = array.get_array_type();
|
||||
let array_ty = array.ty();
|
||||
|
||||
// elements must fit in the target type
|
||||
match array.into_inner() {
|
||||
|
|
|
@ -148,7 +148,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedProgram<'ast, T> {
|
|||
}
|
||||
|
||||
/// A typed module as a collection of functions. Types have been resolved during semantic checking.
|
||||
#[derive(PartialEq, Clone)]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct TypedModule<'ast, T> {
|
||||
/// Functions of the module
|
||||
pub functions: TypedFunctionSymbols<'ast, T>,
|
||||
|
@ -156,24 +156,13 @@ pub struct TypedModule<'ast, T> {
|
|||
pub constants: TypedConstantSymbols<'ast, T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum TypedFunctionSymbol<'ast, T> {
|
||||
Here(TypedFunction<'ast, T>),
|
||||
There(DeclarationFunctionKey<'ast>),
|
||||
Flat(FlatEmbed),
|
||||
}
|
||||
|
||||
// this should be deriveable but it seems like the bounds are not infered correctly
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for TypedFunctionSymbol<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
TypedFunctionSymbol::Here(s) => write!(f, "Here({:?})", s),
|
||||
TypedFunctionSymbol::There(key) => write!(f, "There({:?})", key),
|
||||
TypedFunctionSymbol::Flat(s) => write!(f, "Flat({:?})", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> TypedFunctionSymbol<'ast, T> {
|
||||
pub fn signature<'a>(
|
||||
&'a self,
|
||||
|
@ -225,27 +214,8 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedModule<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for TypedModule<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"TypedModule(\n\tFunctions:\n\t\t{:?}\n\tConstants:\n\t\t{:?}\n)",
|
||||
self.functions
|
||||
.iter()
|
||||
.map(|x| format!("{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\t\t"),
|
||||
self.constants
|
||||
.iter()
|
||||
.map(|x| format!("{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\t\t")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A typed function
|
||||
#[derive(Clone, PartialEq, Hash)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash)]
|
||||
pub struct TypedFunction<'ast, T> {
|
||||
/// Arguments of the function
|
||||
pub arguments: Vec<DeclarationParameter<'ast>>,
|
||||
|
@ -318,26 +288,10 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedFunction<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for TypedFunction<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"TypedFunction(signature: {:?}, arguments: {:?}, ...):\n{}",
|
||||
self.signature,
|
||||
self.arguments,
|
||||
self.statements
|
||||
.iter()
|
||||
.map(|x| format!("\t{:?}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct TypedConstant<'ast, T> {
|
||||
ty: Type<'ast, T>,
|
||||
expression: TypedExpression<'ast, T>,
|
||||
pub ty: Type<'ast, T>,
|
||||
pub expression: TypedExpression<'ast, T>,
|
||||
}
|
||||
|
||||
impl<'ast, T> TypedConstant<'ast, T> {
|
||||
|
@ -346,12 +300,6 @@ impl<'ast, T> TypedConstant<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for TypedConstant<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "TypedConstant({:?}, {:?})", self.ty, self.expression)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Display> fmt::Display for TypedConstant<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "const {}({})", self.ty, self.expression)
|
||||
|
@ -365,7 +313,7 @@ impl<'ast, T: Clone> Typed<'ast, T> for TypedConstant<'ast, T> {
|
|||
}
|
||||
|
||||
/// Something we can assign to.
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub enum TypedAssignee<'ast, T> {
|
||||
Identifier(Variable<'ast, T>),
|
||||
Select(Box<TypedAssignee<'ast, T>>, Box<UExpression<'ast, T>>),
|
||||
|
@ -389,7 +337,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedSpread<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq, Debug)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub enum TypedExpressionOrSpread<'ast, T> {
|
||||
Expression(TypedExpression<'ast, T>),
|
||||
Spread(TypedSpread<'ast, T>),
|
||||
|
@ -475,16 +423,6 @@ impl<'ast, T: Clone> Typed<'ast, T> for TypedAssignee<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for TypedAssignee<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedAssignee::Identifier(ref s) => write!(f, "{:?}", s.id),
|
||||
TypedAssignee::Select(ref a, ref e) => write!(f, "Select({:?}, {:?})", a, e),
|
||||
TypedAssignee::Member(ref s, ref m) => write!(f, "Member({:?}, {:?})", s, m),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Display> fmt::Display for TypedAssignee<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
@ -497,7 +435,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedAssignee<'ast, T> {
|
|||
|
||||
/// A statement in a `TypedFunction`
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub enum TypedStatement<'ast, T> {
|
||||
Return(Vec<TypedExpression<'ast, T>>),
|
||||
Definition(TypedAssignee<'ast, T>, TypedExpression<'ast, T>),
|
||||
|
@ -518,42 +456,6 @@ pub enum TypedStatement<'ast, T> {
|
|||
PopCallLog,
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for TypedStatement<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedStatement::Return(ref exprs) => {
|
||||
write!(f, "Return(")?;
|
||||
for (i, expr) in exprs.iter().enumerate() {
|
||||
write!(f, "{:?}", expr)?;
|
||||
if i < exprs.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
TypedStatement::Declaration(ref var) => write!(f, "({:?})", var),
|
||||
TypedStatement::Definition(ref lhs, ref rhs) => {
|
||||
write!(f, "Definition({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
TypedStatement::Assertion(ref e) => write!(f, "Assertion({:?})", e),
|
||||
TypedStatement::For(ref var, ref start, ref stop, ref list) => {
|
||||
writeln!(f, "for {:?} in {:?}..{:?} do", var, start, stop)?;
|
||||
for l in list {
|
||||
writeln!(f, "\t\t{:?}", l)?;
|
||||
}
|
||||
write!(f, "\tendfor")
|
||||
}
|
||||
TypedStatement::MultipleDefinition(ref lhs, ref rhs) => {
|
||||
write!(f, "MultipleDefinition({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
TypedStatement::PushCallLog(ref key, ref generics) => {
|
||||
write!(f, "PushCallLog({:?}, {:?})", key, generics)
|
||||
}
|
||||
TypedStatement::PopCallLog => write!(f, "PopCallLog"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Display> TypedStatement<'ast, T> {
|
||||
fn fmt_indented(&self, f: &mut fmt::Formatter, depth: usize) -> fmt::Result {
|
||||
match self {
|
||||
|
@ -621,7 +523,7 @@ pub trait Typed<'ast, T> {
|
|||
|
||||
/// A typed expression
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub enum TypedExpression<'ast, T> {
|
||||
Boolean(BooleanExpression<'ast, T>),
|
||||
FieldElement(FieldElementExpression<'ast, T>),
|
||||
|
@ -680,34 +582,16 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedExpression<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for TypedExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpression::Boolean(ref e) => write!(f, "{:?}", e),
|
||||
TypedExpression::FieldElement(ref e) => write!(f, "{:?}", e),
|
||||
TypedExpression::Uint(ref e) => write!(f, "{:?}", e),
|
||||
TypedExpression::Array(ref e) => write!(f, "{:?}", e),
|
||||
TypedExpression::Struct(ref s) => write!(f, "{:?}", s),
|
||||
TypedExpression::Int(ref s) => write!(f, "{:?}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Display> fmt::Display for ArrayExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for ArrayExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Display> fmt::Display for StructExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.inner {
|
||||
StructExpressionInner::Block(ref block) => write!(f, "{}", block),
|
||||
StructExpressionInner::Identifier(ref var) => write!(f, "{}", var),
|
||||
StructExpressionInner::Value(ref values) => write!(
|
||||
f,
|
||||
|
@ -759,12 +643,6 @@ impl<'ast, T: fmt::Display> fmt::Display for StructExpression<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for StructExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Clone> Typed<'ast, T> for TypedExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type<'ast, T> {
|
||||
match *self {
|
||||
|
@ -812,7 +690,7 @@ pub trait MultiTyped<'ast, T> {
|
|||
fn get_types(&self) -> &Vec<Type<'ast, T>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub enum TypedExpressionList<'ast, T> {
|
||||
FunctionCall(
|
||||
DeclarationFunctionKey<'ast>,
|
||||
|
@ -836,10 +714,25 @@ impl<'ast, T> MultiTyped<'ast, T> for TypedExpressionList<'ast, T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub struct BlockExpression<'ast, T, E> {
|
||||
pub statements: Vec<TypedStatement<'ast, T>>,
|
||||
pub value: Box<E>,
|
||||
}
|
||||
|
||||
impl<'ast, T, E> BlockExpression<'ast, T, E> {
|
||||
pub fn new(statements: Vec<TypedStatement<'ast, T>>, value: E) -> Self {
|
||||
BlockExpression {
|
||||
statements,
|
||||
value: box value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An expression of type `field`
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub enum FieldElementExpression<'ast, T> {
|
||||
Block(BlockExpression<'ast, T, Self>),
|
||||
Number(T),
|
||||
Identifier(Identifier<'ast>),
|
||||
Add(
|
||||
|
@ -922,8 +815,9 @@ impl<'ast, T> From<T> for FieldElementExpression<'ast, T> {
|
|||
}
|
||||
|
||||
/// An expression of type `bool`
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub enum BooleanExpression<'ast, T> {
|
||||
Block(BlockExpression<'ast, T, Self>),
|
||||
Identifier(Identifier<'ast>),
|
||||
Value(bool),
|
||||
FieldLt(
|
||||
|
@ -994,7 +888,7 @@ impl<'ast, T> From<bool> for BooleanExpression<'ast, T> {
|
|||
/// * Contrary to basic types which are represented as enums, we wrap an enum `ArrayExpressionInner` in a struct in order to keep track of the type (content and size)
|
||||
/// of the array. Only using an enum would require generics, which would propagate up to TypedExpression which we want to keep simple, hence this "runtime"
|
||||
/// type checking
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub struct ArrayExpression<'ast, T> {
|
||||
ty: Box<ArrayType<'ast, T>>,
|
||||
inner: ArrayExpressionInner<'ast, T>,
|
||||
|
@ -1026,7 +920,7 @@ impl<'ast, T: Clone> ArrayValue<'ast, T> {
|
|||
TypedExpressionOrSpread::Expression(e) => vec![Some(e.clone())],
|
||||
TypedExpressionOrSpread::Spread(s) => match s.array.size().into_inner() {
|
||||
UExpressionInner::Value(size) => {
|
||||
let array_ty = s.array.get_array_type().clone();
|
||||
let array_ty = s.array.ty().clone();
|
||||
|
||||
match s.array.into_inner() {
|
||||
ArrayExpressionInner::Value(v) => v
|
||||
|
@ -1078,8 +972,9 @@ impl<'ast, T> std::iter::FromIterator<TypedExpressionOrSpread<'ast, T>> for Arra
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub enum ArrayExpressionInner<'ast, T> {
|
||||
Block(BlockExpression<'ast, T, ArrayExpression<'ast, T>>),
|
||||
Identifier(Identifier<'ast>),
|
||||
Value(ArrayValue<'ast, T>),
|
||||
FunctionCall(
|
||||
|
@ -1136,7 +1031,7 @@ impl<'ast, T: Clone> ArrayExpression<'ast, T> {
|
|||
self.inner
|
||||
}
|
||||
|
||||
pub fn get_array_type(&self) -> ArrayType<'ast, T> {
|
||||
pub fn ty(&self) -> ArrayType<'ast, T> {
|
||||
ArrayType {
|
||||
size: self.size(),
|
||||
ty: box self.inner_type().clone(),
|
||||
|
@ -1144,7 +1039,7 @@ impl<'ast, T: Clone> ArrayExpression<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub struct StructExpression<'ast, T> {
|
||||
ty: StructType<'ast, T>,
|
||||
inner: StructExpressionInner<'ast, T>,
|
||||
|
@ -1186,8 +1081,9 @@ impl<'ast, T> StructExpression<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
#[derive(Clone, PartialEq, Debug, Hash, Eq)]
|
||||
pub enum StructExpressionInner<'ast, T> {
|
||||
Block(BlockExpression<'ast, T, StructExpression<'ast, T>>),
|
||||
Identifier(Identifier<'ast>),
|
||||
Value(Vec<TypedExpression<'ast, T>>),
|
||||
FunctionCall(
|
||||
|
@ -1332,9 +1228,25 @@ impl<'ast, T> TryFrom<TypedConstant<'ast, T>> for IntExpression<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Display, E: fmt::Display> fmt::Display for BlockExpression<'ast, T, E> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{{\n{}\n}}",
|
||||
self.statements
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.chain(std::iter::once(self.value.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Display> fmt::Display for FieldElementExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElementExpression::Block(ref block) => write!(f, "{}", block),
|
||||
FieldElementExpression::Number(ref i) => write!(f, "{}f", i),
|
||||
FieldElementExpression::Identifier(ref var) => write!(f, "{}", var),
|
||||
FieldElementExpression::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs),
|
||||
|
@ -1385,6 +1297,7 @@ impl<'ast, T: fmt::Display> fmt::Display for FieldElementExpression<'ast, T> {
|
|||
impl<'ast, T: fmt::Display> fmt::Display for UExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self.inner {
|
||||
UExpressionInner::Block(ref block) => write!(f, "{}", block,),
|
||||
UExpressionInner::Value(ref v) => write!(f, "{}", v),
|
||||
UExpressionInner::Identifier(ref var) => write!(f, "{}", var),
|
||||
UExpressionInner::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs),
|
||||
|
@ -1442,6 +1355,7 @@ impl<'ast, T: fmt::Display> fmt::Display for UExpression<'ast, T> {
|
|||
impl<'ast, T: fmt::Display> fmt::Display for BooleanExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
BooleanExpression::Block(ref block) => write!(f, "{}", block,),
|
||||
BooleanExpression::Identifier(ref var) => write!(f, "{}", var),
|
||||
BooleanExpression::FieldLt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
|
||||
BooleanExpression::FieldLe(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
|
||||
|
@ -1499,6 +1413,7 @@ impl<'ast, T: fmt::Display> fmt::Display for BooleanExpression<'ast, T> {
|
|||
impl<'ast, T: fmt::Display> fmt::Display for ArrayExpressionInner<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ArrayExpressionInner::Block(ref block) => write!(f, "{}", block,),
|
||||
ArrayExpressionInner::Identifier(ref var) => write!(f, "{}", var),
|
||||
ArrayExpressionInner::Value(ref values) => write!(
|
||||
f,
|
||||
|
@ -1551,167 +1466,6 @@ impl<'ast, T: fmt::Display> fmt::Display for ArrayExpressionInner<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for BooleanExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
BooleanExpression::Identifier(ref var) => write!(f, "Ide({})", var),
|
||||
BooleanExpression::Value(b) => write!(f, "Value({})", b),
|
||||
BooleanExpression::IfElse(ref condition, ref consequent, ref alternative) => write!(
|
||||
f,
|
||||
"IfElse({:?}, {:?}, {:?})",
|
||||
condition, consequent, alternative
|
||||
),
|
||||
BooleanExpression::FieldLt(ref lhs, ref rhs) => {
|
||||
write!(f, "FieldLt({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::FieldLe(ref lhs, ref rhs) => {
|
||||
write!(f, "FieldLe({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::FieldGe(ref lhs, ref rhs) => {
|
||||
write!(f, "FieldGe({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::FieldGt(ref lhs, ref rhs) => {
|
||||
write!(f, "FieldGt({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::UintLt(ref lhs, ref rhs) => {
|
||||
write!(f, "UintLt({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::UintLe(ref lhs, ref rhs) => {
|
||||
write!(f, "UintLe({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::UintGe(ref lhs, ref rhs) => {
|
||||
write!(f, "UintGe({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::UintGt(ref lhs, ref rhs) => {
|
||||
write!(f, "UintGt({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::FieldEq(ref lhs, ref rhs) => {
|
||||
write!(f, "FieldEq({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::BoolEq(ref lhs, ref rhs) => {
|
||||
write!(f, "BoolEq({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::ArrayEq(ref lhs, ref rhs) => {
|
||||
write!(f, "ArrayEq({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::StructEq(ref lhs, ref rhs) => {
|
||||
write!(f, "StructEq({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::UintEq(ref lhs, ref rhs) => {
|
||||
write!(f, "UintEq({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
BooleanExpression::And(ref lhs, ref rhs) => write!(f, "And({:?}, {:?})", lhs, rhs),
|
||||
BooleanExpression::Not(ref exp) => write!(f, "Not({:?})", exp),
|
||||
BooleanExpression::FunctionCall(ref i, ref g, ref p) => {
|
||||
write!(f, "FunctionCall({:?}, {:?}, (", g, i)?;
|
||||
f.debug_list().entries(p.iter()).finish()?;
|
||||
write!(f, ")")
|
||||
}
|
||||
BooleanExpression::Select(ref array, ref index) => {
|
||||
write!(f, "Select({:?}, {:?})", array, index)
|
||||
}
|
||||
BooleanExpression::Member(ref struc, ref id) => {
|
||||
write!(f, "Access({:?}, {:?})", struc, id)
|
||||
}
|
||||
BooleanExpression::Or(ref lhs, ref rhs) => write!(f, "Or({:?}, {:?})", lhs, rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for FieldElementExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElementExpression::Number(ref i) => write!(f, "Num({:?})", i),
|
||||
FieldElementExpression::Identifier(ref var) => write!(f, "Ide({:?})", var),
|
||||
FieldElementExpression::Add(ref lhs, ref rhs) => write!(f, "Add({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Sub(ref lhs, ref rhs) => write!(f, "Sub({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Mult(ref lhs, ref rhs) => {
|
||||
write!(f, "Mult({:?}, {:?})", lhs, rhs)
|
||||
}
|
||||
FieldElementExpression::Div(ref lhs, ref rhs) => write!(f, "Div({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Pow(ref lhs, ref rhs) => write!(f, "Pow({:?}, {:?})", lhs, rhs),
|
||||
FieldElementExpression::Neg(ref e) => write!(f, "Neg({:?})", e),
|
||||
FieldElementExpression::Pos(ref e) => write!(f, "Pos({:?})", e),
|
||||
FieldElementExpression::IfElse(ref condition, ref consequent, ref alternative) => {
|
||||
write!(
|
||||
f,
|
||||
"IfElse({:?}, {:?}, {:?})",
|
||||
condition, consequent, alternative
|
||||
)
|
||||
}
|
||||
FieldElementExpression::FunctionCall(ref i, ref g, ref p) => {
|
||||
write!(f, "FunctionCall({:?}, {:?}, (", g, i)?;
|
||||
f.debug_list().entries(p.iter()).finish()?;
|
||||
write!(f, ")")
|
||||
}
|
||||
FieldElementExpression::Member(ref struc, ref id) => {
|
||||
write!(f, "Member({:?}, {:?})", struc, id)
|
||||
}
|
||||
FieldElementExpression::Select(ref id, ref index) => {
|
||||
write!(f, "Select({:?}, {:?})", id, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for ArrayExpressionInner<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ArrayExpressionInner::Identifier(ref var) => write!(f, "Identifier({:?})", var),
|
||||
ArrayExpressionInner::Value(ref values) => write!(f, "Value({:?})", values),
|
||||
ArrayExpressionInner::FunctionCall(ref i, ref g, ref p) => {
|
||||
write!(f, "FunctionCall({:?}, {:?}, (", g, i)?;
|
||||
f.debug_list().entries(p.iter()).finish()?;
|
||||
write!(f, ")")
|
||||
}
|
||||
ArrayExpressionInner::IfElse(ref condition, ref consequent, ref alternative) => write!(
|
||||
f,
|
||||
"IfElse({:?}, {:?}, {:?})",
|
||||
condition, consequent, alternative
|
||||
),
|
||||
ArrayExpressionInner::Member(ref struc, ref id) => {
|
||||
write!(f, "Member({:?}, {:?})", struc, id)
|
||||
}
|
||||
ArrayExpressionInner::Select(ref array, ref index) => {
|
||||
write!(f, "Select({:?}, {:?})", array, index)
|
||||
}
|
||||
ArrayExpressionInner::Slice(ref array, ref from, ref to) => {
|
||||
write!(f, "Slice({:?}, {:?}, {:?})", array, from, to)
|
||||
}
|
||||
ArrayExpressionInner::Repeat(ref e, ref count) => {
|
||||
write!(f, "Repeat({:?}, {:?})", e, count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for StructExpressionInner<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
StructExpressionInner::Identifier(ref var) => write!(f, "{:?}", var),
|
||||
StructExpressionInner::Value(ref values) => write!(f, "{:?}", values),
|
||||
StructExpressionInner::FunctionCall(ref i, ref g, ref p) => {
|
||||
write!(f, "FunctionCall({:?}, {:?}, (", g, i)?;
|
||||
f.debug_list().entries(p.iter()).finish()?;
|
||||
write!(f, ")")
|
||||
}
|
||||
StructExpressionInner::IfElse(ref condition, ref consequent, ref alternative) => {
|
||||
write!(
|
||||
f,
|
||||
"IfElse({:?}, {:?}, {:?})",
|
||||
condition, consequent, alternative
|
||||
)
|
||||
}
|
||||
StructExpressionInner::Member(ref struc, ref id) => {
|
||||
write!(f, "Member({:?}, {:?})", struc, id)
|
||||
}
|
||||
StructExpressionInner::Select(ref id, ref index) => {
|
||||
write!(f, "Select({:?}, {:?})", id, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Display> fmt::Display for TypedExpressionList<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
@ -1766,23 +1520,6 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedExpressionList<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for TypedExpressionList<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(ref i, ref g, ref p, _) => {
|
||||
write!(f, "FunctionCall({:?}, {:?}, (", g, i)?;
|
||||
f.debug_list().entries(p.iter()).finish()?;
|
||||
write!(f, ")")
|
||||
}
|
||||
TypedExpressionList::EmbedCall(ref embed, ref g, ref p, _) => {
|
||||
write!(f, "EmbedCall({:?}, {:?}, (", g, embed)?;
|
||||
f.debug_list().entries(p.iter()).finish()?;
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Variable to TypedExpression conversion
|
||||
|
||||
impl<'ast, T: Field> From<Variable<'ast, T>> for TypedExpression<'ast, T> {
|
||||
|
@ -1897,7 +1634,7 @@ impl<'ast, T> Select<'ast, T> for BooleanExpression<'ast, T> {
|
|||
|
||||
impl<'ast, T: Clone> Select<'ast, T> for TypedExpression<'ast, T> {
|
||||
fn select<I: Into<UExpression<'ast, T>>>(array: ArrayExpression<'ast, T>, index: I) -> Self {
|
||||
match *array.get_array_type().ty {
|
||||
match *array.ty().ty {
|
||||
Type::Array(..) => ArrayExpression::select(array, index).into(),
|
||||
Type::Struct(..) => StructExpression::select(array, index).into(),
|
||||
Type::FieldElement => FieldElementExpression::select(array, index).into(),
|
||||
|
@ -2096,3 +1833,42 @@ impl<'ast, T: Field> FunctionCall<'ast, T> for StructExpression<'ast, T> {
|
|||
StructExpressionInner::FunctionCall(key, generics, arguments).annotate(struct_ty)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Block<'ast, T> {
|
||||
fn block(statements: Vec<TypedStatement<'ast, T>>, value: Self) -> Self;
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Block<'ast, T> for FieldElementExpression<'ast, T> {
|
||||
fn block(statements: Vec<TypedStatement<'ast, T>>, value: Self) -> Self {
|
||||
FieldElementExpression::Block(BlockExpression::new(statements, value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Block<'ast, T> for BooleanExpression<'ast, T> {
|
||||
fn block(statements: Vec<TypedStatement<'ast, T>>, value: Self) -> Self {
|
||||
BooleanExpression::Block(BlockExpression::new(statements, value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Block<'ast, T> for UExpression<'ast, T> {
|
||||
fn block(statements: Vec<TypedStatement<'ast, T>>, value: Self) -> Self {
|
||||
let bitwidth = value.bitwidth();
|
||||
UExpressionInner::Block(BlockExpression::new(statements, value)).annotate(bitwidth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Block<'ast, T> for ArrayExpression<'ast, T> {
|
||||
fn block(statements: Vec<TypedStatement<'ast, T>>, value: Self) -> Self {
|
||||
let array_ty = value.ty();
|
||||
ArrayExpressionInner::Block(BlockExpression::new(statements, value))
|
||||
.annotate(*array_ty.ty, array_ty.size)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> Block<'ast, T> for StructExpression<'ast, T> {
|
||||
fn block(statements: Vec<TypedStatement<'ast, T>>, value: Self) -> Self {
|
||||
let struct_ty = value.ty().clone();
|
||||
|
||||
StructExpressionInner::Block(BlockExpression::new(statements, value)).annotate(struct_ty)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,40 @@ use crate::typed_absy::types::{ArrayType, StructMember, StructType};
|
|||
use crate::typed_absy::*;
|
||||
use zokrates_field::Field;
|
||||
|
||||
pub trait ResultFold<'ast, T: Field>: Sized {
|
||||
fn fold<F: ResultFolder<'ast, T>>(self, f: &mut F) -> Result<Self, F::Error>;
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> ResultFold<'ast, T> for FieldElementExpression<'ast, T> {
|
||||
fn fold<F: ResultFolder<'ast, T>>(self, f: &mut F) -> Result<Self, F::Error> {
|
||||
f.fold_field_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> ResultFold<'ast, T> for BooleanExpression<'ast, T> {
|
||||
fn fold<F: ResultFolder<'ast, T>>(self, f: &mut F) -> Result<Self, F::Error> {
|
||||
f.fold_boolean_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> ResultFold<'ast, T> for UExpression<'ast, T> {
|
||||
fn fold<F: ResultFolder<'ast, T>>(self, f: &mut F) -> Result<Self, F::Error> {
|
||||
f.fold_uint_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> ResultFold<'ast, T> for ArrayExpression<'ast, T> {
|
||||
fn fold<F: ResultFolder<'ast, T>>(self, f: &mut F) -> Result<Self, F::Error> {
|
||||
f.fold_array_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> ResultFold<'ast, T> for StructExpression<'ast, T> {
|
||||
fn fold<F: ResultFolder<'ast, T>>(self, f: &mut F) -> Result<Self, F::Error> {
|
||||
f.fold_struct_expression(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ResultFolder<'ast, T: Field>: Sized {
|
||||
type Error;
|
||||
|
||||
|
@ -42,6 +76,13 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
|
|||
fold_function_symbol(self, s)
|
||||
}
|
||||
|
||||
fn fold_declaration_function_key(
|
||||
&mut self,
|
||||
key: DeclarationFunctionKey<'ast>,
|
||||
) -> Result<DeclarationFunctionKey<'ast>, Self::Error> {
|
||||
fold_declaration_function_key(self, key)
|
||||
}
|
||||
|
||||
fn fold_function(
|
||||
&mut self,
|
||||
f: TypedFunction<'ast, T>,
|
||||
|
@ -49,6 +90,13 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
|
|||
fold_function(self, f)
|
||||
}
|
||||
|
||||
fn fold_signature(
|
||||
&mut self,
|
||||
s: DeclarationSignature<'ast>,
|
||||
) -> Result<DeclarationSignature<'ast>, Self::Error> {
|
||||
fold_signature(self, s)
|
||||
}
|
||||
|
||||
fn fold_parameter(
|
||||
&mut self,
|
||||
p: DeclarationParameter<'ast>,
|
||||
|
@ -90,6 +138,13 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_block_expression<E: ResultFold<'ast, T>>(
|
||||
&mut self,
|
||||
block: BlockExpression<'ast, T, E>,
|
||||
) -> Result<BlockExpression<'ast, T, E>, Self::Error> {
|
||||
fold_block_expression(self, block)
|
||||
}
|
||||
|
||||
fn fold_array_type(
|
||||
&mut self,
|
||||
t: ArrayType<'ast, T>,
|
||||
|
@ -302,6 +357,9 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
|||
e: ArrayExpressionInner<'ast, T>,
|
||||
) -> Result<ArrayExpressionInner<'ast, T>, F::Error> {
|
||||
let e = match e {
|
||||
ArrayExpressionInner::Block(block) => {
|
||||
ArrayExpressionInner::Block(f.fold_block_expression(block)?)
|
||||
}
|
||||
ArrayExpressionInner::Identifier(id) => ArrayExpressionInner::Identifier(f.fold_name(id)?),
|
||||
ArrayExpressionInner::Value(exprs) => ArrayExpressionInner::Value(
|
||||
exprs
|
||||
|
@ -357,6 +415,9 @@ pub fn fold_struct_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
|||
e: StructExpressionInner<'ast, T>,
|
||||
) -> Result<StructExpressionInner<'ast, T>, F::Error> {
|
||||
let e = match e {
|
||||
StructExpressionInner::Block(block) => {
|
||||
StructExpressionInner::Block(f.fold_block_expression(block)?)
|
||||
}
|
||||
StructExpressionInner::Identifier(id) => {
|
||||
StructExpressionInner::Identifier(f.fold_name(id)?)
|
||||
}
|
||||
|
@ -402,6 +463,9 @@ pub fn fold_field_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
|||
e: FieldElementExpression<'ast, T>,
|
||||
) -> Result<FieldElementExpression<'ast, T>, F::Error> {
|
||||
let e = match e {
|
||||
FieldElementExpression::Block(block) => {
|
||||
FieldElementExpression::Block(f.fold_block_expression(block)?)
|
||||
}
|
||||
FieldElementExpression::Number(n) => FieldElementExpression::Number(n),
|
||||
FieldElementExpression::Identifier(id) => {
|
||||
FieldElementExpression::Identifier(f.fold_name(id)?)
|
||||
|
@ -478,11 +542,31 @@ pub fn fold_int_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
|||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn fold_block_expression<'ast, T: Field, E: ResultFold<'ast, T>, F: ResultFolder<'ast, T>>(
|
||||
f: &mut F,
|
||||
block: BlockExpression<'ast, T, E>,
|
||||
) -> Result<BlockExpression<'ast, T, E>, F::Error> {
|
||||
Ok(BlockExpression {
|
||||
statements: block
|
||||
.statements
|
||||
.into_iter()
|
||||
.map(|s| f.fold_statement(s))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
value: box block.value.fold(f)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fold_boolean_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||
f: &mut F,
|
||||
e: BooleanExpression<'ast, T>,
|
||||
) -> Result<BooleanExpression<'ast, T>, F::Error> {
|
||||
let e = match e {
|
||||
BooleanExpression::Block(block) => {
|
||||
BooleanExpression::Block(f.fold_block_expression(block)?)
|
||||
}
|
||||
BooleanExpression::Value(v) => BooleanExpression::Value(v),
|
||||
BooleanExpression::Identifier(id) => BooleanExpression::Identifier(f.fold_name(id)?),
|
||||
BooleanExpression::FieldEq(box e1, box e2) => {
|
||||
|
@ -610,6 +694,7 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
|||
e: UExpressionInner<'ast, T>,
|
||||
) -> Result<UExpressionInner<'ast, T>, F::Error> {
|
||||
let e = match e {
|
||||
UExpressionInner::Block(block) => UExpressionInner::Block(f.fold_block_expression(block)?),
|
||||
UExpressionInner::Value(v) => UExpressionInner::Value(v),
|
||||
UExpressionInner::Identifier(id) => UExpressionInner::Identifier(f.fold_name(id)?),
|
||||
UExpressionInner::Add(box left, box right) => {
|
||||
|
@ -723,6 +808,16 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
|||
Ok(e)
|
||||
}
|
||||
|
||||
pub fn fold_declaration_function_key<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||
f: &mut F,
|
||||
key: DeclarationFunctionKey<'ast>,
|
||||
) -> Result<DeclarationFunctionKey<'ast>, F::Error> {
|
||||
Ok(DeclarationFunctionKey {
|
||||
signature: f.fold_signature(key.signature)?,
|
||||
..key
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fold_function<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||
f: &mut F,
|
||||
fun: TypedFunction<'ast, T>,
|
||||
|
@ -741,7 +836,26 @@ pub fn fold_function<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
|||
.into_iter()
|
||||
.flatten()
|
||||
.collect(),
|
||||
..fun
|
||||
signature: f.fold_signature(fun.signature)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn fold_signature<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||
f: &mut F,
|
||||
s: DeclarationSignature<'ast>,
|
||||
) -> Result<DeclarationSignature<'ast>, F::Error> {
|
||||
Ok(DeclarationSignature {
|
||||
generics: s.generics,
|
||||
inputs: s
|
||||
.inputs
|
||||
.into_iter()
|
||||
.map(|o| f.fold_declaration_type(o))
|
||||
.collect::<Result<_, _>>()?,
|
||||
outputs: s
|
||||
.outputs
|
||||
.into_iter()
|
||||
.map(|o| f.fold_declaration_type(o))
|
||||
.collect::<Result<_, _>>()?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -801,9 +915,10 @@ pub fn fold_struct_expression<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
|||
f: &mut F,
|
||||
e: StructExpression<'ast, T>,
|
||||
) -> Result<StructExpression<'ast, T>, F::Error> {
|
||||
let ty = f.fold_struct_type(e.ty)?;
|
||||
Ok(StructExpression {
|
||||
inner: f.fold_struct_expression_inner(&e.ty, e.inner)?,
|
||||
..e
|
||||
inner: f.fold_struct_expression_inner(&ty, e.inner)?,
|
||||
ty,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::typed_absy::{OwnedTypedModuleId, UExpression, UExpressionInner};
|
||||
use crate::typed_absy::{Identifier, OwnedTypedModuleId, UExpression, UExpressionInner};
|
||||
use crate::typed_absy::{TryFrom, TryInto};
|
||||
use serde::{de::Error, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::collections::BTreeMap;
|
||||
|
@ -54,6 +54,7 @@ pub struct SpecializationError;
|
|||
pub enum Constant<'ast> {
|
||||
Generic(GenericIdentifier<'ast>),
|
||||
Concrete(u32),
|
||||
Identifier(&'ast str, usize),
|
||||
}
|
||||
|
||||
impl<'ast> From<u32> for Constant<'ast> {
|
||||
|
@ -79,6 +80,7 @@ impl<'ast> fmt::Display for Constant<'ast> {
|
|||
match self {
|
||||
Constant::Generic(i) => write!(f, "{}", i),
|
||||
Constant::Concrete(v) => write!(f, "{}", v),
|
||||
Constant::Identifier(v, _) => write!(f, "{}", v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +98,9 @@ impl<'ast, T> From<Constant<'ast>> for UExpression<'ast, T> {
|
|||
UExpressionInner::Identifier(i.name.into()).annotate(UBitwidth::B32)
|
||||
}
|
||||
Constant::Concrete(v) => UExpressionInner::Value(v as u128).annotate(UBitwidth::B32),
|
||||
Constant::Identifier(v, size) => {
|
||||
UExpressionInner::Identifier(Identifier::from(v)).annotate(UBitwidth::from(size))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +184,7 @@ impl<'ast, T> From<DeclarationStructMember<'ast>> for StructMember<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord, Debug)]
|
||||
pub struct GArrayType<S> {
|
||||
pub size: S,
|
||||
#[serde(flatten)]
|
||||
|
@ -426,7 +431,7 @@ impl fmt::Display for UBitwidth {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
||||
pub enum GType<S> {
|
||||
FieldElement,
|
||||
Boolean,
|
||||
|
@ -627,29 +632,6 @@ impl<S: fmt::Display> fmt::Display for GType<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: fmt::Debug> fmt::Debug for GType<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
GType::FieldElement => write!(f, "field"),
|
||||
GType::Boolean => write!(f, "bool"),
|
||||
GType::Int => write!(f, "integer"),
|
||||
GType::Uint(ref bitwidth) => write!(f, "u{:?}", bitwidth),
|
||||
GType::Array(ref array_type) => write!(f, "{:?}[{:?}]", array_type.ty, array_type.size),
|
||||
GType::Struct(ref struct_type) => write!(
|
||||
f,
|
||||
"{:?} {{{:?}}}",
|
||||
struct_type.name(),
|
||||
struct_type
|
||||
.members
|
||||
.iter()
|
||||
.map(|member| format!("{:?}: {:?}", member.id, member.ty))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> GType<S> {
|
||||
pub fn array<U: Into<GArrayType<S>>>(array_ty: U) -> Self {
|
||||
GType::Array(array_ty.into())
|
||||
|
@ -870,7 +852,7 @@ pub mod signature {
|
|||
use super::*;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Eq)]
|
||||
#[derive(Clone, Serialize, Deserialize, Eq, Debug)]
|
||||
pub struct GSignature<S> {
|
||||
pub generics: Vec<Option<S>>,
|
||||
pub inputs: Vec<GType<S>>,
|
||||
|
@ -943,6 +925,7 @@ pub mod signature {
|
|||
}
|
||||
},
|
||||
Constant::Concrete(s0) => s1 == *s0 as usize,
|
||||
Constant::Identifier(_, s0) => s1 == *s0,
|
||||
}
|
||||
}
|
||||
(DeclarationType::FieldElement, GType::FieldElement)
|
||||
|
@ -968,6 +951,7 @@ pub mod signature {
|
|||
let size = match t0.size {
|
||||
Constant::Generic(s) => constants.0.get(&s).cloned().ok_or(s),
|
||||
Constant::Concrete(s) => Ok(s.into()),
|
||||
Constant::Identifier(_, s) => Ok((s as u32).into()),
|
||||
}?;
|
||||
|
||||
GType::Array(GArrayType { size, ty })
|
||||
|
@ -1136,16 +1120,6 @@ pub mod signature {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: fmt::Debug> fmt::Debug for GSignature<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Signature(generics: {:?}, inputs: {:?}, outputs: {:?})",
|
||||
self.generics, self.inputs, self.outputs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: fmt::Display> fmt::Display for GSignature<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if !self.generics.is_empty() {
|
||||
|
|
|
@ -175,6 +175,7 @@ impl<'ast, T> PartialEq<usize> for UExpression<'ast, T> {
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum UExpressionInner<'ast, T> {
|
||||
Block(BlockExpression<'ast, T, UExpression<'ast, T>>),
|
||||
Identifier(Identifier<'ast>),
|
||||
Value(u128),
|
||||
Add(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
|
||||
|
|
|
@ -104,7 +104,17 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
ZirStatement::Definition(a, e) => {
|
||||
ZirStatement::Definition(f.fold_assignee(a), f.fold_expression(e))
|
||||
}
|
||||
ZirStatement::Declaration(v) => ZirStatement::Declaration(f.fold_variable(v)),
|
||||
ZirStatement::IfElse(condition, consequence, alternative) => ZirStatement::IfElse(
|
||||
f.fold_boolean_expression(condition),
|
||||
consequence
|
||||
.into_iter()
|
||||
.flat_map(|e| f.fold_statement(e))
|
||||
.collect(),
|
||||
alternative
|
||||
.into_iter()
|
||||
.flat_map(|e| f.fold_statement(e))
|
||||
.collect(),
|
||||
),
|
||||
ZirStatement::Assertion(e) => ZirStatement::Assertion(f.fold_boolean_expression(e)),
|
||||
ZirStatement::MultipleDefinition(variables, elist) => ZirStatement::MultipleDefinition(
|
||||
variables.into_iter().map(|v| f.fold_variable(v)).collect(),
|
||||
|
|
|
@ -90,7 +90,11 @@ pub type ZirAssignee<'ast> = Variable<'ast>;
|
|||
pub enum ZirStatement<'ast, T> {
|
||||
Return(Vec<ZirExpression<'ast, T>>),
|
||||
Definition(ZirAssignee<'ast>, ZirExpression<'ast, T>),
|
||||
Declaration(Variable<'ast>),
|
||||
IfElse(
|
||||
BooleanExpression<'ast, T>,
|
||||
Vec<ZirStatement<'ast, T>>,
|
||||
Vec<ZirStatement<'ast, T>>,
|
||||
),
|
||||
Assertion(BooleanExpression<'ast, T>),
|
||||
MultipleDefinition(Vec<ZirAssignee<'ast>>, ZirExpressionList<'ast, T>),
|
||||
}
|
||||
|
@ -108,9 +112,11 @@ impl<'ast, T: fmt::Debug> fmt::Debug for ZirStatement<'ast, T> {
|
|||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
ZirStatement::Declaration(ref var) => write!(f, "Declaration({:?})", var),
|
||||
ZirStatement::Definition(ref lhs, ref rhs) => {
|
||||
write!(f, "Definition({:?}, {:?})", lhs, rhs)
|
||||
ZirStatement::Definition(ref consequence, ref alternative) => {
|
||||
write!(f, "Definition({:?}, {:?})", consequence, alternative)
|
||||
}
|
||||
ZirStatement::IfElse(ref condition, ref lhs, ref rhs) => {
|
||||
write!(f, "IfElse({:?}, {:?}, {:?})", condition, lhs, rhs)
|
||||
}
|
||||
ZirStatement::Assertion(ref e) => write!(f, "Assertion({:?})", e),
|
||||
ZirStatement::MultipleDefinition(ref lhs, ref rhs) => {
|
||||
|
@ -133,9 +139,25 @@ impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> {
|
|||
}
|
||||
write!(f, "")
|
||||
}
|
||||
ZirStatement::Declaration(ref var) => write!(f, "assert({})", var),
|
||||
ZirStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
|
||||
ZirStatement::Assertion(ref e) => write!(f, "{}", e),
|
||||
ZirStatement::IfElse(ref condition, ref consequence, ref alternative) => {
|
||||
write!(
|
||||
f,
|
||||
"if {} then {{{}}} else {{{}}} fi",
|
||||
condition,
|
||||
consequence
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
alternative
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
)
|
||||
}
|
||||
ZirStatement::Assertion(ref e) => write!(f, "assert({})", e),
|
||||
ZirStatement::MultipleDefinition(ref ids, ref rhs) => {
|
||||
for (i, id) in ids.iter().enumerate() {
|
||||
write!(f, "{}", id)?;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_core_test"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
authors = ["schaeff <thibaut@schaeff.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const field[2] ARRAY = [1, 2]
|
||||
const u32 N = 2
|
||||
const field[N] ARRAY = [1, 2]
|
||||
|
||||
def main() -> field[2]:
|
||||
def main() -> field[N]:
|
||||
return ARRAY
|
16
zokrates_core_test/tests/tests/constants/array_size.json
Normal file
16
zokrates_core_test/tests/tests/constants/array_size.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/constants/array_size.zok",
|
||||
"max_constraint_count": 2,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["42", "42"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["42", "42"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
5
zokrates_core_test/tests/tests/constants/array_size.zok
Normal file
5
zokrates_core_test/tests/tests/constants/array_size.zok
Normal file
|
@ -0,0 +1,5 @@
|
|||
const u32 SIZE = 2
|
||||
|
||||
def main(field[SIZE] a) -> field[SIZE]:
|
||||
field[SIZE] b = a
|
||||
return b
|
16
zokrates_core_test/tests/tests/constants/mixed.json
Normal file
16
zokrates_core_test/tests/tests/constants/mixed.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/constants/mixed.zok",
|
||||
"max_constraint_count": 6,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": []
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["1", "2", "1", "3", "4", "0"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
15
zokrates_core_test/tests/tests/constants/mixed.zok
Normal file
15
zokrates_core_test/tests/tests/constants/mixed.zok
Normal file
|
@ -0,0 +1,15 @@
|
|||
const u32 N = 2
|
||||
const bool B = true
|
||||
|
||||
struct Foo {
|
||||
field[N] a
|
||||
bool b
|
||||
}
|
||||
|
||||
const Foo[N] F = [
|
||||
Foo { a: [1, 2], b: B },
|
||||
Foo { a: [3, 4], b: !B }
|
||||
]
|
||||
|
||||
def main() -> Foo[N]:
|
||||
return F
|
16
zokrates_core_test/tests/tests/constants/propagate.json
Normal file
16
zokrates_core_test/tests/tests/constants/propagate.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/constants/propagate.zok",
|
||||
"max_constraint_count": 4,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": []
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["42", "42", "42", "42"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
5
zokrates_core_test/tests/tests/constants/propagate.zok
Normal file
5
zokrates_core_test/tests/tests/constants/propagate.zok
Normal file
|
@ -0,0 +1,5 @@
|
|||
const u32 TWO = 2
|
||||
const u32 FOUR = TWO * TWO
|
||||
|
||||
def main() -> field[FOUR]:
|
||||
return [42; FOUR]
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/constants/struct.zok",
|
||||
"max_constraint_count": 1,
|
||||
"max_constraint_count": 6,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
|
@ -8,7 +8,7 @@
|
|||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["4"]
|
||||
"values": ["1", "2", "3", "4", "5", "6"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
struct Foo {
|
||||
field a
|
||||
field b
|
||||
const u32 N = 2
|
||||
|
||||
struct State {
|
||||
field[N] a
|
||||
field[N][N] b
|
||||
}
|
||||
|
||||
const Foo FOO = Foo { a: 2, b: 2 }
|
||||
const State STATE = State {
|
||||
a: [1, 2],
|
||||
b: [[3, 4], [5, 6]]
|
||||
}
|
||||
|
||||
def main() -> field:
|
||||
return FOO.a + FOO.b
|
||||
def main() -> State:
|
||||
return STATE
|
|
@ -1,4 +1,4 @@
|
|||
import "EMBED/unpack" as unpack
|
||||
from "EMBED" import unpack
|
||||
|
||||
def main(field x):
|
||||
bool[1] bits = unpack(x)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import "EMBED/u32_to_bits" as to_bits
|
||||
import "EMBED/u32_from_bits" as from_bits
|
||||
import "utils/casts/u32_to_bits" as to_bits
|
||||
import "utils/casts/u32_from_bits" as from_bits
|
||||
|
||||
def rotl32<N>(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
|
|
66
zokrates_core_test/tests/tests/panics/deep_branch.json
Normal file
66
zokrates_core_test/tests/tests/panics/deep_branch.json
Normal file
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/panics/deep_branch.zok",
|
||||
"curves": ["Bn128"],
|
||||
"config": {
|
||||
"allow_unconstrained_variables": false,
|
||||
"isolate_branches": true
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"1", "1", "1"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": [
|
||||
"1", "1", "1"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"0", "0", "0"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": [
|
||||
"0", "0", "0"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"0", "1", "0"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": [
|
||||
"0", "1", "0"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"1", "0", "1"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": [
|
||||
"1", "0", "1"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
34
zokrates_core_test/tests/tests/panics/deep_branch.zok
Normal file
34
zokrates_core_test/tests/tests/panics/deep_branch.zok
Normal file
|
@ -0,0 +1,34 @@
|
|||
def check<N>(bool[N] conditions, bool[N] expected) -> bool[3]:
|
||||
assert(conditions == expected)
|
||||
return conditions
|
||||
|
||||
def main(bool[3] conditions) -> bool[3]:
|
||||
return if conditions[0] then\
|
||||
if conditions[1] then\
|
||||
if conditions[2] then\
|
||||
check(conditions, [true, true, true])\
|
||||
else\
|
||||
check(conditions, [true, true, false])\
|
||||
fi\
|
||||
else\
|
||||
if conditions[2] then\
|
||||
check(conditions, [true, false, true])\
|
||||
else\
|
||||
check(conditions, [true, false, false])\
|
||||
fi\
|
||||
fi\
|
||||
else\
|
||||
if conditions[1] then\
|
||||
if conditions[2] then\
|
||||
check(conditions, [false, true, true])\
|
||||
else\
|
||||
check(conditions, [false, true, false])\
|
||||
fi\
|
||||
else\
|
||||
if conditions[2] then\
|
||||
check(conditions, [false, false, true])\
|
||||
else\
|
||||
check(conditions, [false, false, false])\
|
||||
fi\
|
||||
fi\
|
||||
fi
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/panics/deep_branch.zok",
|
||||
"curves": ["Bn128"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"0", "0", "0"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Err": {
|
||||
"UnsatisfiedConstraint": {
|
||||
"left": "0",
|
||||
"right": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
34
zokrates_core_test/tests/tests/panics/internal_panic.json
Normal file
34
zokrates_core_test/tests/tests/panics/internal_panic.json
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/panics/internal_panic.zok",
|
||||
"curves": ["Bn128"],
|
||||
"config": {
|
||||
"allow_unconstrained_variables": false,
|
||||
"isolate_branches": true
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["1"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"0"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["0"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
2
zokrates_core_test/tests/tests/panics/internal_panic.zok
Normal file
2
zokrates_core_test/tests/tests/panics/internal_panic.zok
Normal file
|
@ -0,0 +1,2 @@
|
|||
def main(field x) -> field:
|
||||
return if x == 0 then 0 else 1/x fi
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/panics/internal_panic.zok",
|
||||
"curves": ["Bn128"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["1"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"0"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Err": {
|
||||
"UnsatisfiedConstraint": {
|
||||
"left": "0",
|
||||
"right": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
33
zokrates_core_test/tests/tests/panics/loop_bound.json
Normal file
33
zokrates_core_test/tests/tests/panics/loop_bound.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/panics/loop_bound.zok",
|
||||
"curves": ["Bn128", "Bls12_381", "Bls12_377", "Bw6_761"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"0"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Err": {
|
||||
"UnsatisfiedConstraint": {
|
||||
"left": "0",
|
||||
"right": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": []
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
9
zokrates_core_test/tests/tests/panics/loop_bound.zok
Normal file
9
zokrates_core_test/tests/tests/panics/loop_bound.zok
Normal file
|
@ -0,0 +1,9 @@
|
|||
def throwing_bound<N>(u32 x) -> u32:
|
||||
assert(x == N)
|
||||
return 1
|
||||
|
||||
// Even if the bound is constant at compile time, it can throw at runtime
|
||||
def main(u32 x):
|
||||
for u32 i in 0..throwing_bound::<1>(x) do
|
||||
endfor
|
||||
return
|
68
zokrates_core_test/tests/tests/panics/panic_isolation.json
Normal file
68
zokrates_core_test/tests/tests/panics/panic_isolation.json
Normal file
|
@ -0,0 +1,68 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/panics/panic_isolation.zok",
|
||||
"config": {
|
||||
"allow_unconstrained_variables": false,
|
||||
"isolate_branches": true
|
||||
},
|
||||
"curves": ["Bn128"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"1",
|
||||
"42",
|
||||
"42",
|
||||
"0"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Err": {
|
||||
"UnsatisfiedConstraint": {
|
||||
"left": "1",
|
||||
"right": "21888242871839275222246405745257275088548364400416034343698204186575808495577"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": [
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"1"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"0",
|
||||
"2",
|
||||
"2",
|
||||
"0"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": [
|
||||
"0",
|
||||
"2",
|
||||
"2",
|
||||
"0"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
31
zokrates_core_test/tests/tests/panics/panic_isolation.zok
Normal file
31
zokrates_core_test/tests/tests/panics/panic_isolation.zok
Normal file
|
@ -0,0 +1,31 @@
|
|||
def zero(field x) -> field:
|
||||
assert(x == 0)
|
||||
return 0
|
||||
|
||||
def inverse(field x) -> field:
|
||||
assert(x != 0)
|
||||
return 1/x
|
||||
|
||||
def yes(bool x) -> bool:
|
||||
assert(x)
|
||||
return x
|
||||
|
||||
def no(bool x) -> bool:
|
||||
assert(!x)
|
||||
return x
|
||||
|
||||
def ones(field[2] a) -> field[2]:
|
||||
assert(a == [1, 1])
|
||||
return a
|
||||
|
||||
def twos(field[2] a) -> field[2]:
|
||||
assert(a == [2, 2])
|
||||
return a
|
||||
|
||||
def main(bool condition, field[2] a, field x) -> (bool, field[2], field):
|
||||
// first branch asserts that `condition` is true, second branch asserts that `condition` is false. This should never throw.
|
||||
// first branch asserts that all elements in `a` are 1, 2 in the second branch. This should throw only if `a` is neither ones or zeroes
|
||||
// first branch asserts that `x` is zero and returns it, second branch asserts that `x` isn't 0 and returns its inverse (which internally generates a failing assert if x is 0). This should never throw
|
||||
return if condition then yes(condition) else no(condition) fi,\
|
||||
if condition then ones(a) else twos(a) fi,\
|
||||
if x == 0 then zero(x) else inverse(x) fi
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/panics/panic_isolation.zok",
|
||||
"config": {
|
||||
"allow_unconstrained_variables": false,
|
||||
"isolate_branches": false
|
||||
},
|
||||
"curves": ["Bn128"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": [
|
||||
"1",
|
||||
"1",
|
||||
"1",
|
||||
"1"
|
||||
]
|
||||
},
|
||||
"output": {
|
||||
"Err": {
|
||||
"UnsatisfiedConstraint": {
|
||||
"left": "1",
|
||||
"right": "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
16
zokrates_core_test/tests/tests/pass_by_value.json
Normal file
16
zokrates_core_test/tests/tests/pass_by_value.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/pass_by_value.zok",
|
||||
"curves": ["Bn128", "Bls12_381", "Bls12_377", "Bw6_761"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["1", "1", "1"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["2", "1", "2", "1", "2", "1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
18
zokrates_core_test/tests/tests/pass_by_value.zok
Normal file
18
zokrates_core_test/tests/tests/pass_by_value.zok
Normal file
|
@ -0,0 +1,18 @@
|
|||
struct Foo {
|
||||
field a
|
||||
}
|
||||
|
||||
def mutate(field a) -> field:
|
||||
a = a + 1
|
||||
return a
|
||||
|
||||
def mutate(Foo f) -> Foo:
|
||||
f.a = f.a + 1
|
||||
return f
|
||||
|
||||
def mutate(field[1] f) -> field[1]:
|
||||
f[0] = f[0] + 1
|
||||
return f
|
||||
|
||||
def main(field[1] f, Foo g, field h) -> (field[1], field[1], Foo, Foo, field, field):
|
||||
return mutate(f), f, mutate(g), g, mutate(h), h
|
|
@ -1,5 +1,5 @@
|
|||
import "EMBED/u32_to_bits" as to_bits
|
||||
import "EMBED/u32_from_bits" as from_bits
|
||||
import "utils/casts/u32_to_bits" as to_bits
|
||||
import "utils/casts/u32_from_bits" as from_bits
|
||||
|
||||
def rotr32<N>(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import "EMBED/unpack"
|
||||
from "EMBED" import unpack
|
||||
|
||||
def main(field a) -> (bool[255]):
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import "EMBED/unpack"
|
||||
from "EMBED" import unpack
|
||||
|
||||
def main(field a) -> (bool[254]):
|
||||
|
||||
|
|
5
zokrates_core_test/tests/tests/structs/constant.json
Normal file
5
zokrates_core_test/tests/tests/structs/constant.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/structs/constant.zok",
|
||||
"curves": ["Bn128"],
|
||||
"tests": []
|
||||
}
|
8
zokrates_core_test/tests/tests/structs/constant.zok
Normal file
8
zokrates_core_test/tests/tests/structs/constant.zok
Normal file
|
@ -0,0 +1,8 @@
|
|||
struct State {
|
||||
u32[16] memory
|
||||
}
|
||||
|
||||
def main():
|
||||
State s = State { memory: [0; 16] }
|
||||
s.memory[0] = 0x00000001
|
||||
return
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/structs/identity.code",
|
||||
"entry_point": "./tests/tests/structs/identity.zok",
|
||||
"curves": ["Bn128", "Bls12_381", "Bls12_377", "Bw6_761"],
|
||||
"tests": [
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import "EMBED/u32_to_bits" as to_bits
|
||||
import "EMBED/u32_from_bits" as from_bits
|
||||
import "utils/casts/u32_to_bits" as to_bits
|
||||
import "utils/casts/u32_from_bits" as from_bits
|
||||
|
||||
def right_rotate_2(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import "EMBED/u64_to_bits" as to_bits_64
|
||||
import "EMBED/u64_from_bits" as from_bits_64
|
||||
import "EMBED/u32_to_bits" as to_bits_32
|
||||
import "EMBED/u32_from_bits" as from_bits_32
|
||||
import "EMBED/u16_to_bits" as to_bits_16
|
||||
import "EMBED/u16_from_bits" as from_bits_16
|
||||
import "EMBED/u8_to_bits" as to_bits_8
|
||||
import "EMBED/u8_from_bits" as from_bits_8
|
||||
import "utils/casts/u64_to_bits" as to_bits_64
|
||||
import "utils/casts/u64_from_bits" as from_bits_64
|
||||
import "utils/casts/u32_to_bits" as to_bits_32
|
||||
import "utils/casts/u32_from_bits" as from_bits_32
|
||||
import "utils/casts/u16_to_bits" as to_bits_16
|
||||
import "utils/casts/u16_from_bits" as from_bits_16
|
||||
import "utils/casts/u8_to_bits" as to_bits_8
|
||||
import "utils/casts/u8_from_bits" as from_bits_8
|
||||
|
||||
def main(u64 d, u32 e, u16 f, u8 g) -> (u64, u32, u16, u8):
|
||||
bool[64] d_bits = to_bits_64(d)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import "EMBED/u32_to_bits" as to_bits
|
||||
import "EMBED/u32_from_bits" as from_bits
|
||||
import "utils/casts/u32_to_bits" as to_bits
|
||||
import "utils/casts/u32_from_bits" as from_bits
|
||||
|
||||
def right_rotate_2(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
|
|
|
@ -1,60 +1,9 @@
|
|||
import "EMBED/u32_to_bits" as to_bits
|
||||
import "EMBED/u32_from_bits" as from_bits
|
||||
from "EMBED" import u32_to_bits as to_bits
|
||||
from "EMBED" import u32_from_bits as from_bits
|
||||
|
||||
def right_rotate_2(u32 e) -> u32:
|
||||
def right_rotate<N>(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[30..], ...b[..30]])
|
||||
return res
|
||||
|
||||
def right_rotate_4(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[28..], ...b[..28]])
|
||||
return res
|
||||
|
||||
def right_rotate_6(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[26..], ...b[..26]])
|
||||
return res
|
||||
|
||||
def right_rotate_7(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[25..], ...b[..25]])
|
||||
return res
|
||||
|
||||
def right_rotate_11(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[21..], ...b[..21]])
|
||||
return res
|
||||
|
||||
def right_rotate_13(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[19..], ...b[..19]])
|
||||
return res
|
||||
|
||||
def right_rotate_17(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[15..], ...b[..15]])
|
||||
return res
|
||||
|
||||
def right_rotate_18(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[14..], ...b[..14]])
|
||||
return res
|
||||
|
||||
def right_rotate_19(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[13..], ...b[..13]])
|
||||
return res
|
||||
|
||||
def right_rotate_22(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[10..], ...b[..10]])
|
||||
return res
|
||||
|
||||
def right_rotate_25(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
u32 res = from_bits([...b[7..], ...b[..7]])
|
||||
|
||||
u32 res = from_bits([...b[32-N..], ...b[..32-N]])
|
||||
return res
|
||||
|
||||
def main():
|
||||
|
@ -62,7 +11,7 @@ def main():
|
|||
u32 f = 0x01234567
|
||||
|
||||
// rotate
|
||||
u32 rotated = right_rotate_4(e)
|
||||
u32 rotated = right_rotate::<4>(e)
|
||||
assert(rotated == 0x81234567)
|
||||
|
||||
// and
|
||||
|
@ -93,16 +42,16 @@ def main():
|
|||
assert(f == from_bits(expected2))
|
||||
|
||||
// S0
|
||||
u32 e2 = right_rotate_2(e)
|
||||
u32 e13 = right_rotate_13(e)
|
||||
u32 e22 = right_rotate_22(e)
|
||||
u32 e2 = right_rotate::<2>(e)
|
||||
u32 e13 = right_rotate::<13>(e)
|
||||
u32 e22 = right_rotate::<22>(e)
|
||||
u32 S0 = e2 ^ e13 ^ e22
|
||||
assert(S0 == 0x66146474)
|
||||
|
||||
// S1
|
||||
u32 e6 = right_rotate_6(e)
|
||||
u32 e11 = right_rotate_11(e)
|
||||
u32 e25 = right_rotate_25(e)
|
||||
u32 e6 = right_rotate::<6>(e)
|
||||
u32 e11 = right_rotate::<11>(e)
|
||||
u32 e25 = right_rotate::<25>(e)
|
||||
u32 S1 = e6 ^ e11 ^ e25
|
||||
assert(S1 == 0x3561abda)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import "EMBED/u32_to_bits" as to_bits
|
||||
import "EMBED/u32_from_bits" as from_bits
|
||||
import "utils/casts/u32_to_bits" as to_bits
|
||||
import "utils/casts/u32_from_bits" as from_bits
|
||||
|
||||
def right_rotate_4(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
|
|
|
@ -1,49 +1,9 @@
|
|||
import "EMBED/u32_to_bits" as to_bits
|
||||
import "EMBED/u32_from_bits" as from_bits
|
||||
|
||||
def right_rotate_2(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[30..], ...b[..30]])
|
||||
|
||||
def right_rotate_6(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[26..], ...b[..26]])
|
||||
|
||||
def right_rotate_7(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[25..], ...b[..25]])
|
||||
|
||||
def right_rotate_11(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[21..], ...b[..21]])
|
||||
|
||||
def right_rotate_13(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[19..], ...b[..19]])
|
||||
|
||||
def right_rotate_17(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[15..], ...b[..15]])
|
||||
|
||||
def right_rotate_18(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[14..], ...b[..14]])
|
||||
|
||||
def right_rotate_19(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[13..], ...b[..13]])
|
||||
|
||||
def right_rotate_22(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[10..], ...b[..10]])
|
||||
|
||||
def right_rotate_25(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[7..], ...b[..7]])
|
||||
def right_rotate<N>(u32 x) -> u32:
|
||||
return (x >> N) | (x << (32 - N))
|
||||
|
||||
def extend(u32[64] w, u32 i) -> u32:
|
||||
u32 s0 = right_rotate_7(w[i-15]) ^ right_rotate_18(w[i-15]) ^ (w[i-15] >> 3)
|
||||
u32 s1 = right_rotate_17(w[i-2]) ^ right_rotate_19(w[i-2]) ^ (w[i-2] >> 10)
|
||||
u32 s0 = right_rotate::<7>(w[i-15]) ^ right_rotate::<18>(w[i-15]) ^ (w[i-15] >> 3)
|
||||
u32 s1 = right_rotate::<17>(w[i-2]) ^ right_rotate::<19>(w[i-2]) ^ (w[i-2] >> 10)
|
||||
return w[i-16] + s0 + w[i-7] + s1
|
||||
|
||||
def temp1(u32 e, u32 f, u32 g, u32 h, u32 k, u32 w) -> u32:
|
||||
|
@ -51,7 +11,7 @@ def temp1(u32 e, u32 f, u32 g, u32 h, u32 k, u32 w) -> u32:
|
|||
u32 ch = (e & f) ^ ((!e) & g)
|
||||
|
||||
// S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
|
||||
u32 S1 = right_rotate_6(e) ^ right_rotate_11(e) ^ right_rotate_25(e)
|
||||
u32 S1 = right_rotate::<6>(e) ^ right_rotate::<11>(e) ^ right_rotate::<25>(e)
|
||||
|
||||
// temp1 := h + S1 + ch + k + w
|
||||
return h + S1 + ch + k + w
|
||||
|
@ -61,7 +21,7 @@ def temp2(u32 a, u32 b, u32 c) -> u32:
|
|||
u32 maj = (a & b) ^ (a & c) ^ (b & c)
|
||||
|
||||
// S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
|
||||
u32 S0 = right_rotate_2(a) ^ right_rotate_13(a) ^ right_rotate_22(a)
|
||||
u32 S0 = right_rotate::<2>(a) ^ right_rotate::<13>(a) ^ right_rotate::<22>(a)
|
||||
|
||||
// temp2 := S0 + maj
|
||||
return S0 + maj
|
||||
|
|
|
@ -1,17 +1,5 @@
|
|||
import "EMBED/u32_to_bits" as to_bits
|
||||
import "EMBED/u32_from_bits" as from_bits
|
||||
|
||||
def right_rotate_6(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[26..], ...b[..26]])
|
||||
|
||||
def right_rotate_11(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[21..], ...b[..21]])
|
||||
|
||||
def right_rotate_25(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[7..], ...b[..7]])
|
||||
def right_rotate<N>(u32 x) -> u32:
|
||||
return (x >> N) | (x << (32 - N))
|
||||
|
||||
// input constraining costs 6 * 33 = 198 constraints, the rest 200
|
||||
def main(u32 e, u32 f, u32 g, u32 h, u32 k, u32 w) -> u32:
|
||||
|
@ -19,7 +7,7 @@ def main(u32 e, u32 f, u32 g, u32 h, u32 k, u32 w) -> u32:
|
|||
u32 ch = (e & f) ^ ((!e) & g) // should be 100 constraints
|
||||
|
||||
// S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
|
||||
u32 S1 = right_rotate_6(e) ^ right_rotate_11(e) ^ right_rotate_25(e) // should be 66 constraints
|
||||
u32 S1 = right_rotate::<6>(e) ^ right_rotate::<11>(e) ^ right_rotate::<25>(e) // should be 66 constraints
|
||||
|
||||
// temp1 := h + S1 + ch + k + w
|
||||
return h + S1 + ch + k + w // should be 35 constraints
|
|
@ -1,17 +1,5 @@
|
|||
import "EMBED/u32_to_bits" as to_bits
|
||||
import "EMBED/u32_from_bits" as from_bits
|
||||
|
||||
def right_rotate_2(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[30..], ...b[..30]])
|
||||
|
||||
def right_rotate_13(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[19..], ...b[..19]])
|
||||
|
||||
def right_rotate_22(u32 e) -> u32:
|
||||
bool[32] b = to_bits(e)
|
||||
return from_bits([...b[10..], ...b[..10]])
|
||||
def right_rotate<N>(u32 x) -> u32:
|
||||
return (x >> N) | (x << (32 - N))
|
||||
|
||||
// input constraining is 99 constraints, the rest is 265 -> total 364
|
||||
def main(u32 a, u32 b, u32 c) -> u32:
|
||||
|
@ -19,7 +7,7 @@ def main(u32 a, u32 b, u32 c) -> u32:
|
|||
u32 maj = (a & b) ^ (a & c) ^ (b & c) // 165 constraints
|
||||
|
||||
// S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
|
||||
u32 S0 = right_rotate_2(a) ^ right_rotate_13(a) ^ right_rotate_22(a) // 66 constraints
|
||||
u32 S0 = right_rotate::<2>(a) ^ right_rotate::<13>(a) ^ right_rotate::<22>(a) // 66 constraints
|
||||
|
||||
// temp2 := S0 + maj
|
||||
return S0 + maj // 34 constraints
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/uint/u16/sub.zok",
|
||||
"max_constraint_count": 53,
|
||||
"max_constraint_count": 91,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
|
@ -8,7 +8,7 @@
|
|||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["0xfffe"]
|
||||
"values": ["0xfffe", "0xfffe", "0x0002"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -18,7 +18,7 @@
|
|||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["0xffff"]
|
||||
"values": ["0xffff", "0xffff", "0x0001"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
def main(u16 a, u16 b) -> u16:
|
||||
return a - b
|
||||
def main(u16 a, u16 b) -> (u16, u16, u16):
|
||||
return a - b, a - 1, 1 - a
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/uint/u32/sub.zok",
|
||||
"max_constraint_count": 101,
|
||||
"max_constraint_count": 171,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
|
@ -8,7 +8,7 @@
|
|||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["0xfffffffe"]
|
||||
"values": ["0xfffffffe", "0xfffffffe", "0x00000002"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -18,7 +18,7 @@
|
|||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["0xffffffff"]
|
||||
"values": ["0xffffffff", "0xffffffff", "0x00000001"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
def main(u32 a, u32 b) -> u32:
|
||||
return a - b
|
||||
def main(u32 a, u32 b) -> (u32, u32, u32):
|
||||
return a - b, a - 1, 1 - a
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/uint/u64/sub.zok",
|
||||
"max_constraint_count": 197,
|
||||
"max_constraint_count": 331,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
|
@ -8,7 +8,7 @@
|
|||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["0xfffffffffffffffe"]
|
||||
"values": ["0xfffffffffffffffe", "0xfffffffffffffffe", "0x0000000000000002"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -18,7 +18,7 @@
|
|||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["0xffffffffffffffff"]
|
||||
"values": ["0xffffffffffffffff", "0xffffffffffffffff", "0x0000000000000001"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
def main(u64 a, u64 b) -> u64:
|
||||
return a - b
|
||||
def main(u64 a, u64 b) -> (u64, u64, u64):
|
||||
return a - b, a - 1, 1 - a
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/uint/u8/sub.zok",
|
||||
"max_constraint_count": 29,
|
||||
"max_constraint_count": 51,
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
|
@ -8,7 +8,7 @@
|
|||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["0xfe"]
|
||||
"values": ["0xfe", "0xfe", "0x02"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -18,7 +18,7 @@
|
|||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["0xff"]
|
||||
"values": ["0xff", "0xff", "0x01"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
def main(u8 a, u8 b) -> u8:
|
||||
return a - b
|
||||
def main(u8 a, u8 b) -> (u8, u8, u8):
|
||||
return a - b, a - 1, 1 - a
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_js"
|
||||
version = "1.0.30"
|
||||
version = "1.0.31"
|
||||
authors = ["Darko Macesic"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
3
zokrates_js/index.d.ts
vendored
3
zokrates_js/index.d.ts
vendored
|
@ -11,7 +11,8 @@ declare module 'zokrates-js' {
|
|||
export type ResolveCallback = (location: string, path: string) => ResolverResult;
|
||||
|
||||
export interface CompileConfig {
|
||||
allow_unconstrained_variables?: boolean
|
||||
allow_unconstrained_variables?: boolean,
|
||||
isolate_branches?: boolean
|
||||
}
|
||||
|
||||
export interface CompileOptions {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "zokrates-js",
|
||||
"main": "index.js",
|
||||
"author": "Darko Macesic <darem966@gmail.com>",
|
||||
"version": "1.0.30",
|
||||
"version": "1.0.31",
|
||||
"keywords": [
|
||||
"zokrates",
|
||||
"wasm-bindgen",
|
||||
|
|
149
zokrates_logo.svg
Normal file
149
zokrates_logo.svg
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 330 330" style="enable-background:new 0 0 330 330;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#020202;}
|
||||
</style>
|
||||
<rect class="st0" width="330" height="330"/>
|
||||
<g id="layer101">
|
||||
<path class="st1" d="M140.8,292.6c-5.6-1.1-8.2-2.7-20.7-13.1c-2.7-2.2-6.7-6.2-9-8.8c-3.6-4.2-4.1-5.4-4.1-9.6
|
||||
c0-3.4-0.7-5.8-2.3-8.2l-2.3-3.4h-12c-6.5,0-13.2,0.5-14.9,1.2c-1.6,0.6-5,1.6-7.5,2.3s-5.8,1.7-7.3,2.3c-1.5,0.5-3,0.7-3.3,0.4
|
||||
c-0.5-0.5,12.3-6.9,16.1-8c2.6-0.8,13.8-2.1,20.8-2.5L97,245l-3.7-3.8c-4.4-4.3-7.3-12.3-7.3-20c0-3.6-0.9-7.1-3.1-11.9
|
||||
c-2.8-6.1-3-7.5-2.8-15.2c0.2-4.8,1.1-11.5,2.2-15.1c1-3.6,1.8-8.1,1.7-10c-0.1-1.9-0.2-9.3-0.4-16.5c-0.3-13.4-1.2-22.3-2.7-26.3
|
||||
c-0.5-1.3-0.5-4.1,0.1-6.7c0.5-2.4,1.4-7.8,1.9-12.2c1-9.1,3.2-14.2,10.1-23.8c4.7-6.4,8.1-12.7,7.9-14.3c-0.5-3.4,0.6-5.4,4.3-7.9
|
||||
c2.2-1.5,6.2-4.9,8.7-7.4c5-5,11.2-8.4,17.6-9.5c2.2-0.3,4.5-1,5-1.4c1.5-1.1,7.3-2,14.6-2.3c4.9-0.1,7.3-0.7,8.7-2
|
||||
c2.7-2.5,17.7-2.6,21.9-0.3c7.6,4.2,11.1,5.6,14.1,5.6c6.2,0,8.6,2,18.9,15.9c1,1.3,2.5,3.1,3.3,4.1c0.8,0.9,2,2.3,2.5,3.2
|
||||
c7.3,10.8,10.5,16.3,16.1,27.3c3.6,7.2,6.9,13.7,7.3,14.5c2.1,3.7,2.8,7.8,1.8,9.6c-0.6,1.1-1.4,6.4-1.7,12
|
||||
c-0.4,6.2-1.3,11.4-2.3,13.4c-1,1.8-1.7,3.8-1.7,4.3c0,0.6-0.7,1.8-1.5,2.7c-0.9,1-2.2,5-3,9.1c-0.9,4.1-2.4,9.2-3.4,11.4
|
||||
c-3.4,7-3.3,9.6,0.2,17.3c0.8,1.8,0.6,2.6-1.1,4.5c-1.5,1.6-2.2,3.6-2.2,6.3c0,4.2-2.7,9.4-6.7,13.1c-1.9,1.8-2.4,3.2-2.2,6.5
|
||||
c0.1,2.4-0.3,5.3-0.8,6.6s-0.4,5.9,0.2,11.4l1,9.1l7.5,3.8c4.1,2.1,10.5,5.2,14.1,6.9c7.4,3.4,15.4,8.8,14.5,9.7
|
||||
c-0.3,0.4-1.6,0.2-2.9-0.4c-1.2-0.6-5.1-2.4-8.7-4.1c-3.6-1.6-11.2-4.9-17-7.2c-11.2-4.4-13-5.8-13-10c0-1.4-0.7-3.5-1.5-4.6
|
||||
c-1.4-1.8-1.6-1.8-4.2,1.2c-1.6,1.7-4.6,4.3-6.8,5.9c-5.1,3.6-7.1,5.9-9.6,11.5c-1.2,2.5-3.1,6.8-4.4,9.5
|
||||
c-2.1,4.5-11.8,14.5-14.2,14.5c-0.4,0-3,2.1-5.8,4.6c-2.7,2.6-6,5-7.3,5.5C158.1,294.3,147.9,294.1,140.8,292.6z M141.5,286.4
|
||||
c0.5-3-0.2-16.4-1-16.4c-0.1,0-1.6,0.7-3.3,1.6c-2,1-3.2,2.3-3.2,3.6c0,1.7-0.2,1.8-1.5,0.8c-0.8-0.7-1.5-2.1-1.5-3.1
|
||||
c0-1.8-3.6-5.9-5.2-5.9c-1.8,0-0.6,5.8,2.2,11c1.7,3,3.3,6.3,3.7,7.3c0.3,0.9,1.3,1.7,2.2,1.7c1,0,2.6,0.7,3.7,1.5
|
||||
C140.4,290.6,140.7,290.4,141.5,286.4z M170.4,282.1c1-1.1,4.1-3.5,6.7-5.2c4.7-2.9,10.9-10.8,10.9-13.6c0-0.8,1.2-3.9,2.6-6.9
|
||||
l2.6-5.4l-2.1-5.8l-2.1-5.7l0.3,6.5c0.4,7,0.1,9-1.4,9c-0.6,0-0.8-0.4-0.4-0.9c0.3-0.6-1.2-4.7-3.4-9.3s-4-9.6-4.2-11.3
|
||||
c-0.4-4.4,0.9-9.1,3.2-11.1c2.4-2.2,2.4-5-0.1-10.8c-2.4-5.2-5.2-6.6-9.7-4.4c-3.6,1.7-4,4-1.2,7.9c2.8,4,4.4,9.7,4.1,15.2
|
||||
c-0.2,2.8-2.2,3.9-2.2,1.2c0-0.8-0.4-1.5-0.9-1.5c-1.6,0-4.1,6.1-4.1,9.8c0,4-1,3.6-2.6-1.1c-1.5-4.4-3.8-4.5-5.8-0.2
|
||||
c-0.9,1.9-2.2,3.5-2.8,3.5c-0.7,0-3.2-2.1-5.6-4.7l-4.5-4.8l0.6,3.2c0.4,1.8,1.8,5.1,3.2,7.3c2,3.1,2.2,4,1,4
|
||||
c-1.2,0-1.4,0.6-0.8,2.8c1.1,3.8,1,10.8-0.1,10.2c-1.2-0.6-2.7,4.6-1.9,6.6c0.4,1.1,0.9,1.2,1.8,0.4c0.7-0.6,1.9-0.9,2.6-0.8
|
||||
c1,0.2,1.3-0.6,1.1-2.6c-0.4-2.8-0.3-2.8,3.4-2.1c3.8,0.7,8,3.1,10.3,5.9c0.7,0.8,1.4,4.3,1.7,7.7c0.3,4.9,0.1,6-1,5.6
|
||||
c-0.8-0.3-1.7,0.1-2,0.9s-1.9,1.4-3.6,1.4c-3.1,0-3.9,1.7-1.8,3.8C163.4,288,166.8,286.1,170.4,282.1z M155.8,278
|
||||
c0.5,0,1.2,1.4,1.6,3.1c0.6,2.9,2.6,3.2,2.6,0.4c0-0.8,1.3-2.1,3-3c3.1-1.6,5.4-4.8,4.3-5.9c-1.4-1.4-3.2-0.4-5.2,2.9
|
||||
c-2.4,4.1-4.4,4.7-3.5,1c0.6-2.6-1.2-8.5-2.6-8.5c-1.6,0-4,7-4,11.7l0.1,4.8l1.4-3.2C154.3,279.5,155.3,278,155.8,278z
|
||||
M142.3,264.2c2.8-2.9,3.5-6.6,1.6-7.8c-1.4-0.8-7.4,5.2-8.4,8.4c-0.5,1.8-0.3,2.2,1.7,2.2C138.6,267,140.8,265.7,142.3,264.2z
|
||||
M113.6,258.9c0.9-1,2.8-1.9,4.1-1.9c1.3,0,2.6-0.7,2.9-1.5c0.8-2.1,3.4-1.9,3.4,0.3c0,1-0.7,2.7-1.5,3.8c-0.8,1-1.5,2.7-1.5,3.7
|
||||
c0,1.7,0.2,1.7,2.9-0.2c1.6-1.2,4.1-2.1,5.5-2.1c3.9,0,7.6-4.1,7.6-8.5c0-1.9,0.5-3.5,1-3.5c0.6,0,1,1.4,1,3c0,1.7,0.5,3,1,3
|
||||
c1.6,0,3.2-5.1,2.6-8.1c-0.3-1.5,0.1-3.5,1-4.7c1.2-1.7,1.3-3,0.5-5.9c-1.6-5.7-1.3-9.1,1.1-13.9c3.2-6.4,7.9-10.6,11.4-10.2
|
||||
l2.9,0.4l-3,1.3c-2.3,1-2.6,1.4-1.5,2.1c0.8,0.6,2.7,1,4.3,1c3.2,0,3.4,0.9,0.9,4c-1.2,1.4-3,2.3-5.1,2.4l-3.2,0.1l2.2,1.8
|
||||
c1.3,1,3.8,1.7,6.6,1.7c2.7,0,4.2,0.4,3.8,1c-0.3,0.6-1.8,1-3.3,1c-2.6,0.1-2.6,0.1-0.7,1.6c2.4,1.8,7.2,1.2,9.5-1.3
|
||||
c0.8-0.9,1-1.3,0.3-0.9c-0.8,0.4-1.6-0.7-2.3-3.1c-0.6-2.1-1.6-4.8-2.3-6.1c-1.1-1.8-1-3.4,0.3-8.7c0.8-3.6,1.8-6.5,2.3-6.5
|
||||
c0.4,0,0.7,0.5,0.7,1.1c0,0.5,1.5-0.1,3.3-1.4c1.7-1.4,4.3-2.8,5.7-3.2s3.2-1.4,4.2-2.2c1-0.9,1.8-1,2.2-0.4c0.3,0.5-0.6,1.9-2,3
|
||||
c-2.5,2-2.5,2.1-0.6,2.1c1.2,0,3.7-0.9,5.7-2s4.1-2,4.8-2s2.5-0.7,4.1-1.5c1.6-0.9,3.2-1.3,3.5-0.9c0.9,0.9-4.2,4.4-6.6,4.4
|
||||
c-1.2,0-3.5,1.4-5.2,3.2c-3.4,3.7-3.2,4.5,2.8,10.1c4.5,4.2,6.1,9.3,4.2,13.3c-1.5,3.4-2.7,3-2.7-1.1c0-1.9-0.5-4-1-4.5
|
||||
c-1.7-1.7-4.2-0.1-4.9,3.1c-0.5,2.4-0.1,3.9,2.1,7l2.7,4l2.5-2.3c4-3.8,5.1-6.8,4.2-11.8c-0.4-2.5-1.1-5.3-1.5-6.2
|
||||
c-1.1-2.7,1.2-2.2,2.6,0.5c2.3,4.4,4,5.7,5.9,4.5c2.6-1.7,4.7-0.4,7.1,4.3l2.1,4.3l1.5-3.5c0.9-2.1,1.3-5.3,1-8.1
|
||||
c-0.2-2.7-0.1-4.8,0.3-4.8c1.5,0,7.8-6.6,8.4-8.7c1-3.3,0.2-2.9-4.5,2.2c-2.3,2.5-4.5,4.5-5,4.5c-1.7,0-0.9-2.9,1.1-4.3
|
||||
c2.2-1.5,3.9-7.7,2.2-7.7c-0.6,0-1.6,1.4-2.4,3c-0.7,1.7-1.6,3-1.9,3c-0.8,0-1.9-3.7-1.9-6.3c0-1-1.7-4-3.7-6.8l-3.8-5l-1.1,3.3
|
||||
l-1.1,3.3l-0.5-5.5c-0.5-6.8-0.1-7.7,2.6-5.2c1.1,1.1,3.8,2.5,5.8,3.1c3.6,1.2,9.4,6.7,11.8,11.1c1.1,2.1,1.2,2.1,4.2-1.9l3-4.1
|
||||
l-1.9-3.1l-2-3l-1.7,2.5c-2.1,3.2-3.9,3.4-2.7,0.4c2.9-7.8,2-16.1-1.7-15.7c-0.9,0.1-2.7,0.1-4,0c-2.2-0.1-2.2-0.2,1.3-5.3
|
||||
c3.5-5.2,4.3-9.3,2.9-14.6c-0.8-2.9-2.5-2.8-5.8,0.3c-1.5,1.4-3.1,2.5-3.7,2.5c-1.4,0-1.1-2.6,0.6-4c0.8-0.7,1.5-2.1,1.5-3.2
|
||||
c0-1.3,1.4-2.5,4.3-3.8c6.1-2.8,6.5-2.6,6.2,2.3c-0.4,5.6,3.8,13.7,7,13.7c2.2,0,2.4-2.6,0.7-8.9c-1.3-4.9-2-6-3.3-5.6
|
||||
c-1.5,0.5-1.9-0.4-2.5-5.2c-0.6-5.1-2.7-11.3-3.8-11.3c-0.3,0-1.1-0.3-2-0.6c-1.3-0.5-1.6,0.2-1.6,4.1c0,5.3-1.6,5.3-2.6-0.1
|
||||
c-0.8-4.5,0.9-9.9,4.6-14.4c3.4-4.2,4.8-3.5,2.5,1.2c-0.9,1.9-1,2.6-0.3,1.7c0.8-0.9,2.2-1.8,3.3-2.1c1.3-0.2,1.9-1.1,1.8-2.3
|
||||
c-0.1-1.1-0.3-3.8-0.4-6c-0.3-5-3.2-11.5-6.7-14.9c-5.3-5-6.3-6.4-7.2-9.6c-1.1-3.8-0.3-12.9,1.2-14.8c1.8-2.1,2.9,0.1,1.9,3.6
|
||||
c-1.4,4.9-0.4,10,3.1,14.8c1.7,2.4,3.5,4.4,4,4.4c1.1,0,1-2.4-0.1-3.6c-1.2-1.2-1.7-9.3-0.7-12.1c0.8-2.4,0.2-3.4-4.6-9.2
|
||||
c-2.6-3-3.4-3.3-10.8-4c-5.1-0.6-8.7-1.5-9.9-2.5c-1-0.9-2.3-1.6-2.9-1.6c-0.7,0-1.2-0.7-1.2-1.5c0-1.9,0.2-1.9,4.5,0.5
|
||||
c3.9,2.2,7,2.6,8,1c0.3-0.5,1.5-1,2.6-1c2.2,0,2.4-1.7,0.6-4.2c-0.9-1.1-4-2-9.6-2.8c-5.5-0.7-9.3-1.8-11.2-3.2
|
||||
c-3.6-2.7-2.8-4.1,1.1-2.1c3.9,1.9,15,3.1,13.4,1.3c-0.6-0.6-3.1-1.4-5.5-1.7c-4.7-0.5-5.6-0.8-14-4.7C177.2,40,167,38.9,167,41
|
||||
c0,0.6,0.5,1,1.2,1c0.9,0,0.9,0.3,0,1.2c-0.9,0.9-5.1,1.3-13.5,1.4c-11.6,0-20.3,1.5-25.9,4.5c-1,0.5-2.4,0.9-3.2,0.9
|
||||
c-0.8,0-5,3.3-9.3,7.3c-4.3,4.1-8.8,7.9-9.9,8.5c-1.2,0.6-2.5,2.4-2.9,3.9c-1.3,5.4-8,17.2-10.5,18.8c-0.6,0.3-1.5,1.5-2.1,2.6
|
||||
c-1,2-1,2,1.5,0.4c1.4-1,2.6-2.1,2.6-2.6s0.4-0.9,1-0.9c1.4,0,7-6.1,7-7.6c0-0.8,0.7-1.4,1.5-1.4c0.8,0,1.5,0.3,1.5,0.7
|
||||
c0,1.4-4.4,9.9-6.7,12.9c-1.3,1.8-2.9,4.7-3.4,6.5c-1.4,4.5-2,13.7-0.9,14.4c0.5,0.3,0.9,5.3,0.9,11.2c0,9-0.3,11-1.9,13.1
|
||||
c-1.1,1.3-2.2,4-2.6,6.1c-0.9,4.9-1.5,5.7-2.9,3.7c-1.1-1.4-1.4-0.8-2.4,4.1c-0.9,4.7-0.8,7,0.4,12.2c1.5,6.1,1.5,6.8-0.6,13.4
|
||||
c-2.6,8.3-3.9,18.4-2.8,21.2c0.4,1.1,0.8,1.5,0.8,0.8c0.1-1.9,5.2-7.4,6.3-6.7c0.6,0.4,0.7,2.1,0.3,4.3c-1.1,5.4-1.5,8.6-1.6,14.4
|
||||
c-0.1,4.4,0.6,16.1,1,17.7c0.4,1.4,3-4.9,3.1-7.3c0-1.6,0.4-2.6,0.9-2.3c0.5,0.4,1,3.9,1.1,7.9c0,3.9,0.2,8.2,0.3,9.4
|
||||
c0.2,2.2,8.9,12.3,10.6,12.3c0.5,0,1.4,1.4,2.1,3c1.2,2.9,1.4,3,3,1.5c2.9-2.7,3.3,0,0.5,4.1c-2.5,3.7-3.1,6.4-1.8,7.8
|
||||
c0.4,0.4,1.1-0.5,1.5-1.9C111.6,262,112.7,259.9,113.6,258.9z M206,239.9c0-0.4,0.3-1.6,0.6-2.6c0.6-1.6,0.5-1.5-0.9,0.2
|
||||
c-2.2,2.8-3,1.4-1.2-2.1c1.4-2.7,1.3-2.9-0.5-3.6c-1.4-0.5-2-1.7-2-3.7c0-5.2-1.8-4.3-2.5,1.1c-0.4,2.9-1.3,6.4-2,7.8
|
||||
c-1,2-1.4,7.7-0.6,9.8C197.1,247.4,206,240.7,206,239.9z M147.5,228.5c0.5-3,0.4-3.7-0.5-2.9c-0.6,0.6-1.3,2.8-1.4,4.8
|
||||
C145.2,235.1,146.5,233.8,147.5,228.5z M218.9,194.7c-0.6-1.3-1.9-2.9-3-3.5c-1.8-1.1-1.7-0.9,0.3,2.3
|
||||
C218.8,197.4,220.5,198.2,218.9,194.7z M89,137.2c0-4.2-0.1-4.4-1.5-2.6c-1.5,1.9-2,6.6-0.9,7.7C88,143.7,89,141.6,89,137.2z
|
||||
M240.9,129.3c-0.2-2.1,0.1-5,0.5-6.5c1.3-4.6-1.1-3.3-2.7,1.5c-0.9,2.7-1.1,5.1-0.6,6.5C239.4,134.3,241.1,133.4,240.9,129.3z
|
||||
M230,125.4c0-0.8,0.7-1.4,1.5-1.4s1.5,0.5,1.5,1c0,2.3,1.9,0.7,3-2.5c0.6-1.9,2-4,3-4.5c1.8-0.9,1.8-1.1,0-4.7
|
||||
c-2.3-4.6-7.6-11-8.4-10.2c-0.4,0.3,0.2,1.7,1.2,3c2.3,3.1,4.5,10,4,12.5c-0.4,1.5-0.8,1.1-2.2-1.9c-2.1-4.8-3.5-4-2.9,1.7
|
||||
c0.5,3.7,0.2,4.6-1.5,5.5c-1.3,0.7-1.9,1.7-1.6,2.6C228.3,128.3,230,127.5,230,125.4z M87.6,111.8c0.9-2.9,2-5.7,2.4-6.3
|
||||
c1.2-1.7,3.9-10.5,3.2-10.5c-4.8,0.1-6.4,2.8-7.6,12.2c-0.3,2.7-0.8,5.9-1.2,7.3C83.2,119.3,85.8,117,87.6,111.8z M231.2,91.3
|
||||
c-1.6-3.2-3.8-7.6-4.8-9.7c-1.7-3.5-1.9-3.7-2.2-1.7c-0.7,4.7,0.9,9.1,5,13.6c2.3,2.5,4.3,4.3,4.5,4.1
|
||||
C234,97.4,232.8,94.5,231.2,91.3z"/>
|
||||
<path class="st1" d="M173,271.1c0-4.4-1.6-7.7-5.5-11.6c-5.2-5.3-4.8-6.8,1.8-6.1c11.4,1.4,12.5,1.8,15.3,4.7
|
||||
c3.2,3.3,2.2,4-1.3,0.7c-3.1-2.9-4.1-1.6-1.4,1.8c1.1,1.5,2.1,3.4,2.1,4.3c-0.1,1.9-2.3,5.1-3.7,5.1c-0.5,0-1.8,0.9-2.8,2
|
||||
C174.9,274.9,173,274.5,173,271.1z"/>
|
||||
<path class="st1" d="M158.1,250.9c-1.3-3.8-1.4-5.9-0.3-5.9c0.8,0,3.2,6.5,3.2,8.4C161,255.3,159,253.6,158.1,250.9z"/>
|
||||
<path class="st1" d="M126,250.6c0-0.8,0.5-1.8,1-2.1c1.3-0.8,1.3-6.2-0.1-7c-1.9-1.3-6.9-8.8-6.9-10.6c0-1.5,0.4-1.6,2.9-0.6
|
||||
c1.5,0.5,3.7,0.7,4.7,0.3c1.7-0.7,1.5-0.9-1.3-2.1c-3.6-1.5-4.6-4.1-1.3-3.2c3.3,0.8,3.3-1,0-3.3c-1.7-1.2-2.7-2.6-2.4-3.1
|
||||
c0.4-0.6,1.3-0.4,2.3,0.5c0.9,0.8,3.4,2.1,5.5,2.8c2.2,0.7,4.4,2.2,5,3.3c0.6,1,2.1,2.7,3.3,3.7c1.1,1,2.5,3.1,3.1,4.6
|
||||
c0.8,2.4,0.6,3.3-1.9,6.3s-2.8,3.2-2.9,1.2c0-3-1.1-5.4-2.1-4.7c-1.2,0.7-1.1,12.1,0.1,12.9c1.3,0.8,1.3,2.5-0.1,2.5
|
||||
c-0.5,0-1.9-2-3-4.5c-1.8-4.1-3.6-6.5-2.3-3c0.7,1.8-1.4,7.5-2.7,7.5C126.4,252,126,251.4,126,250.6z"/>
|
||||
<path class="st1" d="M117.1,244.8c0.2-2.8-2.8-12.9-4.8-16.1c-0.3-0.5-1.2,0.5-1.9,2.2c-1.9,4.5-3.8,4.1-2.8-0.6
|
||||
c1.3-6,0.8-11.9-1.5-17.2c-2.6-6.1-2.6-7-0.2-6.4c1.8,0.5,7.3,7.3,8.3,10.3c0.3,1,1,0.5,2.1-1.7c2.2-4.2,2.1-5.6-0.2-5
|
||||
c-1.3,0.3-3.1-1-6.2-4.5c-5.7-6.5-5.6-6.4-6-12.2c-0.3-3.4,0-5.1,0.9-5.4c0.9-0.3,1.1,0.3,0.7,2c-0.4,1.4,0.2,4.1,1.3,6.6
|
||||
c1.9,4.3,2,4.3,2.6,1.6l0.7-2.7l2.4,3.4c1.3,1.9,3.2,4.5,4.1,5.8l1.8,2.5l1.3-3c0.6-1.6,1.2-5.6,1.3-9c0-5.6-0.2-6.2-3.5-9.4
|
||||
c-1.9-1.9-3.5-4.4-3.5-5.6c0-1.2,1.7-3.9,3.8-6c5.4-5.7,8.8-10.5,9.6-13.7c0.4-1.6,1.2-2.7,1.9-2.4c1.6,0.5,1,5.7-0.9,7.8
|
||||
c-2.3,2.5-1.6,2.8,2.4,0.8c2.1-1.1,6.2-2.1,9.2-2.3c3-0.3,6.2-0.7,7-1c2.1-0.8,14.9,2.5,18.3,4.8c1.5,1,2.7,2.6,2.7,3.6
|
||||
s0.5,2,1.1,2.2c0.9,0.3,0.7,1.8-0.4,5.3c-1.2,3.7-1.5,7.4-1.2,14.5c0.5,8.4,0.3,9.3-0.9,7.7c-0.8-1.1-1.8-3.8-2.1-6
|
||||
c-1.1-6.1-2.9-9.2-7.2-11.7c-5.2-3.1-11.4-3.2-19.4-0.3c-5.4,1.9-7.1,3.2-10.2,7.2c-2,2.6-4,6.3-4.3,8.2s-0.9,4.3-1.4,5.4
|
||||
c-0.9,2.2-4.1,18.3-4.6,23c-0.1,1.7,0.3,5.7,1.1,9c1.3,6,1,11.5-0.6,11.5C117.3,248,117,246.5,117.1,244.8z"/>
|
||||
<path class="st1" d="M104.9,242.3c-0.6-1.6-1.8-3.7-2.8-4.8c-4.4-4.9-5.4-20.1-1.5-23c2.6-1.9,3.9-0.3,2.6,3.3
|
||||
c-0.6,1.7-0.9,4.1-0.8,5.4c0.7,6.1,1.9,11.5,3.1,13.8c1.9,3.9,2.7,8,1.5,8C106.4,245,105.5,243.8,104.9,242.3z"/>
|
||||
<path class="st1" d="M139.2,224.8c-0.5-0.7-1.1-2.2-1.3-3.3c-0.2-1.1-1.9-2.6-3.7-3.4c-1.7-0.8-3.2-1.8-3.2-2.3
|
||||
c0-1.2,4.4-1,5.8,0.4c0.6,0.6,1.4,0.9,1.8,0.5c1.2-1.2-4.9-7.8-7.8-8.4c-1.5-0.3-2.8-1.2-2.8-2c0-2.2,6.8-0.5,10.7,2.6
|
||||
c3.2,2.5,3.3,2.9,3.3,9.9S141.3,227.3,139.2,224.8z"/>
|
||||
<path class="st1" d="M143,213.8c0-3.9,7.3-9,11.3-8c3.2,0.8,1.9,3.2-1.7,3.2c-2.5,0-4.3,0.8-6.5,3.1
|
||||
C144.3,213.8,143,214.6,143,213.8z"/>
|
||||
<path class="st1" d="M95.7,206.9c-1.2-1.4-1.6-2.9-1.2-4.7c0.7-3.3,4.1-7.9,5.1-7c0.8,0.9-0.5,13.8-1.5,13.8
|
||||
C97.8,209,96.6,208.1,95.7,206.9z"/>
|
||||
<path class="st1" d="M113.6,197.5c-2-3.8-2.6-6.2-2.2-8c0.8-3.1,2.5-3.3,1.9-0.2c-0.3,1.3,0.6,3.6,2.1,5.6c2.4,3.3,3.5,8.1,1.9,8.1
|
||||
C116.8,203,115.2,200.5,113.6,197.5z"/>
|
||||
<path class="st1" d="M147.5,198c1-1.1,2.8-2,3.9-2c2,0,2,0.1-0.4,2C147.6,200.7,145.1,200.7,147.5,198z"/>
|
||||
<path class="st1" d="M170.4,195.5c0.4-1.6,1.7-4.2,2.8-5.7c1.9-2.8,2.1-2.8,3.9-1.2c1,0.9,1.9,1.8,1.9,1.9c0,0.2-2.1,2-4.7,4.1
|
||||
l-4.6,3.8L170.4,195.5z"/>
|
||||
<path class="st1" d="M192.6,186.8c-1-3.8-0.7-5.8,0.9-5.8c1.1,0,1.5,1.1,1.5,4C195,189.3,193.6,190.4,192.6,186.8z"/>
|
||||
<path class="st1" d="M170.4,185.1c0.7-4,1.1-4.5,2.5-3.6c1.7,1,1.3,3-1.1,5.1l-2.1,1.9L170.4,185.1z"/>
|
||||
<path class="st1" d="M104,178.3c0.2-3.9,7.4-20.3,9-20.3c0.5,0,2.8-2.7,5-6c2.3-3.3,4.5-5.8,5-5.5c1.2,0.8,4-0.5,4-1.9
|
||||
c0-0.6,1.2-2.6,2.8-4.4c3.4-4,9.2-4.9,13.7-2.2c1.7,1,4.5,2.1,6.2,2.5c1.8,0.3,4.7,2,6.5,3.7c3.1,2.9,3.2,3.1,1.3,4.4
|
||||
c-1,0.8-2.9,1.4-4.2,1.4s-5,1.1-8.3,2.5c-6.5,2.7-8,3-8,1.5c0-0.5,0.6-1,1.4-1c0.8,0,1.8-0.5,2.2-1.2c0.5-0.7,0.1-0.9-1.3-0.6
|
||||
c-1,0.3-4.6,0.2-7.8-0.3c-5.5-0.7-5.9-0.6-8.6,2.1c-1.6,1.6-2.9,3.2-2.9,3.5c0,0.4-1.6,2.9-3.5,5.5s-3.5,5.4-3.5,6.2
|
||||
c0,2.3-5.8,10.8-7.5,10.8C104.7,179,104,178.7,104,178.3z"/>
|
||||
<path class="st1" d="M211.2,177.8c-0.5-0.7-1.7-2.8-2.6-4.6c-1.4-2.7-1.5-3.6-0.5-4.9c1.1-1.2,1.7-0.7,4,3.9
|
||||
c1.6,2.9,2.8,5.6,2.9,6.1C215,179.5,212.3,179.1,211.2,177.8z"/>
|
||||
<path class="st1" d="M89.5,174.9c-0.9-1.4-0.5-1.7,3-2.1c2.1-0.2,3,0.2,3.3,1.5c0.3,1.3-0.3,1.7-2.7,1.7
|
||||
C91.5,176,89.8,175.5,89.5,174.9z"/>
|
||||
<path class="st1" d="M203.2,171.8c-0.7-0.7-1.2-2.1-1.2-3.2c0-2.5,4.7-8.6,6.6-8.6c1.9,0,1.8,0.3-1.1,4.6c-1.4,2.1-2.3,4.5-2,5.5
|
||||
C206.2,172.3,204.7,173.3,203.2,171.8z"/>
|
||||
<path class="st1" d="M179.5,164.3c-1.5-1.6-3.9-4.4-5.4-6.3c-1.4-1.9-3.6-4.3-4.9-5.3c-2.1-1.8-8.2-10-8.2-11.1
|
||||
c0-1.8,3.7-0.1,6.9,3.2c2,2,5.3,5.1,7.3,6.9c4.4,3.7,8.8,10.5,8.8,13.3C184,167.7,182.8,167.5,179.5,164.3z"/>
|
||||
<path class="st1" d="M89.8,163.5c-0.8-0.9,2.8-14.9,3.9-15.2c2-0.7,2.3,1.5,0.9,5.9c-0.8,2.4-1.6,5.4-1.8,6.7
|
||||
C92.5,163.3,90.9,164.6,89.8,163.5z"/>
|
||||
<path class="st1" d="M116.5,133c-0.3-0.5,0.4-1.2,1.6-1.5c2.6-0.9,1.8-1.7-2.1-2.1c-5.8-0.7-6.3-2.4-2.9-8.8c1.1-2.1,1.8-4,1.6-4.2
|
||||
c-0.8-0.8-5.1,4.8-6.3,8.2c-1.1,3.3-1,3.6,0.9,4.4c2.6,1.1,2.4,1.2-3.1,1.5c-3.6,0.3-4.2,0.1-3.8-1.3c0.2-1,0.7-3.1,1.1-4.9
|
||||
c0.6-3.1,6.1-9,11.8-12.8c1.5-0.9,2.7-2.2,2.7-2.7c0-1.3-7.9,0-10.7,1.8c-3,1.9-3.8,0.2-1-2.4c2.6-2.4,9-4.3,17.2-4.9
|
||||
c7.4-0.5,8.5-0.7,10.8-1.8c1.2-0.5,3.1-0.2,5.3,0.9c4.3,2,7.8,2.1,9.4,0.1c0.7-0.8,2-1.5,3-1.5c0.9,0,3-1,4.6-2.2
|
||||
c3.9-3.1,16.8-4,18.8-1.3c1,1.4,2.3,1.7,5.8,1.3c3.6-0.4,4.7-0.2,5.6,1.3c0.7,1,1.2,2.1,1.2,2.4c0,0.8-11.5-0.1-12.9-0.9
|
||||
c-0.6-0.4-2.2,0.1-3.6,1.2l-2.5,2l6.6,1.2c3.8,0.7,7.7,2.2,9.2,3.5c3.4,2.7,6,3.7,6.7,2.5s4.5-1.3,4.5-0.2c0,0.5-1.1,1.9-2.5,3.2
|
||||
c-1.4,1.3-2.5,3.4-2.5,4.6c0,3.2-3.4,4-5.9,1.5c-1.9-1.9-2.2-1.9-6.6-0.5c-5.2,1.8-5.9,3.4-1.5,3.4c1.7,0,3,0.4,3,1
|
||||
c0,1.4-7.8,3.2-11.1,2.5c-3.7-0.8-12.5-8.3-14.9-12.6c-1.9-3.7-1.9-3.7-12.4-2.3l-5.8,0.7l0.5,3.9c0.4,3.3,0,4.5-2.6,8
|
||||
c-1.8,2.3-4.3,4.9-5.7,5.9C125.3,133,117.3,134.3,116.5,133z M187.3,114.3c-0.9-0.7-2.2-1.3-2.9-1.3c-0.6,0-1.7-0.6-2.3-1.4
|
||||
c-1.1-1.3-5-2.6-9.8-3.2c-1.7-0.2-2.3,0.2-2.3,1.7c0,1.4,0.7,1.9,2.9,1.9c1.5,0,5.5,1.3,8.7,3c4.3,2.1,6,2.6,6.6,1.7
|
||||
C188.6,116,188.3,115,187.3,114.3z"/>
|
||||
<path class="st1" d="M209.5,116.4c-2-4.4-4.7-10.2-6.1-12.9c-3.4-7-4.4-10.9-5.1-19.2c-0.7-9.7,0.2-12.1,2.7-6.8
|
||||
c1.1,2.2,1.9,4.5,2,5c0.1,3.7,10.4,17.5,12.9,17.5c1.7,0,1.4-0.4-2.9-5.1c-2.2-2.4-4.6-5.5-5.3-6.9c-1.5-3.1-0.6-11.8,1.3-13
|
||||
c2.1-1.3,2.3-0.6,0.9,3.8c-1,3.6-0.9,4.5,1.1,8.6c1.2,2.5,2.5,4.6,2.9,4.6s2.3,1.8,4.1,4.1c2.3,2.9,2.9,4.3,2.1,4.9
|
||||
c-0.9,0.5-0.7,1.7,0.8,4.6c2.4,4.9,2.9,6.8,1.6,7.4c-0.6,0.3-1.7-1-2.6-2.8c-1.9-3.7-7.3-9.2-9-9.2c-0.7,0-0.5,0.9,0.5,2.3
|
||||
c0.9,1.2,2.4,3.3,3.3,4.5c2,2.8,1.9,11.5-0.2,14.5C213.3,124.1,212.9,123.6,209.5,116.4z"/>
|
||||
<path class="st1" d="M99.3,100.3c1-5.2,2.6-8.3,4.3-8.3s1.7,0-0.8,7.3C101.3,103.7,98.4,104.5,99.3,100.3z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 15 KiB |
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "zokrates_parser"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
authors = ["JacobEberhardt <jacob.eberhardt@tu-berlin.de>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
|
||||
file = { SOI ~ NEWLINE* ~ pragma? ~ NEWLINE* ~ import_directive* ~ NEWLINE* ~ ty_struct_definition* ~ NEWLINE* ~ const_definition* ~ NEWLINE* ~ function_definition* ~ EOI }
|
||||
file = { SOI ~ NEWLINE* ~ pragma? ~ NEWLINE* ~ symbol_declaration* ~ EOI }
|
||||
|
||||
pragma = { "#pragma" ~ "curve" ~ curve }
|
||||
curve = @{ (ASCII_ALPHANUMERIC | "_") * }
|
||||
|
||||
symbol_declaration = { (import_directive | ty_struct_definition | const_definition | function_definition) ~ NEWLINE* }
|
||||
|
||||
import_directive = { main_import_directive | from_import_directive }
|
||||
from_import_directive = { "from" ~ "\"" ~ import_source ~ "\"" ~ "import" ~ import_symbol_list ~ NEWLINE* }
|
||||
main_import_directive = { "import" ~ "\"" ~ import_source ~ "\"" ~ ("as" ~ identifier)? ~ NEWLINE+ }
|
||||
|
@ -155,7 +157,7 @@ op_right_shift = @{">>"}
|
|||
op_binary = _ { op_or | op_and | op_bit_xor | op_bit_and | op_bit_or | op_left_shift | op_right_shift | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div | op_rem }
|
||||
op_unary = { op_pos | op_neg | op_not }
|
||||
|
||||
WHITESPACE = _{ " " | "\t" | "\\" ~ NEWLINE}
|
||||
WHITESPACE = _{ " " | "\t" | "\\" ~ COMMENT? ~ NEWLINE}
|
||||
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
|
||||
|
||||
// the ordering of reserved keywords matters: if "as" is before "assert", then "assert" gets parsed as (as)(sert) and incorrectly
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue