resolve merge conflicts

This commit is contained in:
gluax 2021-04-14 12:51:20 -04:00
commit eaa07934ed
691 changed files with 30525 additions and 376 deletions

View File

@ -1 +1 @@
v1.2.3
v1.3.0

70
Cargo.lock generated
View File

@ -138,11 +138,10 @@ checksum = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c"
[[package]]
name = "bincode"
version = "1.3.2"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"byteorder",
"serde",
]
@ -640,6 +639,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "dtoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]]
name = "either"
version = "1.6.1"
@ -1241,7 +1246,7 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "leo-abnf"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"abnf",
"anyhow",
@ -1249,7 +1254,7 @@ dependencies = [
[[package]]
name = "leo-asg"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"criterion",
"indexmap",
@ -1265,14 +1270,14 @@ dependencies = [
[[package]]
name = "leo-asg-passes"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"leo-asg",
]
[[package]]
name = "leo-ast"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"anyhow",
"criterion",
@ -1287,7 +1292,7 @@ dependencies = [
[[package]]
name = "leo-compiler"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"bincode",
"hex",
@ -1322,7 +1327,7 @@ dependencies = [
[[package]]
name = "leo-imports"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"indexmap",
"leo-asg",
@ -1334,7 +1339,7 @@ dependencies = [
[[package]]
name = "leo-input"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"from-pest",
"pest",
@ -1346,8 +1351,9 @@ dependencies = [
[[package]]
name = "leo-lang"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"ansi_term 0.12.1",
"anyhow",
"clap",
"colored",
@ -1385,11 +1391,11 @@ dependencies = [
[[package]]
name = "leo-linter"
version = "1.2.3"
version = "1.3.0"
[[package]]
name = "leo-package"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"lazy_static",
"serde",
@ -1402,7 +1408,7 @@ dependencies = [
[[package]]
name = "leo-parser"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"criterion",
"indexmap",
@ -1410,6 +1416,7 @@ dependencies = [
"leo-ast",
"serde",
"serde_json",
"serde_yaml",
"tendril",
"thiserror",
"tracing",
@ -1417,7 +1424,7 @@ dependencies = [
[[package]]
name = "leo-state"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"indexmap",
"leo-ast",
@ -1435,7 +1442,7 @@ dependencies = [
[[package]]
name = "leo-synthesizer"
version = "1.2.3"
version = "1.3.0"
dependencies = [
"num-bigint",
"serde",
@ -1499,6 +1506,12 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lock_api"
version = "0.4.2"
@ -2253,9 +2266,9 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.11.2"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf12057f289428dbf5c591c74bf10392e4a8003f993405a902f20117019022d4"
checksum = "2296f2fac53979e8ccbc4a1136b25dcefd37be9ed7e4a1f6b05a6029c84ff124"
dependencies = [
"base64",
"bytes",
@ -2509,6 +2522,18 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.8.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
dependencies = [
"dtoa",
"linked-hash-map",
"serde",
"yaml-rust",
]
[[package]]
name = "sha-1"
version = "0.8.2"
@ -3422,6 +3447,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "zip"
version = "0.5.10"

View File

@ -1,6 +1,6 @@
[package]
name = "leo-lang"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "The Leo programming language"
homepage = "https://aleo.org"
@ -27,6 +27,7 @@ path = "leo/main.rs"
[workspace]
members = [
"asg",
"asg-passes",
"ast",
"compiler",
"grammar",
@ -36,41 +37,39 @@ members = [
"package",
"parser",
"state",
"synthesizer",
"asg-passes",
"synthesizer"
]
[dependencies.leo-ast]
path = "./ast"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-compiler]
path = "./compiler"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-imports]
path = "./imports"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-input]
path = "./input"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-package]
path = "./package"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-state]
path = "./state"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-synthesizer]
path = "./synthesizer"
version = "1.2.3"
version = "1.3.0"
[dependencies.snarkvm-algorithms]
version = "0.2.2"
#default-features = false
[dependencies.snarkvm-curves]
version = "0.2.2"
@ -121,7 +120,7 @@ version = "0.8"
version = "0.6.2"
[dependencies.reqwest]
version = "0.11.2"
version = "0.11.3"
features = [ "blocking", "json", "multipart" ]
[dependencies.self_update]
@ -151,14 +150,17 @@ features = [ "fmt" ]
[dependencies.zip]
version = "0.5"
# add ansi support for Windows builds
[target.'cfg(windows)'.dependencies.ansi_term]
version = "0.12.1"
[dev-dependencies.rusty-hook]
version = "0.11.2"
[features]
default = []
default = [ ]
ci_skip = [ "leo-compiler/ci_skip" ]
# This feature flag is used to disable `target-cpu=native` in `.cargo/config`.
noconfig = []
noconfig = [ ]
[profile.release]
opt-level = 3

View File

@ -1,6 +1,6 @@
[package]
name = "leo-asg-passes"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "The Leo programming language"
homepage = "https://aleo.org"
@ -13,7 +13,7 @@ keywords = [
"zero-knowledge"
]
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "leo", "README.md", "LICENSE.md" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
@ -22,4 +22,4 @@ path = "src/lib.rs"
[dependencies.leo-asg]
path = "../asg"
version = "1.2.3"
version = "1.3.0"

View File

@ -1,6 +1,6 @@
[package]
name = "leo-asg"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "ASG of the Leo programming language"
homepage = "https://aleo.org"
@ -30,11 +30,11 @@ version = "1.6"
version = "1.0"
[dependencies.leo-ast]
version = "1.2.3"
version = "1.3.0"
path = "../ast"
[dependencies.leo-parser]
version = "1.2.3"
version = "1.3.0"
path = "../parser"
[dependencies.num-bigint]

View File

@ -1,6 +1,6 @@
[package]
name = "leo-ast"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Core AST of the Leo programming language"
homepage = "https://aleo.org"
@ -19,7 +19,7 @@ edition = "2018"
[dependencies.leo-input]
path = "../input"
version = "1.2.3"
version = "1.3.0"
[dependencies.indexmap]
version = "1.6.2"
@ -30,7 +30,7 @@ version = "2.0"
[dependencies.serde]
version = "1.0"
features = ["derive", "rc"]
features = [ "derive", "rc" ]
[dependencies.serde_json]
version = "1.0"

View File

@ -75,7 +75,7 @@ fn underline(mut start: usize, mut end: usize) -> String {
impl fmt::Display for FormattedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let underline = underline(self.col_start - 1, self.col_stop - 1);
let underline = underline(self.col_start, self.col_stop);
write!(
f,
@ -99,7 +99,7 @@ impl fmt::Display for FormattedError {
write!(
f,
"{indent } | {underline}\n\
"{indent } |{underline}\n\
{indent } |\n\
{indent } = {message}",
indent = INDENT,
@ -121,8 +121,8 @@ fn test_error() {
path: std::sync::Arc::new("file.leo".to_string()),
line_start: 2,
line_stop: 2,
col_start: 8,
col_stop: 9,
col_start: 9,
col_stop: 10,
content: "let a = x;".into(),
message: "undefined value `x`".to_string(),
};
@ -130,7 +130,7 @@ fn test_error() {
assert_eq!(
err.to_string(),
vec![
" --> file.leo: 2:8",
" --> file.leo: 2:9",
" |",
" 2 | let a = x;",
" | ^",

View File

@ -1,6 +1,6 @@
[package]
name = "leo-compiler"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Compiler of the Leo programming language"
homepage = "https://aleo.org"
@ -19,35 +19,35 @@ edition = "2018"
[dependencies.leo-ast]
path = "../ast"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-imports]
path = "../imports"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-input]
path = "../input"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-package]
path = "../package"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-state]
path = "../state"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-asg]
path = "../asg"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-parser]
path = "../parser"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-asg-passes]
path = "../asg-passes"
version = "1.2.3"
version = "1.3.0"
[dependencies.tendril]
version = "0.4"

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,11 @@
circuit Foo {
f: u8,
y: (u8, u8),
function z (mut self) -> u16 {
self.y.0 += 1u8;
return 1u16
}
}
function main() {
let x = 10u32;
@ -14,11 +20,18 @@ function main() {
z.1 += 3u8;
console.assert(z.1 == 5u8);
let foo = Foo { f: 6u8 };
let foo = Foo { f: 6u8, y: (1u8, 1u8) };
foo.f += 2u8;
console.assert(foo.f == 8u8);
let complex = 2u8;
complex += 22u8 - 2u8+ 1u8;
console.assert(complex == 23u8);
let a = [[0u8; 1]; 4];
a[2][0] += 1u8;
console.assert(a[2][0] == 1u8);
let b = [0u8; (4, 1)];
b[2][0] += 1u8;
console.assert(a[2][0] == 1u8);
}

View File

@ -1,17 +1,21 @@
[package]
name = "leo-abnf"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "ABNF to Markdown converter"
edition = "2018"
description = "ABNF to Markdown converter for the Leo programming language"
homepage = "https://aleo.org"
repository = "https://github.com/AleoHQ/leo"
keywords = [
"aleo",
"cryptography",
"leo",
"programming-language",
"zero-knowledge",
"leo-abnf"
"zero-knowledge"
]
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
[dependencies]
abnf = "0.10.2"

View File

@ -475,7 +475,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs.
whitespace = space / horizontal-tab / newline
```
Go to: _[space](#user-content-space), [horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline)_;
Go to: _[horizontal-tab](#user-content-horizontal-tab), [space](#user-content-space), [newline](#user-content-newline)_;
There are two kinds of comments in Leo, as in other languages.
@ -510,7 +510,7 @@ rest-of-block-comment = "*" rest-of-block-comment-after-star
/ not-star rest-of-block-comment
```
Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star](#user-content-not-star), [rest-of-block-comment](#user-content-rest-of-block-comment)_;
Go to: _[not-star](#user-content-not-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_;
<a name="rest-of-block-comment-after-star"></a>
@ -520,7 +520,7 @@ rest-of-block-comment-after-star = "/"
/ not-star-or-slash rest-of-block-comment
```
Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [rest-of-block-comment](#user-content-rest-of-block-comment), [not-star-or-slash](#user-content-not-star-or-slash)_;
Go to: _[rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment](#user-content-rest-of-block-comment)_;
<a name="end-of-line-comment"></a>
@ -595,7 +595,7 @@ lowercase-letter = %x61-7A ; a-z
letter = uppercase-letter / lowercase-letter
```
Go to: _[lowercase-letter](#user-content-lowercase-letter), [uppercase-letter](#user-content-uppercase-letter)_;
Go to: _[uppercase-letter](#user-content-uppercase-letter), [lowercase-letter](#user-content-lowercase-letter)_;
An identifier is a non-empty sequence of letters, digits, and underscores,
@ -807,7 +807,7 @@ atomic-literal = untyped-literal
/ address-literal
```
Go to: _[signed-literal](#user-content-signed-literal), [field-literal](#user-content-field-literal), [boolean-literal](#user-content-boolean-literal), [untyped-literal](#user-content-untyped-literal), [unsigned-literal](#user-content-unsigned-literal), [product-group-literal](#user-content-product-group-literal), [address-literal](#user-content-address-literal)_;
Go to: _[boolean-literal](#user-content-boolean-literal), [address-literal](#user-content-address-literal), [untyped-literal](#user-content-untyped-literal), [unsigned-literal](#user-content-unsigned-literal), [field-literal](#user-content-field-literal), [product-group-literal](#user-content-product-group-literal), [signed-literal](#user-content-signed-literal)_;
After defining the (mostly) alphanumeric tokens above,
@ -880,7 +880,7 @@ token = keyword
/ symbol
```
Go to: _[atomic-literal](#user-content-atomic-literal), [package-name](#user-content-package-name), [formatted-string](#user-content-formatted-string), [annotation-name](#user-content-annotation-name), [symbol](#user-content-symbol), [identifier](#user-content-identifier), [keyword](#user-content-keyword)_;
Go to: _[identifier](#user-content-identifier), [keyword](#user-content-keyword), [package-name](#user-content-package-name), [formatted-string](#user-content-formatted-string), [atomic-literal](#user-content-atomic-literal), [annotation-name](#user-content-annotation-name), [symbol](#user-content-symbol)_;
@ -916,7 +916,7 @@ signed-type = %s"i8" / %s"i16" / %s"i32" / %s"i64" / %s"i128"
integer-type = unsigned-type / signed-type
```
Go to: _[signed-type](#user-content-signed-type), [unsigned-type](#user-content-unsigned-type)_;
Go to: _[unsigned-type](#user-content-unsigned-type), [signed-type](#user-content-signed-type)_;
The integer types, along with the field and group types,
@ -937,7 +937,7 @@ group-type = %s"group"
arithmetic-type = integer-type / field-type / group-type
```
Go to: _[integer-type](#user-content-integer-type), [field-type](#user-content-field-type), [group-type](#user-content-group-type)_;
Go to: _[integer-type](#user-content-integer-type), [group-type](#user-content-group-type), [field-type](#user-content-field-type)_;
The arithmetic types, along with the boolean and address types,
@ -958,7 +958,7 @@ address-type = %s"address"
scalar-type = boolean-type / arithmetic-type / address-type
```
Go to: _[boolean-type](#user-content-boolean-type), [address-type](#user-content-address-type), [arithmetic-type](#user-content-arithmetic-type)_;
Go to: _[arithmetic-type](#user-content-arithmetic-type), [address-type](#user-content-address-type), [boolean-type](#user-content-boolean-type)_;
Circuit types are denoted by identifiers and the keyword 'Self'.
@ -998,7 +998,7 @@ or a tuple of one or more dimensions.
array-type = "[" type ";" array-dimensions "]"
```
Go to: _[type](#user-content-type), [array-dimensions](#user-content-array-dimensions)_;
Go to: _[array-dimensions](#user-content-array-dimensions), [type](#user-content-type)_;
<a name="array-dimensions"></a>
@ -1019,7 +1019,7 @@ i.e. types whose values contain (sub-)values
aggregate-type = tuple-type / array-type / circuit-type
```
Go to: _[array-type](#user-content-array-type), [tuple-type](#user-content-tuple-type), [circuit-type](#user-content-circuit-type)_;
Go to: _[array-type](#user-content-array-type), [circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type)_;
Scalar and aggregate types form all the types.
@ -1107,7 +1107,7 @@ primary-expression = identifier
/ circuit-expression
```
Go to: _[identifier](#user-content-identifier), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression), [literal](#user-content-literal), [tuple-expression](#user-content-tuple-expression), [expression](#user-content-expression)_;
Go to: _[tuple-expression](#user-content-tuple-expression), [identifier](#user-content-identifier), [expression](#user-content-expression), [literal](#user-content-literal), [array-expression](#user-content-array-expression), [circuit-expression](#user-content-circuit-expression)_;
Tuple expressions construct tuples.
@ -1168,7 +1168,7 @@ Go to: _[expression](#user-content-expression), [array-dimensions](#user-content
array-construction = array-inline-construction / array-repeat-construction
```
Go to: _[array-inline-construction](#user-content-array-inline-construction), [array-repeat-construction](#user-content-array-repeat-construction)_;
Go to: _[array-repeat-construction](#user-content-array-repeat-construction), [array-inline-construction](#user-content-array-inline-construction)_;
<a name="array-expression"></a>
@ -1254,7 +1254,7 @@ postfix-expression = primary-expression
/ postfix-expression "[" [expression] ".." [expression] "]"
```
Go to: _[natural](#user-content-natural), [identifier](#user-content-identifier), [circuit-type](#user-content-circuit-type), [postfix-expression](#user-content-postfix-expression), [primary-expression](#user-content-primary-expression), [function-arguments](#user-content-function-arguments), [expression](#user-content-expression)_;
Go to: _[function-arguments](#user-content-function-arguments), [expression](#user-content-expression), [natural](#user-content-natural), [circuit-type](#user-content-circuit-type), [primary-expression](#user-content-primary-expression), [identifier](#user-content-identifier), [postfix-expression](#user-content-postfix-expression)_;
Unary operators have the highest operator precedence.
@ -1268,7 +1268,7 @@ unary-expression = postfix-expression
/ "-" unary-expression
```
Go to: _[unary-expression](#user-content-unary-expression), [postfix-expression](#user-content-postfix-expression)_;
Go to: _[postfix-expression](#user-content-postfix-expression), [unary-expression](#user-content-unary-expression)_;
Next in the operator precedence is casting.
@ -1290,10 +1290,10 @@ i.e. 'a ** b ** c' must be parsed as '(a ** b) ** c'.
<a name="exponential-expression"></a>
```abnf
exponential-expression = cast-expression
/ exponential-expression "**" cast-expression
/ cast-expression "**" exponential-expression
```
Go to: _[cast-expression](#user-content-cast-expression), [exponential-expression](#user-content-exponential-expression)_;
Go to: _[exponential-expression](#user-content-exponential-expression), [cast-expression](#user-content-cast-expression)_;
Next in precedence come multiplication and division, both left-associative.
@ -1317,7 +1317,7 @@ additive-expression = multiplicative-expression
/ additive-expression "-" multiplicative-expression
```
Go to: _[multiplicative-expression](#user-content-multiplicative-expression), [additive-expression](#user-content-additive-expression)_;
Go to: _[additive-expression](#user-content-additive-expression), [multiplicative-expression](#user-content-multiplicative-expression)_;
Next in the precedence order are ordering relations.
@ -1345,7 +1345,7 @@ equality-expression = ordering-expression
/ equality-expression "!=" ordering-expression
```
Go to: _[ordering-expression](#user-content-ordering-expression), [equality-expression](#user-content-equality-expression)_;
Go to: _[equality-expression](#user-content-equality-expression), [ordering-expression](#user-content-ordering-expression)_;
Next come conjunctive expressions, left-associative.
@ -1356,7 +1356,7 @@ conjunctive-expression = equality-expression
/ conjunctive-expression "&&" equality-expression
```
Go to: _[equality-expression](#user-content-equality-expression), [conjunctive-expression](#user-content-conjunctive-expression)_;
Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [equality-expression](#user-content-equality-expression)_;
Next come disjunctive expressions, left-associative.
@ -1367,7 +1367,7 @@ disjunctive-expression = conjunctive-expression
/ disjunctive-expression "||" conjunctive-expression
```
Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conjunctive-expression](#user-content-conjunctive-expression)_;
Go to: _[conjunctive-expression](#user-content-conjunctive-expression), [disjunctive-expression](#user-content-disjunctive-expression)_;
Finally we have conditional expressions.
@ -1380,7 +1380,7 @@ conditional-expression = disjunctive-expression
":" conditional-expression
```
Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [conditional-expression](#user-content-conditional-expression), [expression](#user-content-expression)_;
Go to: _[conditional-expression](#user-content-conditional-expression), [disjunctive-expression](#user-content-disjunctive-expression), [expression](#user-content-expression)_;
Those above are all the expressions.
@ -1412,7 +1412,7 @@ statement = expression-statement
/ block
```
Go to: _[variable-definition-statement](#user-content-variable-definition-statement), [return-statement](#user-content-return-statement), [loop-statement](#user-content-loop-statement), [block](#user-content-block), [console-statement](#user-content-console-statement), [conditional-statement](#user-content-conditional-statement), [expression-statement](#user-content-expression-statement), [assignment-statement](#user-content-assignment-statement)_;
Go to: _[expression-statement](#user-content-expression-statement), [conditional-statement](#user-content-conditional-statement), [loop-statement](#user-content-loop-statement), [console-statement](#user-content-console-statement), [variable-definition-statement](#user-content-variable-definition-statement), [assignment-statement](#user-content-assignment-statement), [block](#user-content-block), [return-statement](#user-content-return-statement)_;
<a name="block"></a>
@ -1455,7 +1455,7 @@ variable-definition-statement = ( %s"let" / %s"const" )
[ ":" type ] "=" expression ";"
```
Go to: _[type](#user-content-type), [expression](#user-content-expression), [identifier-or-identifiers](#user-content-identifier-or-identifiers)_;
Go to: _[expression](#user-content-expression), [identifier-or-identifiers](#user-content-identifier-or-identifiers), [type](#user-content-type)_;
<a name="identifier-or-identifiers"></a>
@ -1478,7 +1478,7 @@ Note that blocks are required in all branches, not merely statements.
branch = %s"if" expression block
```
Go to: _[block](#user-content-block), [expression](#user-content-expression)_;
Go to: _[expression](#user-content-expression), [block](#user-content-block)_;
<a name="conditional-statement"></a>
@ -1488,7 +1488,7 @@ conditional-statement = branch
/ branch %s"else" conditional-statement
```
Go to: _[conditional-statement](#user-content-conditional-statement), [block](#user-content-block), [branch](#user-content-branch)_;
Go to: _[branch](#user-content-branch), [conditional-statement](#user-content-conditional-statement), [block](#user-content-block)_;
A loop statement implicitly defines a loop variable
@ -1500,7 +1500,7 @@ The body is a block.
loop-statement = %s"for" identifier %s"in" expression ".." expression block
```
Go to: _[expression](#user-content-expression), [block](#user-content-block), [identifier](#user-content-identifier)_;
Go to: _[identifier](#user-content-identifier), [block](#user-content-block), [expression](#user-content-expression)_;
An assignment statement is straightforward.
@ -1517,7 +1517,7 @@ assignment-operator = "=" / "+=" / "-=" / "*=" / "/=" / "**="
assignment-statement = expression assignment-operator expression ";"
```
Go to: _[expression](#user-content-expression), [assignment-operator](#user-content-assignment-operator)_;
Go to: _[assignment-operator](#user-content-assignment-operator), [expression](#user-content-expression)_;
Console statements start with the 'console' keyword,
@ -1544,7 +1544,7 @@ console-call = assert-call
/ print-call
```
Go to: _[print-call](#user-content-print-call), [assert-call](#user-content-assert-call)_;
Go to: _[assert-call](#user-content-assert-call), [print-call](#user-content-print-call)_;
<a name="assert-call"></a>
@ -1586,7 +1586,7 @@ annotation = annotation-name
[ "(" identifier *( "," identifier ) ")" ]
```
Go to: _[annotation-name](#user-content-annotation-name), [identifier](#user-content-identifier)_;
Go to: _[identifier](#user-content-identifier), [annotation-name](#user-content-annotation-name)_;
A function declaration defines a function.
@ -1604,7 +1604,7 @@ function-declaration = *annotation %s"function" identifier
block
```
Go to: _[type](#user-content-type), [function-parameters](#user-content-function-parameters), [block](#user-content-block), [identifier](#user-content-identifier)_;
Go to: _[function-parameters](#user-content-function-parameters), [identifier](#user-content-identifier), [block](#user-content-block), [type](#user-content-type)_;
<a name="function-parameters"></a>
@ -1661,7 +1661,7 @@ Go to: _[member-variable-declaration](#user-content-member-variable-declaration)
member-variable-declaration = identifier ":" type
```
Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_;
Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_;
<a name="member-function-declaration"></a>
@ -1710,7 +1710,7 @@ package-path = "*"
/ "(" package-path *( "," package-path ) [","] ")"
```
Go to: _[package-path](#user-content-package-path), [identifier](#user-content-identifier), [package-name](#user-content-package-name)_;
Go to: _[package-name](#user-content-package-name), [identifier](#user-content-identifier), [package-path](#user-content-package-path)_;
Finally, we define a file as a sequence of zero or more declarations.
@ -1722,7 +1722,7 @@ declaration = import-declaration
/ circuit-declaration
```
Go to: _[import-declaration](#user-content-import-declaration), [circuit-declaration](#user-content-circuit-declaration), [function-declaration](#user-content-function-declaration)_;
Go to: _[circuit-declaration](#user-content-circuit-declaration), [import-declaration](#user-content-import-declaration), [function-declaration](#user-content-function-declaration)_;
<a name="file"></a>

View File

@ -813,7 +813,7 @@ cast-expression = unary-expression
; i.e. 'a ** b ** c' must be parsed as '(a ** b) ** c'.
exponential-expression = cast-expression
/ exponential-expression "**" cast-expression
/ cast-expression "**" exponential-expression
; Next in precedence come multiplication and division, both left-associative.

View File

@ -1,6 +1,6 @@
[package]
name = "leo-imports"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Import parser for Leo program package dependencies"
homepage = "https://aleo.org"
@ -19,15 +19,15 @@ edition = "2018"
[dependencies.leo-ast]
path = "../ast"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-asg]
path = "../asg"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-parser]
path = "../parser"
version = "1.2.3"
version = "1.3.0"
[dependencies.indexmap]
version = "1.6.2"

View File

@ -1,6 +1,6 @@
[package]
name = "leo-input"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Input parser of the Leo programming language"
homepage = "https://aleo.org"

View File

@ -202,6 +202,10 @@ where
/// Initialize logger with custom format and verbosity.
pub fn init_logger(_app_name: &'static str, verbosity: usize) {
// This line enables Windows 10 ANSI coloring API.
#[cfg(target_family = "windows")]
ansi_term::enable_ansi_support();
let subscriber = FmtSubscriber::builder()
// all spans/events with a level higher than TRACE (e.g, debug, info, warn, etc.)
// will be written to stdout.

View File

@ -2,7 +2,7 @@ dependencies = { }
[package]
name = "leo-linter"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Linter of the Leo programming language"
homepage = "https://aleo.org"

View File

@ -1,6 +1,6 @@
[package]
name = "leo-package"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Package parser of the Leo programming language"
homepage = "https://aleo.org"

View File

@ -106,7 +106,8 @@ impl ZipFile {
// Write file or directory
if path.is_file() {
tracing::info!("Adding file {:?} as {:?}", path, name);
zip.start_file(name.to_string_lossy(), options)?;
#[allow(deprecated)]
zip.start_file_from_path(name, options)?;
let mut f = File::open(path)?;
f.read_to_end(&mut buffer)?;
@ -116,7 +117,8 @@ impl ZipFile {
// Only if not root Avoids path spec / warning
// and mapname conversion failed error on unzip
tracing::info!("Adding directory {:?} as {:?}", path, name);
zip.add_directory(name.to_string_lossy(), options)?;
#[allow(deprecated)]
zip.add_directory_from_path(name, options)?;
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "leo-parser"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "AST generated by pest from the Leo grammar rules"
homepage = "https://aleo.org"
@ -24,7 +24,7 @@ harness = false
[dependencies.leo-ast]
path = "../ast"
version = "1.2.3"
version = "1.3.0"
[dependencies.lazy_static]
version = "1.3.0"
@ -42,15 +42,18 @@ version = "1.0"
[dependencies.tracing]
version = "0.1"
[dev-dependencies.criterion]
version = "0.3"
[dependencies.indexmap]
version = "1.6"
[dependencies.tendril]
version = "0.4"
[dev-dependencies.criterion]
version = "0.3"
[dev-dependencies.serde_yaml]
version = "0.8"
[features]
default = [ ]
ci_skip = [ ]

View File

@ -16,7 +16,7 @@
use leo_ast::{FormattedError, LeoError, Span};
use crate::{DeprecatedError, Token, TokenError};
use crate::{DeprecatedError, SyntaxResult, Token, TokenError};
#[derive(Debug, Error)]
pub enum SyntaxError {
@ -32,6 +32,17 @@ pub enum SyntaxError {
impl LeoError for SyntaxError {}
pub fn assert_no_whitespace(left_span: &Span, right_span: &Span, left: &str, right: &str) -> SyntaxResult<()> {
if left_span.col_stop != right_span.col_start {
let mut error_span = left_span + right_span;
error_span.col_start = left_span.col_stop - 1;
error_span.col_stop = right_span.col_start - 1;
return Err(SyntaxError::unexpected_whitespace(left, right, &error_span));
}
Ok(())
}
impl SyntaxError {
fn new_from_span(message: String, span: &Span) -> Self {
SyntaxError::Error(FormattedError::new_from_span(message, span))

View File

@ -14,9 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use std::unimplemented;
use std::{borrow::Cow, unimplemented};
use crate::{tokenizer::*, unexpected_whitespace, SyntaxError, SyntaxResult, Token, KEYWORD_TOKENS};
use crate::{assert_no_whitespace, tokenizer::*, SyntaxError, SyntaxResult, Token, KEYWORD_TOKENS};
use leo_ast::*;
use tendril::format_tendril;
@ -49,7 +49,11 @@ impl ParserContext {
.filter(|x| !matches!(x.token, Token::CommentLine(_) | Token::CommentBlock(_)))
.collect();
ParserContext {
end_span: tokens.last().map(|x| x.span.clone()).unwrap_or_default(),
end_span: tokens
.iter()
.find(|x| !x.span.content.trim().is_empty())
.map(|x| x.span.clone())
.unwrap_or_default(),
tokens,
fuzzy_struct_state: false,
}
@ -69,6 +73,14 @@ impl ParserContext {
self.tokens.last().ok_or_else(|| self.eof())
}
pub fn peek_token(&self) -> Cow<'_, Token> {
self.tokens
.last()
.map(|x| &x.token)
.map(Cow::Borrowed)
.unwrap_or_else(|| Cow::Owned(Token::Eof))
}
// pub fn peek_oneof(&self, token: &[Token]) -> SyntaxResult<&SpannedToken> {
// if let Some(spanned_token) = self.inner.last() {
// if token.iter().any(|x| x == &spanned_token.token) {
@ -140,15 +152,21 @@ impl ParserContext {
/// the next token is not a [`GroupCoordinate`].
///
fn peek_group_coordinate(&self, i: &mut usize) -> Option<GroupCoordinate> {
let token = self.tokens.get(*i)?;
if *i < 1 {
return None;
}
let token = self.tokens.get(*i - 1)?;
*i -= 1;
Some(match &token.token {
Token::Add => GroupCoordinate::SignHigh,
Token::Minus => match self.tokens.get(*i) {
Token::Minus if *i > 0 => match self.tokens.get(*i - 1) {
Some(SpannedToken {
token: Token::Int(value),
span,
}) => {
if *i < 1 {
return None;
}
*i -= 1;
GroupCoordinate::Number(format_tendril!("-{}", value), span.clone())
}
@ -164,32 +182,32 @@ impl ParserContext {
/// Removes the next two tokens if they are a pair of [`GroupCoordinate`] and returns them,
/// or [None] if the next token is not a [`GroupCoordinate`].
///
pub fn eat_group_partial(&mut self) -> SyntaxResult<Option<(GroupCoordinate, GroupCoordinate, Span)>> {
let mut i = self.tokens.len() - 1;
let start_span = match self.tokens.get(i) {
Some(span) => span.span.clone(),
None => return Ok(None),
};
let first = match self.peek_group_coordinate(&mut i) {
Some(coord) => coord,
None => return Ok(None),
};
match self.tokens.get(i) {
pub fn eat_group_partial(&mut self) -> Option<SyntaxResult<(GroupCoordinate, GroupCoordinate, Span)>> {
let mut i = self.tokens.len();
if i < 1 {
return None;
}
let start_span = self.tokens.get(i - 1)?.span.clone();
let first = self.peek_group_coordinate(&mut i)?;
if i < 1 {
return None;
}
match self.tokens.get(i - 1) {
Some(SpannedToken {
token: Token::Comma, ..
}) => {
i -= 1;
}
_ => {
return Ok(None);
return None;
}
}
let second = match self.peek_group_coordinate(&mut i) {
Some(coord) => coord,
None => return Ok(None),
};
let second = self.peek_group_coordinate(&mut i)?;
if i < 1 {
return None;
}
let right_paren_span;
match self.tokens.get(i) {
match self.tokens.get(i - 1) {
Some(SpannedToken {
token: Token::RightParen,
span,
@ -198,11 +216,14 @@ impl ParserContext {
i -= 1;
}
_ => {
return Ok(None);
return None;
}
}
if i < 1 {
return None;
}
let end_span;
match self.tokens.get(i) {
match self.tokens.get(i - 1) {
Some(SpannedToken {
token: Token::Group,
span,
@ -211,18 +232,20 @@ impl ParserContext {
i -= 1;
}
_ => {
return Ok(None);
return None;
}
}
self.tokens.drain((i + 1)..);
unexpected_whitespace(
self.tokens.drain(i..);
if let Err(e) = assert_no_whitespace(
&right_paren_span,
&end_span,
&format!("({},{})", first, second),
"group",
)?;
Ok(Some((first, second, start_span + end_span)))
) {
return Some(Err(e));
}
Some(Ok((first, second, start_span + end_span)))
}
///

View File

@ -404,7 +404,7 @@ impl ParserContext {
match token.token {
Token::LeftSquare => {
if self.eat(Token::DotDot).is_some() {
let right = if self.peek()?.token != Token::RightSquare {
let right = if self.peek_token().as_ref() != &Token::RightSquare {
Some(Box::new(self.parse_expression()?))
} else {
None
@ -422,7 +422,7 @@ impl ParserContext {
let left = self.parse_expression()?;
if self.eat(Token::DotDot).is_some() {
let right = if self.peek()?.token != Token::RightSquare {
let right = if self.peek_token().as_ref() != &Token::RightSquare {
Some(Box::new(self.parse_expression()?))
} else {
None
@ -554,7 +554,7 @@ impl ParserContext {
/// tuple initialization expression.
///
pub fn parse_tuple_expression(&mut self, span: &Span) -> SyntaxResult<Expression> {
if let Some((left, right, span)) = self.eat_group_partial()? {
if let Some((left, right, span)) = self.eat_group_partial().transpose()? {
return Ok(Expression::Value(ValueExpression::Group(Box::new(GroupValue::Tuple(
GroupTuple {
span,
@ -625,6 +625,10 @@ impl ParserContext {
}
if elements.len() == 1 {
self.expect(Token::Comma)?;
if let Some(token) = self.eat(Token::RightSquare) {
end_span = token.span;
break;
}
}
elements.push(self.parse_spread_or_expression()?);
if self.eat(Token::Comma).is_none() {
@ -658,21 +662,21 @@ impl ParserContext {
token: Token::Field,
span: type_span,
}) => {
unexpected_whitespace(&span, &type_span, &value, "field")?;
assert_no_whitespace(&span, &type_span, &value, "field")?;
Expression::Value(ValueExpression::Field(value, span + type_span))
}
Some(SpannedToken {
token: Token::Group,
span: type_span,
}) => {
unexpected_whitespace(&span, &type_span, &value, "group")?;
assert_no_whitespace(&span, &type_span, &value, "group")?;
Expression::Value(ValueExpression::Group(Box::new(GroupValue::Single(
value,
span + type_span,
))))
}
Some(SpannedToken { token, span: type_span }) => {
unexpected_whitespace(&span, &type_span, &value, &token.to_string())?;
assert_no_whitespace(&span, &type_span, &value, &token.to_string())?;
Expression::Value(ValueExpression::Integer(
Self::token_to_int_type(token).expect("unknown int type token"),
value,
@ -705,7 +709,7 @@ impl ParserContext {
Token::LeftSquare => self.parse_array_expression(&span)?,
Token::Ident(name) => {
let ident = Identifier { name, span };
if !self.fuzzy_struct_state && self.peek()?.token == Token::LeftCurly {
if !self.fuzzy_struct_state && self.peek_token().as_ref() == &Token::LeftCurly {
self.parse_circuit_expression(ident)?
} else {
Expression::Identifier(ident)
@ -716,7 +720,7 @@ impl ParserContext {
name: token.to_string().into(),
span,
};
if !self.fuzzy_struct_state && self.peek()?.token == Token::LeftCurly {
if !self.fuzzy_struct_state && self.peek_token().as_ref() == &Token::LeftCurly {
self.parse_circuit_expression(ident)?
} else {
Expression::Identifier(ident)

View File

@ -91,7 +91,7 @@ impl ParserContext {
)));
}
unexpected_whitespace(&start, &name.span, &name.name, "@")?;
assert_no_whitespace(&start, &name.span, &name.name, "@")?;
let end_span;
let arguments = if self.eat(Token::LeftParen).is_some() {
@ -153,7 +153,7 @@ impl ParserContext {
Ok(PackageAccess::Star(span))
} else {
let name = self.expect_ident()?;
if self.peek()?.token == Token::Dot {
if self.peek_token().as_ref() == &Token::Dot {
self.backtrack(SpannedToken {
token: Token::Ident(name.name),
span: name.span,
@ -188,7 +188,7 @@ impl ParserContext {
// Build the rest of the package name including dashes.
loop {
match &self.peek()?.token {
match &self.peek_token().as_ref() {
Token::Minus => {
let span = self.expect(Token::Minus)?;
base.span = base.span + span;
@ -369,7 +369,7 @@ impl ParserContext {
///
pub fn parse_function_declaration(&mut self) -> SyntaxResult<(Identifier, Function)> {
let mut annotations = Vec::new();
while self.peek()?.token == Token::At {
while self.peek_token().as_ref() == &Token::At {
annotations.push(self.parse_annotation()?);
}
let start = self.expect(Token::Function)?;

View File

@ -20,16 +20,16 @@
//! method to create a new program ast.
mod context;
use context::*;
pub use context::*;
mod expression;
mod file;
mod statement;
mod type_;
pub mod expression;
pub mod file;
pub mod statement;
pub mod type_;
use std::unimplemented;
use crate::{tokenizer::*, DeprecatedError, SyntaxError, Token};
use crate::{errors::assert_no_whitespace, tokenizer::*, DeprecatedError, SyntaxError, Token};
use indexmap::IndexMap;
use leo_ast::*;
@ -41,14 +41,3 @@ pub fn parse(path: &str, source: &str) -> SyntaxResult<Program> {
tokens.parse_program()
}
pub fn unexpected_whitespace(left_span: &Span, right_span: &Span, left: &str, right: &str) -> SyntaxResult<()> {
if left_span.col_stop != right_span.col_start {
let mut error_span = left_span + right_span;
error_span.col_start = left_span.col_stop - 1;
error_span.col_stop = right_span.col_start - 1;
return Err(SyntaxError::unexpected_whitespace(left, right, &error_span));
}
Ok(())
}

View File

@ -167,7 +167,7 @@ impl ParserContext {
pub fn parse_return_statement(&mut self) -> SyntaxResult<ReturnStatement> {
let start = self.expect(Token::Return)?;
let expr = self.parse_expression()?;
self.eat(Token::Comma);
self.eat(Token::Semicolon);
Ok(ReturnStatement {
span: &start + expr.span(),
@ -316,10 +316,17 @@ impl ParserContext {
let mut variable_names = Vec::new();
if self.eat(Token::LeftParen).is_some() {
variable_names.push(self.parse_variable_name(&declare)?);
let mut eaten_ending = false;
while self.eat(Token::Comma).is_some() {
if self.eat(Token::RightParen).is_some() {
eaten_ending = true;
break;
}
variable_names.push(self.parse_variable_name(&declare)?);
}
self.expect(Token::RightParen)?;
if !eaten_ending {
self.expect(Token::RightParen)?;
}
} else {
variable_names.push(self.parse_variable_name(&declare)?);
}

View File

@ -15,15 +15,69 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use std::{
fmt,
fs,
path::{Path, PathBuf},
sync::Arc,
};
use crate::SyntaxError;
use leo_ast::{Expression, ExpressionStatement, Program, Span, Statement, ValueExpression};
use serde_yaml::Value;
use tokenizer::Token;
use crate::{tokenizer, DeprecatedError, ParserContext, SyntaxError, TokenError};
struct TestFailure {
path: String,
error: SyntaxError,
errors: Vec<TestError>,
}
#[derive(Debug)]
enum TestError {
UnexpectedOutput {
index: usize,
expected: String,
output: String,
},
PassedAndShouldntHave {
index: usize,
},
FailedAndShouldntHave {
index: usize,
error: String,
},
UnexpectedError {
index: usize,
expected: String,
output: String,
},
MismatchedTestExpectationLength,
}
impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TestError::UnexpectedOutput {
index,
expected,
output,
} => {
write!(f, "test #{} expected\n{}\ngot\n{}", index + 1, expected, output)
}
TestError::PassedAndShouldntHave { index } => write!(f, "test #{} passed and shouldn't have", index + 1),
TestError::FailedAndShouldntHave { index, error } => {
write!(f, "test #{} failed and shouldn't have:\n{}", index + 1, error)
}
TestError::UnexpectedError {
expected,
output,
index,
} => {
write!(f, "test #{} expected error\n{}\ngot\n{}", index + 1, expected, output)
}
TestError::MismatchedTestExpectationLength => write!(f, "invalid number of test expectations"),
}
}
}
pub fn find_tests<T: AsRef<Path>>(path: T, out: &mut Vec<(String, String)>) {
@ -40,13 +94,411 @@ pub fn find_tests<T: AsRef<Path>>(path: T, out: &mut Vec<(String, String)>) {
}
}
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug, Clone)]
enum TestNamespace {
Parse,
ParseStatement,
ParseExpression,
Token,
}
#[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug, Clone)]
enum TestExpectationMode {
Pass,
Fail,
}
#[derive(serde::Serialize, serde::Deserialize)]
struct TestConfig {
namespace: TestNamespace,
expectation: TestExpectationMode,
}
#[derive(serde::Serialize, serde::Deserialize, Clone)]
struct TestExpectation {
namespace: TestNamespace,
expectation: TestExpectationMode,
outputs: Vec<Value>,
}
fn extract_test_config(source: &str) -> Option<TestConfig> {
let first_comment_start = source.find("/*")?;
let end_first_comment = source[first_comment_start + 2..].find("*/")?;
let comment_inner = &source[first_comment_start + 2..first_comment_start + 2 + end_first_comment];
Some(serde_yaml::from_str(comment_inner).expect("invalid test configuration"))
}
fn split_tests_oneline(source: &str) -> Vec<&str> {
source.lines().map(|x| x.trim()).filter(|x| !x.is_empty()).collect()
}
fn split_tests_twoline(source: &str) -> Vec<String> {
let mut out = vec![];
let mut lines = vec![];
for line in source.lines() {
let line = line.trim();
if line.is_empty() {
if !lines.is_empty() {
out.push(lines.join("\n"));
}
lines.clear();
continue;
}
lines.push(line);
}
let last_test = lines.join("\n");
if !last_test.trim().is_empty() {
out.push(last_test.trim().to_string());
}
out
}
fn run_individual_token_test(path: &str, source: &str) -> Result<String, String> {
let output = tokenizer::tokenize(path, source.into());
output
.map(|tokens| {
tokens
.into_iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join(",")
})
.map_err(|x| strip_path_syntax_error(x.into()))
}
fn not_fully_consumed(tokens: &mut ParserContext) -> Result<(), String> {
if !tokens.has_next() {
return Ok(());
}
let mut out = "did not consume all input: ".to_string();
while tokens.has_next() {
out.push_str(&tokens.expect_any().unwrap().to_string());
out.push('\n');
}
Err(out)
}
fn run_individual_expression_test(path: &str, source: &str) -> Result<Expression, String> {
let tokenizer = tokenizer::tokenize(path, source.into()).map_err(|x| strip_path_syntax_error(x.into()))?;
if tokenizer
.iter()
.all(|x| matches!(x.token, Token::CommentLine(_) | Token::CommentBlock(_)))
{
return Ok(Expression::Value(ValueExpression::Implicit("".into(), Span::default())));
}
let mut tokens = ParserContext::new(tokenizer);
let parsed = tokens.parse_expression().map_err(strip_path_syntax_error)?;
not_fully_consumed(&mut tokens)?;
Ok(parsed)
}
fn run_individual_statement_test(path: &str, source: &str) -> Result<Statement, String> {
let tokenizer = tokenizer::tokenize(path, source.into()).map_err(|x| strip_path_syntax_error(x.into()))?;
if tokenizer
.iter()
.all(|x| matches!(x.token, Token::CommentLine(_) | Token::CommentBlock(_)))
{
return Ok(Statement::Expression(ExpressionStatement {
expression: Expression::Value(ValueExpression::Implicit("".into(), Span::default())),
span: Span::default(),
}));
}
let mut tokens = ParserContext::new(tokenizer);
let parsed = tokens.parse_statement().map_err(strip_path_syntax_error)?;
not_fully_consumed(&mut tokens)?;
Ok(parsed)
}
fn strip_path_syntax_error(mut err: SyntaxError) -> String {
let inner = match &mut err {
SyntaxError::DeprecatedError(DeprecatedError::Error(x)) => x,
SyntaxError::Error(x) => x,
SyntaxError::TokenError(TokenError::Error(x)) => x,
};
inner.path = Arc::new("test".to_string());
err.to_string()
}
fn run_individual_parse_test(path: &str, source: &str) -> Result<Program, String> {
let tokenizer = tokenizer::tokenize(path, source.into()).map_err(|x| strip_path_syntax_error(x.into()))?;
let mut tokens = ParserContext::new(tokenizer);
let parsed = tokens.parse_program().map_err(strip_path_syntax_error)?;
not_fully_consumed(&mut tokens)?;
Ok(parsed)
}
fn emit_errors<T: PartialEq + ToString + serde::de::DeserializeOwned>(
output: Result<&T, &str>,
mode: &TestExpectationMode,
expected_output: Option<Value>,
test_index: usize,
) -> Option<TestError> {
match (output, mode) {
(Ok(output), TestExpectationMode::Pass) => {
let expected_output: Option<T> =
expected_output.map(|x| serde_yaml::from_value(x).expect("test expectation deserialize failed"));
// passed and should have
if let Some(expected_output) = expected_output.as_ref() {
if output != expected_output {
// invalid output
return Some(TestError::UnexpectedOutput {
index: test_index,
expected: expected_output.to_string(),
output: output.to_string(),
});
}
}
None
}
(Ok(_tokens), TestExpectationMode::Fail) => Some(TestError::PassedAndShouldntHave { index: test_index }),
(Err(err), TestExpectationMode::Pass) => Some(TestError::FailedAndShouldntHave {
error: err.to_string(),
index: test_index,
}),
(Err(err), TestExpectationMode::Fail) => {
let expected_output: Option<String> =
expected_output.map(|x| serde_yaml::from_value(x).expect("test expectation deserialize failed"));
if let Some(expected_output) = expected_output.as_deref() {
if err != expected_output {
// invalid output
return Some(TestError::UnexpectedError {
expected: expected_output.to_string(),
output: err.to_string(),
index: test_index,
});
}
}
None
}
}
}
fn run_test(
config: &TestConfig,
path: &str,
source: &str,
expectations: Option<&TestExpectation>,
errors: &mut Vec<TestError>,
) -> Vec<Value> {
let end_of_header = source.find("*/").expect("failed to find header block in test");
let source = &source[end_of_header + 2..];
let mut outputs = vec![];
match &config.namespace {
TestNamespace::Token => {
let tests = split_tests_oneline(source);
if let Some(expectations) = expectations.as_ref() {
if tests.len() != expectations.outputs.len() {
errors.push(TestError::MismatchedTestExpectationLength);
}
}
let mut expected_output = expectations.as_ref().map(|x| x.outputs.iter());
for (i, test) in tests.into_iter().enumerate() {
let expected_output = expected_output
.as_mut()
.map(|x| x.next())
.flatten()
.map(|x| x.as_str())
.flatten();
let output = run_individual_token_test(path, test);
if let Some(error) = emit_errors(
output.as_ref().map_err(|x| &**x),
&config.expectation,
expected_output.map(|x| Value::String(x.to_string())),
i,
) {
errors.push(error);
} else {
outputs.push(serde_yaml::to_value(output.unwrap_or_else(|e| e)).expect("serialization failed"));
}
}
}
TestNamespace::Parse => {
if let Some(expectations) = expectations.as_ref() {
if expectations.outputs.len() != 1 {
errors.push(TestError::MismatchedTestExpectationLength);
}
}
let expected_output = expectations
.map(|x| x.outputs.get(0))
.flatten()
.map(|x| serde_yaml::from_value(x.clone()).expect("invalid test expectation form"));
let output = run_individual_parse_test(path, source);
if let Some(error) = emit_errors(
output.as_ref().map_err(|x| &**x),
&config.expectation,
expected_output,
0,
) {
errors.push(error);
} else {
outputs.push(
output
.map(|x| serde_yaml::to_value(x).expect("serialization failed"))
.unwrap_or_else(|e| serde_yaml::to_value(e).expect("serialization failed")),
);
}
}
TestNamespace::ParseStatement => {
let tests = split_tests_twoline(source);
if let Some(expectations) = expectations.as_ref() {
if tests.len() != expectations.outputs.len() {
errors.push(TestError::MismatchedTestExpectationLength);
}
}
let mut expected_output = expectations.as_ref().map(|x| x.outputs.iter());
for (i, test) in tests.into_iter().enumerate() {
let expected_output = expected_output
.as_mut()
.map(|x| x.next())
.flatten()
.map(|x| serde_yaml::from_value(x.clone()).expect("invalid test expectation form"));
let output = run_individual_statement_test(path, &test);
if let Some(error) = emit_errors(
output.as_ref().map_err(|x| &**x),
&config.expectation,
expected_output,
i,
) {
errors.push(error);
} else {
outputs.push(
output
.map(|x| serde_yaml::to_value(x).expect("serialization failed"))
.unwrap_or_else(|e| serde_yaml::to_value(e).expect("serialization failed")),
);
}
}
}
TestNamespace::ParseExpression => {
let tests = split_tests_oneline(source);
if let Some(expectations) = expectations.as_ref() {
if tests.len() != expectations.outputs.len() {
errors.push(TestError::MismatchedTestExpectationLength);
}
}
let mut expected_output = expectations.as_ref().map(|x| x.outputs.iter());
for (i, test) in tests.into_iter().enumerate() {
let expected_output = expected_output
.as_mut()
.map(|x| x.next())
.flatten()
.map(|x| serde_yaml::from_value(x.clone()).expect("invalid test expectation form"));
let output = run_individual_expression_test(path, test);
if let Some(error) = emit_errors(
output.as_ref().map_err(|x| &**x),
&config.expectation,
expected_output,
i,
) {
errors.push(error);
} else {
outputs.push(
output
.map(|x| serde_yaml::to_value(x).expect("serialization failed"))
.unwrap_or_else(|e| serde_yaml::to_value(e).expect("serialization failed")),
);
}
}
}
}
outputs
}
#[test]
pub fn parser_tests() {
let mut pass = 0;
let mut fail = Vec::new();
let mut tests = Vec::new();
let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
test_dir.push("../tests/parser/");
find_tests(&test_dir, &mut tests);
let mut outputs = vec![];
for (path, content) in tests.into_iter() {
let config = extract_test_config(&content);
if config.is_none() {
panic!("missing configuration for {}", path);
}
let config = config.unwrap();
let mut expectation_path = path.clone();
expectation_path += ".out";
let expectations: Option<TestExpectation> = if std::path::Path::new(&expectation_path).exists() {
if !std::env::var("CLEAR_LEO_TEST_EXPECTATIONS")
.unwrap_or_default()
.trim()
.is_empty()
{
None
} else {
let raw = std::fs::read_to_string(&expectation_path).expect("failed to read expectations file");
Some(serde_yaml::from_str(&raw).expect("invalid yaml in expectations file"))
}
} else {
None
};
let mut errors = vec![];
let raw_path = Path::new(&path);
let new_outputs = run_test(
&config,
raw_path.file_name().unwrap_or_default().to_str().unwrap_or_default(),
&content,
expectations.as_ref(),
&mut errors,
);
if errors.is_empty() {
if expectations.is_none() {
outputs.push((expectation_path, TestExpectation {
namespace: config.namespace,
expectation: config.expectation,
outputs: new_outputs,
}));
}
pass += 1;
} else {
fail.push(TestFailure {
path: path.clone(),
errors,
})
}
}
if !fail.is_empty() {
for (i, fail) in fail.iter().enumerate() {
println!(
"\n\n-----------------TEST #{} FAILED (and shouldn't have)-----------------",
i + 1
);
println!("File: {}", fail.path);
for error in &fail.errors {
println!("{}", error);
}
}
panic!("failed {}/{} tests", fail.len(), fail.len() + pass);
} else {
for (path, new_expectation) in outputs {
std::fs::write(
&path,
serde_yaml::to_string(&new_expectation).expect("failed to serialize expectation yaml"),
)
.expect("failed to write expectation file");
}
println!("passed {}/{} tests", pass, pass);
}
}
#[test]
pub fn parser_pass_tests() {
let mut pass = 0;
let mut fail = Vec::new();
let mut tests = Vec::new();
let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
test_dir.push("../tests/pass/parse/");
test_dir.push("../tests/old/pass/");
find_tests(&test_dir, &mut tests);
for (path, content) in tests.into_iter() {
match crate::parse(&path, &content) {
@ -54,7 +506,13 @@ pub fn parser_pass_tests() {
pass += 1;
}
Err(e) => {
fail.push(TestFailure { path, error: e });
fail.push(TestFailure {
path,
errors: vec![TestError::FailedAndShouldntHave {
index: 0,
error: e.to_string(),
}],
});
}
}
}
@ -65,7 +523,9 @@ pub fn parser_pass_tests() {
i + 1
);
println!("File: {}", fail.path);
println!("{}", fail.error);
for error in &fail.errors {
println!("{}", error);
}
}
panic!("failed {}/{} tests", fail.len(), fail.len() + pass);
} else {
@ -79,7 +539,7 @@ pub fn parser_fail_tests() {
let mut fail = Vec::new();
let mut tests = Vec::new();
let mut test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
test_dir.push("../tests/fail/parse/");
test_dir.push("../tests/old/fail/");
find_tests(&test_dir, &mut tests);
for (path, content) in tests.into_iter() {
match crate::parse(&path, &content) {

View File

@ -306,11 +306,7 @@ impl Token {
return (
ident.len(),
Some(match &*ident {
x if x.starts_with("aleo1")
&& x.chars().skip(5).all(|x| x.is_ascii_lowercase() || x.is_ascii_digit()) =>
{
Token::AddressLit(ident)
}
x if x.starts_with("aleo1") => Token::AddressLit(ident),
"address" => Token::Address,
"as" => Token::As,
"bool" => Token::Bool,

View File

@ -146,6 +146,9 @@ pub enum Token {
// ModEq,
// OrEq,
// AndEq,
// Meta Tokens
Eof,
}
/// Represents all valid Leo keyword tokens.
@ -289,6 +292,7 @@ impl fmt::Display for Token {
Return => write!(f, "return"),
Static => write!(f, "static"),
String => write!(f, "string"),
Eof => write!(f, ""),
// BitAnd => write!(f, "&"),
// BitAndEq => write!(f, "&="),
// BitOr => write!(f, "|"),

View File

@ -1,6 +1,6 @@
[package]
name = "leo-state"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "State parser of the Leo programming language"
homepage = "https://aleo.org"
@ -19,15 +19,14 @@ edition = "2018"
[dependencies.leo-input]
path = "../input"
version = "1.2.3"
version = "1.3.0"
[dependencies.leo-ast]
path = "../ast"
version = "1.2.3"
version = "1.3.0"
[dependencies.snarkvm-algorithms]
version = "0.2.2"
#default-features = false
[dependencies.snarkvm-curves]
version = "0.2.2"

View File

@ -1,6 +1,6 @@
[package]
name = "leo-synthesizer"
version = "1.2.3"
version = "1.3.0"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Circuit synthesizer of the Leo programming language"
homepage = "https://aleo.org"
@ -27,7 +27,6 @@ default-features = false
[dependencies.snarkvm-gadgets]
version = "0.2.2"
default-features = false
[dependencies.snarkvm-r1cs]
version = "0.2.2"

Some files were not shown because too many files have changed in this diff Show More