migrate spans crate, which involves rust 2021 ed, and dep updates

This commit is contained in:
gluax 2022-01-21 12:04:37 -08:00
parent 34a0b4e9b0
commit ea419a7891
26 changed files with 1040 additions and 87 deletions

View File

@ -1,7 +1,7 @@
# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md
# Stable configurations
edition = "2018"
edition = "2021"
max_width = 120
merge_derives = true
use_field_init_shorthand = true

110
Cargo.lock generated
View File

@ -255,15 +255,6 @@ dependencies = [
"generic-array 0.12.4",
]
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array 0.14.5",
]
[[package]]
name = "block-buffer"
version = "0.10.0"
@ -397,12 +388,27 @@ dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"strsim 0.8.0",
"textwrap 0.11.0",
"unicode-width",
"vec_map",
]
[[package]]
name = "clap"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
dependencies = [
"atty",
"bitflags",
"indexmap",
"os_str_bytes",
"strsim 0.10.0",
"termcolor",
"textwrap 0.14.2",
]
[[package]]
name = "color-backtrace"
version = "0.5.1"
@ -488,7 +494,7 @@ checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
dependencies = [
"atty",
"cast",
"clap",
"clap 2.34.0",
"criterion-plot",
"csv",
"itertools 0.10.3",
@ -736,9 +742,9 @@ dependencies = [
[[package]]
name = "eyre"
version = "0.6.5"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "221239d1d5ea86bf5d6f91c9d6bc3646ffe471b08ff9b0f91c44f115ac969d2b"
checksum = "bc225d8f637923fe585089fcf03e705c222131232d2c1fb622e84ecf725d0eb8"
dependencies = [
"indenter",
"once_cell",
@ -1199,9 +1205,9 @@ dependencies = [
[[package]]
name = "indicatif"
version = "0.15.0"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7baab56125e25686df467fe470785512329883aab42696d661247aca2a2896e4"
checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b"
dependencies = [
"console",
"lazy_static",
@ -1376,6 +1382,7 @@ dependencies = [
name = "leo-compiler"
version = "1.5.3"
dependencies = [
"bech32",
"bincode",
"indexmap",
"leo-asg",
@ -1397,7 +1404,7 @@ dependencies = [
"serde",
"serde_json",
"serde_yaml",
"sha2 0.9.9",
"sha2",
"snarkvm-algorithms",
"snarkvm-curves",
"snarkvm-dpc",
@ -1435,6 +1442,7 @@ dependencies = [
"leo-ast-passes",
"leo-errors",
"leo-parser",
"leo-span",
"tracing",
]
@ -1456,7 +1464,7 @@ version = "1.5.3"
dependencies = [
"ansi_term",
"assert_cmd",
"clap",
"clap 3.0.10",
"color-backtrace",
"colored",
"console",
@ -1529,6 +1537,18 @@ dependencies = [
"tracing",
]
[[package]]
name = "leo-span"
version = "1.5.3"
dependencies = [
"fxhash",
"indexmap",
"pest",
"scoped-tls",
"serde",
"tendril",
]
[[package]]
name = "leo-stdlib"
version = "1.5.3"
@ -1550,7 +1570,7 @@ dependencies = [
"num-bigint",
"serde",
"serde_json",
"sha2 0.9.9",
"sha2",
"snarkvm-curves",
"snarkvm-fields",
"snarkvm-gadgets",
@ -1873,9 +1893,9 @@ dependencies = [
[[package]]
name = "number_prefix"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "object"
@ -1943,6 +1963,15 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "paste"
version = "1.0.6"
@ -2429,6 +2458,12 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "scoped-tls"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
[[package]]
name = "scopeguard"
version = "1.1.0"
@ -2460,9 +2495,9 @@ dependencies = [
[[package]]
name = "self_update"
version = "0.27.0"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb85f1802f7b987237b8525c0fde86ea86f31c957c1875467c727d5b921179c"
checksum = "5bc3e89793fe56c82104ddc103c998e4e94713cb975202207829e61031eb4be6"
dependencies = [
"hyper",
"indicatif",
@ -2578,19 +2613,6 @@ dependencies = [
"opaque-debug 0.2.3",
]
[[package]]
name = "sha2"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [
"block-buffer 0.9.0",
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.9.0",
"opaque-debug 0.3.0",
]
[[package]]
name = "sha2"
version = "0.10.1"
@ -2652,7 +2674,7 @@ dependencies = [
"rand_chacha 0.3.1",
"rayon",
"serde",
"sha2 0.10.1",
"sha2",
"smallvec",
"snarkvm-curves",
"snarkvm-fields",
@ -2865,13 +2887,19 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "structopt"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
dependencies = [
"clap",
"clap 2.34.0",
"lazy_static",
"structopt-derive",
]
@ -2997,6 +3025,12 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
[[package]]
name = "thiserror"
version = "1.0.30"

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "leo", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[lib]
path = "leo/lib.rs"
@ -38,6 +39,7 @@ members = [
"linter",
"package",
"parser",
"span",
# "state",
"stdlib",
"synthesizer",
@ -112,10 +114,10 @@ rev = "435f112"
version = "0.3"
[dependencies.clap]
version = "2.33.3"
version = "3.0.10"
[dependencies]
color-backtrace = "0.5.1"
[dependencies.color-backtrace]
version = "0.5.1"
[dependencies.colored]
version = "2.0"
@ -130,7 +132,7 @@ version = "0.15.0"
version = "0.3.1"
[dependencies.indexmap]
version = "1.7"
version = "1.8"
features = ["serde"]
[dependencies.lazy_static]
@ -146,11 +148,11 @@ version = "0.8"
version = "0.6.3"
[dependencies.reqwest]
version = "0.11.6"
version = "0.11.9"
features = [ "blocking", "json", "multipart" ]
[dependencies.self_update]
version = "0.27.0"
version = "0.28.0"
features = [ "archive-zip" ]
[dependencies.serde]
@ -167,7 +169,7 @@ version = "0.5"
version = "0.1"
[dependencies.tracing-subscriber]
version = "0.3"
version = "0.3.6"
features = [ "fmt" ]
[dependencies.zip]
@ -180,7 +182,7 @@ version = "0.12.1"
version = "0.11.2"
[dev-dependencies.assert_cmd]
version = "2.0.2"
version = "2.0.4"
[dev-dependencies.test_dir]
version = "0.1.0"

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[lib]
path = "src/lib.rs"

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[dependencies.serde]
version = "1.0"

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[lib]
path = "src/lib.rs"

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[dependencies.leo-input]
path = "../input"
@ -26,7 +27,7 @@ path = "../errors"
version = "1.5.3"
[dependencies.indexmap]
version = "1.7.0"
version = "1.8.0"
features = [ "serde-1" ]
[dependencies.pest]

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[dependencies.leo-ast]
path = "../ast"
@ -61,8 +62,10 @@ version = "1.5.3"
path = "../synthesizer"
version = "1.5.3"
[dependencies.tendril]
version = "0.4"
[dev-dependencies.snarkvm-algorithms]
git = "https://github.com/AleoHQ/snarkVM.git"
rev = "435f112"
default-features = false
[dependencies.snarkvm-curves]
git = "https://github.com/AleoHQ/snarkVM.git"
@ -94,11 +97,14 @@ default-features = false
git = "https://github.com/AleoHQ/snarkVM.git"
rev = "435f112"
[dependencies.tendril]
version = "0.4"
[dependencies.bincode]
version = "1.3"
[dependencies.indexmap]
version = "1.7.0"
version = "1.8.0"
features = [ "serde-1" ]
[dependencies.pest]
@ -115,12 +121,15 @@ version = "1.0"
features = [ "preserve_order" ]
[dependencies.sha2]
version = "0.9"
version = "0.10"
[dependencies.tracing]
version = "0.1"
[dev-dependencies.num-bigint]
[dependencies.bech32]
version = "0.8"
[dependencies.num-bigint]
version = "0.4"
[dev-dependencies.rand_core]
@ -130,13 +139,8 @@ version = "0.6.3"
version = "0.3"
default-features = false
[dev-dependencies.snarkvm-algorithms]
git = "https://github.com/AleoHQ/snarkVM.git"
rev = "435f112"
default-features = false
[dev-dependencies.tempfile]
version = "3.0.4"
version = "3.3.0"
[dev-dependencies.serde_yaml]
version = "0.8"

View File

@ -47,8 +47,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
if !expected_return.is_assignable_from(&result_type) {
panic!(
"failed type resolution for function return: expected '{}', got '{}'",
expected_return.to_string(),
result_type.to_string()
expected_return, result_type,
);
}

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[dependencies]
colored = "2.0.0"
@ -31,17 +32,17 @@ version = "0.5.1"
version = "2.2.0"
[dependencies.eyre]
version = "0.6.5"
version = "0.6.6"
default-features = false
[dependencies.backtrace]
version = "0.3.63"
version = "0.3.62"
[dependencies.pest]
version = "2.0"
[dependencies.serde]
version = "1.0"
version = "1.0.133"
features = [ "derive", "rc" ]
[dependencies.tendril]

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[dependencies.leo-ast]
path = "../ast"
@ -33,8 +34,12 @@ version = "1.5.3"
path = "../parser"
version = "1.5.3"
[dependencies.leo-span]
path = "../span"
version = "1.5.3"
[dependencies.indexmap]
version = "1.7.0"
version = "1.8.0"
features = [ "serde-1" ]
[dependencies.tracing]

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[dependencies.from-pest]
version = "0.3.1"

View File

@ -17,4 +17,5 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"

View File

@ -15,14 +15,15 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[dependencies.leo-errors]
path = "../errors"
version = "1.5.3"
[dependencies.indexmap]
version = "1.7"
version = "1.8"
features = ["serde"]
[dependencies.serde]

View File

@ -53,7 +53,7 @@ impl InputsDirectory {
}
fn parse_file_paths(directory: ReadDir, file_paths: &mut Vec<PathBuf>) -> Result<()> {
for file_entry in directory.into_iter() {
for file_entry in directory {
let file_entry = file_entry.map_err(PackageError::failed_to_get_input_file_entry)?;
let file_path = file_entry.path();

View File

@ -48,7 +48,7 @@ impl SourceDirectory {
let directory = fs::read_dir(&path).map_err(PackageError::failed_to_read_inputs_directory)?;
let mut file_paths = Vec::new();
for file_entry in directory.into_iter() {
for file_entry in directory {
let file_entry = file_entry.map_err(PackageError::failed_to_get_source_file_entry)?;
let file_path = file_entry.path();

View File

@ -15,7 +15,8 @@ keywords = [
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2018"
edition = "2021"
rust-version = "1.56.1"
[[bench]]
name = "leo_ast"
@ -41,7 +42,7 @@ features = [ "derive" ]
version = "0.1"
[dependencies.indexmap]
version = "1.7"
version = "1.8"
[dependencies.tendril]
version = "0.4"

33
span/Cargo.toml Normal file
View File

@ -0,0 +1,33 @@
[package]
name = "leo-span"
version = "1.5.3"
authors = [ "The Aleo Team <hello@aleo.org>" ]
description = "Span handling in the Leo programming language"
homepage = "https://aleo.org"
repository = "https://github.com/AleoHQ/leo"
keywords = [
"aleo",
"cryptography",
"leo",
"programming-language",
"zero-knowledge"
]
categories = [ "cryptography::cryptocurrencies", "web-programming" ]
include = [ "Cargo.toml", "src", "README.md", "LICENSE.md" ]
license = "GPL-3.0"
edition = "2021"
rust-version = "1.56.1"
[dependencies]
fxhash = "0.2.1"
scoped-tls = "1.0.0"
pest = "2.0"
tendril = "0.4.2"
[dependencies.indexmap]
version = "1.8"
features = ["serde"]
[dependencies.serde]
version = "1.0.133"
features = [ "derive", "rc" ]

175
span/src/dropless.rs Normal file
View File

@ -0,0 +1,175 @@
// Copyright Rust project developers under MIT or APACHE-2.0.
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use core::alloc::Layout;
use core::cell::{Cell, RefCell};
use core::mem::{self, MaybeUninit};
use core::{cmp, ptr, slice};
use std::iter;
// The arenas start with PAGE-sized chunks, and then each new chunk is twice as
// big as its predecessor, up until we reach HUGE_PAGE-sized chunks, whereupon
// we stop growing. This scales well, from arenas that are barely used up to
// arenas that are used for 100s of MiBs. Note also that the chosen sizes match
// the usual sizes of pages and huge pages on Linux.
const PAGE: usize = 4096;
const HUGE_PAGE: usize = 2 * 1024 * 1024;
pub struct DroplessArena {
/// A pointer to the start of the free space.
start: Cell<*mut u8>,
/// A pointer to the end of free space.
///
/// The allocation proceeds from the end of the chunk towards the start.
/// When this pointer crosses the start pointer, a new chunk is allocated.
end: Cell<*mut u8>,
/// A vector of arena chunks.
chunks: RefCell<Vec<TypedArenaChunk<u8>>>,
}
unsafe impl Send for DroplessArena {}
impl Default for DroplessArena {
#[inline]
fn default() -> DroplessArena {
DroplessArena {
start: Cell::new(ptr::null_mut()),
end: Cell::new(ptr::null_mut()),
chunks: Default::default(),
}
}
}
impl DroplessArena {
#[inline(never)]
#[cold]
fn grow(&self, additional: usize) {
unsafe {
let mut chunks = self.chunks.borrow_mut();
let new_cap = if let Some(last_chunk) = chunks.last_mut() {
// If the previous chunk's len is less than HUGE_PAGE bytes,
// then this chunk will be at least double the previous chunk's size.
last_chunk.storage.len().min(HUGE_PAGE / 2) * 2
} else {
PAGE
};
// Also ensure that this chunk can fit `additional`.
let new_cap = cmp::max(additional, new_cap);
let mut chunk = TypedArenaChunk::<u8>::new(new_cap);
self.start.set(chunk.start());
self.end.set(chunk.end());
chunks.push(chunk);
}
}
/// Allocates a byte slice with specified layout from the current memory chunk.
/// Returns `None` if there is no free space left to satisfy the request.
#[inline]
fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> {
let start = self.start.get() as usize;
let end = self.end.get() as usize;
let align = layout.align();
let bytes = layout.size();
let new_end = end.checked_sub(bytes)? & !(align - 1);
if start <= new_end {
let new_end = new_end as *mut u8;
self.end.set(new_end);
Some(new_end)
} else {
// There's no more space since we're growing towards the start.
None
}
}
#[inline]
pub fn alloc_raw(&self, layout: Layout) -> *mut u8 {
assert!(layout.size() != 0);
loop {
if let Some(a) = self.alloc_raw_without_grow(layout) {
break a;
}
// No free space left. Allocate a new chunk to satisfy the request.
// On failure the grow will panic or abort.
self.grow(layout.size());
}
}
/// Allocates a slice of objects that are copied into the `DroplessArena`,
/// returning a mutable reference to it.
/// Will panic if passed a zero-sized type.
///
/// Panics:
///
/// - Zero-sized types
/// - Zero-length slices
#[inline]
#[allow(clippy::mut_from_ref)]
pub fn alloc_slice<T: Copy>(&self, slice: &[T]) -> &mut [T] {
assert!(!mem::needs_drop::<T>());
assert!(mem::size_of::<T>() != 0);
assert!(!slice.is_empty());
let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T;
unsafe {
mem.copy_from_nonoverlapping(slice.as_ptr(), slice.len());
slice::from_raw_parts_mut(mem, slice.len())
}
}
}
struct TypedArenaChunk<T> {
/// The raw storage for the arena chunk.
storage: Box<[MaybeUninit<T>]>,
}
impl<T> TypedArenaChunk<T> {
#[inline]
unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
TypedArenaChunk {
// HACK(Centril) around `Box::new_uninit_slice` not being stable.
storage: iter::repeat_with(MaybeUninit::<T>::uninit).take(capacity).collect(),
}
}
// Returns a pointer to the first allocated object.
#[inline]
fn start(&mut self) -> *mut T {
// HACK(Centril) around `MaybeUninit::slice_as_mut_ptr` not being stable.
self.storage.as_mut_ptr() as *mut T
}
// Returns a pointer to the end of the allocated space.
#[inline]
fn end(&mut self) -> *mut T {
unsafe {
if mem::size_of::<T>() == 0 {
// A pointer as large as possible for zero-sized elements.
!0 as *mut T
} else {
self.start().add(self.storage.len())
}
}
}
}

27
span/src/lib.rs Normal file
View File

@ -0,0 +1,27 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
mod dropless;
pub mod symbol;
pub use symbol::{sym, Symbol};
pub mod span;
pub use span::Span;
pub mod span_json;
pub mod tendril_json;

199
span/src/span.rs Normal file
View File

@ -0,0 +1,199 @@
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! Defines the `Span` type used to track where code comes from.
use std::{fmt, sync::Arc, usize};
use pest::Span as PestSpan;
use serde::ser::{Serialize, SerializeStruct, Serializer};
use serde::Deserialize;
use tendril::StrTendril;
/// The span type which tracks where formatted errors originate from in a Leo file.
/// This is used in many spots throughout the rest of the Leo crates.
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq)]
pub struct Span {
/// The line number where the error started.
pub line_start: usize,
/// The line number where the error stopped.
pub line_stop: usize,
/// The column number where the error started.
pub col_start: usize,
/// The column number where the error stopped.
pub col_stop: usize,
/// The path to the Leo file containing the error.
pub path: Arc<String>,
#[serde(with = "crate::tendril_json")]
/// The content of the file between the above boundries.
pub content: StrTendril,
}
impl Span {
/// Generate a new span from where:
/// - the Leo line starts.
/// - the Leo line stops.
/// - the Leo column starts.
/// - the Leo column stops.
/// - the path to the Leo file.
/// - the content of those specified bounds.
pub fn new(
line_start: usize,
line_stop: usize,
col_start: usize,
col_stop: usize,
path: Arc<String>,
content: StrTendril,
) -> Self {
Self {
line_start,
line_stop,
col_start,
col_stop,
path,
content,
}
}
}
impl Serialize for Span {
/// Custom serialization for testing purposes.
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("Color", 3)?;
state.serialize_field("line_start", &self.line_start)?;
state.serialize_field("line_stop", &self.line_stop)?;
state.serialize_field("col_start", &self.col_start)?;
state.serialize_field("col_stop", &self.col_stop)?;
// This is for testing purposes since the tests are run on a variety of OSes.
if std::env::var("LEO_TESTFRAMEWORK")
.unwrap_or_default()
.trim()
.to_owned()
.is_empty()
{
state.serialize_field("path", &self.path)?;
} else {
state.serialize_field("path", "")?;
}
state.serialize_field("content", &self.content[..])?;
state.end()
}
}
/// Conversion from a pest span where the leo-input library uses these.
impl fmt::Display for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.line_start == self.line_stop {
write!(f, "{}:{}-{}", self.line_start, self.col_start, self.col_stop)
} else {
write!(
f,
"{}:{}-{}:{}",
self.line_start, self.col_start, self.line_stop, self.col_stop
)
}
}
}
impl<'ast> From<PestSpan<'ast>> for Span {
fn from(span: PestSpan) -> Self {
let start = span.start_pos().line_col();
let end = span.end_pos().line_col();
Span::new(
start.0,
end.0,
start.1,
end.1,
Arc::new(String::new()),
span.as_str().into(),
)
}
}
impl std::ops::Add for &Span {
type Output = Span;
fn add(self, other: &Span) -> Span {
self.clone() + other.clone()
}
}
impl std::ops::Add for Span {
type Output = Self;
#[allow(clippy::comparison_chain)]
fn add(self, other: Self) -> Self {
if self.line_start == other.line_stop {
Span {
line_start: self.line_start,
line_stop: self.line_stop,
col_start: self.col_start.min(other.col_start),
col_stop: self.col_stop.max(other.col_stop),
path: self.path,
content: self.content,
}
} else {
let mut new_content = vec![];
let self_lines = self.content.lines().collect::<Vec<_>>();
let other_lines = other.content.lines().collect::<Vec<_>>();
for line in self.line_start.min(other.line_start)..self.line_stop.max(other.line_stop) + 1 {
if line >= self.line_start && line <= self.line_stop {
new_content.push(
self_lines
.get(line - self.line_start)
.copied()
.unwrap_or_default()
.to_string(),
);
} else if line >= other.line_start && line <= other.line_stop {
new_content.push(
other_lines
.get(line - other.line_start)
.copied()
.unwrap_or_default()
.to_string(),
);
} else if new_content.last().map(|x| *x != "...").unwrap_or(true) {
new_content.push(format!("{:<1$}...", " ", other.col_start + 4));
}
}
let new_content = new_content.join("\n").into();
if self.line_start < other.line_stop {
Span {
line_start: self.line_start,
line_stop: other.line_stop,
col_start: self.col_start,
col_stop: other.col_stop,
path: self.path,
content: new_content,
}
} else {
Span {
line_start: other.line_start,
line_stop: self.line_stop,
col_start: other.col_start,
col_stop: self.col_stop,
path: self.path,
content: new_content,
}
}
}
}
}

57
span/src/span_json.rs Normal file
View File

@ -0,0 +1,57 @@
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! Provides custom serialize/deserialize implementations for `Span`.
use crate::Span;
use serde::de::{MapAccess, Visitor};
use serde::ser::SerializeMap;
use serde::{Deserializer, Serializer};
use std::fmt;
/// The AST contains a few tuple-like enum variants the contain spans
/// #[derive(Serialize, Deserialize)] outputs these fields as anonmyous
/// mappings, which makes them difficult to remove from the JSON AST.
/// This function provides a custom serialization that maps the keyword
/// `span` to the span information.
pub fn serialize<S: Serializer>(span: &Span, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("span", span)?;
map.end()
}
/// Custom deserialization to enable removing spans from enums.
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Span, D::Error> {
deserializer.deserialize_map(SpanMapVisitor)
}
/// This visitor is used by the deserializer to unwrap mappings
/// and extract span information.
struct SpanMapVisitor;
impl<'de> Visitor<'de> for SpanMapVisitor {
type Value = Span;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Mapping from `span` keyword to span information")
}
fn visit_map<M: MapAccess<'de>>(self, mut access: M) -> Result<Self::Value, M::Error> {
let (_, value): (String, Span) = access.next_entry()?.unwrap();
Ok(value)
}
}

379
span/src/symbol.rs Normal file
View File

@ -0,0 +1,379 @@
// Copyright (C) 2019-2021 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::dropless::DroplessArena;
use core::cmp::PartialEq;
use core::convert::AsRef;
use core::num::NonZeroU32;
use core::ops::Deref;
use core::{fmt, str};
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cell::RefCell;
use std::intrinsics::transmute;
use std::marker::PhantomData;
/// A helper for `symbols` defined below.
/// The macro's job is to bind conventiently usable `const` items to the symbol names provided.
/// For example, with `symbol { a, b }` you'd have `sym::a` and `sym::b`.
macro_rules! consts {
($val: expr, $sym:ident $(,)?) => {
#[allow(non_upper_case_globals)]
pub const $sym: $crate::symbol::Symbol = $crate::symbol::Symbol::new($val);
};
($val: expr, $sym:ident: $_s:literal $(,)?) => {
consts!($val, $sym);
};
($val: expr, $sym:ident: $_s:literal, $($rest:tt)*) => {
consts!($val, $sym);
consts!($val + 1, $($rest)*);
};
($val: expr, $sym:ident, $($rest:tt)*) => {
consts!($val, $sym);
consts!($val + 1, $($rest)*);
};
}
/// A helper for `symbols` defined below.
/// The macro's job is to merge all the hard coded strings into a single array of strings.
/// The strategy applied is [push-down accumulation](https://danielkeep.github.io/tlborm/book/pat-push-down-accumulation.html).
macro_rules! strings {
// Final step 0) in the push-down accumulation.
// Here, the actual strings gathered in `$acc` are made into an array.
// We have to use this approach because e.g., `$e1 , $e2` is not recognized by any syntactic
// category in Rust, so a macro cannot produce it.
([$($acc:expr),*] []) => {
[$($acc),*]
};
// Recursive case 1): Handles e.g., `x: "frodo"` and `y: "sam"`
// in `symbols! { x: "frodo", y: "sam", z }`.
([$($acc:expr),*] [$_sym:ident: $string:literal, $($rest:tt)*]) => {
strings!([$($acc,)* $string] [$($rest)*])
};
// Recursive case 2): Handles e.g., `x` and `y` in `symbols! { x, y, z }`.
([$($acc:expr),*] [$sym:ident, $($rest:tt)*]) => {
strings!([$($acc,)* stringify!($sym)] [$($rest)*])
};
// Base case 3): As below, but with a specified string, e.g., `symbols! { x, y: "gandalf" }`.
([$($acc:expr),*] [$_sym:ident: $string:literal $(,)?]) => {
strings!([$($acc,)* $string] [])
};
// Base case 4): A single identitifier left.
// So in e.g., `symbols! { x, y }`, this handles `y` with `x` already in `$acc`.
([$($acc:expr),*] [$sym:ident $(,)?]) => {
strings!([$($acc,)* stringify!($sym)] [])
};
}
/// Creates predefined symbols used throughout the Leo compiler and language.
/// Broadly speaking, any hard coded string in the compiler should be defined here.
///
/// The macro accepts symbols separated by commas,
/// and a symbol is either specified as a Rust identifier, in which case it is `stringify!`ed,
/// or as `ident: "string"` where `"string"` is the actual hard coded string.
/// The latter case can be used when the hard coded string is not a valid identifier.
/// In either case, a `const $ident: Symbol` will be created that you can access as `sym::$ident`.
macro_rules! symbols {
($($symbols:tt)*) => {
const PRE_DEFINED: &[&str] = &strings!([] [$($symbols)*]);
pub mod sym {
consts!(0, $($symbols)*);
}
};
}
symbols! {
address,
AlwaysConst,
Ampersand: "@",
array,
As: "as",
assert,
bool,
char,
circuit,
Class: "class",
context,
CoreFunction,
console,
Const: "const",
Else: "else",
error,
False: "false",
field,
For: "for",
function,
group,
i8,
i16,
i32,
i64,
i128,
If: "if",
import,
In: "in",
input,
Let: "let",
log,
main,
Mut: "mut",
prelude,
Return: "return",
SelfLower: "self",
SelfUpper: "Self",
Star: "*",
std,
Static: "static",
Struct: "struct",
test,
True: "true",
Type: "type",
u8,
u16,
u32,
u64,
u128,
CONTAINER_PSEUDO_CIRCUIT: "$InputContainer",
REGISTERS_PSEUDO_CIRCUIT: "$InputRegister",
RECORD_PSEUDO_CIRCUIT: "$InputRecord",
STATE_PSEUDO_CIRCUIT: "$InputState",
STATE_LEAF_PSEUDO_CIRCUIT: "$InputStateLeaf",
registers,
record,
state,
state_leaf,
}
/// An interned string.
///
/// Represented as an index internally, with all operations based on that.
/// A `Symbol` reserves the value `0`, so that `Option<Symbol>` only takes up 4 bytes.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct Symbol(
#[serde(deserialize_with = "Symbol::serde_to_symbol")]
#[serde(serialize_with = "Symbol::serde_from_symbol")]
NonZeroU32,
);
impl Symbol {
/// Returns the corresponding `Symbol` for the given `index`.
pub const fn new(index: u32) -> Self {
let index = index.saturating_add(1);
// SAFETY: per above addition, we know `index > 0` always applies.
Self(unsafe { NonZeroU32::new_unchecked(index) })
}
/// Maps a string to its interned representation.
pub fn intern(string: &str) -> Self {
with_session_globals(|session_globals| session_globals.symbol_interner.intern(string))
}
/// Convert to effectively a `&'static str`.
/// This is a slowish operation because it requires locking the symbol interner.
pub fn as_str(self) -> SymbolStr {
with_session_globals(|session_globals| {
let symbol_str = session_globals.symbol_interner.get(self);
SymbolStr::new(unsafe { std::mem::transmute::<&str, &str>(symbol_str) })
})
}
/// Converts this symbol to the raw index.
pub const fn as_u32(self) -> u32 {
self.0.get() - 1
}
fn serde_to_symbol<'de, D: Deserializer<'de>>(de: D) -> Result<NonZeroU32, D::Error> {
Ok(Symbol::intern(<&str>::deserialize(de)?).0)
}
fn serde_from_symbol<S: Serializer>(index: &NonZeroU32, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(&Self(*index).as_str())
}
}
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.as_str(), f)
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.as_str(), f)
}
}
/// An alternative to [`Symbol`], useful when the chars within the symbol need to
/// be accessed. It deliberately has limited functionality and should only be
/// used for temporary values.
///
/// Because the interner outlives any thread which uses this type, we can
/// safely treat `string` which points to interner data, as an immortal string,
/// as long as this type never crosses between threads.
#[derive(Clone, Eq, PartialOrd, Ord)]
pub struct SymbolStr {
string: &'static str,
/// Ensures the type is neither `Sync` nor `Send`,
/// so that we satisfy "never crosses between threads" per above.
not_sync_send: PhantomData<*mut ()>,
}
impl SymbolStr {
/// Create a `SymbolStr` from a `&'static str`.
pub fn new(string: &'static str) -> Self {
Self {
string,
not_sync_send: PhantomData,
}
}
}
// This impl allows a `SymbolStr` to be directly equated with a `String` or `&str`.
impl<T: Deref<Target = str>> PartialEq<T> for SymbolStr {
fn eq(&self, other: &T) -> bool {
self.string == other.deref()
}
}
/// This impl means that if `ss` is a `SymbolStr`:
/// - `*ss` is a `str`;
/// - `&*ss` is a `&str` (and `match &*ss { ... }` is a common pattern).
/// - `&ss as &str` is a `&str`, which means that `&ss` can be passed to a
/// function expecting a `&str`.
impl Deref for SymbolStr {
type Target = str;
#[inline]
fn deref(&self) -> &str {
self.string
}
}
impl AsRef<str> for SymbolStr {
fn as_ref(&self) -> &str {
self.string
}
}
impl fmt::Debug for SymbolStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.string, f)
}
}
impl fmt::Display for SymbolStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.string, f)
}
}
/// All the globals for a compiler sessions.
pub struct SessionGlobals {
/// The interner for `Symbol`s used in the compiler.
symbol_interner: Interner,
}
impl SessionGlobals {
fn new() -> Self {
Self {
symbol_interner: Interner::prefilled(),
}
}
}
scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals);
/// Creates the session globals and then runs the closure `f`.
#[inline]
pub fn create_session_if_not_set_then<R>(f: impl FnOnce(&SessionGlobals) -> R) -> R {
if !SESSION_GLOBALS.is_set() {
let sg = SessionGlobals::new();
SESSION_GLOBALS.set(&sg, || SESSION_GLOBALS.with(f))
} else {
SESSION_GLOBALS.with(f)
}
}
/// Gives access to read or modify the session globals in `f`.
#[inline]
pub fn with_session_globals<R>(f: impl FnOnce(&SessionGlobals) -> R) -> R {
SESSION_GLOBALS.with(f)
}
/// The inner interner.
/// This construction is used to get interior mutability in `Interner`.
struct InnerInterner {
/// Arena used to allocate the strings, giving us `&'static str`s from it.
arena: DroplessArena,
/// Registration of strings and symbol index allocation is done in this set.
set: IndexSet<&'static str, FxBuildHasher>,
}
/// A symbol-to-string interner.
struct Interner {
inner: RefCell<InnerInterner>,
}
impl Interner {
/// Returns an interner prefilled with commonly used strings in Leo.
fn prefilled() -> Self {
Self::prefill(PRE_DEFINED)
}
/// Returns an interner prefilled with `init`.
fn prefill(init: &[&'static str]) -> Self {
let inner = InnerInterner {
arena: <_>::default(),
set: init.iter().copied().collect(),
};
Self {
inner: RefCell::new(inner),
}
}
/// Interns `string`, returning a `Symbol` corresponding to it.
fn intern(&self, string: &str) -> Symbol {
let InnerInterner { arena, set } = &mut *self.inner.borrow_mut();
if let Some(sym) = set.get_index_of(string) {
// Already internet, return that symbol.
return Symbol::new(sym as u32);
}
// SAFETY: `from_utf8_unchecked` is safe since we just allocated a `&str`,
// which is known to be UTF-8.
let bytes = arena.alloc_slice(string.as_bytes());
let string: &str = unsafe { str::from_utf8_unchecked(bytes) };
unsafe fn transmute_lt<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
transmute(x)
}
// SAFETY: Extending to `'static` is fine. Accesses only happen while the arena is alive.
let string: &'static _ = unsafe { transmute_lt(string) };
Symbol::new(set.insert_full(string).0 as u32)
}
/// Returns the corresponding string for the given symbol.
fn get(&self, symbol: Symbol) -> &str {
self.inner.borrow().set.get_index(symbol.as_u32() as usize).unwrap()
}
}

30
span/src/tendril_json.rs Normal file
View File

@ -0,0 +1,30 @@
// Copyright (C) 2019-2022 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
//! Provides logic for serializing and deserializing the `StrTendril` type.
use serde::{Deserialize, Deserializer, Serializer};
use tendril::StrTendril;
/// Serialization for the StrTendril type.
pub fn serialize<S: Serializer>(tendril: &StrTendril, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&tendril[..])
}
/// Deserialization for the StrTendril type.
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<StrTendril, D::Error> {
Ok(String::deserialize(deserializer)?.into())
}

View File

@ -26,10 +26,6 @@ default-features = false
path = "../errors"
version = "1.5.3"
[dependencies.eyre]
version = "0.6.5"
default-features = false
[dependencies.snarkvm-fields]
git = "https://github.com/AleoHQ/snarkVM.git"
rev = "435f112"
@ -44,6 +40,10 @@ git = "https://github.com/AleoHQ/snarkVM.git"
rev = "435f112"
default-features = false
[dependencies.eyre]
version = "0.6.6"
default-features = false
[dependencies.num-bigint]
version = "0.4"
@ -55,7 +55,7 @@ features = [ "derive" ]
version = "1.0"
[dependencies.sha2]
version = "0.9"
version = "0.10"
[dependencies.hex]
version = "0.4"

View File

@ -17,7 +17,7 @@
use std::{fs, path::Path};
pub fn find_tests<T: AsRef<Path>>(path: T, out: &mut Vec<(String, String)>) {
for entry in fs::read_dir(path).expect("fail to read tests").into_iter() {
for entry in fs::read_dir(path).expect("fail to read tests") {
let entry = entry.expect("fail to read tests").path();
if entry.is_dir() {
find_tests(entry.as_path(), out);