mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-27 12:17:35 +03:00
impl codegen for testnet3
This commit is contained in:
commit
ade332442a
@ -1,29 +0,0 @@
|
||||
{
|
||||
"**/*.rs": [
|
||||
"// 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/>.",
|
||||
""
|
||||
],
|
||||
"ignore": [
|
||||
".cargo",
|
||||
".github",
|
||||
".resources",
|
||||
".travis",
|
||||
"examples",
|
||||
"target/"
|
||||
]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -9,7 +9,6 @@ use_try_shorthand = true
|
||||
|
||||
# Nightly configurations
|
||||
# imports_layout = "HorizontalVertical"
|
||||
# license_template_path = ".resources/license_header"
|
||||
# imports_granularity = "Crate"
|
||||
# overflow_delimited_expr = true
|
||||
# reorder_impl_items = true
|
||||
|
35
Cargo.lock
generated
35
Cargo.lock
generated
@ -387,9 +387,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.5"
|
||||
version = "3.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d53da17d37dba964b9b3ecb5c5a1f193a2762c700e6829201e645b9381c99dc7"
|
||||
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags",
|
||||
@ -404,9 +404,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.5"
|
||||
version = "3.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c11d40217d16aee8508cc8e5fde8b4ff24639758608e5374e731b53f85749fb9"
|
||||
checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro-error",
|
||||
@ -1042,9 +1042,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.0"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c6392766afd7964e2531940894cffe4bd8d7d17dbc3c1c4857040fd4b33bdb3"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
@ -1189,7 +1189,7 @@ dependencies = [
|
||||
"ansi_term",
|
||||
"assert_cmd",
|
||||
"backtrace",
|
||||
"clap 3.2.5",
|
||||
"clap 3.2.8",
|
||||
"color-backtrace",
|
||||
"colored",
|
||||
"console",
|
||||
@ -1214,6 +1214,7 @@ dependencies = [
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"walkdir",
|
||||
"zip",
|
||||
]
|
||||
|
||||
@ -1233,7 +1234,7 @@ dependencies = [
|
||||
name = "leo-parser"
|
||||
version = "1.5.3"
|
||||
dependencies = [
|
||||
"clap 3.2.5",
|
||||
"clap 3.2.8",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"leo-ast",
|
||||
@ -1276,7 +1277,7 @@ name = "leo-test-framework"
|
||||
version = "1.5.3"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"clap 3.2.5",
|
||||
"clap 3.2.8",
|
||||
"criterion",
|
||||
"leo-compiler",
|
||||
"leo-errors",
|
||||
@ -2070,9 +2071,9 @@ checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.137"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||
checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@ -2089,9 +2090,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.137"
|
||||
version = "1.0.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
|
||||
checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.40",
|
||||
"quote 1.0.20",
|
||||
@ -2973,9 +2974,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.27"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7709595b8878a4965ce5e87ebf880a7d39c9afc6837721b21a5a816a8117d921"
|
||||
checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
@ -2994,9 +2995,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.11"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596"
|
||||
checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"sharded-slab",
|
||||
|
@ -62,7 +62,7 @@ rev = "327dd86"
|
||||
version = "0.3.65"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "3.2.1"
|
||||
version = "3.2.8"
|
||||
features = ["derive", "env"]
|
||||
|
||||
[dependencies.color-backtrace]
|
||||
@ -115,7 +115,7 @@ version = "0.5"
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.tracing-subscriber]
|
||||
version = "0.3.11"
|
||||
version = "0.3.14"
|
||||
features = [ "fmt" ]
|
||||
|
||||
[dependencies.zip]
|
||||
@ -133,6 +133,9 @@ version = "0.11.2"
|
||||
[dev-dependencies.test_dir]
|
||||
version = "0.2.0"
|
||||
|
||||
[build-dependencies.walkdir]
|
||||
version = "2"
|
||||
|
||||
[features]
|
||||
default = [ ]
|
||||
ci_skip = [ "leo-compiler/ci_skip" ]
|
||||
|
90
build.rs
Normal file
90
build.rs
Normal file
@ -0,0 +1,90 @@
|
||||
// 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/>.
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufRead, BufReader},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use walkdir::WalkDir;
|
||||
|
||||
// The following license text that should be present at the beginning of every source file.
|
||||
const EXPECTED_LICENSE_TEXT: &str = include_str!(".resources/license_header");
|
||||
|
||||
// The following directories will be excluded from the license scan.
|
||||
const DIRS_TO_SKIP: [&str; 9] = [
|
||||
".cargo",
|
||||
".circleci",
|
||||
".git",
|
||||
".github",
|
||||
".resources",
|
||||
"docs",
|
||||
"examples",
|
||||
"target",
|
||||
"tests",
|
||||
];
|
||||
|
||||
fn compare_license_text(path: &Path, expected_lines: &[&str]) {
|
||||
let file = File::open(path).unwrap();
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
for (i, (file_line, expected_line)) in reader.lines().zip(expected_lines).enumerate() {
|
||||
let file_line = file_line.expect(&format!("Can't read line {} in file \"{}\"!", i + 1, path.display()));
|
||||
|
||||
assert!(
|
||||
&file_line == expected_line,
|
||||
"Line {} in file \"{}\" was expected to contain the license text \"{}\", but contains \"{}\" instead! \
|
||||
Consult the expected license text in \".resources/license_header\"",
|
||||
i + 1,
|
||||
path.display(),
|
||||
expected_line,
|
||||
file_line,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_file_licenses<P: AsRef<Path>>(path: P) {
|
||||
let path = path.as_ref();
|
||||
let license_lines: Vec<_> = EXPECTED_LICENSE_TEXT.lines().collect();
|
||||
|
||||
let mut iter = WalkDir::new(path).into_iter();
|
||||
while let Some(entry) = iter.next() {
|
||||
let entry = entry.unwrap();
|
||||
let entry_type = entry.file_type();
|
||||
|
||||
// Skip the specified directories.
|
||||
if entry_type.is_dir() && DIRS_TO_SKIP.contains(&entry.file_name().to_str().unwrap_or("")) {
|
||||
iter.skip_current_dir();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check all files with the ".rs" extension.
|
||||
if entry_type.is_file() && entry.file_name().to_str().unwrap_or("").ends_with(".rs") {
|
||||
compare_license_text(&entry.path(), &license_lines);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-run upon any changes to the workspace.
|
||||
println!("cargo:rerun-if-changed=.");
|
||||
}
|
||||
|
||||
// The build script; it currently only checks the licenses.
|
||||
fn main() {
|
||||
// Check licenses in the current folder.
|
||||
check_file_licenses(".");
|
||||
}
|
@ -14,27 +14,27 @@
|
||||
// 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::{Expression, Identifier, Node};
|
||||
use crate::{Identifier, Node, Type};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// An access expression to a static member variable, e.g. `Foo::BAR`.
|
||||
/// An access expression to an circuit constant., e.g. `u8::MAX`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct StaticVariableAccess {
|
||||
pub struct AssociatedConstant {
|
||||
/// The inner circuit type.
|
||||
pub inner: Box<Expression>,
|
||||
/// The static circuit member variable that is being accessed.
|
||||
pub ty: Type,
|
||||
/// The circuit constant that is being accessed.
|
||||
pub name: Identifier,
|
||||
/// The span for the entire expression `Foo::bar()`.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for StaticVariableAccess {
|
||||
impl fmt::Display for AssociatedConstant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}::{}", self.inner, self.name)
|
||||
write!(f, "{}::{}", self.ty, self.name)
|
||||
}
|
||||
}
|
||||
|
||||
crate::simple_node_impl!(StaticVariableAccess);
|
||||
crate::simple_node_impl!(AssociatedConstant);
|
@ -14,29 +14,29 @@
|
||||
// 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::{Expression, Identifier, Node};
|
||||
use crate::{Expression, Identifier, Node, Type};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// An access expression to a static function in a circuit, e.g.`Foo::bar()`.
|
||||
/// An access expression to an associated function in a circuit, e.g.`Pedersen64::hash()`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct StaticFunctionAccess {
|
||||
pub struct AssociatedFunction {
|
||||
/// The inner circuit type.
|
||||
pub inner: Box<Expression>,
|
||||
pub ty: Type,
|
||||
/// The static circuit member function that is being accessed.
|
||||
pub name: Identifier,
|
||||
/// The function parameters.
|
||||
pub input: Vec<Expression>,
|
||||
/// The arguments passed to the function `name`.
|
||||
pub args: Vec<Expression>,
|
||||
/// The span for the entire expression `Foo::bar()`.
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for StaticFunctionAccess {
|
||||
impl fmt::Display for AssociatedFunction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}::{}", self.inner, self.name)
|
||||
write!(f, "{}::{}", self.ty, self.name)
|
||||
}
|
||||
}
|
||||
|
||||
crate::simple_node_impl!(StaticFunctionAccess);
|
||||
crate::simple_node_impl!(AssociatedFunction);
|
@ -17,8 +17,8 @@
|
||||
mod member_access;
|
||||
pub use member_access::*;
|
||||
|
||||
mod static_function_access;
|
||||
pub use static_function_access::*;
|
||||
mod associated_function_access;
|
||||
pub use associated_function_access::*;
|
||||
|
||||
mod static_variable_access;
|
||||
pub use static_variable_access::*;
|
||||
mod associated_constant_access;
|
||||
pub use associated_constant_access::*;
|
||||
|
@ -32,6 +32,9 @@ pub struct Circuit {
|
||||
pub identifier: Identifier,
|
||||
/// The fields, constant variables, and functions of this structure.
|
||||
pub members: Vec<CircuitMember>,
|
||||
/// Was this a `record Foo { ... }`?
|
||||
/// If so, it wasn't a circuit.
|
||||
pub is_record: bool,
|
||||
/// The entire span of the circuit definition.
|
||||
pub span: Span,
|
||||
}
|
||||
@ -49,9 +52,18 @@ impl Circuit {
|
||||
pub fn name(&self) -> Symbol {
|
||||
self.identifier.name
|
||||
}
|
||||
}
|
||||
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f, "circuit {} {{ ", self.identifier)?;
|
||||
impl fmt::Debug for Circuit {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
<Self as fmt::Display>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Circuit {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(if self.is_record { "record" } else { "circuit" })?;
|
||||
writeln!(f, " {} {{ ", self.identifier)?;
|
||||
for field in self.members.iter() {
|
||||
writeln!(f, " {}", field)?;
|
||||
}
|
||||
@ -59,16 +71,4 @@ impl Circuit {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Circuit {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Circuit {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.format(f)
|
||||
}
|
||||
}
|
||||
|
||||
crate::simple_node_impl!(Circuit);
|
||||
|
@ -14,7 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Expression, Function, Identifier, Type};
|
||||
use crate::{Identifier, Type};
|
||||
use leo_span::Symbol;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
@ -23,17 +24,18 @@ use std::fmt;
|
||||
/// A member of a circuit definition.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum CircuitMember {
|
||||
/// A static constant in a circuit.
|
||||
/// For example: `const foobar: u8 = 42;`.
|
||||
CircuitConst(
|
||||
/// The identifier of the constant.
|
||||
Identifier,
|
||||
/// The type the constant has.
|
||||
Type,
|
||||
/// The expression representing the constant's value.
|
||||
/// Checked to be of the type above.
|
||||
Expression,
|
||||
),
|
||||
// CAUTION: circuit constants are unstable for Leo testnet3.
|
||||
// /// A static constant in a circuit.
|
||||
// /// For example: `const foobar: u8 = 42;`.
|
||||
// CircuitConst(
|
||||
// /// The identifier of the constant.
|
||||
// Identifier,
|
||||
// /// The type the constant has.
|
||||
// Type,
|
||||
// /// The expression representing the constant's value.
|
||||
// /// Checked to be of the type above.
|
||||
// Expression,
|
||||
// ),
|
||||
/// A variable definition in a circuit;
|
||||
/// For example: `foobar: u8;`.
|
||||
CircuitVariable(
|
||||
@ -42,22 +44,28 @@ pub enum CircuitMember {
|
||||
/// The type the constant has.
|
||||
Type,
|
||||
),
|
||||
/// A function definition in a circuit.
|
||||
/// For example: `function bar() -> u8 { return 2u8; }`.
|
||||
CircuitFunction(
|
||||
/// The function.
|
||||
Box<Function>,
|
||||
),
|
||||
// CAUTION: circuit functions are unstable for Leo testnet3.
|
||||
// /// A function definition in a circuit.
|
||||
// /// For example: `function bar() -> u8 { return 2u8; }`.
|
||||
// CircuitFunction(
|
||||
// /// The function.
|
||||
// Box<Function>,
|
||||
// ),
|
||||
}
|
||||
|
||||
impl CircuitMember {
|
||||
/// Returns the name of the circuit member without span.
|
||||
pub fn name(&self) -> Symbol {
|
||||
match self {
|
||||
CircuitMember::CircuitVariable(ident, _type) => ident.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CircuitMember {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
CircuitMember::CircuitConst(ref identifier, ref type_, ref value) => {
|
||||
write!(f, "{}: {} = {}", identifier, type_, value)
|
||||
}
|
||||
CircuitMember::CircuitVariable(ref identifier, ref type_) => write!(f, "{}: {}", identifier, type_),
|
||||
CircuitMember::CircuitFunction(ref function) => write!(f, "{}", function),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,26 +31,26 @@ pub enum AccessExpression {
|
||||
Member(MemberAccess),
|
||||
// /// Access to a tuple field using its position, e.g., `tuple.1`.
|
||||
// Tuple(TupleAccess),
|
||||
/// Access to a static variable of a circuit.
|
||||
StaticVariable(StaticVariableAccess),
|
||||
/// Access to a static function of a circuit.
|
||||
StaticFunction(StaticFunctionAccess),
|
||||
/// Access to an associated variable of a circuit e.g `u8::MAX`.
|
||||
AssociatedConstant(AssociatedConstant),
|
||||
/// Access to an associated function of a circuit e.g `Pedersen64::hash()`.
|
||||
AssociatedFunction(AssociatedFunction),
|
||||
}
|
||||
|
||||
impl Node for AccessExpression {
|
||||
fn span(&self) -> Span {
|
||||
match self {
|
||||
AccessExpression::Member(n) => n.span(),
|
||||
AccessExpression::StaticVariable(n) => n.span(),
|
||||
AccessExpression::StaticFunction(n) => n.span(),
|
||||
AccessExpression::AssociatedConstant(n) => n.span(),
|
||||
AccessExpression::AssociatedFunction(n) => n.span(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
match self {
|
||||
AccessExpression::Member(n) => n.set_span(span),
|
||||
AccessExpression::StaticVariable(n) => n.set_span(span),
|
||||
AccessExpression::StaticFunction(n) => n.set_span(span),
|
||||
AccessExpression::AssociatedConstant(n) => n.set_span(span),
|
||||
AccessExpression::AssociatedFunction(n) => n.set_span(span),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,8 +64,8 @@ impl fmt::Display for AccessExpression {
|
||||
// ArrayRange(access) => access.fmt(f),
|
||||
Member(access) => access.fmt(f),
|
||||
// Tuple(access) => access.fmt(f),
|
||||
StaticVariable(access) => access.fmt(f),
|
||||
StaticFunction(access) => access.fmt(f),
|
||||
AssociatedConstant(access) => access.fmt(f),
|
||||
AssociatedFunction(access) => access.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,11 +64,11 @@ pub enum BinaryOperation {
|
||||
PowWrapped,
|
||||
/// Shift left operation, i.e. `<<`, `.shl()`.
|
||||
Shl,
|
||||
/// Wrapping shift left operation, i.e. `<<`, `.shl_wrapped()`.
|
||||
/// Wrapping shift left operation, i.e. `.shl_wrapped()`.
|
||||
ShlWrapped,
|
||||
/// Shift right operation, i.e. >>, `.shr()`.
|
||||
Shr,
|
||||
/// Wrapping shift right operation, i.e. >>, `.shr_wrapped()`.
|
||||
/// Wrapping shift right operation, i.e. `.shr_wrapped()`.
|
||||
ShrWrapped,
|
||||
/// Subtraction, i.e. `-`, `.sub()`.
|
||||
Sub,
|
||||
@ -78,6 +78,44 @@ pub enum BinaryOperation {
|
||||
Xor,
|
||||
}
|
||||
|
||||
impl fmt::Display for BinaryOperation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Add => "+",
|
||||
Self::AddWrapped => "add_wrapped",
|
||||
Self::And => "&&",
|
||||
Self::BitwiseAnd => "&",
|
||||
Self::Div => "/",
|
||||
Self::DivWrapped => "div_wrapped",
|
||||
Self::Eq => "==",
|
||||
Self::Gte => ">=",
|
||||
Self::Gt => ">",
|
||||
Self::Lte => "<=",
|
||||
Self::Lt => "<",
|
||||
Self::Mul => "*",
|
||||
Self::MulWrapped => "mul_wrapped",
|
||||
Self::Nand => "NAND",
|
||||
Self::Neq => "!=",
|
||||
Self::Nor => "NOR",
|
||||
Self::Or => "||",
|
||||
Self::BitwiseOr => "|",
|
||||
Self::Pow => "**",
|
||||
Self::PowWrapped => "pow_wrapped",
|
||||
Self::Shl => "<<",
|
||||
Self::ShlWrapped => "shl_wrapped",
|
||||
Self::Shr => ">>",
|
||||
Self::ShrWrapped => "shr_wrapped",
|
||||
Self::Sub => "-",
|
||||
Self::SubWrapped => "sub_wrapped",
|
||||
Self::Xor => "^",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl BinaryOperation {
|
||||
/// Returns a `BinaryOperation` from the given `Symbol`.
|
||||
pub fn from_symbol(symbol: Symbol) -> Option<Self> {
|
||||
@ -110,39 +148,6 @@ impl BinaryOperation {
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Represents the operator as a string.
|
||||
fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Add => "add",
|
||||
Self::AddWrapped => "add_wrapped",
|
||||
Self::And => "&&",
|
||||
Self::BitwiseAnd => "and",
|
||||
Self::Div => "div",
|
||||
Self::DivWrapped => "div_wrapped",
|
||||
Self::Eq => "eq",
|
||||
Self::Gte => "gte",
|
||||
Self::Gt => "gt",
|
||||
Self::Lte => "lte",
|
||||
Self::Lt => "lt",
|
||||
Self::Mul => "mul",
|
||||
Self::MulWrapped => "mul_wrapped",
|
||||
Self::Nand => "nand",
|
||||
Self::Neq => "neq",
|
||||
Self::Nor => "nor",
|
||||
Self::Or => "||",
|
||||
Self::BitwiseOr => "or",
|
||||
Self::Pow => "pow",
|
||||
Self::PowWrapped => "pow_wrapped",
|
||||
Self::Shl => "shl",
|
||||
Self::ShlWrapped => "shl_wrapped",
|
||||
Self::Shr => "shr",
|
||||
Self::ShrWrapped => "shr_wrapped",
|
||||
Self::Sub => "sub",
|
||||
Self::SubWrapped => "sub_wrapped",
|
||||
Self::Xor => "xor",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A binary expression `left op right` of two operands separated by some operator.
|
||||
@ -161,7 +166,7 @@ pub struct BinaryExpression {
|
||||
|
||||
impl fmt::Display for BinaryExpression {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}.{}({})", self.left, self.op.as_str(), self.right)
|
||||
write!(f, "{} {} {}", self.left, self.op, self.right)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{GroupValue, Identifier, IntegerType, Node};
|
||||
use crate::{Identifier, IntegerType, Node};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -49,23 +49,23 @@ pub use value::*;
|
||||
pub enum Expression {
|
||||
/// A circuit access expression, e.g., `Foo.bar`.
|
||||
Access(AccessExpression),
|
||||
/// An identifier expression.
|
||||
Identifier(Identifier),
|
||||
/// A literal expression.
|
||||
Literal(LiteralExpression),
|
||||
/// A binary expression, e.g., `42 + 24`.
|
||||
Binary(BinaryExpression),
|
||||
/// A call expression, e.g., `my_fun(args)`.
|
||||
Call(CallExpression),
|
||||
/// An expression constructing a structure like `Foo { bar: 42, baz }`.
|
||||
/// An expression constructing a circuit like `Foo { bar: 42, baz }`.
|
||||
CircuitInit(CircuitInitExpression),
|
||||
/// An expression of type "error".
|
||||
/// Will result in a compile error eventually.
|
||||
Err(ErrExpression),
|
||||
/// An identifier expression.
|
||||
Identifier(Identifier),
|
||||
/// A ternary conditional expression `cond ? if_expr : else_expr`.
|
||||
Ternary(TernaryExpression),
|
||||
/// An unary expression.
|
||||
Unary(UnaryExpression),
|
||||
/// A literal expression.
|
||||
Value(ValueExpression),
|
||||
}
|
||||
|
||||
impl Node for Expression {
|
||||
@ -73,14 +73,14 @@ impl Node for Expression {
|
||||
use Expression::*;
|
||||
match self {
|
||||
Access(n) => n.span(),
|
||||
Identifier(n) => n.span(),
|
||||
Literal(n) => n.span(),
|
||||
Binary(n) => n.span(),
|
||||
Call(n) => n.span(),
|
||||
CircuitInit(n) => n.span(),
|
||||
Err(n) => n.span(),
|
||||
Identifier(n) => n.span(),
|
||||
Ternary(n) => n.span(),
|
||||
Unary(n) => n.span(),
|
||||
Value(n) => n.span(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,14 +88,14 @@ impl Node for Expression {
|
||||
use Expression::*;
|
||||
match self {
|
||||
Access(n) => n.set_span(span),
|
||||
Identifier(n) => n.set_span(span),
|
||||
Literal(n) => n.set_span(span),
|
||||
Binary(n) => n.set_span(span),
|
||||
Call(n) => n.set_span(span),
|
||||
CircuitInit(n) => n.set_span(span),
|
||||
Err(n) => n.set_span(span),
|
||||
Identifier(n) => n.set_span(span),
|
||||
Ternary(n) => n.set_span(span),
|
||||
Unary(n) => n.set_span(span),
|
||||
Value(n) => n.set_span(span),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,14 +105,14 @@ impl fmt::Display for Expression {
|
||||
use Expression::*;
|
||||
match &self {
|
||||
Access(n) => n.fmt(f),
|
||||
Identifier(n) => n.fmt(f),
|
||||
Literal(n) => n.fmt(f),
|
||||
Binary(n) => n.fmt(f),
|
||||
Call(n) => n.fmt(f),
|
||||
CircuitInit(n) => n.fmt(f),
|
||||
Err(n) => n.fmt(f),
|
||||
Identifier(n) => n.fmt(f),
|
||||
Ternary(n) => n.fmt(f),
|
||||
Unary(n) => n.fmt(f),
|
||||
Value(n) => n.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ impl UnaryOperation {
|
||||
sym::neg => Self::Negate,
|
||||
sym::not => Self::Not,
|
||||
sym::square => Self::Square,
|
||||
sym::sqrt => Self::SquareRoot,
|
||||
sym::square_root => Self::SquareRoot,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
@ -14,22 +14,24 @@
|
||||
// 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::GroupLiteral;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// A literal expression.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ValueExpression {
|
||||
pub enum LiteralExpression {
|
||||
// todo: deserialize values here
|
||||
/// An address literal, e.g., `aleo1qnr4dkkvkgfqph0vzc3y6z2eu975wnpz2925ntjccd5cfqxtyu8s7pyjh9`.
|
||||
Address(String, #[serde(with = "leo_span::span_json")] Span),
|
||||
/// A boolean literal, either `true` or `false`.
|
||||
Boolean(String, #[serde(with = "leo_span::span_json")] Span),
|
||||
Boolean(bool, #[serde(with = "leo_span::span_json")] Span),
|
||||
/// A field literal, e.g., `42field`.
|
||||
/// A signed number followed by the keyword `field`.
|
||||
Field(String, #[serde(with = "leo_span::span_json")] Span),
|
||||
/// A group literal, either product or affine.
|
||||
/// For example, `42group` or `(12, 52)group`.
|
||||
Group(Box<GroupValue>),
|
||||
Group(Box<GroupLiteral>),
|
||||
/// An integer literal, e.g., `42`.
|
||||
Integer(IntegerType, String, #[serde(with = "leo_span::span_json")] Span),
|
||||
/// A scalar literal, e.g. `1scalar`.
|
||||
@ -39,50 +41,47 @@ pub enum ValueExpression {
|
||||
String(String, #[serde(with = "leo_span::span_json")] Span),
|
||||
}
|
||||
|
||||
impl fmt::Display for ValueExpression {
|
||||
impl fmt::Display for LiteralExpression {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use ValueExpression::*;
|
||||
match &self {
|
||||
Address(address, _) => write!(f, "{}", address),
|
||||
Boolean(boolean, _) => write!(f, "{}", boolean),
|
||||
Field(field, _) => write!(f, "{}", field),
|
||||
Group(group) => write!(f, "{}", group),
|
||||
Integer(type_, value, _) => write!(f, "{}{}", value, type_),
|
||||
Scalar(scalar, _) => write!(f, "{}", scalar),
|
||||
String(string, _) => write!(f, "{}", string),
|
||||
Self::Address(address, _) => write!(f, "{}", address),
|
||||
Self::Boolean(boolean, _) => write!(f, "{}", boolean),
|
||||
Self::Field(field, _) => write!(f, "{}", field),
|
||||
Self::Group(group) => write!(f, "{}", group),
|
||||
Self::Integer(type_, value, _) => write!(f, "{}{}", value, type_),
|
||||
Self::Scalar(scalar, _) => write!(f, "{}", scalar),
|
||||
Self::String(string, _) => write!(f, "{}", string),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for ValueExpression {
|
||||
impl Node for LiteralExpression {
|
||||
fn span(&self) -> Span {
|
||||
use ValueExpression::*;
|
||||
match &self {
|
||||
Address(_, span)
|
||||
| Boolean(_, span)
|
||||
| Field(_, span)
|
||||
| Integer(_, _, span)
|
||||
| Scalar(_, span)
|
||||
| String(_, span) => *span,
|
||||
Group(group) => match &**group {
|
||||
GroupValue::Single(_, span) => *span,
|
||||
GroupValue::Tuple(tuple) => tuple.span,
|
||||
Self::Address(_, span)
|
||||
| Self::Boolean(_, span)
|
||||
| Self::Field(_, span)
|
||||
| Self::Integer(_, _, span)
|
||||
| Self::Scalar(_, span)
|
||||
| Self::String(_, span) => *span,
|
||||
Self::Group(group) => match &**group {
|
||||
GroupLiteral::Single(_, span) => *span,
|
||||
GroupLiteral::Tuple(tuple) => tuple.span,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn set_span(&mut self, new_span: Span) {
|
||||
use ValueExpression::*;
|
||||
match self {
|
||||
Address(_, span)
|
||||
| Boolean(_, span)
|
||||
| Field(_, span)
|
||||
| Integer(_, _, span)
|
||||
| Scalar(_, span)
|
||||
| String(_, span) => *span = new_span,
|
||||
Group(group) => match &mut **group {
|
||||
GroupValue::Single(_, span) => *span = new_span,
|
||||
GroupValue::Tuple(tuple) => tuple.span = new_span,
|
||||
Self::Address(_, span)
|
||||
| Self::Boolean(_, span)
|
||||
| Self::Field(_, span)
|
||||
| Self::Integer(_, _, span)
|
||||
| Self::Scalar(_, span)
|
||||
| Self::String(_, span) => *span = new_span,
|
||||
Self::Group(group) => match &mut **group {
|
||||
GroupLiteral::Single(_, span) => *span = new_span,
|
||||
GroupLiteral::Tuple(tuple) => tuple.span = new_span,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -22,34 +22,34 @@ use std::fmt;
|
||||
|
||||
/// A group literal.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum GroupValue {
|
||||
pub enum GroupLiteral {
|
||||
/// Product group literal, e.g., `42group`.
|
||||
Single(String, #[serde(with = "leo_span::span_json")] Span),
|
||||
/// An affine group literal with (x, y) coordinates.
|
||||
Tuple(GroupTuple),
|
||||
}
|
||||
|
||||
impl GroupValue {
|
||||
impl GroupLiteral {
|
||||
pub fn set_span(&mut self, new_span: Span) {
|
||||
match self {
|
||||
GroupValue::Single(_, old_span) => *old_span = new_span,
|
||||
GroupValue::Tuple(tuple) => tuple.span = new_span,
|
||||
Self::Single(_, old_span) => *old_span = new_span,
|
||||
Self::Tuple(tuple) => tuple.span = new_span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> &Span {
|
||||
match self {
|
||||
GroupValue::Single(_, span) => span,
|
||||
GroupValue::Tuple(tuple) => &tuple.span,
|
||||
Self::Single(_, span) => span,
|
||||
Self::Tuple(tuple) => &tuple.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for GroupValue {
|
||||
impl fmt::Display for GroupLiteral {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
GroupValue::Single(string, _) => write!(f, "{}", string),
|
||||
GroupValue::Tuple(tuple) => write!(f, "{}", tuple),
|
||||
Self::Single(string, _) => write!(f, "{}", string),
|
||||
Self::Tuple(tuple) => write!(f, "{}", tuple),
|
||||
}
|
||||
}
|
||||
}
|
@ -17,5 +17,5 @@
|
||||
pub mod group_coordinate;
|
||||
pub use self::group_coordinate::*;
|
||||
|
||||
pub mod group_value;
|
||||
pub use self::group_value::*;
|
||||
pub mod group_literal;
|
||||
pub use self::group_literal::*;
|
||||
|
@ -14,8 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Expression, GroupValue, IntegerType, Node, Type, UnaryOperation, ValueExpression};
|
||||
use leo_errors::{InputError, LeoError, ParserError, Result};
|
||||
use crate::{Expression, GroupLiteral, IntegerType, LiteralExpression, Node, Type, UnaryOperation};
|
||||
use leo_errors::{InputError, LeoError, Result};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
@ -25,7 +25,7 @@ pub enum InputValue {
|
||||
Address(String),
|
||||
Boolean(bool),
|
||||
Field(String),
|
||||
Group(GroupValue),
|
||||
Group(GroupLiteral),
|
||||
Integer(IntegerType, String),
|
||||
}
|
||||
|
||||
@ -33,16 +33,12 @@ impl TryFrom<(Type, Expression)> for InputValue {
|
||||
type Error = LeoError;
|
||||
fn try_from(value: (Type, Expression)) -> Result<Self> {
|
||||
Ok(match value {
|
||||
(type_, Expression::Value(value)) => {
|
||||
match (type_, value) {
|
||||
(Type::Address, ValueExpression::Address(value, _)) => Self::Address(value),
|
||||
(Type::Boolean, ValueExpression::Boolean(value, span)) => {
|
||||
let bool_value = value.parse::<bool>().map_err(|_| ParserError::unexpected_eof(span))?; // TODO: change error
|
||||
Self::Boolean(bool_value)
|
||||
}
|
||||
(Type::Field, ValueExpression::Field(value, _)) => Self::Field(value),
|
||||
(Type::Group, ValueExpression::Group(value)) => Self::Group(*value),
|
||||
(Type::IntegerType(expected), ValueExpression::Integer(actual, value, span)) => {
|
||||
(type_, Expression::Literal(lit)) => match (type_, lit) {
|
||||
(Type::Address, LiteralExpression::Address(value, _)) => Self::Address(value),
|
||||
(Type::Boolean, LiteralExpression::Boolean(value, _)) => Self::Boolean(value),
|
||||
(Type::Field, LiteralExpression::Field(value, _)) => Self::Field(value),
|
||||
(Type::Group, LiteralExpression::Group(value)) => Self::Group(*value),
|
||||
(Type::IntegerType(expected), LiteralExpression::Integer(actual, value, span)) => {
|
||||
if expected == actual {
|
||||
Self::Integer(expected, value)
|
||||
} else {
|
||||
@ -52,8 +48,7 @@ impl TryFrom<(Type, Expression)> for InputValue {
|
||||
(x, y) => {
|
||||
return Err(InputError::unexpected_type(x, &y, y.span()).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
(type_, Expression::Unary(unary)) if unary.op == UnaryOperation::Negate => {
|
||||
InputValue::try_from((type_, *unary.receiver))?
|
||||
}
|
||||
|
@ -19,14 +19,8 @@
|
||||
|
||||
// todo @gluax: Move the files in this module into `leo-passes` in a future PR.
|
||||
|
||||
// pub mod reconstructing_reducer;
|
||||
// pub use reconstructing_reducer::*;
|
||||
//
|
||||
// pub mod reconstructing_director;
|
||||
// pub use reconstructing_director::*;
|
||||
pub mod reconstructor;
|
||||
pub use reconstructor::*;
|
||||
|
||||
pub mod visitor;
|
||||
pub use visitor::*;
|
||||
|
||||
pub mod visitor_director;
|
||||
pub use visitor_director::*;
|
||||
|
@ -1,367 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! This module contains a Director for how to map over the AST
|
||||
//! and applies a reducer call to each node.
|
||||
|
||||
use crate::*;
|
||||
|
||||
use leo_errors::{AstError, Result};
|
||||
use leo_span::Span;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
pub struct ReconstructingDirector<R: ReconstructingReducer> {
|
||||
reducer: R,
|
||||
}
|
||||
|
||||
impl<R: ReconstructingReducer> ReconstructingDirector<R> {
|
||||
pub fn new(reducer: R) -> Self {
|
||||
Self { reducer }
|
||||
}
|
||||
|
||||
pub fn reduce_type(&mut self, type_: &Type, span: &Span) -> Result<Type> {
|
||||
self.reducer.reduce_type(type_, *type_, span)
|
||||
}
|
||||
|
||||
// Expressions
|
||||
pub fn reduce_expression(&mut self, expression: &Expression) -> Result<Expression> {
|
||||
let new = match expression {
|
||||
Expression::Identifier(identifier) => Expression::Identifier(self.reduce_identifier(identifier)?),
|
||||
Expression::Value(value) => self.reduce_value(value)?,
|
||||
Expression::Binary(binary) => Expression::Binary(self.reduce_binary(binary)?),
|
||||
Expression::Unary(unary) => Expression::Unary(self.reduce_unary(unary)?),
|
||||
Expression::Ternary(ternary) => Expression::Ternary(self.reduce_ternary(ternary)?),
|
||||
Expression::Call(call) => Expression::Call(self.reduce_call(call)?),
|
||||
Expression::CircuitInit(circuit_init) => Expression::CircuitInit(self.reduce_circuit_init(circuit_init)?),
|
||||
Expression::Err(s) => Expression::Err(s.clone()),
|
||||
};
|
||||
|
||||
self.reducer.reduce_expression(expression, new)
|
||||
}
|
||||
|
||||
pub fn reduce_identifier(&mut self, identifier: &Identifier) -> Result<Identifier> {
|
||||
self.reducer.reduce_identifier(identifier)
|
||||
}
|
||||
|
||||
pub fn reduce_group_tuple(&mut self, group_tuple: &GroupTuple) -> Result<GroupTuple> {
|
||||
self.reducer.reduce_group_tuple(group_tuple)
|
||||
}
|
||||
|
||||
pub fn reduce_group_value(&mut self, group_value: &GroupValue) -> Result<GroupValue> {
|
||||
let new = match group_value {
|
||||
GroupValue::Tuple(group_tuple) => GroupValue::Tuple(self.reduce_group_tuple(group_tuple)?),
|
||||
_ => group_value.clone(),
|
||||
};
|
||||
|
||||
self.reducer.reduce_group_value(group_value, new)
|
||||
}
|
||||
|
||||
pub fn reduce_string(&mut self, string: &str, span: &Span) -> Result<Expression> {
|
||||
self.reducer.reduce_string(string, span)
|
||||
}
|
||||
|
||||
pub fn reduce_value(&mut self, value: &ValueExpression) -> Result<Expression> {
|
||||
let new = match value {
|
||||
ValueExpression::Group(group_value) => {
|
||||
Expression::Value(ValueExpression::Group(Box::new(self.reduce_group_value(group_value)?)))
|
||||
}
|
||||
ValueExpression::String(string, span) => self.reduce_string(string, span)?,
|
||||
_ => Expression::Value(value.clone()),
|
||||
};
|
||||
|
||||
self.reducer.reduce_value(value, new)
|
||||
}
|
||||
|
||||
pub fn reduce_binary(&mut self, binary: &BinaryExpression) -> Result<BinaryExpression> {
|
||||
let left = self.reduce_expression(&binary.left)?;
|
||||
let right = self.reduce_expression(&binary.right)?;
|
||||
|
||||
self.reducer.reduce_binary(binary, left, right, binary.op)
|
||||
}
|
||||
|
||||
pub fn reduce_unary(&mut self, unary: &UnaryExpression) -> Result<UnaryExpression> {
|
||||
let inner = self.reduce_expression(&unary.receiver)?;
|
||||
|
||||
self.reducer.reduce_unary(unary, inner, unary.op)
|
||||
}
|
||||
|
||||
pub fn reduce_ternary(&mut self, ternary: &TernaryExpression) -> Result<TernaryExpression> {
|
||||
let condition = self.reduce_expression(&ternary.condition)?;
|
||||
let if_true = self.reduce_expression(&ternary.if_true)?;
|
||||
let if_false = self.reduce_expression(&ternary.if_false)?;
|
||||
|
||||
self.reducer.reduce_ternary(ternary, condition, if_true, if_false)
|
||||
}
|
||||
|
||||
pub fn reduce_call(&mut self, call: &CallExpression) -> Result<CallExpression> {
|
||||
let function = self.reduce_expression(&call.function)?;
|
||||
|
||||
let mut arguments = vec![];
|
||||
for argument in call.arguments.iter() {
|
||||
arguments.push(self.reduce_expression(argument)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_call(call, function, arguments)
|
||||
}
|
||||
|
||||
// Statements
|
||||
pub fn reduce_statement(&mut self, statement: &Statement) -> Result<Statement> {
|
||||
let new = match statement {
|
||||
Statement::Return(return_statement) => Statement::Return(self.reduce_return(return_statement)?),
|
||||
Statement::Definition(definition) => Statement::Definition(self.reduce_definition(definition)?),
|
||||
Statement::Assign(assign) => Statement::Assign(Box::new(self.reduce_assign(assign)?)),
|
||||
Statement::Conditional(conditional) => Statement::Conditional(self.reduce_conditional(conditional)?),
|
||||
Statement::Iteration(iteration) => Statement::Iteration(Box::new(self.reduce_iteration(iteration)?)),
|
||||
Statement::Console(console) => Statement::Console(self.reduce_console(console)?),
|
||||
Statement::Block(block) => Statement::Block(self.reduce_block(block)?),
|
||||
};
|
||||
|
||||
self.reducer.reduce_statement(statement, new)
|
||||
}
|
||||
|
||||
pub fn reduce_return(&mut self, return_statement: &ReturnStatement) -> Result<ReturnStatement> {
|
||||
let expression = self.reduce_expression(&return_statement.expression)?;
|
||||
|
||||
self.reducer.reduce_return(return_statement, expression)
|
||||
}
|
||||
|
||||
pub fn reduce_variable_name(&mut self, variable_name: &VariableName) -> Result<VariableName> {
|
||||
let identifier = self.reduce_identifier(&variable_name.identifier)?;
|
||||
|
||||
self.reducer.reduce_variable_name(variable_name, identifier)
|
||||
}
|
||||
|
||||
pub fn reduce_definition(&mut self, definition: &DefinitionStatement) -> Result<DefinitionStatement> {
|
||||
let mut variable_names = vec![];
|
||||
for variable_name in definition.variable_names.iter() {
|
||||
variable_names.push(self.reduce_variable_name(variable_name)?);
|
||||
}
|
||||
|
||||
let type_ = self.reduce_type(&definition.type_, &definition.span)?;
|
||||
|
||||
let value = self.reduce_expression(&definition.value)?;
|
||||
|
||||
self.reducer.reduce_definition(definition, variable_names, type_, value)
|
||||
}
|
||||
|
||||
pub fn reduce_assignee_access(&mut self, access: &AssigneeAccess) -> Result<AssigneeAccess> {
|
||||
let new = match access {
|
||||
AssigneeAccess::ArrayRange(left, right) => {
|
||||
let left = left.as_ref().map(|left| self.reduce_expression(left)).transpose()?;
|
||||
let right = right.as_ref().map(|right| self.reduce_expression(right)).transpose()?;
|
||||
|
||||
AssigneeAccess::ArrayRange(left, right)
|
||||
}
|
||||
AssigneeAccess::ArrayIndex(index) => AssigneeAccess::ArrayIndex(self.reduce_expression(index)?),
|
||||
AssigneeAccess::Member(identifier) => AssigneeAccess::Member(self.reduce_identifier(identifier)?),
|
||||
_ => access.clone(),
|
||||
};
|
||||
|
||||
self.reducer.reduce_assignee_access(access, new)
|
||||
}
|
||||
|
||||
pub fn reduce_assignee(&mut self, assignee: &Assignee) -> Result<Assignee> {
|
||||
let identifier = self.reduce_identifier(&assignee.identifier)?;
|
||||
|
||||
let mut accesses = vec![];
|
||||
for access in assignee.accesses.iter() {
|
||||
accesses.push(self.reduce_assignee_access(access)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_assignee(assignee, identifier, accesses)
|
||||
}
|
||||
|
||||
pub fn reduce_assign(&mut self, assign: &AssignStatement) -> Result<AssignStatement> {
|
||||
let assignee = self.reduce_assignee(&assign.assignee)?;
|
||||
let value = self.reduce_expression(&assign.value)?;
|
||||
|
||||
self.reducer.reduce_assign(assign, assignee, value)
|
||||
}
|
||||
|
||||
pub fn reduce_conditional(&mut self, conditional: &ConditionalStatement) -> Result<ConditionalStatement> {
|
||||
let condition = self.reduce_expression(&conditional.condition)?;
|
||||
let block = self.reduce_block(&conditional.block)?;
|
||||
let next = conditional
|
||||
.next
|
||||
.as_ref()
|
||||
.map(|condition| self.reduce_statement(condition))
|
||||
.transpose()?;
|
||||
|
||||
self.reducer.reduce_conditional(conditional, condition, block, next)
|
||||
}
|
||||
|
||||
pub fn reduce_iteration(&mut self, iteration: &IterationStatement) -> Result<IterationStatement> {
|
||||
let variable = self.reduce_identifier(&iteration.variable)?;
|
||||
let type_ = self.reduce_type(&iteration.type_, &iteration.span())?;
|
||||
let start = self.reduce_expression(&iteration.start)?;
|
||||
let stop = self.reduce_expression(&iteration.stop)?;
|
||||
let block = self.reduce_block(&iteration.block)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_iteration(iteration, variable, type_, start, stop, block)
|
||||
}
|
||||
|
||||
pub fn reduce_console(&mut self, console_function_call: &ConsoleStatement) -> Result<ConsoleStatement> {
|
||||
let function = match &console_function_call.function {
|
||||
ConsoleFunction::Assert(expression) => ConsoleFunction::Assert(self.reduce_expression(expression)?),
|
||||
ConsoleFunction::Error(args) | ConsoleFunction::Log(args) => {
|
||||
let mut parameters = vec![];
|
||||
for parameter in args.parameters.iter() {
|
||||
parameters.push(self.reduce_expression(parameter)?);
|
||||
}
|
||||
|
||||
let formatted = ConsoleArgs {
|
||||
string: args.string.clone(),
|
||||
parameters,
|
||||
span: args.span,
|
||||
};
|
||||
|
||||
match &console_function_call.function {
|
||||
ConsoleFunction::Error(_) => ConsoleFunction::Error(formatted),
|
||||
ConsoleFunction::Log(_) => ConsoleFunction::Log(formatted),
|
||||
_ => return Err(AstError::impossible_console_assert_call(args.span).into()),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.reducer.reduce_console(console_function_call, function)
|
||||
}
|
||||
|
||||
pub fn reduce_block(&mut self, block: &Block) -> Result<Block> {
|
||||
let mut statements = vec![];
|
||||
for statement in block.statements.iter() {
|
||||
statements.push(self.reduce_statement(statement)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_block(block, statements)
|
||||
}
|
||||
|
||||
// Program
|
||||
pub fn reduce_program(&mut self, program: &Program) -> Result<Program> {
|
||||
let mut inputs = vec![];
|
||||
for input in program.expected_input.iter() {
|
||||
inputs.push(self.reduce_function_input(input)?);
|
||||
}
|
||||
|
||||
let mut functions = IndexMap::new();
|
||||
let mut circuits = IndexMap::new();
|
||||
for (name, function) in program.functions.iter() {
|
||||
functions.insert(*name, self.reduce_function(function)?);
|
||||
}
|
||||
for (name, circuit) in program.circuits.iter() {
|
||||
circuits.insert(*name, self.reduce_circuit(circuit)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_program(program, inputs, functions, circuits)
|
||||
}
|
||||
|
||||
// Functions
|
||||
|
||||
pub fn reduce_function_input_variable(
|
||||
&mut self,
|
||||
variable: &FunctionInputVariable,
|
||||
) -> Result<FunctionInputVariable> {
|
||||
let identifier = self.reduce_identifier(&variable.identifier)?;
|
||||
let type_ = self.reduce_type(&variable.type_, &variable.span)?;
|
||||
|
||||
self.reducer.reduce_function_input_variable(variable, identifier, type_)
|
||||
}
|
||||
|
||||
pub fn reduce_function_input(&mut self, input: &FunctionInput) -> Result<FunctionInput> {
|
||||
let new = match input {
|
||||
FunctionInput::Variable(function_input_variable) => {
|
||||
FunctionInput::Variable(self.reduce_function_input_variable(function_input_variable)?)
|
||||
}
|
||||
};
|
||||
|
||||
self.reducer.reduce_function_input(input, new)
|
||||
}
|
||||
|
||||
pub fn reduce_function(&mut self, function: &Function) -> Result<Function> {
|
||||
let identifier = self.reduce_identifier(&function.identifier)?;
|
||||
|
||||
let mut inputs = vec![];
|
||||
for input in function.input.iter() {
|
||||
inputs.push(self.reduce_function_input(input)?);
|
||||
}
|
||||
|
||||
let output = self.reduce_type(&function.output, &function.span)?;
|
||||
|
||||
let block = self.reduce_block(&function.block)?;
|
||||
|
||||
self.reducer
|
||||
.reduce_function(function, identifier, inputs, output, block)
|
||||
}
|
||||
|
||||
// Circuits
|
||||
|
||||
pub fn reduce_circuit_variable_initializer(
|
||||
&mut self,
|
||||
variable: &CircuitVariableInitializer,
|
||||
) -> Result<CircuitVariableInitializer> {
|
||||
let identifier = self.reduce_identifier(&variable.identifier)?;
|
||||
let expression = variable
|
||||
.expression
|
||||
.as_ref()
|
||||
.map(|expr| self.reduce_expression(expr))
|
||||
.transpose()?;
|
||||
|
||||
self.reducer
|
||||
.reduce_circuit_variable_initializer(variable, identifier, expression)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit_init(&mut self, circuit_init: &CircuitInitExpression) -> Result<CircuitInitExpression> {
|
||||
let name = self.reduce_identifier(&circuit_init.name)?;
|
||||
|
||||
let mut members = vec![];
|
||||
for member in circuit_init.members.iter() {
|
||||
members.push(self.reduce_circuit_variable_initializer(member)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_circuit_init(circuit_init, name, members)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit_member(&mut self, circuit_member: &CircuitMember) -> Result<CircuitMember> {
|
||||
let new = match circuit_member {
|
||||
CircuitMember::CircuitConst(identifier, type_, value) => CircuitMember::CircuitConst(
|
||||
self.reduce_identifier(identifier)?,
|
||||
self.reduce_type(type_, &identifier.span)?,
|
||||
self.reduce_expression(value)?,
|
||||
),
|
||||
CircuitMember::CircuitVariable(identifier, type_) => CircuitMember::CircuitVariable(
|
||||
self.reduce_identifier(identifier)?,
|
||||
self.reduce_type(type_, &identifier.span)?,
|
||||
),
|
||||
CircuitMember::CircuitFunction(function) => {
|
||||
CircuitMember::CircuitFunction(Box::new(self.reduce_function(function)?))
|
||||
}
|
||||
};
|
||||
|
||||
self.reducer.reduce_circuit_member(circuit_member, new)
|
||||
}
|
||||
|
||||
pub fn reduce_circuit(&mut self, circuit: &Circuit) -> Result<Circuit> {
|
||||
let circuit_name = self.reduce_identifier(&circuit.identifier)?;
|
||||
|
||||
let mut members = vec![];
|
||||
for member in circuit.members.iter() {
|
||||
members.push(self.reduce_circuit_member(member)?);
|
||||
}
|
||||
|
||||
self.reducer.reduce_circuit(circuit, circuit_name, members)
|
||||
}
|
||||
}
|
@ -1,334 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! This module contains a Reducer Trait for the AST.
|
||||
//! It implements default methods for each node to be made
|
||||
//! given the information of the old node.
|
||||
|
||||
use crate::*;
|
||||
|
||||
use leo_errors::Result;
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
// Needed to fix clippy bug.
|
||||
#[allow(clippy::redundant_closure)]
|
||||
pub trait ReconstructingReducer {
|
||||
fn in_circuit(&self) -> bool;
|
||||
fn swap_in_circuit(&mut self);
|
||||
|
||||
fn reduce_type(&mut self, _type_: &Type, new: Type, _span: &Span) -> Result<Type> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
// Expressions
|
||||
fn reduce_expression(&mut self, _expression: &Expression, new: Expression) -> Result<Expression> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_identifier(&mut self, identifier: &Identifier) -> Result<Identifier> {
|
||||
Ok(Identifier {
|
||||
name: identifier.name,
|
||||
span: identifier.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_group_tuple(&mut self, group_tuple: &GroupTuple) -> Result<GroupTuple> {
|
||||
Ok(GroupTuple {
|
||||
x: group_tuple.x.clone(),
|
||||
y: group_tuple.y.clone(),
|
||||
span: group_tuple.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_group_value(&mut self, _group_value: &GroupValue, new: GroupValue) -> Result<GroupValue> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_string(&mut self, string: &str, span: &Span) -> Result<Expression> {
|
||||
Ok(Expression::Value(ValueExpression::String(string.to_string(), *span)))
|
||||
}
|
||||
|
||||
fn reduce_value(&mut self, _value: &ValueExpression, new: Expression) -> Result<Expression> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_binary(
|
||||
&mut self,
|
||||
binary: &BinaryExpression,
|
||||
left: Expression,
|
||||
right: Expression,
|
||||
op: BinaryOperation,
|
||||
) -> Result<BinaryExpression> {
|
||||
Ok(BinaryExpression {
|
||||
left: Box::new(left),
|
||||
right: Box::new(right),
|
||||
op,
|
||||
span: binary.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_unary(
|
||||
&mut self,
|
||||
unary: &UnaryExpression,
|
||||
inner: Expression,
|
||||
op: UnaryOperation,
|
||||
) -> Result<UnaryExpression> {
|
||||
Ok(UnaryExpression {
|
||||
receiver: Box::new(inner),
|
||||
op,
|
||||
span: unary.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_ternary(
|
||||
&mut self,
|
||||
ternary: &TernaryExpression,
|
||||
condition: Expression,
|
||||
if_true: Expression,
|
||||
if_false: Expression,
|
||||
) -> Result<TernaryExpression> {
|
||||
Ok(TernaryExpression {
|
||||
condition: Box::new(condition),
|
||||
if_true: Box::new(if_true),
|
||||
if_false: Box::new(if_false),
|
||||
span: ternary.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_call(
|
||||
&mut self,
|
||||
call: &CallExpression,
|
||||
function: Expression,
|
||||
arguments: Vec<Expression>,
|
||||
) -> Result<CallExpression> {
|
||||
Ok(CallExpression {
|
||||
function: Box::new(function),
|
||||
arguments,
|
||||
span: call.span,
|
||||
})
|
||||
}
|
||||
|
||||
// Statements
|
||||
fn reduce_statement(&mut self, _statement: &Statement, new: Statement) -> Result<Statement> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_return(&mut self, return_statement: &ReturnStatement, expression: Expression) -> Result<ReturnStatement> {
|
||||
Ok(ReturnStatement {
|
||||
expression,
|
||||
span: return_statement.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_variable_name(&mut self, variable_name: &VariableName, identifier: Identifier) -> Result<VariableName> {
|
||||
Ok(VariableName {
|
||||
mutable: variable_name.mutable,
|
||||
identifier,
|
||||
span: variable_name.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_definition(
|
||||
&mut self,
|
||||
definition: &DefinitionStatement,
|
||||
variable_names: Vec<VariableName>,
|
||||
type_: Type,
|
||||
value: Expression,
|
||||
) -> Result<DefinitionStatement> {
|
||||
Ok(DefinitionStatement {
|
||||
declaration_type: definition.declaration_type,
|
||||
variable_names,
|
||||
type_,
|
||||
value,
|
||||
span: definition.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_assignee_access(&mut self, _access: &AssigneeAccess, new: AssigneeAccess) -> Result<AssigneeAccess> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_assignee(
|
||||
&mut self,
|
||||
assignee: &Assignee,
|
||||
identifier: Identifier,
|
||||
accesses: Vec<AssigneeAccess>,
|
||||
) -> Result<Assignee> {
|
||||
Ok(Assignee {
|
||||
identifier,
|
||||
accesses,
|
||||
span: assignee.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_assign(
|
||||
&mut self,
|
||||
assign: &AssignStatement,
|
||||
assignee: Assignee,
|
||||
value: Expression,
|
||||
) -> Result<AssignStatement> {
|
||||
Ok(AssignStatement {
|
||||
operation: assign.operation,
|
||||
assignee,
|
||||
value,
|
||||
span: assign.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_conditional(
|
||||
&mut self,
|
||||
conditional: &ConditionalStatement,
|
||||
condition: Expression,
|
||||
block: Block,
|
||||
statement: Option<Statement>,
|
||||
) -> Result<ConditionalStatement> {
|
||||
Ok(ConditionalStatement {
|
||||
condition,
|
||||
block,
|
||||
next: statement.map(|statement| Box::new(statement)),
|
||||
span: conditional.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_iteration(
|
||||
&mut self,
|
||||
iteration: &IterationStatement,
|
||||
variable: Identifier,
|
||||
type_: Type,
|
||||
start: Expression,
|
||||
stop: Expression,
|
||||
block: Block,
|
||||
) -> Result<IterationStatement> {
|
||||
Ok(IterationStatement {
|
||||
variable,
|
||||
type_,
|
||||
start,
|
||||
stop,
|
||||
inclusive: iteration.inclusive,
|
||||
block,
|
||||
span: iteration.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_console(&mut self, console: &ConsoleStatement, function: ConsoleFunction) -> Result<ConsoleStatement> {
|
||||
Ok(ConsoleStatement {
|
||||
function,
|
||||
span: console.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_block(&mut self, block: &Block, statements: Vec<Statement>) -> Result<Block> {
|
||||
Ok(Block {
|
||||
statements,
|
||||
span: block.span,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
// Program
|
||||
fn reduce_program(
|
||||
&mut self,
|
||||
program: &Program,
|
||||
expected_input: Vec<FunctionInput>,
|
||||
functions: IndexMap<Identifier, Function>,
|
||||
circuits: IndexMap<Identifier, Circuit>,
|
||||
) -> Result<Program> {
|
||||
Ok(Program {
|
||||
name: program.name.clone(),
|
||||
expected_input,
|
||||
functions,
|
||||
circuits,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_function_input_variable(
|
||||
&mut self,
|
||||
variable: &FunctionInputVariable,
|
||||
identifier: Identifier,
|
||||
type_: Type,
|
||||
) -> Result<FunctionInputVariable> {
|
||||
Ok(FunctionInputVariable::new(
|
||||
identifier,
|
||||
variable.mode(),
|
||||
type_,
|
||||
variable.span,
|
||||
))
|
||||
}
|
||||
|
||||
fn reduce_function_input(&mut self, _input: &FunctionInput, new: FunctionInput) -> Result<FunctionInput> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_import(&mut self, identifier: Vec<Symbol>, import: Program) -> Result<(Vec<Symbol>, Program)> {
|
||||
Ok((identifier, import))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn reduce_function(
|
||||
&mut self,
|
||||
function: &Function,
|
||||
identifier: Identifier,
|
||||
input: Vec<FunctionInput>,
|
||||
output: Type,
|
||||
block: Block,
|
||||
) -> Result<Function> {
|
||||
Ok(Function {
|
||||
identifier,
|
||||
input,
|
||||
output,
|
||||
block,
|
||||
core_mapping: function.core_mapping.clone(),
|
||||
span: function.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_circuit_variable_initializer(
|
||||
&mut self,
|
||||
_variable: &CircuitVariableInitializer,
|
||||
identifier: Identifier,
|
||||
expression: Option<Expression>,
|
||||
) -> Result<CircuitVariableInitializer> {
|
||||
Ok(CircuitVariableInitializer { identifier, expression })
|
||||
}
|
||||
|
||||
fn reduce_circuit_init(
|
||||
&mut self,
|
||||
circuit_init: &CircuitInitExpression,
|
||||
name: Identifier,
|
||||
members: Vec<CircuitVariableInitializer>,
|
||||
) -> Result<CircuitInitExpression> {
|
||||
Ok(CircuitInitExpression {
|
||||
name,
|
||||
members,
|
||||
span: circuit_init.span.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn reduce_circuit_member(&mut self, _circuit_member: &CircuitMember, new: CircuitMember) -> Result<CircuitMember> {
|
||||
Ok(new)
|
||||
}
|
||||
|
||||
fn reduce_circuit(
|
||||
&mut self,
|
||||
circuit: &Circuit,
|
||||
circuit_name: Identifier,
|
||||
members: Vec<CircuitMember>,
|
||||
) -> Result<Circuit> {
|
||||
Ok(Circuit { identifier: circuit_name, members, span: circuit.span.clone() })
|
||||
}
|
||||
}
|
245
compiler/ast/src/passes/reconstructor.rs
Normal file
245
compiler/ast/src/passes/reconstructor.rs
Normal file
@ -0,0 +1,245 @@
|
||||
// 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/>.
|
||||
|
||||
//! This module contains a Reconstructor trait for the AST.
|
||||
//! It implements default methods for each node to be made
|
||||
//! given the information of the old node.
|
||||
|
||||
use crate::*;
|
||||
|
||||
/// A Reconstructor trait for expressions in the AST.
|
||||
pub trait ExpressionReconstructor {
|
||||
type AdditionalOutput: Default;
|
||||
|
||||
fn reconstruct_expression(&mut self, input: Expression) -> (Expression, Self::AdditionalOutput) {
|
||||
match input {
|
||||
Expression::Access(access) => self.reconstruct_access(access),
|
||||
Expression::Identifier(identifier) => self.reconstruct_identifier(identifier),
|
||||
Expression::Literal(value) => self.reconstruct_literal(value),
|
||||
Expression::Binary(binary) => self.reconstruct_binary(binary),
|
||||
Expression::Call(call) => self.reconstruct_call(call),
|
||||
Expression::CircuitInit(circuit) => self.reconstruct_circuit_init(circuit),
|
||||
Expression::Unary(unary) => self.reconstruct_unary(unary),
|
||||
Expression::Ternary(ternary) => self.reconstruct_ternary(ternary),
|
||||
Expression::Err(err) => self.reconstruct_err(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) {
|
||||
(Expression::Identifier(input), Default::default())
|
||||
}
|
||||
|
||||
fn reconstruct_literal(&mut self, input: LiteralExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(Expression::Literal(input), Default::default())
|
||||
}
|
||||
|
||||
fn reconstruct_access(&mut self, input: AccessExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(Expression::Access(input), Default::default())
|
||||
}
|
||||
|
||||
fn reconstruct_circuit_init(&mut self, input: CircuitInitExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(Expression::CircuitInit(input), Default::default())
|
||||
}
|
||||
|
||||
fn reconstruct_binary(&mut self, input: BinaryExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(
|
||||
Expression::Binary(BinaryExpression {
|
||||
left: Box::new(self.reconstruct_expression(*input.left).0),
|
||||
right: Box::new(self.reconstruct_expression(*input.right).0),
|
||||
op: input.op,
|
||||
span: input.span,
|
||||
}),
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn reconstruct_unary(&mut self, input: UnaryExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(
|
||||
Expression::Unary(UnaryExpression {
|
||||
receiver: Box::new(self.reconstruct_expression(*input.receiver).0),
|
||||
op: input.op,
|
||||
span: input.span,
|
||||
}),
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn reconstruct_ternary(&mut self, input: TernaryExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(
|
||||
Expression::Ternary(TernaryExpression {
|
||||
condition: Box::new(self.reconstruct_expression(*input.condition).0),
|
||||
if_true: Box::new(self.reconstruct_expression(*input.if_true).0),
|
||||
if_false: Box::new(self.reconstruct_expression(*input.if_false).0),
|
||||
span: input.span,
|
||||
}),
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn reconstruct_call(&mut self, input: CallExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(
|
||||
Expression::Call(CallExpression {
|
||||
function: Box::new(self.reconstruct_expression(*input.function).0),
|
||||
arguments: input
|
||||
.arguments
|
||||
.into_iter()
|
||||
.map(|arg| self.reconstruct_expression(arg).0)
|
||||
.collect(),
|
||||
span: input.span,
|
||||
}),
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
|
||||
fn reconstruct_err(&mut self, input: ErrExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(Expression::Err(input), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
/// A Reconstructor trait for statements in the AST.
|
||||
pub trait StatementReconstructor: ExpressionReconstructor {
|
||||
fn reconstruct_statement(&mut self, input: Statement) -> Statement {
|
||||
match input {
|
||||
Statement::Return(stmt) => self.reconstruct_return(stmt),
|
||||
Statement::Definition(stmt) => self.reconstruct_definition(stmt),
|
||||
Statement::Assign(stmt) => self.reconstruct_assign(*stmt),
|
||||
Statement::Conditional(stmt) => self.reconstruct_conditional(stmt),
|
||||
Statement::Iteration(stmt) => self.reconstruct_iteration(*stmt),
|
||||
Statement::Console(stmt) => self.reconstruct_console(stmt),
|
||||
Statement::Block(stmt) => Statement::Block(self.reconstruct_block(stmt)),
|
||||
}
|
||||
}
|
||||
|
||||
fn reconstruct_return(&mut self, input: ReturnStatement) -> Statement {
|
||||
Statement::Return(ReturnStatement {
|
||||
expression: self.reconstruct_expression(input.expression).0,
|
||||
span: input.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reconstruct_definition(&mut self, input: DefinitionStatement) -> Statement {
|
||||
Statement::Definition(DefinitionStatement {
|
||||
declaration_type: input.declaration_type,
|
||||
variable_names: input.variable_names.clone(),
|
||||
type_: input.type_,
|
||||
value: self.reconstruct_expression(input.value).0,
|
||||
span: input.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reconstruct_assign(&mut self, input: AssignStatement) -> Statement {
|
||||
Statement::Assign(Box::new(AssignStatement {
|
||||
operation: input.operation,
|
||||
place: input.place,
|
||||
value: self.reconstruct_expression(input.value).0,
|
||||
span: input.span,
|
||||
}))
|
||||
}
|
||||
|
||||
fn reconstruct_conditional(&mut self, input: ConditionalStatement) -> Statement {
|
||||
Statement::Conditional(ConditionalStatement {
|
||||
condition: self.reconstruct_expression(input.condition).0,
|
||||
block: self.reconstruct_block(input.block),
|
||||
next: input.next.map(|n| Box::new(self.reconstruct_statement(*n))),
|
||||
span: input.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reconstruct_iteration(&mut self, input: IterationStatement) -> Statement {
|
||||
Statement::Iteration(Box::new(IterationStatement {
|
||||
variable: input.variable,
|
||||
type_: input.type_,
|
||||
start: self.reconstruct_expression(input.start).0,
|
||||
stop: self.reconstruct_expression(input.stop).0,
|
||||
block: self.reconstruct_block(input.block),
|
||||
inclusive: input.inclusive,
|
||||
span: input.span,
|
||||
}))
|
||||
}
|
||||
|
||||
fn reconstruct_console(&mut self, input: ConsoleStatement) -> Statement {
|
||||
Statement::Console(ConsoleStatement {
|
||||
function: match input.function {
|
||||
ConsoleFunction::Assert(expr) => ConsoleFunction::Assert(self.reconstruct_expression(expr).0),
|
||||
ConsoleFunction::Error(fmt) => ConsoleFunction::Error(ConsoleArgs {
|
||||
string: fmt.string,
|
||||
parameters: fmt
|
||||
.parameters
|
||||
.into_iter()
|
||||
.map(|p| self.reconstruct_expression(p).0)
|
||||
.collect(),
|
||||
span: fmt.span,
|
||||
}),
|
||||
ConsoleFunction::Log(fmt) => ConsoleFunction::Log(ConsoleArgs {
|
||||
string: fmt.string,
|
||||
parameters: fmt
|
||||
.parameters
|
||||
.into_iter()
|
||||
.map(|p| self.reconstruct_expression(p).0)
|
||||
.collect(),
|
||||
span: fmt.span,
|
||||
}),
|
||||
},
|
||||
span: input.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn reconstruct_block(&mut self, input: Block) -> Block {
|
||||
Block {
|
||||
statements: input
|
||||
.statements
|
||||
.into_iter()
|
||||
.map(|s| self.reconstruct_statement(s))
|
||||
.collect(),
|
||||
span: input.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A Reconstructor trait for the program represented by the AST.
|
||||
pub trait ProgramReconstructor: StatementReconstructor {
|
||||
fn reconstruct_program(&mut self, input: Program) -> Program {
|
||||
Program {
|
||||
name: input.name,
|
||||
expected_input: input.expected_input,
|
||||
functions: input
|
||||
.functions
|
||||
.into_iter()
|
||||
.map(|(i, f)| (i, self.reconstruct_function(f)))
|
||||
.collect(),
|
||||
circuits: input
|
||||
.circuits
|
||||
.into_iter()
|
||||
.map(|(i, c)| (i, self.reconstruct_circuit(c)))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn reconstruct_function(&mut self, input: Function) -> Function {
|
||||
Function {
|
||||
identifier: input.identifier,
|
||||
input: input.input,
|
||||
output: input.output,
|
||||
core_mapping: input.core_mapping,
|
||||
block: self.reconstruct_block(input.block),
|
||||
span: input.span,
|
||||
}
|
||||
}
|
||||
|
||||
fn reconstruct_circuit(&mut self, input: Circuit) -> Circuit {
|
||||
input
|
||||
}
|
||||
}
|
@ -14,107 +14,156 @@
|
||||
// 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/>.
|
||||
|
||||
//! This module contains Visitor traits for the AST.
|
||||
//! This module contains Visitor trait implementations for the AST.
|
||||
//! It implements default methods for each node to be made
|
||||
//! given the type of node its visiting.
|
||||
|
||||
use crate::*;
|
||||
|
||||
pub enum VisitResult {
|
||||
VisitChildren,
|
||||
SkipChildren,
|
||||
}
|
||||
|
||||
impl Default for VisitResult {
|
||||
fn default() -> Self {
|
||||
VisitResult::VisitChildren
|
||||
}
|
||||
}
|
||||
|
||||
/// A Visitor trait for expressions in the AST.
|
||||
pub trait ExpressionVisitor<'a> {
|
||||
fn visit_expression(&mut self, _input: &'a Expression) -> VisitResult {
|
||||
type AdditionalInput: Default;
|
||||
type Output: Default;
|
||||
|
||||
fn visit_expression(&mut self, input: &'a Expression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||
match input {
|
||||
Expression::Access(expr) => self.visit_access(expr, additional),
|
||||
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, additional),
|
||||
Expression::Identifier(expr) => self.visit_identifier(expr, additional),
|
||||
Expression::Literal(expr) => self.visit_literal(expr, additional),
|
||||
Expression::Binary(expr) => self.visit_binary(expr, additional),
|
||||
Expression::Unary(expr) => self.visit_unary(expr, additional),
|
||||
Expression::Ternary(expr) => self.visit_ternary(expr, additional),
|
||||
Expression::Call(expr) => self.visit_call(expr, additional),
|
||||
Expression::Err(expr) => self.visit_err(expr, additional),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_access(&mut self, _input: &'a AccessExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_access(&mut self, _input: &'a AccessExpression) -> VisitResult {
|
||||
fn visit_circuit_init(
|
||||
&mut self,
|
||||
_input: &'a CircuitInitExpression,
|
||||
_additional: &Self::AdditionalInput,
|
||||
) -> Self::Output {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_binary(&mut self, _input: &'a BinaryExpression) -> VisitResult {
|
||||
fn visit_identifier(&mut self, _input: &'a Identifier, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_call(&mut self, _input: &'a CallExpression) -> VisitResult {
|
||||
fn visit_literal(&mut self, _input: &'a LiteralExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_circuit_init(&mut self, _input: &'a CircuitInitExpression) -> VisitResult {
|
||||
fn visit_binary(&mut self, input: &'a BinaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||
self.visit_expression(&input.left, additional);
|
||||
self.visit_expression(&input.right, additional);
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_err(&mut self, _input: &'a ErrExpression) -> VisitResult {
|
||||
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||
self.visit_expression(&input.receiver, additional);
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_identifier(&mut self, _input: &'a Identifier) -> VisitResult {
|
||||
fn visit_ternary(&mut self, input: &'a TernaryExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||
self.visit_expression(&input.condition, additional);
|
||||
self.visit_expression(&input.if_true, additional);
|
||||
self.visit_expression(&input.if_false, additional);
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_ternary(&mut self, _input: &'a TernaryExpression) -> VisitResult {
|
||||
fn visit_call(&mut self, input: &'a CallExpression, additional: &Self::AdditionalInput) -> Self::Output {
|
||||
input.arguments.iter().for_each(|expr| {
|
||||
self.visit_expression(expr, additional);
|
||||
});
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_unary(&mut self, _input: &'a UnaryExpression) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_value(&mut self, _input: &'a ValueExpression) -> VisitResult {
|
||||
fn visit_err(&mut self, _input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Self::Output {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StatementVisitor<'a> {
|
||||
fn visit_statement(&mut self, _input: &'a Statement) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_return(&mut self, _input: &'a ReturnStatement) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_definition(&mut self, _input: &'a DefinitionStatement) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_assign(&mut self, _input: &'a AssignStatement) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_conditional(&mut self, _input: &'a ConditionalStatement) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_iteration(&mut self, _input: &'a IterationStatement) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_console(&mut self, _input: &'a ConsoleStatement) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, _input: &'a Block) -> VisitResult {
|
||||
Default::default()
|
||||
/// A Visitor trait for statements in the AST.
|
||||
pub trait StatementVisitor<'a>: ExpressionVisitor<'a> {
|
||||
fn visit_statement(&mut self, input: &'a Statement) {
|
||||
match input {
|
||||
Statement::Return(stmt) => self.visit_return(stmt),
|
||||
Statement::Definition(stmt) => self.visit_definition(stmt),
|
||||
Statement::Assign(stmt) => self.visit_assign(stmt),
|
||||
Statement::Conditional(stmt) => self.visit_conditional(stmt),
|
||||
Statement::Iteration(stmt) => self.visit_iteration(stmt),
|
||||
Statement::Console(stmt) => self.visit_console(stmt),
|
||||
Statement::Block(stmt) => self.visit_block(stmt),
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ProgramVisitor<'a> {
|
||||
fn visit_program(&mut self, _input: &'a Program) -> VisitResult {
|
||||
Default::default()
|
||||
fn visit_return(&mut self, input: &'a ReturnStatement) {
|
||||
self.visit_expression(&input.expression, &Default::default());
|
||||
}
|
||||
|
||||
fn visit_function(&mut self, _input: &'a Function) -> VisitResult {
|
||||
Default::default()
|
||||
fn visit_definition(&mut self, input: &'a DefinitionStatement) {
|
||||
self.visit_expression(&input.value, &Default::default());
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, _input: &'a Circuit) -> VisitResult {
|
||||
Default::default()
|
||||
fn visit_assign(&mut self, input: &'a AssignStatement) {
|
||||
self.visit_expression(&input.value, &Default::default());
|
||||
}
|
||||
|
||||
fn visit_conditional(&mut self, input: &'a ConditionalStatement) {
|
||||
self.visit_expression(&input.condition, &Default::default());
|
||||
self.visit_block(&input.block);
|
||||
if let Some(stmt) = input.next.as_ref() {
|
||||
self.visit_statement(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_iteration(&mut self, input: &'a IterationStatement) {
|
||||
self.visit_expression(&input.start, &Default::default());
|
||||
self.visit_expression(&input.stop, &Default::default());
|
||||
self.visit_block(&input.block);
|
||||
}
|
||||
|
||||
fn visit_console(&mut self, input: &'a ConsoleStatement) {
|
||||
match &input.function {
|
||||
ConsoleFunction::Assert(expr) => {
|
||||
self.visit_expression(expr, &Default::default());
|
||||
}
|
||||
ConsoleFunction::Error(fmt) | ConsoleFunction::Log(fmt) => {
|
||||
fmt.parameters.iter().for_each(|expr| {
|
||||
self.visit_expression(expr, &Default::default());
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, input: &'a Block) {
|
||||
input.statements.iter().for_each(|stmt| self.visit_statement(stmt));
|
||||
}
|
||||
}
|
||||
|
||||
/// A Visitor trait for the program represented by the AST.
|
||||
pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
|
||||
fn visit_program(&mut self, input: &'a Program) {
|
||||
input
|
||||
.functions
|
||||
.values()
|
||||
.for_each(|function| self.visit_function(function));
|
||||
|
||||
input
|
||||
.circuits
|
||||
.values()
|
||||
.for_each(|function| self.visit_circuit(function));
|
||||
}
|
||||
|
||||
fn visit_function(&mut self, input: &'a Function) {
|
||||
self.visit_block(&input.block);
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, _input: &'a Circuit) {}
|
||||
}
|
||||
|
@ -1,249 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! This module contains Visitor trait implementations for the AST.
|
||||
//! It implements default methods for each node to be made
|
||||
//! given the type of node its visiting.
|
||||
|
||||
use crate::*;
|
||||
|
||||
pub trait VisitorDirector<'a> {
|
||||
type Visitor: ExpressionVisitor<'a> + ProgramVisitor<'a> + StatementVisitor<'a>;
|
||||
|
||||
fn visitor(self) -> Self::Visitor;
|
||||
|
||||
fn visitor_ref(&mut self) -> &mut Self::Visitor;
|
||||
}
|
||||
|
||||
pub trait ExpressionVisitorDirector<'a>: VisitorDirector<'a> {
|
||||
type AdditionalInput: Default;
|
||||
type Output;
|
||||
|
||||
fn visit_expression(&mut self, input: &'a Expression, additional: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_expression(input) {
|
||||
match input {
|
||||
Expression::Access(expr) => self.visit_access(expr, additional),
|
||||
Expression::Binary(expr) => self.visit_binary(expr, additional),
|
||||
Expression::Call(expr) => self.visit_call(expr, additional),
|
||||
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, additional),
|
||||
Expression::Err(expr) => self.visit_err(expr, additional),
|
||||
Expression::Identifier(expr) => self.visit_identifier(expr, additional),
|
||||
Expression::Ternary(expr) => self.visit_ternary(expr, additional),
|
||||
Expression::Unary(expr) => self.visit_unary(expr, additional),
|
||||
Expression::Value(expr) => self.visit_value(expr, additional),
|
||||
};
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_identifier(&mut self, input: &'a Identifier, _additional: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
self.visitor_ref().visit_identifier(input);
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_value(&mut self, input: &'a ValueExpression, _additional: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
self.visitor_ref().visit_value(input);
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_access(
|
||||
&mut self,
|
||||
input: &'a AccessExpression,
|
||||
additional: &Self::AdditionalInput,
|
||||
) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_access(input) {
|
||||
match input {
|
||||
AccessExpression::Member(member) => self.visit_expression(&member.inner, additional),
|
||||
AccessExpression::StaticVariable(member) => self.visit_expression(&member.inner, additional),
|
||||
AccessExpression::StaticFunction(member) => {
|
||||
member.input.iter().for_each(|member| {
|
||||
self.visit_expression(member, additional);
|
||||
});
|
||||
self.visit_expression(&member.inner, additional)
|
||||
}
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_binary(
|
||||
&mut self,
|
||||
input: &'a BinaryExpression,
|
||||
additional: &Self::AdditionalInput,
|
||||
) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_binary(input) {
|
||||
self.visit_expression(&input.left, additional);
|
||||
self.visit_expression(&input.right, additional);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_unary(&mut self, input: &'a UnaryExpression, additional: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_unary(input) {
|
||||
self.visit_expression(&input.receiver, additional);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_ternary(
|
||||
&mut self,
|
||||
input: &'a TernaryExpression,
|
||||
additional: &Self::AdditionalInput,
|
||||
) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_ternary(input) {
|
||||
self.visit_expression(&input.condition, additional);
|
||||
self.visit_expression(&input.if_true, additional);
|
||||
self.visit_expression(&input.if_false, additional);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_call(&mut self, input: &'a CallExpression, additional: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_call(input) {
|
||||
input.arguments.iter().for_each(|expr| {
|
||||
self.visit_expression(expr, additional);
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_circuit_init(
|
||||
&mut self,
|
||||
input: &'a CircuitInitExpression,
|
||||
additional: &Self::AdditionalInput,
|
||||
) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_circuit_init(input) {
|
||||
input.members.iter().for_each(|member| {
|
||||
if let Some(expr) = &member.expression {
|
||||
self.visit_expression(expr, additional);
|
||||
}
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_err(&mut self, input: &'a ErrExpression, _additional: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
self.visitor_ref().visit_err(input);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StatementVisitorDirector<'a>: VisitorDirector<'a> + ExpressionVisitorDirector<'a> {
|
||||
fn visit_statement(&mut self, input: &'a Statement) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_statement(input) {
|
||||
match input {
|
||||
Statement::Return(stmt) => self.visit_return(stmt),
|
||||
Statement::Definition(stmt) => self.visit_definition(stmt),
|
||||
Statement::Assign(stmt) => self.visit_assign(stmt),
|
||||
Statement::Conditional(stmt) => self.visit_conditional(stmt),
|
||||
Statement::Iteration(stmt) => self.visit_iteration(stmt),
|
||||
Statement::Console(stmt) => self.visit_console(stmt),
|
||||
Statement::Block(stmt) => self.visit_block(stmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_return(&mut self, input: &'a ReturnStatement) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_return(input) {
|
||||
self.visit_expression(&input.expression, &Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_definition(&mut self, input: &'a DefinitionStatement) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_definition(input) {
|
||||
self.visit_expression(&input.value, &Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_assign(&mut self, input: &'a AssignStatement) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_assign(input) {
|
||||
self.visit_expression(&input.value, &Default::default());
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_conditional(&mut self, input: &'a ConditionalStatement) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_conditional(input) {
|
||||
self.visit_expression(&input.condition, &Default::default());
|
||||
self.visit_block(&input.block);
|
||||
if let Some(stmt) = input.next.as_ref() {
|
||||
self.visit_statement(stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_iteration(&mut self, input: &'a IterationStatement) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_iteration(input) {
|
||||
self.visit_expression(&input.start, &Default::default());
|
||||
self.visit_expression(&input.stop, &Default::default());
|
||||
self.visit_block(&input.block);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_console(&mut self, input: &'a ConsoleStatement) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_console(input) {
|
||||
match &input.function {
|
||||
ConsoleFunction::Assert(expr) => self.visit_expression(expr, &Default::default()),
|
||||
ConsoleFunction::Error(fmt) | ConsoleFunction::Log(fmt) => {
|
||||
fmt.parameters.iter().for_each(|expr| {
|
||||
self.visit_expression(expr, &Default::default());
|
||||
});
|
||||
None
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_block(&mut self, input: &'a Block) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_block(input) {
|
||||
input.statements.iter().for_each(|stmt| self.visit_statement(stmt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ProgramVisitorDirector<'a>: VisitorDirector<'a> + StatementVisitorDirector<'a> {
|
||||
fn visit_program(&mut self, input: &'a Program) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_program(input) {
|
||||
input
|
||||
.functions
|
||||
.values()
|
||||
.for_each(|function| self.visit_function(function));
|
||||
input.circuits.values().for_each(|circuit| self.visit_circuit(circuit));
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_function(&mut self, input: &'a Function) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_function(input) {
|
||||
self.visit_block(&input.block);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, input: &'a Circuit) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_circuit(input) {
|
||||
input.members.iter().for_each(|member| {
|
||||
match member {
|
||||
CircuitMember::CircuitConst(_, _, expr) => {
|
||||
self.visit_expression(expr, &Default::default());
|
||||
}
|
||||
CircuitMember::CircuitFunction(func) => {
|
||||
self.visit_function(func);
|
||||
}
|
||||
CircuitMember::CircuitVariable(_, _) => {}
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
@ -38,18 +38,16 @@ pub struct Program {
|
||||
pub circuits: IndexMap<Identifier, Circuit>,
|
||||
}
|
||||
|
||||
impl AsRef<Program> for Program {
|
||||
fn as_ref(&self) -> &Program {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Program {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for (_, function) in self.functions.iter() {
|
||||
function.fmt(f)?;
|
||||
writeln!(f,)?;
|
||||
}
|
||||
for (_, circuit) in self.circuits.iter() {
|
||||
circuit.fmt(f)?;
|
||||
writeln!(f,)?;
|
||||
}
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
||||
@ -66,12 +64,12 @@ impl Program {
|
||||
}
|
||||
|
||||
/// Extract the name of the program.
|
||||
pub fn get_name(&self) -> String {
|
||||
self.name.to_string()
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Sets the name of the program.
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
pub fn set_name(mut self, name: String) -> Self {
|
||||
self.name = name;
|
||||
self
|
||||
}
|
||||
|
@ -1,72 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
use crate::{Expression, Identifier, PositiveNumber};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
/// A sub-place in a variable to assign to.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AssigneeAccess {
|
||||
/// Assignment to a range in an array.
|
||||
ArrayRange(Option<Expression>, Option<Expression>),
|
||||
/// Assignment to an element of an array identified by its index.
|
||||
ArrayIndex(Expression),
|
||||
/// Assignment to a tuple field by its position, e.g., `2`.
|
||||
Tuple(PositiveNumber, #[serde(with = "leo_span::span_json")] Span),
|
||||
/// Assignment to a field in a structure.
|
||||
Member(Identifier),
|
||||
}
|
||||
|
||||
/// Definition assignee, e.g., `v`, `arr[0..2]`, `p.x`.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Assignee {
|
||||
/// The base variable to assign to.
|
||||
pub identifier: Identifier,
|
||||
/// Sub-places within `identifier` to assign to, if any.
|
||||
pub accesses: Vec<AssigneeAccess>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Assignee {
|
||||
/// Returns the name of the variable being assigned to.
|
||||
pub fn identifier(&self) -> &Identifier {
|
||||
&self.identifier
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Assignee {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.identifier)?;
|
||||
|
||||
for access in &self.accesses {
|
||||
match access {
|
||||
AssigneeAccess::ArrayRange(Some(left), Some(right)) => write!(f, "[{}..{}]", left, right)?,
|
||||
AssigneeAccess::ArrayRange(None, Some(right)) => write!(f, "[..{}]", right)?,
|
||||
AssigneeAccess::ArrayRange(Some(left), None) => write!(f, "[{}..]", left)?,
|
||||
AssigneeAccess::ArrayRange(None, None) => write!(f, "[..]")?,
|
||||
AssigneeAccess::ArrayIndex(index) => write!(f, "[{}]", index)?,
|
||||
AssigneeAccess::Tuple(index, _span) => write!(f, ".{}", index)?,
|
||||
AssigneeAccess::Member(member) => write!(f, ".{}", member)?,
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
@ -20,9 +20,6 @@ use leo_span::Span;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
mod assignee;
|
||||
pub use assignee::*;
|
||||
|
||||
/// The assignment operator.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub enum AssignOperation {
|
||||
@ -87,7 +84,7 @@ pub struct AssignStatement {
|
||||
/// For plain assignment, use `AssignOperation::Assign`.
|
||||
pub operation: AssignOperation,
|
||||
/// The place to assign to.
|
||||
pub assignee: Assignee,
|
||||
pub place: Expression,
|
||||
/// The value to assign to the `assignee`.
|
||||
pub value: Expression,
|
||||
/// The span, excluding the semicolon.
|
||||
@ -96,7 +93,7 @@ pub struct AssignStatement {
|
||||
|
||||
impl fmt::Display for AssignStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} {} {};", self.assignee, self.operation.as_ref(), self.value)
|
||||
write!(f, "{} {} {};", self.place, self.operation.as_ref(), self.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,6 @@ pub enum Type {
|
||||
IntegerType(IntegerType),
|
||||
/// A reference to a built in type.
|
||||
Identifier(Identifier),
|
||||
/// The `Self` type, allowed within `circuit` definitions.
|
||||
SelfType,
|
||||
|
||||
/// Placeholder for a type that could not be resolved or was not well-formed.
|
||||
/// Will eventually lead to a compile error.
|
||||
@ -48,20 +46,6 @@ pub enum Type {
|
||||
}
|
||||
|
||||
impl Type {
|
||||
///
|
||||
/// Returns `true` if the self `Type` is the `SelfType`.
|
||||
///
|
||||
pub fn is_self(&self) -> bool {
|
||||
matches!(self, Type::SelfType)
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns `true` if the self `Type` is a `Circuit`.
|
||||
///
|
||||
pub fn is_circuit(&self) -> bool {
|
||||
matches!(self, Type::Identifier(_))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns `true` if the self `Type` is equal to the other `Type`.
|
||||
///
|
||||
@ -74,10 +58,9 @@ impl Type {
|
||||
| (Type::Field, Type::Field)
|
||||
| (Type::Group, Type::Group)
|
||||
| (Type::Scalar, Type::Scalar)
|
||||
| (Type::String, Type::String)
|
||||
| (Type::SelfType, Type::SelfType) => true,
|
||||
| (Type::String, Type::String) => true,
|
||||
(Type::IntegerType(left), Type::IntegerType(right)) => left.eq(right),
|
||||
(Type::Identifier(left), Type::Identifier(right)) => left.eq(right),
|
||||
(Type::Identifier(left), Type::Identifier(right)) => left.matches(right),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -92,7 +75,6 @@ impl fmt::Display for Type {
|
||||
Type::Group => write!(f, "group"),
|
||||
Type::Scalar => write!(f, "scalar"),
|
||||
Type::String => write!(f, "string"),
|
||||
Type::SelfType => write!(f, "SelfType"),
|
||||
Type::IntegerType(ref integer_type) => write!(f, "{}", integer_type),
|
||||
Type::Identifier(ref variable) => write!(f, "circuit {}", variable),
|
||||
Type::Err => write!(f, "error"),
|
||||
|
@ -46,7 +46,7 @@ path = "../../tests/test-framework"
|
||||
version = "1.4.0"
|
||||
|
||||
[dev-dependencies.serde]
|
||||
version = "1.0.137"
|
||||
version = "1.0.138"
|
||||
features = ["derive"]
|
||||
|
||||
[dev-dependencies.serde_yaml]
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
@ -54,23 +54,23 @@ impl CoreInstruction {
|
||||
/// Returns a `CoreInstruction` from the given circuit and method symbols.
|
||||
pub fn from_symbols(circuit: Symbol, function: Symbol) -> Option<Self> {
|
||||
Some(match (circuit, function) {
|
||||
(sym::bhp256, sym::commit) => Self::BHP256Commit,
|
||||
(sym::bhp256, sym::hash) => Self::BHP256Hash,
|
||||
(sym::bhp512, sym::commit) => Self::BHP512Commit,
|
||||
(sym::bhp512, sym::hash) => Self::BHP512Hash,
|
||||
(sym::bhp768, sym::commit) => Self::BHP768Commit,
|
||||
(sym::bhp768, sym::hash) => Self::BHP768Hash,
|
||||
(sym::bhp1024, sym::commit) => Self::BHP1024Commit,
|
||||
(sym::bhp1024, sym::hash) => Self::BHP1024Hash,
|
||||
(sym::BHP256, sym::commit) => Self::BHP256Commit,
|
||||
(sym::BHP256, sym::hash) => Self::BHP256Hash,
|
||||
(sym::BHP512, sym::commit) => Self::BHP512Commit,
|
||||
(sym::BHP512, sym::hash) => Self::BHP512Hash,
|
||||
(sym::BHP768, sym::commit) => Self::BHP768Commit,
|
||||
(sym::BHP768, sym::hash) => Self::BHP768Hash,
|
||||
(sym::BHP1024, sym::commit) => Self::BHP1024Commit,
|
||||
(sym::BHP1024, sym::hash) => Self::BHP1024Hash,
|
||||
|
||||
(sym::ped64, sym::commit) => Self::Pedersen64Commit,
|
||||
(sym::ped64, sym::hash) => Self::Pedersen64Hash,
|
||||
(sym::ped128, sym::commit) => Self::Pedersen128Commit,
|
||||
(sym::ped128, sym::hash) => Self::Pedersen128Hash,
|
||||
(sym::Pedersen64, sym::commit) => Self::Pedersen64Commit,
|
||||
(sym::Pedersen64, sym::hash) => Self::Pedersen64Hash,
|
||||
(sym::Pedersen128, sym::commit) => Self::Pedersen128Commit,
|
||||
(sym::Pedersen128, sym::hash) => Self::Pedersen128Hash,
|
||||
|
||||
(sym::psd2, sym::hash) => Self::Poseidon2Hash,
|
||||
(sym::psd4, sym::hash) => Self::Poseidon4Hash,
|
||||
(sym::psd8, sym::hash) => Self::Poseidon8Hash,
|
||||
(sym::Poseidon2, sym::hash) => Self::Poseidon2Hash,
|
||||
(sym::Poseidon4, sym::hash) => Self::Poseidon4Hash,
|
||||
(sym::Poseidon8, sym::hash) => Self::Poseidon8Hash,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@ -78,92 +78,92 @@ impl CoreInstruction {
|
||||
/// Returns the number of arguments required by the instruction.
|
||||
pub fn num_args(&self) -> usize {
|
||||
match self {
|
||||
CoreInstruction::BHP256Commit => BHP256Commit::NUM_ARGS,
|
||||
CoreInstruction::BHP256Hash => BHP256Hash::NUM_ARGS,
|
||||
CoreInstruction::BHP512Commit => BHP512Commit::NUM_ARGS,
|
||||
CoreInstruction::BHP512Hash => BHP512Hash::NUM_ARGS,
|
||||
CoreInstruction::BHP768Commit => BHP768Commit::NUM_ARGS,
|
||||
CoreInstruction::BHP768Hash => BHP768Hash::NUM_ARGS,
|
||||
CoreInstruction::BHP1024Commit => BHP1024Commit::NUM_ARGS,
|
||||
CoreInstruction::BHP1024Hash => BHP1024Hash::NUM_ARGS,
|
||||
Self::BHP256Commit => BHP256Commit::NUM_ARGS,
|
||||
Self::BHP256Hash => BHP256Hash::NUM_ARGS,
|
||||
Self::BHP512Commit => BHP512Commit::NUM_ARGS,
|
||||
Self::BHP512Hash => BHP512Hash::NUM_ARGS,
|
||||
Self::BHP768Commit => BHP768Commit::NUM_ARGS,
|
||||
Self::BHP768Hash => BHP768Hash::NUM_ARGS,
|
||||
Self::BHP1024Commit => BHP1024Commit::NUM_ARGS,
|
||||
Self::BHP1024Hash => BHP1024Hash::NUM_ARGS,
|
||||
|
||||
CoreInstruction::Pedersen64Commit => Pedersen64Commit::NUM_ARGS,
|
||||
CoreInstruction::Pedersen64Hash => Pedersen64Hash::NUM_ARGS,
|
||||
CoreInstruction::Pedersen128Commit => Pedersen128Commit::NUM_ARGS,
|
||||
CoreInstruction::Pedersen128Hash => Pedersen128Hash::NUM_ARGS,
|
||||
Self::Pedersen64Commit => Pedersen64Commit::NUM_ARGS,
|
||||
Self::Pedersen64Hash => Pedersen64Hash::NUM_ARGS,
|
||||
Self::Pedersen128Commit => Pedersen128Commit::NUM_ARGS,
|
||||
Self::Pedersen128Hash => Pedersen128Hash::NUM_ARGS,
|
||||
|
||||
CoreInstruction::Poseidon2Hash => Poseidon2Hash::NUM_ARGS,
|
||||
CoreInstruction::Poseidon4Hash => Poseidon4Hash::NUM_ARGS,
|
||||
CoreInstruction::Poseidon8Hash => Poseidon8Hash::NUM_ARGS,
|
||||
Self::Poseidon2Hash => Poseidon2Hash::NUM_ARGS,
|
||||
Self::Poseidon4Hash => Poseidon4Hash::NUM_ARGS,
|
||||
Self::Poseidon8Hash => Poseidon8Hash::NUM_ARGS,
|
||||
}
|
||||
}
|
||||
|
||||
/// The allowed types for the first argument of the instruction.
|
||||
pub fn first_arg_types(&self) -> &'static [Type] {
|
||||
match self {
|
||||
CoreInstruction::BHP256Commit => BHP256Commit::first_arg_types(),
|
||||
CoreInstruction::BHP256Hash => BHP256Hash::first_arg_types(),
|
||||
CoreInstruction::BHP512Commit => BHP512Commit::first_arg_types(),
|
||||
CoreInstruction::BHP512Hash => BHP512Hash::first_arg_types(),
|
||||
CoreInstruction::BHP768Commit => BHP768Commit::first_arg_types(),
|
||||
CoreInstruction::BHP768Hash => BHP768Hash::first_arg_types(),
|
||||
CoreInstruction::BHP1024Commit => BHP1024Commit::first_arg_types(),
|
||||
CoreInstruction::BHP1024Hash => BHP1024Hash::first_arg_types(),
|
||||
Self::BHP256Commit => BHP256Commit::first_arg_types(),
|
||||
Self::BHP256Hash => BHP256Hash::first_arg_types(),
|
||||
Self::BHP512Commit => BHP512Commit::first_arg_types(),
|
||||
Self::BHP512Hash => BHP512Hash::first_arg_types(),
|
||||
Self::BHP768Commit => BHP768Commit::first_arg_types(),
|
||||
Self::BHP768Hash => BHP768Hash::first_arg_types(),
|
||||
Self::BHP1024Commit => BHP1024Commit::first_arg_types(),
|
||||
Self::BHP1024Hash => BHP1024Hash::first_arg_types(),
|
||||
|
||||
CoreInstruction::Pedersen64Commit => Pedersen64Commit::first_arg_types(),
|
||||
CoreInstruction::Pedersen64Hash => Pedersen64Hash::first_arg_types(),
|
||||
CoreInstruction::Pedersen128Commit => Pedersen128Commit::first_arg_types(),
|
||||
CoreInstruction::Pedersen128Hash => Pedersen128Hash::first_arg_types(),
|
||||
Self::Pedersen64Commit => Pedersen64Commit::first_arg_types(),
|
||||
Self::Pedersen64Hash => Pedersen64Hash::first_arg_types(),
|
||||
Self::Pedersen128Commit => Pedersen128Commit::first_arg_types(),
|
||||
Self::Pedersen128Hash => Pedersen128Hash::first_arg_types(),
|
||||
|
||||
CoreInstruction::Poseidon2Hash => Poseidon2Hash::first_arg_types(),
|
||||
CoreInstruction::Poseidon4Hash => Poseidon4Hash::first_arg_types(),
|
||||
CoreInstruction::Poseidon8Hash => Poseidon8Hash::first_arg_types(),
|
||||
Self::Poseidon2Hash => Poseidon2Hash::first_arg_types(),
|
||||
Self::Poseidon4Hash => Poseidon4Hash::first_arg_types(),
|
||||
Self::Poseidon8Hash => Poseidon8Hash::first_arg_types(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The allowed types for the second argument of the instruction.
|
||||
pub fn second_arg_types(&self) -> &'static [Type] {
|
||||
match self {
|
||||
CoreInstruction::BHP256Commit => BHP256Commit::second_arg_types(),
|
||||
CoreInstruction::BHP256Hash => BHP256Hash::second_arg_types(),
|
||||
CoreInstruction::BHP512Commit => BHP512Commit::second_arg_types(),
|
||||
CoreInstruction::BHP512Hash => BHP512Hash::second_arg_types(),
|
||||
CoreInstruction::BHP768Commit => BHP768Commit::second_arg_types(),
|
||||
CoreInstruction::BHP768Hash => BHP768Hash::second_arg_types(),
|
||||
CoreInstruction::BHP1024Commit => BHP1024Commit::second_arg_types(),
|
||||
CoreInstruction::BHP1024Hash => BHP1024Hash::second_arg_types(),
|
||||
Self::BHP256Commit => BHP256Commit::second_arg_types(),
|
||||
Self::BHP256Hash => BHP256Hash::second_arg_types(),
|
||||
Self::BHP512Commit => BHP512Commit::second_arg_types(),
|
||||
Self::BHP512Hash => BHP512Hash::second_arg_types(),
|
||||
Self::BHP768Commit => BHP768Commit::second_arg_types(),
|
||||
Self::BHP768Hash => BHP768Hash::second_arg_types(),
|
||||
Self::BHP1024Commit => BHP1024Commit::second_arg_types(),
|
||||
Self::BHP1024Hash => BHP1024Hash::second_arg_types(),
|
||||
|
||||
CoreInstruction::Pedersen64Commit => Pedersen64Commit::second_arg_types(),
|
||||
CoreInstruction::Pedersen64Hash => Pedersen64Hash::second_arg_types(),
|
||||
CoreInstruction::Pedersen128Commit => Pedersen128Commit::second_arg_types(),
|
||||
CoreInstruction::Pedersen128Hash => Pedersen128Hash::second_arg_types(),
|
||||
Self::Pedersen64Commit => Pedersen64Commit::second_arg_types(),
|
||||
Self::Pedersen64Hash => Pedersen64Hash::second_arg_types(),
|
||||
Self::Pedersen128Commit => Pedersen128Commit::second_arg_types(),
|
||||
Self::Pedersen128Hash => Pedersen128Hash::second_arg_types(),
|
||||
|
||||
CoreInstruction::Poseidon2Hash => Poseidon2Hash::second_arg_types(),
|
||||
CoreInstruction::Poseidon4Hash => Poseidon4Hash::second_arg_types(),
|
||||
CoreInstruction::Poseidon8Hash => Poseidon8Hash::second_arg_types(),
|
||||
Self::Poseidon2Hash => Poseidon2Hash::second_arg_types(),
|
||||
Self::Poseidon4Hash => Poseidon4Hash::second_arg_types(),
|
||||
Self::Poseidon8Hash => Poseidon8Hash::second_arg_types(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The type of the instruction output.
|
||||
pub fn return_type(&self) -> Type {
|
||||
match self {
|
||||
CoreInstruction::BHP256Commit => BHP256Commit::return_type(),
|
||||
CoreInstruction::BHP256Hash => BHP256Hash::return_type(),
|
||||
CoreInstruction::BHP512Commit => BHP512Commit::return_type(),
|
||||
CoreInstruction::BHP512Hash => BHP512Hash::return_type(),
|
||||
CoreInstruction::BHP768Commit => BHP768Commit::return_type(),
|
||||
CoreInstruction::BHP768Hash => BHP768Hash::return_type(),
|
||||
CoreInstruction::BHP1024Commit => BHP1024Commit::return_type(),
|
||||
CoreInstruction::BHP1024Hash => BHP1024Hash::return_type(),
|
||||
Self::BHP256Commit => BHP256Commit::return_type(),
|
||||
Self::BHP256Hash => BHP256Hash::return_type(),
|
||||
Self::BHP512Commit => BHP512Commit::return_type(),
|
||||
Self::BHP512Hash => BHP512Hash::return_type(),
|
||||
Self::BHP768Commit => BHP768Commit::return_type(),
|
||||
Self::BHP768Hash => BHP768Hash::return_type(),
|
||||
Self::BHP1024Commit => BHP1024Commit::return_type(),
|
||||
Self::BHP1024Hash => BHP1024Hash::return_type(),
|
||||
|
||||
CoreInstruction::Pedersen64Commit => Pedersen64Commit::return_type(),
|
||||
CoreInstruction::Pedersen64Hash => Pedersen64Hash::return_type(),
|
||||
CoreInstruction::Pedersen128Commit => Pedersen128Commit::return_type(),
|
||||
CoreInstruction::Pedersen128Hash => Pedersen128Hash::return_type(),
|
||||
Self::Pedersen64Commit => Pedersen64Commit::return_type(),
|
||||
Self::Pedersen64Hash => Pedersen64Hash::return_type(),
|
||||
Self::Pedersen128Commit => Pedersen128Commit::return_type(),
|
||||
Self::Pedersen128Hash => Pedersen128Hash::return_type(),
|
||||
|
||||
CoreInstruction::Poseidon2Hash => Poseidon2Hash::return_type(),
|
||||
CoreInstruction::Poseidon4Hash => Poseidon4Hash::return_type(),
|
||||
CoreInstruction::Poseidon8Hash => Poseidon8Hash::return_type(),
|
||||
Self::Poseidon2Hash => Poseidon2Hash::return_type(),
|
||||
Self::Poseidon4Hash => Poseidon4Hash::return_type(),
|
||||
Self::Poseidon8Hash => Poseidon8Hash::return_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,7 +177,7 @@ trait CoreFunction {
|
||||
fn first_arg_types() -> &'static [Type];
|
||||
|
||||
/// Returns the second argument allowed types.
|
||||
/// Implementing this method is optional since some functions may not require a second argument.
|
||||
/// Implementing this method is optional since some functions may not allow a second argument.
|
||||
fn second_arg_types() -> &'static [Type] {
|
||||
&[]
|
||||
}
|
||||
@ -220,6 +220,19 @@ const BOOL_INT_STRING_TYPES: [Type; 12] = [
|
||||
Type::String,
|
||||
];
|
||||
|
||||
const BOOL_INT64_STRING_TYPES: [Type; 10] = [
|
||||
Type::Boolean,
|
||||
Type::IntegerType(IntegerType::I8),
|
||||
Type::IntegerType(IntegerType::I16),
|
||||
Type::IntegerType(IntegerType::I32),
|
||||
Type::IntegerType(IntegerType::I64),
|
||||
Type::IntegerType(IntegerType::U8),
|
||||
Type::IntegerType(IntegerType::U16),
|
||||
Type::IntegerType(IntegerType::U32),
|
||||
Type::IntegerType(IntegerType::U64),
|
||||
Type::String,
|
||||
];
|
||||
|
||||
// todo (collin): deprecate this code
|
||||
pub struct Algorithms;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::algorithms::{CoreFunction, BOOL_INT_STRING_TYPES};
|
||||
use crate::algorithms::{CoreFunction, BOOL_INT64_STRING_TYPES, BOOL_INT_STRING_TYPES};
|
||||
use leo_ast::Type;
|
||||
|
||||
pub struct Pedersen64Hash;
|
||||
@ -23,7 +23,7 @@ impl CoreFunction for Pedersen64Hash {
|
||||
const NUM_ARGS: usize = 1;
|
||||
|
||||
fn first_arg_types() -> &'static [Type] {
|
||||
&BOOL_INT_STRING_TYPES
|
||||
&BOOL_INT64_STRING_TYPES
|
||||
}
|
||||
|
||||
fn return_type() -> Type {
|
||||
@ -37,7 +37,7 @@ impl CoreFunction for Pedersen64Commit {
|
||||
const NUM_ARGS: usize = 2;
|
||||
|
||||
fn first_arg_types() -> &'static [Type] {
|
||||
&BOOL_INT_STRING_TYPES
|
||||
&BOOL_INT64_STRING_TYPES
|
||||
}
|
||||
|
||||
fn second_arg_types() -> &'static [Type] {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -15,9 +15,9 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::*;
|
||||
|
||||
use leo_errors::{ParserError, Result};
|
||||
use leo_span::sym;
|
||||
|
||||
use snarkvm_dpc::{prelude::Address, testnet2::Testnet2};
|
||||
|
||||
const INT_TYPES: &[Token] = &[
|
||||
Token::I8,
|
||||
@ -258,10 +258,7 @@ impl ParserContext<'_> {
|
||||
|
||||
/// Returns an [`Expression`] AST node if the next tokens represent a
|
||||
/// method call expression.
|
||||
fn parse_method_call_expression(&mut self, receiver: Expression) -> Result<Expression> {
|
||||
// Parse the method name.
|
||||
let method = self.expect_ident()?;
|
||||
|
||||
fn parse_method_call_expression(&mut self, receiver: Expression, method: Identifier) -> Result<Expression> {
|
||||
// Parse the argument list.
|
||||
let (mut args, _, span) = self.parse_expr_tuple()?;
|
||||
let span = receiver.span() + span;
|
||||
@ -283,35 +280,41 @@ impl ParserContext<'_> {
|
||||
}))
|
||||
} else {
|
||||
// Either an invalid unary/binary operator, or more arguments given.
|
||||
// todo: add circuit member access
|
||||
self.emit_err(ParserError::expr_arbitrary_method_call(span));
|
||||
self.emit_err(ParserError::invalid_method_call(receiver, method, span));
|
||||
Ok(Expression::Err(ErrExpression { span }))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an [`Expression`] AST node if the next tokens represent a
|
||||
/// static access expression.
|
||||
fn parse_static_access_expression(&mut self, circuit_name: Expression) -> Result<Expression> {
|
||||
fn parse_associated_access_expression(&mut self, circuit_name: Expression) -> Result<Expression> {
|
||||
// Parse circuit name expression into circuit type.
|
||||
let circuit_type = if let Expression::Identifier(ident) = circuit_name {
|
||||
Type::Identifier(ident)
|
||||
} else {
|
||||
return Err(ParserError::invalid_associated_access(&circuit_name, circuit_name.span()).into());
|
||||
};
|
||||
|
||||
// Parse the circuit member name (can be variable or function name).
|
||||
let member_name = self.expect_ident()?;
|
||||
|
||||
// Check if there are arguments.
|
||||
Ok(Expression::Access(if self.check(&Token::LeftParen) {
|
||||
// Parse the arguments
|
||||
let (input, _, end) = self.parse_expr_tuple()?;
|
||||
let (args, _, end) = self.parse_expr_tuple()?;
|
||||
|
||||
// Return the static function access expression.
|
||||
AccessExpression::StaticFunction(StaticFunctionAccess {
|
||||
// Return the circuit function.
|
||||
AccessExpression::AssociatedFunction(AssociatedFunction {
|
||||
span: circuit_name.span() + end,
|
||||
inner: Box::new(circuit_name),
|
||||
ty: circuit_type,
|
||||
name: member_name,
|
||||
input,
|
||||
args,
|
||||
})
|
||||
} else {
|
||||
// Return the static variable access expression.
|
||||
AccessExpression::StaticVariable(StaticVariableAccess {
|
||||
// Return the circuit constant.
|
||||
AccessExpression::AssociatedConstant(AssociatedConstant {
|
||||
span: circuit_name.span() + member_name.span(),
|
||||
inner: Box::new(circuit_name),
|
||||
ty: circuit_type,
|
||||
name: member_name,
|
||||
})
|
||||
}))
|
||||
@ -333,10 +336,23 @@ impl ParserContext<'_> {
|
||||
let mut expr = self.parse_primary_expression()?;
|
||||
loop {
|
||||
if self.eat(&Token::Dot) {
|
||||
// Parse the method name.
|
||||
let name = self.expect_ident()?;
|
||||
|
||||
if self.check(&Token::LeftParen) {
|
||||
// Eat a method call on a type
|
||||
expr = self.parse_method_call_expression(expr)?
|
||||
expr = self.parse_method_call_expression(expr, name)?
|
||||
} else {
|
||||
// Eat a circuit member access.
|
||||
expr = Expression::Access(AccessExpression::Member(MemberAccess {
|
||||
span: expr.span(),
|
||||
inner: Box::new(expr),
|
||||
name,
|
||||
}))
|
||||
}
|
||||
} else if self.eat(&Token::DoubleColon) {
|
||||
expr = self.parse_static_access_expression(expr)?;
|
||||
// Eat a core circuit constant or core circuit function call.
|
||||
expr = self.parse_associated_access_expression(expr)?;
|
||||
} else if self.check(&Token::LeftParen) {
|
||||
// Parse a function call that's by itself.
|
||||
let (arguments, _, span) = self.parse_paren_comma_list(|p| p.parse_expression().map(Some))?;
|
||||
@ -358,9 +374,9 @@ impl ParserContext<'_> {
|
||||
/// tuple initialization expression or an affine group literal.
|
||||
fn parse_tuple_expression(&mut self) -> Result<Expression> {
|
||||
if let Some(gt) = self.eat_group_partial().transpose()? {
|
||||
return Ok(Expression::Value(ValueExpression::Group(Box::new(GroupValue::Tuple(
|
||||
gt,
|
||||
)))));
|
||||
return Ok(Expression::Literal(LiteralExpression::Group(Box::new(
|
||||
GroupLiteral::Tuple(gt),
|
||||
))));
|
||||
}
|
||||
|
||||
let (mut tuple, trailing, span) = self.parse_expr_tuple()?;
|
||||
@ -485,45 +501,43 @@ impl ParserContext<'_> {
|
||||
// Literal followed by `field`, e.g., `42field`.
|
||||
Some(Token::Field) => {
|
||||
assert_no_whitespace("field")?;
|
||||
Expression::Value(ValueExpression::Field(value, full_span))
|
||||
Expression::Literal(LiteralExpression::Field(value, full_span))
|
||||
}
|
||||
// Literal followed by `group`, e.g., `42group`.
|
||||
Some(Token::Group) => {
|
||||
assert_no_whitespace("group")?;
|
||||
Expression::Value(ValueExpression::Group(Box::new(GroupValue::Single(value, full_span))))
|
||||
Expression::Literal(LiteralExpression::Group(Box::new(GroupLiteral::Single(
|
||||
value, full_span,
|
||||
))))
|
||||
}
|
||||
// Literal followed by `scalar` e.g., `42scalar`.
|
||||
Some(Token::Scalar) => {
|
||||
assert_no_whitespace("scalar")?;
|
||||
Expression::Value(ValueExpression::Scalar(value, full_span))
|
||||
Expression::Literal(LiteralExpression::Scalar(value, full_span))
|
||||
}
|
||||
// Literal followed by other type suffix, e.g., `42u8`.
|
||||
Some(suffix) => {
|
||||
assert_no_whitespace(&suffix.to_string())?;
|
||||
let int_ty = Self::token_to_int_type(suffix).expect("unknown int type token");
|
||||
Expression::Value(ValueExpression::Integer(int_ty, value, full_span))
|
||||
Expression::Literal(LiteralExpression::Integer(int_ty, value, full_span))
|
||||
}
|
||||
None => return Err(ParserError::implicit_values_not_allowed(value, span).into()),
|
||||
}
|
||||
}
|
||||
Token::True => Expression::Value(ValueExpression::Boolean("true".into(), span)),
|
||||
Token::False => Expression::Value(ValueExpression::Boolean("false".into(), span)),
|
||||
Token::AddressLit(value) => Expression::Value(ValueExpression::Address(value, span)),
|
||||
Token::StaticString(value) => Expression::Value(ValueExpression::String(value, span)),
|
||||
Token::True => Expression::Literal(LiteralExpression::Boolean(true, span)),
|
||||
Token::False => Expression::Literal(LiteralExpression::Boolean(false, span)),
|
||||
Token::AddressLit(addr) => {
|
||||
if addr.parse::<Address<Testnet2>>().is_err() {
|
||||
self.emit_err(ParserError::invalid_address_lit(&addr, span));
|
||||
}
|
||||
Expression::Literal(LiteralExpression::Address(addr, span))
|
||||
}
|
||||
Token::StaticString(value) => Expression::Literal(LiteralExpression::String(value, span)),
|
||||
Token::Ident(name) => {
|
||||
let ident = Identifier { name, span };
|
||||
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
||||
self.parse_circuit_expression(ident)?
|
||||
} else {
|
||||
Expression::Identifier(ident)
|
||||
}
|
||||
}
|
||||
Token::SelfUpper => {
|
||||
let ident = Identifier {
|
||||
name: sym::SelfUpper,
|
||||
span,
|
||||
};
|
||||
if !self.disallow_circuit_construction && self.check(&Token::LeftCurly) {
|
||||
// Parse circuit and records inits as circuit expressions.
|
||||
// Enforce circuit or record type later at type checking.
|
||||
self.parse_circuit_expression(ident)?
|
||||
} else {
|
||||
Expression::Identifier(ident)
|
||||
|
@ -27,7 +27,7 @@ impl ParserContext<'_> {
|
||||
|
||||
while self.has_next() {
|
||||
match &self.token.token {
|
||||
Token::Circuit => {
|
||||
Token::Circuit | Token::Record => {
|
||||
let (id, circuit) = self.parse_circuit()?;
|
||||
circuits.insert(id, circuit);
|
||||
}
|
||||
@ -36,12 +36,10 @@ impl ParserContext<'_> {
|
||||
functions.insert(id, function);
|
||||
}
|
||||
Token::Ident(sym::test) => return Err(ParserError::test_function(self.token.span).into()),
|
||||
// Const functions share the first token with the global Const.
|
||||
Token::Function => {
|
||||
let (id, function) = self.parse_function()?;
|
||||
functions.insert(id, function);
|
||||
}
|
||||
|
||||
_ => return Err(Self::unexpected_item(&self.token).into()),
|
||||
}
|
||||
}
|
||||
@ -65,9 +63,9 @@ impl ParserContext<'_> {
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member variable
|
||||
/// Returns a [`Vec<CircuitMember>`] AST node if the next tokens represent a circuit member variable
|
||||
/// or circuit member function or circuit member constant.
|
||||
pub fn parse_circuit_declaration(&mut self) -> Result<(Vec<CircuitMember>, Span)> {
|
||||
pub fn parse_circuit_members(&mut self) -> Result<(Vec<CircuitMember>, Span)> {
|
||||
let mut members = Vec::new();
|
||||
|
||||
let (mut semi_colons, mut commas) = (false, false);
|
||||
@ -102,35 +100,11 @@ impl ParserContext<'_> {
|
||||
}
|
||||
let span = self.expect(&Token::RightCurly)?;
|
||||
|
||||
self.ban_mixed_member_order(&members);
|
||||
|
||||
Ok((members, span))
|
||||
}
|
||||
|
||||
/// Emits errors if order isn't `consts variables functions`.
|
||||
fn ban_mixed_member_order(&self, members: &[CircuitMember]) {
|
||||
let mut had_var = false;
|
||||
let mut had_fun = false;
|
||||
for member in members {
|
||||
match member {
|
||||
CircuitMember::CircuitConst(id, _, e) if had_var => {
|
||||
self.emit_err(ParserError::member_const_after_var(id.span() + e.span()));
|
||||
}
|
||||
CircuitMember::CircuitConst(id, _, e) if had_fun => {
|
||||
self.emit_err(ParserError::member_const_after_fun(id.span() + e.span()));
|
||||
}
|
||||
CircuitMember::CircuitVariable(id, _) if had_fun => {
|
||||
self.emit_err(ParserError::member_var_after_fun(id.span()));
|
||||
}
|
||||
CircuitMember::CircuitConst(..) => {}
|
||||
CircuitMember::CircuitVariable(..) => had_var = true,
|
||||
CircuitMember::CircuitFunction(..) => had_fun = true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses `IDENT: TYPE`.
|
||||
fn parse_typed_field_name(&mut self) -> Result<(Identifier, Type)> {
|
||||
fn parse_member(&mut self) -> Result<(Identifier, Type)> {
|
||||
let name = self.expect_ident()?;
|
||||
self.expect(&Token::Colon)?;
|
||||
let type_ = self.parse_all_types()?.0;
|
||||
@ -144,18 +118,21 @@ impl ParserContext<'_> {
|
||||
self.expect(&Token::Const)?;
|
||||
|
||||
// `IDENT: TYPE = EXPR`:
|
||||
let (name, type_) = self.parse_typed_field_name()?;
|
||||
let (_name, _type_) = self.parse_member()?;
|
||||
self.expect(&Token::Assign)?;
|
||||
let expr = self.parse_expression()?;
|
||||
|
||||
self.expect(&Token::Semicolon)?;
|
||||
|
||||
Ok(CircuitMember::CircuitConst(name, type_, expr))
|
||||
// CAUTION: function members are unstable for testnet3.
|
||||
Err(ParserError::circuit_constants_unstable(expr.span()).into())
|
||||
|
||||
// Ok(CircuitMember::CircuitConst(name, type_, expr))
|
||||
}
|
||||
|
||||
/// Returns a [`CircuitMember`] AST node if the next tokens represent a circuit member variable.
|
||||
pub fn parse_member_variable_declaration(&mut self) -> Result<CircuitMember> {
|
||||
let (name, type_) = self.parse_typed_field_name()?;
|
||||
let (name, type_) = self.parse_member()?;
|
||||
|
||||
Ok(CircuitMember::CircuitVariable(name, type_))
|
||||
}
|
||||
@ -166,26 +143,28 @@ impl ParserContext<'_> {
|
||||
// CAUTION: function members are unstable for testnet3.
|
||||
let function = self.parse_function()?;
|
||||
|
||||
return Err(ParserError::circuit_functions_unstable(function.1.span()).into());
|
||||
Err(ParserError::circuit_functions_unstable(function.1.span()).into())
|
||||
// Ok(CircuitMember::CircuitFunction(Box::new(function.1)))
|
||||
} else {
|
||||
return Err(Self::unexpected_item(&self.token).into());
|
||||
Err(Self::unexpected_item(&self.token).into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an [`(Identifier, Function)`] ast node if the next tokens represent a circuit declaration.
|
||||
/// Parses a circuit or record definition, e.g., `circit Foo { ... }` or `record Foo { ... }`.
|
||||
pub(super) fn parse_circuit(&mut self) -> Result<(Identifier, Circuit)> {
|
||||
let start = self.expect(&Token::Circuit)?;
|
||||
let is_record = matches!(&self.token.token, Token::Record);
|
||||
let start = self.expect_any(&[Token::Circuit, Token::Record])?;
|
||||
let circuit_name = self.expect_ident()?;
|
||||
|
||||
self.expect(&Token::LeftCurly)?;
|
||||
let (members, end) = self.parse_circuit_declaration()?;
|
||||
let (members, end) = self.parse_circuit_members()?;
|
||||
|
||||
Ok((
|
||||
circuit_name.clone(),
|
||||
circuit_name,
|
||||
Circuit {
|
||||
identifier: circuit_name,
|
||||
members,
|
||||
is_record,
|
||||
span: start + end,
|
||||
},
|
||||
))
|
||||
|
@ -22,25 +22,6 @@ use leo_span::sym;
|
||||
const ASSIGN_TOKENS: &[Token] = &[Token::Assign];
|
||||
|
||||
impl ParserContext<'_> {
|
||||
/// Returns an [`Identifier`] AST node if the given [`Expression`] AST node evaluates to an
|
||||
/// identifier access. The access is stored in the given accesses.
|
||||
fn construct_assignee_access(expr: Expression, _accesses: &mut [AssigneeAccess]) -> Result<Identifier> {
|
||||
match expr {
|
||||
Expression::Identifier(id) => Ok(id),
|
||||
_ => Err(ParserError::invalid_assignment_target(expr.span()).into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an [`Assignee`] AST node from the given [`Expression`] AST node with accesses.
|
||||
fn construct_assignee(expr: Expression) -> Result<Assignee> {
|
||||
let mut accesses = Vec::new();
|
||||
Ok(Assignee {
|
||||
span: expr.span(),
|
||||
identifier: Self::construct_assignee_access(expr, &mut accesses)?,
|
||||
accesses,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a [`Statement`] AST node if the next tokens represent a statement.
|
||||
pub(crate) fn parse_statement(&mut self) -> Result<Statement> {
|
||||
match &self.token.token {
|
||||
@ -56,15 +37,14 @@ impl ParserContext<'_> {
|
||||
|
||||
/// Returns a [`Block`] AST node if the next tokens represent a assign, or expression statement.
|
||||
fn parse_assign_statement(&mut self) -> Result<Statement> {
|
||||
let expr = self.parse_expression()?;
|
||||
let place = self.parse_expression()?;
|
||||
|
||||
if self.eat_any(ASSIGN_TOKENS) {
|
||||
let value = self.parse_expression()?;
|
||||
let assignee = Self::construct_assignee(expr)?;
|
||||
self.expect(&Token::Semicolon)?;
|
||||
Ok(Statement::Assign(Box::new(AssignStatement {
|
||||
span: assignee.span + value.span(),
|
||||
assignee,
|
||||
span: place.span() + value.span(),
|
||||
place,
|
||||
// Currently only `=` so this is alright.
|
||||
operation: AssignOperation::Assign,
|
||||
value,
|
||||
@ -72,7 +52,7 @@ impl ParserContext<'_> {
|
||||
} else {
|
||||
// Error on `expr;` but recover as an empty block `{}`.
|
||||
self.expect(&Token::Semicolon)?;
|
||||
let span = expr.span() + self.prev_token.span;
|
||||
let span = place.span() + self.prev_token.span;
|
||||
self.emit_err(ParserError::expr_stmts_disallowed(span));
|
||||
Ok(Statement::dummy(span))
|
||||
}
|
||||
|
@ -17,13 +17,11 @@
|
||||
use crate::tokenizer::Token;
|
||||
use leo_errors::{ParserError, Result};
|
||||
use leo_span::{Span, Symbol};
|
||||
use snarkvm_dpc::{prelude::*, testnet2::Testnet2};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fmt,
|
||||
iter::{from_fn, Peekable},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
/// Eat an identifier, that is, a string matching '[a-zA-Z][a-zA-Z\d_]*', if any.
|
||||
@ -38,6 +36,14 @@ fn is_bidi_override(c: char) -> bool {
|
||||
(0x202A..=0x202E).contains(&i) || (0x2066..=0x2069).contains(&i)
|
||||
}
|
||||
|
||||
/// Ensure that `string` contains no Unicode Bidirectional Override code points.
|
||||
fn ensure_no_bidi_override(string: &str) -> Result<()> {
|
||||
if string.chars().any(is_bidi_override) {
|
||||
return Err(ParserError::lexer_bidi_override().into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Token {
|
||||
// todo: remove this unused code or reference https://github.com/Geal/nom/blob/main/examples/string.rs
|
||||
// // Eats the parts of the unicode character after \u.
|
||||
@ -176,6 +182,7 @@ impl Token {
|
||||
return Err(ParserError::lexer_empty_input().into());
|
||||
}
|
||||
|
||||
let input_str = input;
|
||||
let mut input = input.chars().peekable();
|
||||
|
||||
// Consumes a single character token.
|
||||
@ -207,28 +214,15 @@ impl Token {
|
||||
match *input.peek().ok_or_else(ParserError::lexer_empty_input)? {
|
||||
x if x.is_ascii_whitespace() => return single(&mut input, Token::WhiteSpace),
|
||||
'"' => {
|
||||
let mut string = String::new();
|
||||
input.next();
|
||||
// Find end string quotation mark.
|
||||
// Instead of checking each `char` and pushing, we can avoid reallocations.
|
||||
let rest = &input_str[1..];
|
||||
let string = match rest.as_bytes().iter().position(|c| *c == b'"') {
|
||||
None => return Err(ParserError::lexer_string_not_closed(rest).into()),
|
||||
Some(idx) => rest[..idx].to_owned(),
|
||||
};
|
||||
|
||||
let mut ended = false;
|
||||
while let Some(c) = input.next() {
|
||||
// Check for illegal characters.
|
||||
if is_bidi_override(c) {
|
||||
return Err(ParserError::lexer_bidi_override().into());
|
||||
}
|
||||
|
||||
// Check for end string quotation mark.
|
||||
if c == '"' {
|
||||
input.next();
|
||||
ended = true;
|
||||
break;
|
||||
}
|
||||
string.push(c);
|
||||
}
|
||||
|
||||
if !ended {
|
||||
return Err(ParserError::lexer_string_not_closed(string).into());
|
||||
}
|
||||
ensure_no_bidi_override(&string)?;
|
||||
|
||||
// + 2 to account for parsing quotation marks.
|
||||
return Ok((string.len() + 2, Token::StaticString(string)));
|
||||
@ -248,21 +242,14 @@ impl Token {
|
||||
'/' => {
|
||||
input.next();
|
||||
if input.next_if_eq(&'/').is_some() {
|
||||
let mut comment = String::from("//");
|
||||
// Find the end of the comment line.
|
||||
let comment = match input_str.as_bytes().iter().position(|c| *c == b'\n') {
|
||||
None => input_str,
|
||||
Some(idx) => &input_str[..idx + 1],
|
||||
};
|
||||
|
||||
while let Some(c) = input.next_if(|c| c != &'\n') {
|
||||
if is_bidi_override(c) {
|
||||
return Err(ParserError::lexer_bidi_override().into());
|
||||
}
|
||||
comment.push(c);
|
||||
}
|
||||
|
||||
if let Some(newline) = input.next_if_eq(&'\n') {
|
||||
comment.push(newline);
|
||||
return Ok((comment.len(), Token::CommentLine(comment)));
|
||||
}
|
||||
|
||||
return Ok((comment.len(), Token::CommentLine(comment)));
|
||||
ensure_no_bidi_override(comment)?;
|
||||
return Ok((comment.len(), Token::CommentLine(comment.to_owned())));
|
||||
} else if input.next_if_eq(&'*').is_some() {
|
||||
let mut comment = String::from("/*");
|
||||
|
||||
@ -272,9 +259,6 @@ impl Token {
|
||||
|
||||
let mut ended = false;
|
||||
while let Some(c) = input.next() {
|
||||
if is_bidi_override(c) {
|
||||
return Err(ParserError::lexer_bidi_override().into());
|
||||
}
|
||||
comment.push(c);
|
||||
if c == '*' && input.next_if_eq(&'/').is_some() {
|
||||
comment.push('/');
|
||||
@ -283,6 +267,8 @@ impl Token {
|
||||
}
|
||||
}
|
||||
|
||||
ensure_no_bidi_override(&comment)?;
|
||||
|
||||
if !ended {
|
||||
return Err(ParserError::lexer_block_comment_does_not_close_before_eof(comment).into());
|
||||
}
|
||||
@ -330,6 +316,7 @@ impl Token {
|
||||
"in" => Token::In,
|
||||
"let" => Token::Let,
|
||||
"public" => Token::Public,
|
||||
"record" => Token::Record,
|
||||
"return" => Token::Return,
|
||||
"scalar" => Token::Scalar,
|
||||
"string" => Token::String,
|
||||
@ -381,8 +368,3 @@ impl fmt::Debug for SpannedToken {
|
||||
<SpannedToken as fmt::Display>::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the given string is a valid Aleo address.
|
||||
pub(crate) fn check_address(address: &str) -> bool {
|
||||
Address::<Testnet2>::from_str(address).is_ok()
|
||||
}
|
||||
|
@ -28,11 +28,8 @@ pub(crate) use self::token::*;
|
||||
pub(crate) mod lexer;
|
||||
pub(crate) use self::lexer::*;
|
||||
|
||||
use leo_errors::{ParserError, Result};
|
||||
use leo_span::{
|
||||
span::{BytePos, Pos},
|
||||
Span,
|
||||
};
|
||||
use leo_errors::Result;
|
||||
use leo_span::span::{BytePos, Pos, Span};
|
||||
|
||||
/// Creates a new vector of spanned tokens from a given file path and source code text.
|
||||
pub(crate) fn tokenize(input: &str, start_pos: BytePos) -> Result<Vec<SpannedToken>> {
|
||||
@ -42,24 +39,20 @@ pub(crate) fn tokenize(input: &str, start_pos: BytePos) -> Result<Vec<SpannedTok
|
||||
/// Yields spanned tokens from the given source code text.
|
||||
///
|
||||
/// The `lo` byte position determines where spans will start.
|
||||
pub(crate) fn tokenize_iter(input: &str, mut lo: BytePos) -> impl '_ + Iterator<Item = Result<SpannedToken>> {
|
||||
let mut index = 0usize;
|
||||
pub(crate) fn tokenize_iter(mut input: &str, mut lo: BytePos) -> impl '_ + Iterator<Item = Result<SpannedToken>> {
|
||||
iter::from_fn(move || {
|
||||
while input.len() > index {
|
||||
let (token_len, token) = match Token::eat(&input[index..]) {
|
||||
while !input.is_empty() {
|
||||
let (token_len, token) = match Token::eat(input) {
|
||||
Err(e) => return Some(Err(e)),
|
||||
Ok(t) => t,
|
||||
};
|
||||
index += token_len;
|
||||
input = &input[token_len..];
|
||||
|
||||
let span = Span::new(lo, lo + BytePos::from_usize(token_len));
|
||||
lo = span.hi;
|
||||
|
||||
match token {
|
||||
Token::WhiteSpace => continue,
|
||||
Token::AddressLit(address) if !check_address(&address) => {
|
||||
return Some(Err(ParserError::invalid_address_lit(address, span).into()));
|
||||
}
|
||||
_ => return Some(Ok(SpannedToken { token, span })),
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ pub enum Token {
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
SelfUpper,
|
||||
Record,
|
||||
|
||||
// Regular Keywords
|
||||
Circuit,
|
||||
@ -140,9 +140,9 @@ pub const KEYWORD_TOKENS: &[Token] = &[
|
||||
Token::In,
|
||||
Token::Let,
|
||||
Token::Public,
|
||||
Token::Record,
|
||||
Token::Return,
|
||||
Token::SelfLower,
|
||||
Token::SelfUpper,
|
||||
Token::Scalar,
|
||||
Token::Static,
|
||||
Token::String,
|
||||
@ -184,10 +184,10 @@ impl Token {
|
||||
Token::In => sym::In,
|
||||
Token::Let => sym::Let,
|
||||
Token::Public => sym::Public,
|
||||
Token::Record => sym::record,
|
||||
Token::Return => sym::Return,
|
||||
Token::Scalar => sym::scalar,
|
||||
Token::SelfLower => sym::SelfLower,
|
||||
Token::SelfUpper => sym::SelfUpper,
|
||||
Token::Static => sym::Static,
|
||||
Token::String => sym::string,
|
||||
Token::True => sym::True,
|
||||
@ -267,7 +267,7 @@ impl fmt::Display for Token {
|
||||
U32 => write!(f, "u32"),
|
||||
U64 => write!(f, "u64"),
|
||||
U128 => write!(f, "u128"),
|
||||
SelfUpper => write!(f, "Self"),
|
||||
Record => write!(f, "record"),
|
||||
|
||||
Circuit => write!(f, "circuit"),
|
||||
Console => write!(f, "console"),
|
||||
|
@ -28,6 +28,8 @@ pub struct CodeGenerator<'a> {
|
||||
pub(crate) current_function: Option<&'a Function>,
|
||||
/// Mapping of variables to registers.
|
||||
pub(crate) variable_mapping: HashMap<&'a Symbol, String>,
|
||||
/// Mapping of composite names to type (`circuit` or `register`).
|
||||
pub(crate) composite_mapping: HashMap<&'a Symbol, String>,
|
||||
}
|
||||
|
||||
impl<'a> CodeGenerator<'a> {
|
||||
@ -38,6 +40,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
next_register: 0,
|
||||
current_function: None,
|
||||
variable_mapping: HashMap::new(),
|
||||
composite_mapping: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,7 @@
|
||||
|
||||
use crate::CodeGenerator;
|
||||
|
||||
use leo_ast::{
|
||||
BinaryExpression, BinaryOperation, CallExpression, ErrExpression, Expression, Identifier, TernaryExpression,
|
||||
UnaryExpression, UnaryOperation, ValueExpression,
|
||||
};
|
||||
use leo_ast::{BinaryExpression, BinaryOperation, CallExpression, ErrExpression, Expression, Identifier, TernaryExpression, UnaryExpression, UnaryOperation, LiteralExpression, CircuitInitExpression, AccessExpression, MemberAccess};
|
||||
|
||||
/// Implement the necessary methods to visit nodes in the AST.
|
||||
// Note: We opt for this option instead of using `Visitor` and `Director` because this pass requires
|
||||
@ -28,15 +25,15 @@ use leo_ast::{
|
||||
impl<'a> CodeGenerator<'a> {
|
||||
pub(crate) fn visit_expression(&mut self, input: &'a Expression) -> (String, String) {
|
||||
match input {
|
||||
Expression::Access(_expr) => todo!(),
|
||||
Expression::Access(expr) => self.visit_access(expr),
|
||||
Expression::Binary(expr) => self.visit_binary(expr),
|
||||
Expression::Call(expr) => self.visit_call(expr),
|
||||
Expression::CircuitInit(_expr) => todo!(),
|
||||
Expression::CircuitInit(expr) => self.visit_circuit_init(expr),
|
||||
Expression::Err(expr) => self.visit_err(expr),
|
||||
Expression::Identifier(expr) => self.visit_identifier(expr),
|
||||
Expression::Ternary(expr) => self.visit_ternary(expr),
|
||||
Expression::Unary(expr) => self.visit_unary(expr),
|
||||
Expression::Value(expr) => self.visit_value(expr),
|
||||
Expression::Literal(expr) => self.visit_value(expr),
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +41,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
(self.variable_mapping.get(&input.name).unwrap().clone(), String::new())
|
||||
}
|
||||
|
||||
fn visit_value(&mut self, input: &'a ValueExpression) -> (String, String) {
|
||||
fn visit_value(&mut self, input: &'a LiteralExpression) -> (String, String) {
|
||||
(format!("{}", input), String::new())
|
||||
}
|
||||
|
||||
@ -133,7 +130,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
|
||||
let destination_register = format!("r{}", self.next_register);
|
||||
let ternary_instruction = format!(
|
||||
" ternary {} {} {} into r{};\n",
|
||||
" ternary {} {} {} into {};\n",
|
||||
condition_operand, if_true_operand, if_false_operand, destination_register
|
||||
);
|
||||
|
||||
@ -149,8 +146,80 @@ impl<'a> CodeGenerator<'a> {
|
||||
(destination_register, instructions)
|
||||
}
|
||||
|
||||
fn visit_call(&mut self, _input: &'a CallExpression) -> (String, String) {
|
||||
unreachable!("`CallExpression`s should not be in the AST at this phase of compilation.")
|
||||
fn visit_circuit_init(&mut self, input: &'a CircuitInitExpression) -> (String, String) {
|
||||
// Initialize instruction builder strings.
|
||||
let mut instructions = String::new();
|
||||
let mut circuit_init_instruction = format!(" {} ", input.name.to_string().to_lowercase());
|
||||
|
||||
// Visit each circuit member and accumulate instructions from expressions.
|
||||
for member in input.members.iter() {
|
||||
let operand = if let Some(expr) = member.expression.as_ref() {
|
||||
// Visit variable expression.
|
||||
let (variable_operand, variable_instructions) = self.visit_expression(expr);
|
||||
instructions.push_str(&variable_instructions);
|
||||
|
||||
variable_operand
|
||||
} else {
|
||||
// Push operand identifier.
|
||||
let (ident_operand, ident_instructions) = self.visit_identifier(&member.identifier);
|
||||
instructions.push_str(&ident_instructions);
|
||||
|
||||
ident_operand
|
||||
};
|
||||
|
||||
// Push operand name to circuit init instruction.
|
||||
circuit_init_instruction.push_str(&format!("{} ", operand))
|
||||
}
|
||||
|
||||
// Push destination register to circuit init instruction.
|
||||
let destination_register = format!("r{}", self.next_register);
|
||||
circuit_init_instruction.push_str(&format!("into {};\n", destination_register));
|
||||
instructions.push_str(&circuit_init_instruction);
|
||||
|
||||
// Increment the register counter.
|
||||
self.next_register += 1;
|
||||
|
||||
(destination_register, instructions)
|
||||
}
|
||||
|
||||
fn visit_member_access(&mut self, input: &'a MemberAccess) -> (String, String) {
|
||||
let (inner_circuit, _inner_instructions) = self.visit_expression(&input.inner);
|
||||
let member_access_instruction = format!(
|
||||
"{}.{}",
|
||||
inner_circuit,
|
||||
input.name
|
||||
);
|
||||
|
||||
(member_access_instruction, String::new())
|
||||
}
|
||||
|
||||
fn visit_access(&mut self, input: &'a AccessExpression) -> (String, String) {
|
||||
match input {
|
||||
AccessExpression::Member(access) => self.visit_member_access(access),
|
||||
AccessExpression::AssociatedConstant(_) => todo!(),
|
||||
AccessExpression::AssociatedFunction(_) => todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_call(&mut self, input: &'a CallExpression) -> (String, String) {
|
||||
let mut call_instruction = format!(" {} ", input.function);
|
||||
let mut instructions = String::new();
|
||||
|
||||
for argument in input.arguments.iter() {
|
||||
let (argument, argument_instructions) = self.visit_expression(&argument);
|
||||
call_instruction.push_str(&format!("{} ", argument));
|
||||
instructions.push_str(&argument_instructions);
|
||||
}
|
||||
|
||||
// Push destination register to call instruction.
|
||||
let destination_register = format!("r{}", self.next_register);
|
||||
call_instruction.push_str(&format!("into {};\n", destination_register));
|
||||
instructions.push_str(&call_instruction);
|
||||
|
||||
// Increment the register counter.
|
||||
self.next_register += 1;
|
||||
|
||||
(destination_register, instructions)
|
||||
}
|
||||
|
||||
fn visit_err(&mut self, _input: &'a ErrExpression) -> (String, String) {
|
||||
|
@ -16,19 +16,86 @@
|
||||
|
||||
use crate::CodeGenerator;
|
||||
|
||||
use leo_ast::{Function, Program};
|
||||
use leo_ast::{Circuit, CircuitMember, Function, Program};
|
||||
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
|
||||
impl<'a> CodeGenerator<'a> {
|
||||
pub(crate) fn visit_program(&mut self, input: &'a Program) -> String {
|
||||
let mut program_string = String::new();
|
||||
|
||||
// Visit each `Circuit` or `Record` in the Leo AST and produce a bytecode circuit.
|
||||
program_string.push_str(&input
|
||||
.circuits
|
||||
.values()
|
||||
.map(|circuit| self.visit_circuit_or_record(circuit))
|
||||
.join("\n"));
|
||||
|
||||
program_string.push_str("\n");
|
||||
|
||||
// Visit each `Function` in the Leo AST and produce a bytecode function.
|
||||
input
|
||||
program_string.push_str(&input
|
||||
.functions
|
||||
.values()
|
||||
.map(|function| self.visit_function(function))
|
||||
.join("\n")
|
||||
.join("\n"));
|
||||
|
||||
program_string
|
||||
}
|
||||
|
||||
fn visit_circuit_or_record(&mut self, circuit: &'a Circuit) -> String {
|
||||
if circuit.is_record {
|
||||
self.visit_record(circuit)
|
||||
} else {
|
||||
self.visit_circuit(circuit)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, circuit: &'a Circuit) -> String {
|
||||
// Add private symbol to composite types.
|
||||
self.composite_mapping.insert(&circuit.identifier.name, String::from("private")); // todo: private by default here.
|
||||
|
||||
let mut output_string =
|
||||
format!("interface {}:\n", circuit.identifier.to_string().to_lowercase()); // todo: check if this is safe from name conflicts.
|
||||
|
||||
// Construct and append the record variables.
|
||||
for var in circuit.members.iter() {
|
||||
let (name, type_) = match var {
|
||||
CircuitMember::CircuitVariable(name, type_) => (name, type_)
|
||||
};
|
||||
|
||||
output_string.push_str(&format!(
|
||||
" {} as {};\n",
|
||||
name,
|
||||
type_,
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
output_string
|
||||
}
|
||||
|
||||
fn visit_record(&mut self, record: &'a Circuit) -> String {
|
||||
// Add record symbol to composite types.
|
||||
let mut output_string = String::from("record");
|
||||
self.composite_mapping.insert(&record.identifier.name, output_string.clone());
|
||||
output_string.push_str( &format!(" {}:\n", record.identifier.to_string().to_lowercase())); // todo: check if this is safe from name conflicts.
|
||||
|
||||
// Construct and append the record variables.
|
||||
for var in record.members.iter() {
|
||||
let (name, type_) = match var {
|
||||
CircuitMember::CircuitVariable(name, type_) => (name, type_)
|
||||
};
|
||||
|
||||
output_string.push_str(&format!(
|
||||
" {} as {}.private;\n", // todo: CAUTION private record variables only.
|
||||
name,
|
||||
type_,
|
||||
))
|
||||
}
|
||||
|
||||
output_string
|
||||
}
|
||||
|
||||
fn visit_function(&mut self, function: &'a Function) -> String {
|
||||
@ -48,12 +115,11 @@ impl<'a> CodeGenerator<'a> {
|
||||
self.variable_mapping
|
||||
.insert(&input.get_variable().identifier.name, register_string.clone());
|
||||
|
||||
let type_string = self.visit_type(&input.get_variable().type_);
|
||||
let type_string = self.visit_type_with_visibility(&input.get_variable().type_, Some(input.get_variable().mode()));
|
||||
function_string.push_str(&format!(
|
||||
" input {} as {}.{};\n",
|
||||
" input {} as {};\n",
|
||||
register_string,
|
||||
type_string,
|
||||
input.get_variable().mode()
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -38,9 +38,9 @@ impl<'a> CodeGenerator<'a> {
|
||||
|
||||
fn visit_return(&mut self, input: &'a ReturnStatement) -> String {
|
||||
let (operand, mut expression_instructions) = self.visit_expression(&input.expression);
|
||||
let output_type = self.visit_type(&self.current_function.unwrap().output);
|
||||
let output_type = self.visit_type_with_visibility(&self.current_function.unwrap().output, None);
|
||||
// TODO: Bytecode functions have an associated output mode. Currently defaulting to private since we do not yet support this at the Leo level.
|
||||
let output_statement = format!(" output {} as {}.private;\n", operand, output_type);
|
||||
let output_statement = format!(" output {} as {};\n", operand, output_type);
|
||||
expression_instructions.push_str(&output_statement);
|
||||
|
||||
expression_instructions
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use crate::CodeGenerator;
|
||||
|
||||
use leo_ast::Type;
|
||||
use leo_ast::{ParamMode, Type};
|
||||
|
||||
impl<'a> CodeGenerator<'a> {
|
||||
pub(crate) fn visit_type(&mut self, input: &'a Type) -> String {
|
||||
@ -27,10 +27,30 @@ impl<'a> CodeGenerator<'a> {
|
||||
| Type::Group
|
||||
| Type::Scalar
|
||||
| Type::String
|
||||
| Type::IntegerType(..)
|
||||
| Type::SelfType => format!("{}", input),
|
||||
Type::Identifier(_) => unimplemented!("Support for composite types is not yet implemented"),
|
||||
| Type::IntegerType(..) => format!("{}", input),
|
||||
Type::Identifier(ident) => {
|
||||
if let Some(type_) = self.composite_mapping.get(&ident.name) {
|
||||
format!("{}.{}", ident.to_string().to_lowercase(), type_)
|
||||
} else {
|
||||
unreachable!("All composite types should be known at this phase of compilation")
|
||||
}
|
||||
}
|
||||
Type::Err => unreachable!("Error types should not exist at this phase of compilation"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn visit_type_with_visibility(&mut self, input: &'a Type, visibility: Option<ParamMode>) -> String {
|
||||
let mut return_type = self.visit_type(input);
|
||||
|
||||
if let Type::Identifier(_) = input {
|
||||
// Do not append anything for record and circuit types.
|
||||
} else {
|
||||
// Append `.private` to return type.
|
||||
// todo: CAUTION private by default.
|
||||
return_type.push_str(&format!(".{}", visibility.unwrap_or(ParamMode::Private).to_string()));
|
||||
}
|
||||
|
||||
return_type
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -36,22 +36,23 @@ impl<'a> CreateSymbolTable<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExpressionVisitor<'a> for CreateSymbolTable<'a> {}
|
||||
impl<'a> ExpressionVisitor<'a> for CreateSymbolTable<'a> {
|
||||
type AdditionalInput = ();
|
||||
type Output = ();
|
||||
}
|
||||
|
||||
impl<'a> StatementVisitor<'a> for CreateSymbolTable<'a> {}
|
||||
|
||||
impl<'a> ProgramVisitor<'a> for CreateSymbolTable<'a> {
|
||||
fn visit_function(&mut self, input: &'a Function) -> VisitResult {
|
||||
fn visit_function(&mut self, input: &'a Function) {
|
||||
if let Err(err) = self.symbol_table.insert_fn(input.name(), input) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
VisitResult::SkipChildren
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, input: &'a Circuit) -> VisitResult {
|
||||
fn visit_circuit(&mut self, input: &'a Circuit) {
|
||||
if let Err(err) = self.symbol_table.insert_circuit(input.name(), input) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
VisitResult::SkipChildren
|
||||
}
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
use leo_ast::{ExpressionVisitorDirector, ProgramVisitorDirector, StatementVisitorDirector, VisitorDirector};
|
||||
use leo_errors::emitter::Handler;
|
||||
|
||||
use crate::CreateSymbolTable;
|
||||
|
||||
pub(crate) struct Director<'a> {
|
||||
visitor: CreateSymbolTable<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Director<'a> {
|
||||
pub(crate) fn new(handler: &'a Handler) -> Self {
|
||||
Self {
|
||||
visitor: CreateSymbolTable::new(handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VisitorDirector<'a> for Director<'a> {
|
||||
type Visitor = CreateSymbolTable<'a>;
|
||||
|
||||
fn visitor(self) -> Self::Visitor {
|
||||
self.visitor
|
||||
}
|
||||
|
||||
fn visitor_ref(&mut self) -> &mut Self::Visitor {
|
||||
&mut self.visitor
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
type AdditionalInput = ();
|
||||
type Output = ();
|
||||
}
|
||||
|
||||
impl<'a> StatementVisitorDirector<'a> for Director<'a> {}
|
||||
|
||||
impl<'a> ProgramVisitorDirector<'a> for Director<'a> {}
|
@ -17,9 +17,6 @@
|
||||
pub mod create;
|
||||
pub use create::*;
|
||||
|
||||
pub mod director;
|
||||
use director::*;
|
||||
|
||||
pub mod table;
|
||||
pub use table::*;
|
||||
|
||||
@ -31,7 +28,7 @@ pub use variable_symbol::*;
|
||||
|
||||
use crate::Pass;
|
||||
|
||||
use leo_ast::{Ast, ProgramVisitorDirector, VisitorDirector};
|
||||
use leo_ast::{Ast, ProgramVisitor};
|
||||
use leo_errors::{emitter::Handler, Result};
|
||||
|
||||
impl<'a> Pass for CreateSymbolTable<'a> {
|
||||
@ -39,10 +36,10 @@ impl<'a> Pass for CreateSymbolTable<'a> {
|
||||
type Output = Result<SymbolTable<'a>>;
|
||||
|
||||
fn do_pass((ast, handler): Self::Input) -> Self::Output {
|
||||
let mut visitor = Director::new(handler);
|
||||
let mut visitor = CreateSymbolTable::new(handler);
|
||||
visitor.visit_program(ast.as_repr());
|
||||
handler.last_err()?;
|
||||
|
||||
Ok(visitor.visitor().symbol_table())
|
||||
Ok(visitor.symbol_table())
|
||||
}
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ pub struct SymbolTable<'a> {
|
||||
}
|
||||
|
||||
impl<'a> SymbolTable<'a> {
|
||||
pub fn check_shadowing(&self, symbol: &Symbol, span: Span) -> Result<()> {
|
||||
if self.functions.contains_key(symbol) {
|
||||
pub fn check_shadowing(&self, symbol: Symbol, span: Span) -> Result<()> {
|
||||
if self.functions.contains_key(&symbol) {
|
||||
Err(AstError::shadowed_function(symbol, span).into())
|
||||
} else {
|
||||
self.variables.check_shadowing(symbol, span)?;
|
||||
@ -52,28 +52,33 @@ impl<'a> SymbolTable<'a> {
|
||||
}
|
||||
|
||||
pub fn insert_fn(&mut self, symbol: Symbol, insert: &'a Function) -> Result<()> {
|
||||
self.check_shadowing(&symbol, insert.span)?;
|
||||
self.check_shadowing(symbol, insert.span)?;
|
||||
self.functions.insert(symbol, insert);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_circuit(&mut self, symbol: Symbol, insert: &'a Circuit) -> Result<()> {
|
||||
if self.circuits.contains_key(&symbol) {
|
||||
// Return an error if the circuit name has already been inserted.
|
||||
return Err(AstError::shadowed_circuit(symbol, insert.span).into());
|
||||
if let Some(existing) = self.circuits.get(&symbol) {
|
||||
// Error if the circuit or record already exists.
|
||||
let err = if existing.is_record {
|
||||
AstError::shadowed_record(symbol, insert.span).into()
|
||||
} else {
|
||||
AstError::shadowed_circuit(symbol, insert.span).into()
|
||||
};
|
||||
return Err(err);
|
||||
}
|
||||
self.circuits.insert(symbol, insert);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_variable(&mut self, symbol: Symbol, insert: VariableSymbol<'a>) -> Result<()> {
|
||||
self.check_shadowing(&symbol, insert.span)?;
|
||||
self.check_shadowing(symbol, insert.span)?;
|
||||
self.variables.variables.insert(symbol, insert);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lookup_fn(&self, symbol: &Symbol) -> Option<&&'a Function> {
|
||||
self.functions.get(symbol)
|
||||
pub fn lookup_fn(&self, symbol: Symbol) -> Option<&&'a Function> {
|
||||
self.functions.get(&symbol)
|
||||
}
|
||||
|
||||
pub fn lookup_circuit(&self, symbol: &Symbol) -> Option<&&'a Circuit> {
|
||||
@ -99,7 +104,7 @@ impl<'a> SymbolTable<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Display for SymbolTable<'a> {
|
||||
impl Display for SymbolTable<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "SymbolTable")?;
|
||||
|
||||
|
@ -35,8 +35,8 @@ pub struct VariableScope<'a> {
|
||||
}
|
||||
|
||||
impl<'a> VariableScope<'a> {
|
||||
pub fn check_shadowing(&self, symbol: &Symbol, span: Span) -> Result<()> {
|
||||
if self.variables.contains_key(symbol) {
|
||||
pub fn check_shadowing(&self, symbol: Symbol, span: Span) -> Result<()> {
|
||||
if self.variables.contains_key(&symbol) {
|
||||
Err(AstError::shadowed_variable(symbol, span).into())
|
||||
} else if let Some(parent) = &self.parent {
|
||||
parent.check_shadowing(symbol, span)
|
||||
|
@ -19,10 +19,6 @@ use leo_errors::TypeCheckerError;
|
||||
|
||||
use crate::TypeChecker;
|
||||
|
||||
use super::director::Director;
|
||||
|
||||
impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {}
|
||||
|
||||
fn return_incorrect_type(t1: Option<Type>, t2: Option<Type>, expected: &Option<Type>) -> Option<Type> {
|
||||
match (t1, t2) {
|
||||
(Some(t1), Some(t2)) if t1 == t2 => Some(t1),
|
||||
@ -41,236 +37,175 @@ fn return_incorrect_type(t1: Option<Type>, t2: Option<Type>, expected: &Option<T
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
type AdditionalInput = Option<Type>;
|
||||
type Output = Type;
|
||||
type Output = Option<Type>;
|
||||
|
||||
fn visit_expression(&mut self, input: &'a Expression, expected: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_expression(input) {
|
||||
return match input {
|
||||
fn visit_expression(&mut self, input: &'a Expression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
match input {
|
||||
Expression::Access(expr) => self.visit_access(expr, expected),
|
||||
Expression::Identifier(expr) => self.visit_identifier(expr, expected),
|
||||
Expression::Literal(expr) => self.visit_literal(expr, expected),
|
||||
Expression::Binary(expr) => self.visit_binary(expr, expected),
|
||||
Expression::Call(expr) => self.visit_call(expr, expected),
|
||||
Expression::CircuitInit(expr) => self.visit_circuit_init(expr, expected),
|
||||
Expression::Err(expr) => self.visit_err(expr, expected),
|
||||
Expression::Identifier(expr) => self.visit_identifier(expr, expected),
|
||||
Expression::Ternary(expr) => self.visit_ternary(expr, expected),
|
||||
Expression::Unary(expr) => self.visit_unary(expr, expected),
|
||||
Expression::Value(expr) => self.visit_value(expr, expected),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_identifier(&mut self, input: &'a Identifier, expected: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_identifier(input) {
|
||||
return if let Some(circuit) = self.visitor.symbol_table.clone().lookup_circuit(&input.name) {
|
||||
Some(self.visitor.assert_expected_option(
|
||||
Type::Identifier(circuit.identifier.clone()),
|
||||
expected,
|
||||
circuit.span(),
|
||||
))
|
||||
} else if let Some(var) = self.visitor.symbol_table.clone().lookup_variable(&input.name) {
|
||||
Some(self.visitor.assert_expected_option(*var.type_, expected, var.span))
|
||||
fn visit_identifier(&mut self, var: &'a Identifier, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
if let Some(circuit) = self.symbol_table.clone().lookup_circuit(&var.name) {
|
||||
Some(self.assert_expected_option(Type::Identifier(circuit.identifier), expected, circuit.span()))
|
||||
} else if let Some(var) = self.symbol_table.clone().lookup_variable(&var.name) {
|
||||
Some(self.assert_expected_option(*var.type_, expected, var.span))
|
||||
} else {
|
||||
self.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", input.name, input.span()).into());
|
||||
None
|
||||
};
|
||||
}
|
||||
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", var.name, var.span()).into());
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_value(&mut self, input: &'a ValueExpression, expected: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_value(input) {
|
||||
return Some(match input {
|
||||
ValueExpression::Address(_, _) => {
|
||||
self.visitor
|
||||
.assert_expected_option(Type::Address, expected, input.span())
|
||||
}
|
||||
ValueExpression::Boolean(_, _) => {
|
||||
self.visitor
|
||||
.assert_expected_option(Type::Boolean, expected, input.span())
|
||||
}
|
||||
ValueExpression::Field(_, _) => {
|
||||
self.visitor.assert_expected_option(Type::Field, expected, input.span())
|
||||
}
|
||||
ValueExpression::Integer(type_, str_content, _) => {
|
||||
fn visit_literal(&mut self, input: &'a LiteralExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
Some(match input {
|
||||
LiteralExpression::Address(_, _) => self.assert_expected_option(Type::Address, expected, input.span()),
|
||||
LiteralExpression::Boolean(_, _) => self.assert_expected_option(Type::Boolean, expected, input.span()),
|
||||
LiteralExpression::Field(_, _) => self.assert_expected_option(Type::Field, expected, input.span()),
|
||||
LiteralExpression::Integer(type_, str_content, _) => {
|
||||
match type_ {
|
||||
IntegerType::I8 => {
|
||||
let int = if self.visitor.negate {
|
||||
let int = if self.negate {
|
||||
format!("-{str_content}")
|
||||
} else {
|
||||
str_content.clone()
|
||||
};
|
||||
|
||||
if int.parse::<i8>().is_err() {
|
||||
self.visitor
|
||||
.handler
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i8", input.span()).into());
|
||||
}
|
||||
}
|
||||
IntegerType::I16 => {
|
||||
let int = if self.visitor.negate {
|
||||
let int = if self.negate {
|
||||
format!("-{str_content}")
|
||||
} else {
|
||||
str_content.clone()
|
||||
};
|
||||
|
||||
if int.parse::<i16>().is_err() {
|
||||
self.visitor
|
||||
.handler
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i16", input.span()).into());
|
||||
}
|
||||
}
|
||||
IntegerType::I32 => {
|
||||
let int = if self.visitor.negate {
|
||||
let int = if self.negate {
|
||||
format!("-{str_content}")
|
||||
} else {
|
||||
str_content.clone()
|
||||
};
|
||||
|
||||
if int.parse::<i32>().is_err() {
|
||||
self.visitor
|
||||
.handler
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i32", input.span()).into());
|
||||
}
|
||||
}
|
||||
IntegerType::I64 => {
|
||||
let int = if self.visitor.negate {
|
||||
let int = if self.negate {
|
||||
format!("-{str_content}")
|
||||
} else {
|
||||
str_content.clone()
|
||||
};
|
||||
|
||||
if int.parse::<i64>().is_err() {
|
||||
self.visitor
|
||||
.handler
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i64", input.span()).into());
|
||||
}
|
||||
}
|
||||
IntegerType::I128 => {
|
||||
let int = if self.visitor.negate {
|
||||
let int = if self.negate {
|
||||
format!("-{str_content}")
|
||||
} else {
|
||||
str_content.clone()
|
||||
};
|
||||
|
||||
if int.parse::<i128>().is_err() {
|
||||
self.visitor
|
||||
.handler
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(int, "i128", input.span()).into());
|
||||
}
|
||||
}
|
||||
IntegerType::U8 if str_content.parse::<u8>().is_err() => self
|
||||
.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u8", input.span()).into()),
|
||||
IntegerType::U16 if str_content.parse::<u16>().is_err() => self
|
||||
.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u16", input.span()).into()),
|
||||
IntegerType::U32 if str_content.parse::<u32>().is_err() => self
|
||||
.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u32", input.span()).into()),
|
||||
IntegerType::U64 if str_content.parse::<u64>().is_err() => self
|
||||
.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u64", input.span()).into()),
|
||||
IntegerType::U128 if str_content.parse::<u128>().is_err() => self
|
||||
.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::invalid_int_value(str_content, "u128", input.span()).into()),
|
||||
_ => {}
|
||||
}
|
||||
self.visitor
|
||||
.assert_expected_option(Type::IntegerType(*type_), expected, input.span())
|
||||
self.assert_expected_option(Type::IntegerType(*type_), expected, input.span())
|
||||
}
|
||||
ValueExpression::Group(_) => self.visitor.assert_expected_option(Type::Group, expected, input.span()),
|
||||
ValueExpression::Scalar(_, _) => {
|
||||
self.visitor
|
||||
.assert_expected_option(Type::Scalar, expected, input.span())
|
||||
}
|
||||
ValueExpression::String(_, _) => {
|
||||
self.visitor
|
||||
.assert_expected_option(Type::String, expected, input.span())
|
||||
}
|
||||
});
|
||||
LiteralExpression::Group(_) => self.assert_expected_option(Type::Group, expected, input.span()),
|
||||
LiteralExpression::Scalar(_, _) => self.assert_expected_option(Type::Scalar, expected, input.span()),
|
||||
LiteralExpression::String(_, _) => self.assert_expected_option(Type::String, expected, input.span()),
|
||||
})
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_access(&mut self, input: &'a AccessExpression, expected: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
fn visit_access(&mut self, input: &'a AccessExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
// CAUTION: This implementation only allows access to core circuits.
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_access(input) {
|
||||
match input {
|
||||
AccessExpression::StaticFunction(access) => {
|
||||
// Visit core circuit function
|
||||
let circuit = self.visit_expression(&access.inner, &None);
|
||||
if let Some(core_instruction) = self.visitor.assert_core_circuit_call(&circuit, &access.name) {
|
||||
AccessExpression::AssociatedFunction(access) => {
|
||||
// Check core circuit name and function.
|
||||
if let Some(core_instruction) = self.assert_core_circuit_call(&access.ty, &access.name) {
|
||||
// Check num input arguments.
|
||||
if core_instruction.num_args() != access.input.len() {
|
||||
self.visitor.handler.emit_err(
|
||||
if core_instruction.num_args() != access.args.len() {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_args_to_call(
|
||||
core_instruction.num_args(),
|
||||
access.input.len(),
|
||||
access.args.len(),
|
||||
input.span(),
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
// Check input argument types.
|
||||
access.input.iter().enumerate().for_each(|(index, input_expr)| {
|
||||
let input_type = self.visit_expression(input_expr, &None);
|
||||
// Check first argument type.
|
||||
if let Some(first_arg) = access.args.get(0usize) {
|
||||
let first_arg_type = self.visit_expression(first_arg, &None);
|
||||
self.assert_one_of_types(&first_arg_type, core_instruction.first_arg_types(), access.span());
|
||||
}
|
||||
|
||||
match index {
|
||||
0 => self.visitor.assert_one_of_types(
|
||||
&input_type,
|
||||
core_instruction.first_arg_types(),
|
||||
access.span(),
|
||||
),
|
||||
1 => self.visitor.assert_one_of_types(
|
||||
&input_type,
|
||||
core_instruction.second_arg_types(),
|
||||
access.span(),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
});
|
||||
// Check second argument type.
|
||||
if let Some(second_arg) = access.args.get(1usize) {
|
||||
let second_arg_type = self.visit_expression(second_arg, &None);
|
||||
self.assert_one_of_types(&second_arg_type, core_instruction.second_arg_types(), access.span());
|
||||
}
|
||||
|
||||
// Check return type.
|
||||
return Some(self.visitor.assert_expected_option(
|
||||
core_instruction.return_type(),
|
||||
expected,
|
||||
access.span(),
|
||||
));
|
||||
Some(self.assert_expected_option(core_instruction.return_type(), expected, access.span()))
|
||||
} else {
|
||||
// todo: return Err for unknown circuit or function
|
||||
}
|
||||
}
|
||||
_ => unimplemented!("only static core circuit function calls are supported"),
|
||||
}
|
||||
}
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_access_expression(access, access.span()).into());
|
||||
None
|
||||
}
|
||||
}
|
||||
_expr => None, // todo: Add support for associated constants (u8::MAX).
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_binary(
|
||||
&mut self,
|
||||
input: &'a BinaryExpression,
|
||||
destination: &Self::AdditionalInput,
|
||||
) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_binary(input) {
|
||||
return match input.op {
|
||||
fn visit_binary(&mut self, input: &'a BinaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
|
||||
match input.op {
|
||||
BinaryOperation::And | BinaryOperation::Or | BinaryOperation::Nand | BinaryOperation::Nor => {
|
||||
// Assert equal boolean types.
|
||||
self.visitor
|
||||
.assert_expected_option(Type::Boolean, destination, input.span());
|
||||
self.assert_expected_option(Type::Boolean, destination, input.span());
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
|
||||
@ -278,7 +213,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
BinaryOperation::BitwiseAnd | BinaryOperation::BitwiseOr | BinaryOperation::Xor => {
|
||||
// Assert equal boolean or integer types.
|
||||
self.visitor.assert_bool_int_type(destination, input.span());
|
||||
self.assert_bool_int_type(destination, input.span());
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
|
||||
@ -286,8 +221,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
BinaryOperation::Add => {
|
||||
// Assert equal field, group, scalar, or integer types.
|
||||
self.visitor
|
||||
.assert_field_group_scalar_int_type(destination, input.span());
|
||||
self.assert_field_group_scalar_int_type(destination, input.span());
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
|
||||
@ -295,7 +229,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
BinaryOperation::Sub => {
|
||||
// Assert equal field, group, or integer types.
|
||||
self.visitor.assert_field_group_int_type(destination, input.span());
|
||||
self.assert_field_group_int_type(destination, input.span());
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
|
||||
@ -303,7 +237,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
BinaryOperation::Mul => {
|
||||
// Assert field, group or integer types.
|
||||
self.visitor.assert_field_group_int_type(destination, input.span());
|
||||
self.assert_field_group_int_type(destination, input.span());
|
||||
|
||||
let t1 = self.visit_expression(&input.left, &None);
|
||||
let t2 = self.visit_expression(&input.right, &None);
|
||||
@ -311,24 +245,16 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
// Allow `group` * `scalar` multiplication.
|
||||
match (t1, t2) {
|
||||
(Some(Type::Group), other) => {
|
||||
self.visitor
|
||||
.assert_expected_type(&other, Type::Scalar, input.right.span());
|
||||
Some(
|
||||
self.visitor
|
||||
.assert_expected_type(destination, Type::Group, input.span()),
|
||||
)
|
||||
self.assert_expected_type(&other, Type::Scalar, input.right.span());
|
||||
Some(self.assert_expected_type(destination, Type::Group, input.span()))
|
||||
}
|
||||
(other, Some(Type::Group)) => {
|
||||
self.visitor
|
||||
.assert_expected_type(&other, Type::Scalar, input.left.span());
|
||||
Some(
|
||||
self.visitor
|
||||
.assert_expected_type(destination, Type::Group, input.span()),
|
||||
)
|
||||
self.assert_expected_type(&other, Type::Scalar, input.left.span());
|
||||
Some(self.assert_expected_type(destination, Type::Group, input.span()))
|
||||
}
|
||||
(t1, t2) => {
|
||||
// Assert equal field or integer types.
|
||||
self.visitor.assert_field_int_type(destination, input.span());
|
||||
self.assert_field_int_type(destination, input.span());
|
||||
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
}
|
||||
@ -336,7 +262,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
BinaryOperation::Div => {
|
||||
// Assert equal field or integer types.
|
||||
self.visitor.assert_field_int_type(destination, input.span());
|
||||
self.assert_field_int_type(destination, input.span());
|
||||
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
@ -345,7 +271,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
BinaryOperation::Pow => {
|
||||
// Assert field or integer types.
|
||||
self.visitor.assert_field_int_type(destination, input.span());
|
||||
self.assert_field_int_type(destination, input.span());
|
||||
|
||||
let t1 = self.visit_expression(&input.left, &None);
|
||||
let t2 = self.visit_expression(&input.right, &None);
|
||||
@ -353,29 +279,21 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
// Allow field * field.
|
||||
match (t1, t2) {
|
||||
(Some(Type::Field), type_) => {
|
||||
self.visitor
|
||||
.assert_expected_type(&type_, Type::Field, input.right.span());
|
||||
Some(
|
||||
self.visitor
|
||||
.assert_expected_type(destination, Type::Field, input.span()),
|
||||
)
|
||||
self.assert_expected_type(&type_, Type::Field, input.right.span());
|
||||
Some(self.assert_expected_type(destination, Type::Field, input.span()))
|
||||
}
|
||||
(type_, Some(Type::Field)) => {
|
||||
self.visitor
|
||||
.assert_expected_type(&type_, Type::Field, input.left.span());
|
||||
Some(
|
||||
self.visitor
|
||||
.assert_expected_type(destination, Type::Field, input.span()),
|
||||
)
|
||||
self.assert_expected_type(&type_, Type::Field, input.left.span());
|
||||
Some(self.assert_expected_type(destination, Type::Field, input.span()))
|
||||
}
|
||||
(Some(t1), t2) => {
|
||||
// Allow integer t2 magnitude (u8, u16, u32)
|
||||
self.visitor.assert_magnitude_type(&t2, input.right.span());
|
||||
Some(self.visitor.assert_expected_type(destination, t1, input.span()))
|
||||
self.assert_magnitude_type(&t2, input.right.span());
|
||||
Some(self.assert_expected_type(destination, t1, input.span()))
|
||||
}
|
||||
(None, t2) => {
|
||||
// Allow integer t2 magnitude (u8, u16, u32)
|
||||
self.visitor.assert_magnitude_type(&t2, input.right.span());
|
||||
self.assert_magnitude_type(&t2, input.right.span());
|
||||
*destination
|
||||
}
|
||||
}
|
||||
@ -388,22 +306,19 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
match (t1, t2) {
|
||||
(Some(Type::IntegerType(_)), t2) => {
|
||||
// Assert rhs is integer.
|
||||
self.visitor.assert_int_type(&t2, input.left.span());
|
||||
self.assert_int_type(&t2, input.left.span());
|
||||
}
|
||||
(t1, Some(Type::IntegerType(_))) => {
|
||||
// Assert lhs is integer.
|
||||
self.visitor.assert_int_type(&t1, input.right.span());
|
||||
self.assert_int_type(&t1, input.right.span());
|
||||
}
|
||||
(t1, t2) => {
|
||||
self.visitor.assert_eq_types(t1, t2, input.span());
|
||||
self.assert_eq_types(t1, t2, input.span());
|
||||
}
|
||||
}
|
||||
|
||||
// Assert destination is boolean.
|
||||
Some(
|
||||
self.visitor
|
||||
.assert_expected_type(destination, Type::Boolean, input.span()),
|
||||
)
|
||||
Some(self.assert_expected_type(destination, Type::Boolean, input.span()))
|
||||
}
|
||||
BinaryOperation::Lt | BinaryOperation::Gt | BinaryOperation::Lte | BinaryOperation::Gte => {
|
||||
// Assert left and right are equal field, scalar, or integer types.
|
||||
@ -411,29 +326,34 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
let t2 = self.visit_expression(&input.right, &None);
|
||||
|
||||
match (t1, t2) {
|
||||
(Some(Type::Address), _) | (_, Some(Type::Address)) => {
|
||||
// Emit an error for address comparison.
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::compare_address(input.op, input.span()).into());
|
||||
}
|
||||
(Some(Type::Field), t2) => {
|
||||
// Assert rhs is field.
|
||||
self.visitor.assert_expected_type(&t2, Type::Field, input.left.span());
|
||||
self.assert_expected_type(&t2, Type::Field, input.left.span());
|
||||
}
|
||||
(t1, Some(Type::Field)) => {
|
||||
// Assert lhs is field.
|
||||
self.visitor.assert_expected_type(&t1, Type::Field, input.right.span());
|
||||
self.assert_expected_type(&t1, Type::Field, input.right.span());
|
||||
}
|
||||
(Some(Type::Scalar), t2) => {
|
||||
// Assert rhs is scalar.
|
||||
self.visitor.assert_expected_type(&t2, Type::Scalar, input.left.span());
|
||||
self.assert_expected_type(&t2, Type::Scalar, input.left.span());
|
||||
}
|
||||
(t1, Some(Type::Scalar)) => {
|
||||
// Assert lhs is scalar.
|
||||
self.visitor.assert_expected_type(&t1, Type::Scalar, input.right.span());
|
||||
self.assert_expected_type(&t1, Type::Scalar, input.right.span());
|
||||
}
|
||||
(Some(Type::IntegerType(_)), t2) => {
|
||||
// Assert rhs is integer.
|
||||
self.visitor.assert_int_type(&t2, input.left.span());
|
||||
self.assert_int_type(&t2, input.left.span());
|
||||
}
|
||||
(t1, Some(Type::IntegerType(_))) => {
|
||||
// Assert lhs is integer.
|
||||
self.visitor.assert_int_type(&t1, input.right.span());
|
||||
self.assert_int_type(&t1, input.right.span());
|
||||
}
|
||||
(_, _) => {
|
||||
// Not enough info to assert type.
|
||||
@ -441,17 +361,14 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
|
||||
// Assert destination is boolean.
|
||||
Some(
|
||||
self.visitor
|
||||
.assert_expected_type(destination, Type::Boolean, input.span()),
|
||||
)
|
||||
Some(self.assert_expected_type(destination, Type::Boolean, input.span()))
|
||||
}
|
||||
BinaryOperation::AddWrapped
|
||||
| BinaryOperation::SubWrapped
|
||||
| BinaryOperation::DivWrapped
|
||||
| BinaryOperation::MulWrapped => {
|
||||
// Assert equal integer types.
|
||||
self.visitor.assert_int_type(destination, input.span);
|
||||
self.assert_int_type(destination, input.span);
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
let t2 = self.visit_expression(&input.right, destination);
|
||||
|
||||
@ -463,51 +380,46 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
| BinaryOperation::ShrWrapped
|
||||
| BinaryOperation::PowWrapped => {
|
||||
// Assert left and destination are equal integer types.
|
||||
self.visitor.assert_int_type(destination, input.span);
|
||||
self.assert_int_type(destination, input.span);
|
||||
let t1 = self.visit_expression(&input.left, destination);
|
||||
|
||||
// Assert right type is a magnitude (u8, u16, u32).
|
||||
let t2 = self.visit_expression(&input.right, &None);
|
||||
self.visitor.assert_magnitude_type(&t2, input.right.span());
|
||||
self.assert_magnitude_type(&t2, input.right.span());
|
||||
|
||||
return_incorrect_type(t1, t2, destination)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_unary(&mut self, input: &'a UnaryExpression, destination: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_unary(input) {
|
||||
fn visit_unary(&mut self, input: &'a UnaryExpression, destination: &Self::AdditionalInput) -> Self::Output {
|
||||
match input.op {
|
||||
UnaryOperation::Abs => {
|
||||
// Assert integer type only.
|
||||
self.visitor.assert_signed_int_type(destination, input.span());
|
||||
self.assert_signed_int_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::AbsWrapped => {
|
||||
// Assert integer type only.
|
||||
self.visitor.assert_signed_int_type(destination, input.span());
|
||||
self.assert_signed_int_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Double => {
|
||||
// Assert field and group type only.
|
||||
self.visitor.assert_field_group_type(destination, input.span());
|
||||
self.assert_field_group_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Inverse => {
|
||||
// Assert field type only.
|
||||
self.visitor
|
||||
.assert_expected_type(destination, Type::Field, input.span());
|
||||
self.assert_expected_type(destination, Type::Field, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Negate => {
|
||||
let prior_negate_state = self.visitor.negate;
|
||||
self.visitor.negate = true;
|
||||
let prior_negate_state = self.negate;
|
||||
self.negate = true;
|
||||
|
||||
let type_ = self.visit_expression(&input.receiver, destination);
|
||||
self.visitor.negate = prior_negate_state;
|
||||
self.negate = prior_negate_state;
|
||||
match type_.as_ref() {
|
||||
Some(
|
||||
Type::IntegerType(
|
||||
@ -521,7 +433,6 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
| Type::Group,
|
||||
) => {}
|
||||
Some(t) => self
|
||||
.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::type_is_not_negatable(t, input.receiver.span()).into()),
|
||||
_ => {}
|
||||
@ -530,52 +441,40 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
UnaryOperation::Not => {
|
||||
// Assert boolean, integer types only.
|
||||
self.visitor.assert_bool_int_type(destination, input.span());
|
||||
self.assert_bool_int_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::Square => {
|
||||
// Assert field type only.
|
||||
self.visitor
|
||||
.assert_expected_type(destination, Type::Field, input.span());
|
||||
self.assert_expected_type(destination, Type::Field, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
UnaryOperation::SquareRoot => {
|
||||
// Assert field type only.
|
||||
self.visitor
|
||||
.assert_expected_type(destination, Type::Field, input.span());
|
||||
// Assert field or scalar type.
|
||||
self.assert_field_scalar_type(destination, input.span());
|
||||
self.visit_expression(&input.receiver, destination)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ternary(
|
||||
&mut self,
|
||||
input: &'a TernaryExpression,
|
||||
expected: &Self::AdditionalInput,
|
||||
) -> Option<Self::Output> {
|
||||
if let VisitResult::VisitChildren = self.visitor.visit_ternary(input) {
|
||||
fn visit_ternary(&mut self, input: &'a TernaryExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
self.visit_expression(&input.condition, &Some(Type::Boolean));
|
||||
|
||||
let t1 = self.visit_expression(&input.if_true, expected);
|
||||
let t2 = self.visit_expression(&input.if_false, expected);
|
||||
|
||||
return return_incorrect_type(t1, t2, expected);
|
||||
return_incorrect_type(t1, t2, expected)
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Option<Self::Output> {
|
||||
fn visit_call(&mut self, input: &'a CallExpression, expected: &Self::AdditionalInput) -> Self::Output {
|
||||
match &*input.function {
|
||||
Expression::Identifier(ident) => {
|
||||
if let Some(func) = self.visitor.symbol_table.clone().lookup_fn(&ident.name) {
|
||||
let ret = self.visitor.assert_expected_option(func.output, expected, func.span());
|
||||
if let Some(func) = self.symbol_table.clone().lookup_fn(ident.name) {
|
||||
let ret = self.assert_expected_option(func.output, expected, func.span());
|
||||
|
||||
// Check number of function arguments.
|
||||
if func.input.len() != input.arguments.len() {
|
||||
self.visitor.handler.emit_err(
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_args_to_call(
|
||||
func.input.len(),
|
||||
input.arguments.len(),
|
||||
@ -585,6 +484,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
);
|
||||
}
|
||||
|
||||
// Check function argument types.
|
||||
func.input
|
||||
.iter()
|
||||
.zip(input.arguments.iter())
|
||||
@ -594,8 +494,7 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
|
||||
Some(ret)
|
||||
} else {
|
||||
self.visitor
|
||||
.handler
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("function", &ident.name, ident.span()).into());
|
||||
None
|
||||
}
|
||||
@ -608,16 +507,14 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
&mut self,
|
||||
input: &'a CircuitInitExpression,
|
||||
additional: &Self::AdditionalInput,
|
||||
) -> Option<Self::Output> {
|
||||
if let Some(circ) = self.visitor.symbol_table.clone().lookup_circuit(&input.name.name) {
|
||||
) -> Self::Output {
|
||||
if let Some(circ) = self.symbol_table.clone().lookup_circuit(&input.name.name) {
|
||||
// Check circuit type name.
|
||||
let ret = self
|
||||
.visitor
|
||||
.assert_expected_circuit(circ.identifier, additional, input.name.span());
|
||||
let ret = self.assert_expected_circuit(circ.identifier, additional, input.name.span());
|
||||
|
||||
// Check number of circuit members.
|
||||
if circ.members.len() != input.members.len() {
|
||||
self.visitor.handler.emit_err(
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::incorrect_num_circuit_members(
|
||||
circ.members.len(),
|
||||
input.members.len(),
|
||||
@ -626,25 +523,26 @@ impl<'a> ExpressionVisitorDirector<'a> for Director<'a> {
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
// Check circuit member types
|
||||
|
||||
// Check circuit member types.
|
||||
circ.members
|
||||
.iter()
|
||||
.zip(input.members.iter())
|
||||
.for_each(|(expected, actual)| {
|
||||
match expected {
|
||||
CircuitMember::CircuitVariable(_name, type_) => {
|
||||
.for_each(|CircuitMember::CircuitVariable(name, ty)| {
|
||||
// Lookup circuit variable name.
|
||||
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == name.name) {
|
||||
if let Some(expr) = &actual.expression {
|
||||
self.visit_expression(expr, &Some(*type_));
|
||||
}
|
||||
}
|
||||
_ => { /* Circuit functions cannot be inside circuit init expressions */ }
|
||||
self.visit_expression(expr, &Some(*ty));
|
||||
}
|
||||
} else {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::unknown_sym("circuit member variable", name, name.span()).into(),
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
Some(ret)
|
||||
} else {
|
||||
self.visitor
|
||||
.handler
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("circuit", &input.name.name, input.name.span()).into());
|
||||
None
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::TypeCheckerError;
|
||||
|
||||
use crate::{Declaration, TypeChecker, VariableSymbol};
|
||||
|
||||
use super::director::Director;
|
||||
|
||||
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {}
|
||||
|
||||
impl<'a> ProgramVisitorDirector<'a> for Director<'a> {
|
||||
fn visit_function(&mut self, input: &'a Function) {
|
||||
if let VisitResult::VisitChildren = self.visitor_ref().visit_function(input) {
|
||||
self.visitor.has_return = false;
|
||||
self.visitor.symbol_table.clear_variables();
|
||||
self.visitor.parent = Some(input.name());
|
||||
input.input.iter().for_each(|i| {
|
||||
let input_var = i.get_variable();
|
||||
self.visitor.check_ident_type(&Some(input_var.type_));
|
||||
|
||||
if let Err(err) = self.visitor.symbol_table.insert_variable(
|
||||
input_var.identifier.name,
|
||||
VariableSymbol {
|
||||
type_: &input_var.type_,
|
||||
span: input_var.identifier.span(),
|
||||
declaration: Declaration::Input(input_var.mode()),
|
||||
},
|
||||
) {
|
||||
self.visitor.handler.emit_err(err);
|
||||
}
|
||||
});
|
||||
self.visit_block(&input.block);
|
||||
|
||||
if !self.visitor.has_return {
|
||||
self.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
85
compiler/passes/src/type_checker/check_program.rs
Normal file
85
compiler/passes/src/type_checker/check_program.rs
Normal file
@ -0,0 +1,85 @@
|
||||
// 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/>.
|
||||
|
||||
use crate::{Declaration, TypeChecker, VariableSymbol};
|
||||
use leo_ast::*;
|
||||
use leo_errors::TypeCheckerError;
|
||||
|
||||
use leo_span::sym;
|
||||
use std::collections::HashSet;
|
||||
|
||||
impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_function(&mut self, input: &'a Function) {
|
||||
self.has_return = false;
|
||||
self.symbol_table.clear_variables();
|
||||
self.parent = Some(input.name());
|
||||
input.input.iter().for_each(|i| {
|
||||
let input_var = i.get_variable();
|
||||
self.check_ident_type(&Some(input_var.type_));
|
||||
|
||||
// Check for conflicting variable names.
|
||||
if let Err(err) = self.symbol_table.insert_variable(
|
||||
input_var.identifier.name,
|
||||
VariableSymbol {
|
||||
type_: &input_var.type_,
|
||||
span: input_var.identifier.span(),
|
||||
declaration: Declaration::Input(input_var.mode()),
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
});
|
||||
self.visit_block(&input.block);
|
||||
|
||||
if !self.has_return {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::function_has_no_return(input.name(), input.span()).into());
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_circuit(&mut self, input: &'a Circuit) {
|
||||
// Check for conflicting circuit member names.
|
||||
let mut used = HashSet::new();
|
||||
if !input.members.iter().all(|member| used.insert(member.name())) {
|
||||
self.handler.emit_err(if input.is_record {
|
||||
TypeCheckerError::duplicate_record_variable(input.name(), input.span()).into()
|
||||
} else {
|
||||
TypeCheckerError::duplicate_circuit_member(input.name(), input.span()).into()
|
||||
});
|
||||
}
|
||||
|
||||
// For records, enforce presence of `owner: Address` and `balance: u64` members.
|
||||
if input.is_record {
|
||||
let check_has_field = |need, expected_ty: Type| match input
|
||||
.members
|
||||
.iter()
|
||||
.find_map(|CircuitMember::CircuitVariable(v, t)| (v.name == need).then(|| (v, t)))
|
||||
{
|
||||
Some((_, actual_ty)) if expected_ty.eq_flat(actual_ty) => {} // All good, found + right type!
|
||||
Some((field, _)) => {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::record_var_wrong_type(field, expected_ty, input.span()).into());
|
||||
}
|
||||
None => {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::required_record_variable(need, expected_ty, input.span()).into());
|
||||
}
|
||||
};
|
||||
check_has_field(sym::owner, Type::Address);
|
||||
check_has_field(sym::balance, Type::IntegerType(IntegerType::U64));
|
||||
}
|
||||
}
|
||||
}
|
@ -19,19 +19,15 @@ use leo_errors::TypeCheckerError;
|
||||
|
||||
use crate::{Declaration, TypeChecker, VariableSymbol};
|
||||
|
||||
use super::director::Director;
|
||||
|
||||
impl<'a> StatementVisitor<'a> for TypeChecker<'a> {}
|
||||
|
||||
impl<'a> StatementVisitorDirector<'a> for Director<'a> {
|
||||
impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_return(&mut self, input: &'a ReturnStatement) {
|
||||
// we can safely unwrap all self.parent instances because
|
||||
// statements should always have some parent block
|
||||
let parent = self.visitor.parent.unwrap();
|
||||
let parent = self.parent.unwrap();
|
||||
|
||||
let return_type = &self.visitor.symbol_table.lookup_fn(&parent).map(|f| f.output);
|
||||
self.visitor.check_ident_type(return_type);
|
||||
self.visitor.has_return = true;
|
||||
let return_type = &self.symbol_table.lookup_fn(parent).map(|f| f.output);
|
||||
self.check_ident_type(return_type);
|
||||
self.has_return = true;
|
||||
|
||||
self.visit_expression(&input.expression, return_type);
|
||||
}
|
||||
@ -44,11 +40,11 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
|
||||
};
|
||||
|
||||
input.variable_names.iter().for_each(|v| {
|
||||
self.visitor.check_ident_type(&Some(input.type_));
|
||||
self.check_ident_type(&Some(input.type_));
|
||||
|
||||
self.visit_expression(&input.value, &Some(input.type_));
|
||||
|
||||
if let Err(err) = self.visitor.symbol_table.insert_variable(
|
||||
if let Err(err) = self.symbol_table.insert_variable(
|
||||
v.identifier.name,
|
||||
VariableSymbol {
|
||||
type_: &input.type_,
|
||||
@ -56,21 +52,27 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
|
||||
declaration: declaration.clone(),
|
||||
},
|
||||
) {
|
||||
self.visitor.handler.emit_err(err);
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_assign(&mut self, input: &'a AssignStatement) {
|
||||
let var_name = &input.assignee.identifier.name;
|
||||
let var_type = if let Some(var) = self.visitor.symbol_table.lookup_variable(var_name) {
|
||||
let var_name = match input.place {
|
||||
Expression::Identifier(id) => id,
|
||||
_ => {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::invalid_assignment_target(input.place.span()).into());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let var_type = if let Some(var) = self.symbol_table.lookup_variable(&var_name.name) {
|
||||
match &var.declaration {
|
||||
Declaration::Const => self
|
||||
.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::cannont_assign_to_const_var(var_name, var.span).into()),
|
||||
Declaration::Input(ParamMode::Const) => self
|
||||
.visitor
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::cannont_assign_to_const_input(var_name, var.span).into()),
|
||||
_ => {}
|
||||
@ -78,15 +80,14 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
|
||||
|
||||
Some(*var.type_)
|
||||
} else {
|
||||
self.visitor.handler.emit_err(
|
||||
TypeCheckerError::unknown_sym("variable", &input.assignee.identifier.name, input.assignee.span).into(),
|
||||
);
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::unknown_sym("variable", var_name.name, var_name.span).into());
|
||||
|
||||
None
|
||||
};
|
||||
|
||||
if var_type.is_some() {
|
||||
self.visitor.check_ident_type(&var_type);
|
||||
self.check_ident_type(&var_type);
|
||||
self.visit_expression(&input.value, &var_type);
|
||||
}
|
||||
}
|
||||
@ -100,7 +101,7 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
|
||||
}
|
||||
|
||||
fn visit_iteration(&mut self, input: &'a IterationStatement) {
|
||||
if let Err(err) = self.visitor.symbol_table.insert_variable(
|
||||
if let Err(err) = self.symbol_table.insert_variable(
|
||||
input.variable.name,
|
||||
VariableSymbol {
|
||||
type_: &input.type_,
|
||||
@ -108,11 +109,11 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
|
||||
declaration: Declaration::Const,
|
||||
},
|
||||
) {
|
||||
self.visitor.handler.emit_err(err);
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
|
||||
let iter_type = &Some(input.type_);
|
||||
self.visitor.check_ident_type(iter_type);
|
||||
self.check_ident_type(iter_type);
|
||||
self.visit_expression(&input.start, iter_type);
|
||||
self.visit_expression(&input.stop, iter_type);
|
||||
}
|
||||
@ -130,7 +131,7 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
|
||||
|
||||
fn visit_block(&mut self, input: &'a Block) {
|
||||
// creates a new sub-scope since we are in a block.
|
||||
self.visitor.symbol_table.push_variable_scope();
|
||||
self.symbol_table.push_variable_scope();
|
||||
input.statements.iter().for_each(|stmt| {
|
||||
match stmt {
|
||||
Statement::Return(stmt) => self.visit_return(stmt),
|
||||
@ -142,6 +143,6 @@ impl<'a> StatementVisitorDirector<'a> for Director<'a> {
|
||||
Statement::Block(stmt) => self.visit_block(stmt),
|
||||
};
|
||||
});
|
||||
self.visitor.symbol_table.pop_variable_scope();
|
||||
self.symbol_table.pop_variable_scope();
|
||||
}
|
||||
}
|
||||
|
@ -87,6 +87,8 @@ const FIELD_GROUP_SCALAR_INT_TYPES: [Type; 13] = create_type_superset(FIELD_GROU
|
||||
|
||||
const FIELD_GROUP_TYPES: [Type; 2] = [Type::Field, Type::Group];
|
||||
|
||||
const FIELD_SCALAR_TYPES: [Type; 2] = [Type::Field, Type::Scalar];
|
||||
|
||||
impl<'a> TypeChecker<'a> {
|
||||
/// Returns a new type checker given a symbol table and error handler.
|
||||
pub fn new(symbol_table: &'a mut SymbolTable<'a>, handler: &'a Handler) -> Self {
|
||||
@ -101,31 +103,33 @@ impl<'a> TypeChecker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Emits a type checker error.
|
||||
pub(crate) fn emit_err(&self, err: TypeCheckerError) {
|
||||
self.handler.emit_err(err.into());
|
||||
}
|
||||
|
||||
/// Emits an error if the given type conflicts with a core library type.
|
||||
pub(crate) fn check_ident_type(&self, type_: &Option<Type>) {
|
||||
if let Some(Type::Identifier(ident)) = type_ {
|
||||
if self.account_types.contains(&ident.name) || self.algorithms_types.contains(&ident.name) {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::core_type_name_conflict(&ident.name, ident.span()).into());
|
||||
self.emit_err(TypeCheckerError::core_type_name_conflict(&ident.name, ident.span()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Emits an error if the `circuit` is not a core library circuit.
|
||||
/// Emits an error if the `function` is not supported by the circuit.
|
||||
pub(crate) fn assert_core_circuit_call(
|
||||
&self,
|
||||
circuit: &Option<Type>,
|
||||
function: &Identifier,
|
||||
) -> Option<CoreInstruction> {
|
||||
if let Some(Type::Identifier(ident)) = circuit {
|
||||
pub(crate) fn assert_core_circuit_call(&self, circuit: &Type, function: &Identifier) -> Option<CoreInstruction> {
|
||||
if let Type::Identifier(ident) = circuit {
|
||||
// Lookup core circuit
|
||||
match CoreInstruction::from_symbols(ident.name, function.name) {
|
||||
None => {
|
||||
// Not a core library circuit.
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::invalid_core_instruction(&ident.name, function.name, ident.span()).into(),
|
||||
);
|
||||
self.emit_err(TypeCheckerError::invalid_core_instruction(
|
||||
&ident.name,
|
||||
function.name,
|
||||
ident.span(),
|
||||
));
|
||||
}
|
||||
Some(core_circuit) => return Some(core_circuit),
|
||||
}
|
||||
@ -136,12 +140,10 @@ impl<'a> TypeChecker<'a> {
|
||||
/// Emits an error if the two given types are not equal.
|
||||
pub(crate) fn assert_eq_types(&self, t1: Option<Type>, t2: Option<Type>, span: Span) {
|
||||
match (t1, t2) {
|
||||
(Some(t1), Some(t2)) if t1 != t2 => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(t1, t2, span).into()),
|
||||
(Some(type_), None) | (None, Some(type_)) => self
|
||||
.handler
|
||||
.emit_err(TypeCheckerError::type_should_be("no type", type_, span).into()),
|
||||
(Some(t1), Some(t2)) if t1 != t2 => self.emit_err(TypeCheckerError::type_should_be(t1, t2, span)),
|
||||
(Some(type_), None) | (None, Some(type_)) => {
|
||||
self.emit_err(TypeCheckerError::type_should_be("no type", type_, span))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -149,9 +151,8 @@ impl<'a> TypeChecker<'a> {
|
||||
/// Returns the `circuit` type and emits an error if the `expected` type does not match.
|
||||
pub(crate) fn assert_expected_circuit(&mut self, circuit: Identifier, expected: &Option<Type>, span: Span) -> Type {
|
||||
if let Some(Type::Identifier(expected)) = expected {
|
||||
if expected.name != circuit.name {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(circuit.name, expected.name, span).into());
|
||||
if !circuit.matches(expected) {
|
||||
self.emit_err(TypeCheckerError::type_should_be(circuit.name, expected.name, span));
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,9 +162,8 @@ impl<'a> TypeChecker<'a> {
|
||||
/// Returns the given `actual` type and emits an error if the `expected` type does not match.
|
||||
pub(crate) fn assert_expected_option(&mut self, actual: Type, expected: &Option<Type>, span: Span) -> Type {
|
||||
if let Some(expected) = expected {
|
||||
if &actual != expected {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(actual, expected, span).into());
|
||||
if !actual.eq_flat(expected) {
|
||||
self.emit_err(TypeCheckerError::type_should_be(actual, expected, span));
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,9 +174,8 @@ impl<'a> TypeChecker<'a> {
|
||||
/// `span` should be the location of the expected type.
|
||||
pub(crate) fn assert_expected_type(&mut self, actual: &Option<Type>, expected: Type, span: Span) -> Type {
|
||||
if let Some(actual) = actual {
|
||||
if actual != &expected {
|
||||
self.handler
|
||||
.emit_err(TypeCheckerError::type_should_be(actual, expected, span).into());
|
||||
if !actual.eq_flat(&expected) {
|
||||
self.emit_err(TypeCheckerError::type_should_be(actual, expected, span));
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,14 +186,11 @@ impl<'a> TypeChecker<'a> {
|
||||
pub(crate) fn assert_one_of_types(&self, type_: &Option<Type>, expected: &[Type], span: Span) {
|
||||
if let Some(type_) = type_ {
|
||||
if !expected.iter().any(|t: &Type| t == type_) {
|
||||
self.handler.emit_err(
|
||||
TypeCheckerError::expected_one_type_of(
|
||||
self.emit_err(TypeCheckerError::expected_one_type_of(
|
||||
expected.iter().map(|t| t.to_string() + ",").collect::<String>(),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,6 +210,11 @@ impl<'a> TypeChecker<'a> {
|
||||
self.assert_one_of_types(type_, &FIELD_GROUP_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field or scalar.
|
||||
pub(crate) fn assert_field_scalar_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_SCALAR_TYPES, span)
|
||||
}
|
||||
|
||||
/// Emits an error to the handler if the given type is not a field, group, or integer.
|
||||
pub(crate) fn assert_field_group_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.assert_one_of_types(type_, &FIELD_GROUP_INT_TYPES, span)
|
||||
|
@ -1,44 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::emitter::Handler;
|
||||
|
||||
use crate::{SymbolTable, TypeChecker};
|
||||
|
||||
pub(crate) struct Director<'a> {
|
||||
pub(crate) visitor: TypeChecker<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Director<'a> {
|
||||
pub(crate) fn new(symbol_table: &'a mut SymbolTable<'a>, handler: &'a Handler) -> Self {
|
||||
Self {
|
||||
visitor: TypeChecker::new(symbol_table, handler),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VisitorDirector<'a> for Director<'a> {
|
||||
type Visitor = TypeChecker<'a>;
|
||||
|
||||
fn visitor(self) -> Self::Visitor {
|
||||
self.visitor
|
||||
}
|
||||
|
||||
fn visitor_ref(&mut self) -> &mut Self::Visitor {
|
||||
&mut self.visitor
|
||||
}
|
||||
}
|
@ -17,8 +17,8 @@
|
||||
pub mod check_expressions;
|
||||
pub use check_expressions::*;
|
||||
|
||||
pub mod check_file;
|
||||
pub use check_file::*;
|
||||
pub mod check_program;
|
||||
pub use check_program::*;
|
||||
|
||||
pub mod check_statements;
|
||||
pub use check_statements::*;
|
||||
@ -26,12 +26,9 @@ pub use check_statements::*;
|
||||
pub mod checker;
|
||||
pub use checker::*;
|
||||
|
||||
pub mod director;
|
||||
use director::*;
|
||||
|
||||
use crate::{Pass, SymbolTable};
|
||||
|
||||
use leo_ast::{Ast, ProgramVisitorDirector};
|
||||
use leo_ast::{Ast, ProgramVisitor};
|
||||
use leo_errors::{emitter::Handler, Result};
|
||||
|
||||
impl<'a> Pass for TypeChecker<'a> {
|
||||
@ -39,7 +36,7 @@ impl<'a> Pass for TypeChecker<'a> {
|
||||
type Output = Result<()>;
|
||||
|
||||
fn do_pass((ast, symbol_table, handler): Self::Input) -> Self::Output {
|
||||
let mut visitor = Director::new(symbol_table, handler);
|
||||
let mut visitor = TypeChecker::new(symbol_table, handler);
|
||||
visitor.visit_program(ast.as_repr());
|
||||
handler.last_err()?;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -48,15 +48,15 @@ not-line-feed-or-carriage-return =
|
||||
; anything but <LF> or <CR>
|
||||
|
||||
not-star-or-line-feed-or-carriage-return =
|
||||
%x0-9/ %xB-C / %xD-29 / %x2B-7F / safe-nonascii
|
||||
%x0-9 / %xB-C / %xE-29 / %x2B-7F / safe-nonascii
|
||||
; anything but * or <LF> or <CR>
|
||||
|
||||
not-star-or-slash-or-line-feed-or-carriage-return =
|
||||
%x0-9 / %xB-C / %xD-29 / %x2B-2E / %x30-7F / safe-nonascii
|
||||
%x0-9 / %xB-C / %xE-29 / %x2B-2E / %x30-7F / safe-nonascii
|
||||
; anything but * or / or <LF> or <CR>
|
||||
|
||||
not-double-quote-or-backslash-or-line-feed-or-carriage-return =
|
||||
%x0-9 / %xB-C / %xD-21 / %x23-5B / %x5D-7F / safe-nonascii
|
||||
%x0-9 / %xB-C / %xE-21 / %x23-5B / %x5D-7F / safe-nonascii
|
||||
; anything but " or \ or <LF> or <CR>
|
||||
|
||||
comment = block-comment / end-of-line-comment
|
||||
@ -78,6 +78,7 @@ end-of-line-comment = "//" *not-line-feed-or-carriage-return
|
||||
|
||||
keyword = %s"address"
|
||||
/ %s"bool"
|
||||
/ %s"circuit"
|
||||
/ %s"console"
|
||||
/ %s"const"
|
||||
/ %s"constant"
|
||||
@ -95,6 +96,7 @@ keyword = %s"address"
|
||||
/ %s"in"
|
||||
/ %s"let"
|
||||
/ %s"public"
|
||||
/ %s"record"
|
||||
/ %s"return"
|
||||
/ %s"scalar"
|
||||
/ %s"string"
|
||||
@ -185,12 +187,14 @@ atomic-literal = numeric-literal
|
||||
symbol = "!" / "&&" / "||"
|
||||
/ "==" / "!="
|
||||
/ "<" / "<=" / ">" / ">="
|
||||
/ "&" / "|" / "^"
|
||||
/ "<<" / ">>"
|
||||
/ "+" / "-" / "*" / "/" / "**"
|
||||
/ "="
|
||||
/ "(" / ")"
|
||||
/ "[" / "]"
|
||||
/ "{" / "}"
|
||||
/ "," / "." / ".." / ";" / ":" / "?"
|
||||
/ "," / "." / ".." / ";" / ":" / "::" / "?"
|
||||
/ "->" / "_"
|
||||
/ %s")group"
|
||||
|
||||
@ -229,7 +233,9 @@ string-type = %s"string"
|
||||
|
||||
primitive-type = boolean-type / arithmetic-type / address-type / string-type
|
||||
|
||||
type = primitive-type / identifier
|
||||
named-type = primitive-type / identifier
|
||||
|
||||
type = named-type
|
||||
|
||||
group-coordinate = ( [ "-" ] numeral ) / "+" / "-" / "_"
|
||||
|
||||
@ -239,18 +245,37 @@ literal = atomic-literal / affine-group-literal
|
||||
|
||||
group-literal = product-group-literal / affine-group-literal
|
||||
|
||||
primary-expression = identifier
|
||||
/ literal
|
||||
primary-expression = literal
|
||||
/ variable-or-free-constant
|
||||
/ associated-constant
|
||||
/ "(" expression ")"
|
||||
/ function-call
|
||||
/ free-function-call
|
||||
/ static-function-call
|
||||
/ circuit-expression
|
||||
|
||||
function-call = identifier function-arguments
|
||||
variable-or-free-constant = identifier
|
||||
|
||||
associated-constant = named-type "::" identifier
|
||||
|
||||
free-function-call = identifier function-arguments
|
||||
|
||||
static-function-call = named-type "::" identifier function-arguments
|
||||
|
||||
function-arguments = "(" [ expression *( "," expression ) [ "," ] ] ")"
|
||||
|
||||
circuit-expression = identifier "{" circuit-component-initializer
|
||||
*( "," circuit-component-initializer )
|
||||
[ "," ] "}"
|
||||
|
||||
circuit-component-initializer = identifier
|
||||
/ identifier ":" expression
|
||||
|
||||
postfix-expression = primary-expression
|
||||
/ circuit-component-expression
|
||||
/ operator-call
|
||||
|
||||
circuit-component-expression = postfix-expression "." identifier
|
||||
|
||||
operator-call = unary-operator-call / binary-operator-call
|
||||
|
||||
unary-operator-call = postfix-expression "." identifier "(" ")"
|
||||
@ -277,40 +302,41 @@ shift-expression = additive-expression
|
||||
/ shift-expression "<<" additive-expression
|
||||
/ shift-expression ">>" additive-expression
|
||||
|
||||
bitwise-and-expression = shift-expression
|
||||
/ bitwise-and-expression "&" shift-expression
|
||||
conjunctive-expression = shift-expression
|
||||
/ conjunctive-expression "&" shift-expression
|
||||
|
||||
bitwise-inclusive-or-expression =
|
||||
bitwise-and-expression
|
||||
/ bitwise-inclusive-or-expression "|" bitwise-and-expression
|
||||
disjunctive-expression = conjunctive-expression
|
||||
/ disjunctive-expression "|" conjunctive-expression
|
||||
|
||||
bitwise-exclusive-or-expression =
|
||||
bitwise-inclusive-or-expression
|
||||
/ bitwise-exclusive-or-expression "^" bitwise-inclusive-or-expression
|
||||
exclusive-disjunctive-expression =
|
||||
disjunctive-expression
|
||||
/ exclusive-disjunctive-expression "^" disjunctive-expression
|
||||
|
||||
ordering-expression =
|
||||
bitwise-exclusive-or-expression
|
||||
/ bitwise-exclusive-or-expression "<" bitwise-exclusive-or-expression
|
||||
/ bitwise-exclusive-or-expression ">" bitwise-exclusive-or-expression
|
||||
/ bitwise-exclusive-or-expression "<=" bitwise-exclusive-or-expression
|
||||
/ bitwise-exclusive-or-expression ">=" bitwise-exclusive-or-expression
|
||||
exclusive-disjunctive-expression
|
||||
/ exclusive-disjunctive-expression "<" exclusive-disjunctive-expression
|
||||
/ exclusive-disjunctive-expression ">" exclusive-disjunctive-expression
|
||||
/ exclusive-disjunctive-expression "<=" exclusive-disjunctive-expression
|
||||
/ exclusive-disjunctive-expression ">=" exclusive-disjunctive-expression
|
||||
|
||||
equality-expression = ordering-expression
|
||||
/ ordering-expression "==" ordering-expression
|
||||
/ ordering-expression "!=" ordering-expression
|
||||
|
||||
boolean-and-expression = equality-expression
|
||||
/ boolean-and-expression "&&" equality-expression
|
||||
conditional-conjunctive-expression =
|
||||
equality-expression
|
||||
/ conditional-conjunctive-expression "&&" equality-expression
|
||||
|
||||
boolean-or-expression = boolean-and-expression
|
||||
/ boolean-or-expression "||" boolean-and-expression
|
||||
conditional-disjunctive-expression =
|
||||
conditional-conjunctive-expression
|
||||
/ conditional-disjunctive-expression "||" conditional-conjunctive-expression
|
||||
|
||||
binary-expression = boolean-or-expression
|
||||
binary-expression = conditional-disjunctive-expression
|
||||
|
||||
conditional-expression = binary-expression
|
||||
conditional-ternary-expression = binary-expression
|
||||
/ binary-expression "?" expression ":" expression
|
||||
|
||||
expression = conditional-expression
|
||||
expression = conditional-ternary-expression
|
||||
|
||||
statement = return-statement
|
||||
/ variable-declaration
|
||||
@ -365,7 +391,19 @@ function-parameters = function-parameter *( "," function-parameter ) [ "," ]
|
||||
function-parameter = [ %s"public" / %s"constant" / %s"const" ]
|
||||
identifier ":" type
|
||||
|
||||
circuit-declaration = %s"circuit" "{" circuit-component-declaration
|
||||
*( "," circuit-component-declaration )
|
||||
[ "," ] "}"
|
||||
|
||||
circuit-component-declaration = identifier ":" type
|
||||
|
||||
record-declaration = %s"record" "{" circuit-component-declaration
|
||||
*( "," circuit-component-declaration )
|
||||
[ "," ] "}"
|
||||
|
||||
declaration = function-declaration
|
||||
/ circuit-declaration
|
||||
/ record-declaration
|
||||
|
||||
file = *declaration
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
[main]
|
||||
a: u8 = 1u8;
|
||||
|
||||
[registers]
|
||||
r0: field = 1field;
|
||||
r1: field = 1field;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// CAUTION: Work in progress
|
||||
|
||||
circuit Token {
|
||||
record Token {
|
||||
// The token owner.
|
||||
owner: address,
|
||||
// The Aleo balance (in gates).
|
||||
@ -11,17 +11,18 @@ circuit Token {
|
||||
|
||||
circuit Receiver {
|
||||
// The token owner.
|
||||
owner: Address,
|
||||
owner: address,
|
||||
// The token amount.
|
||||
amount: u64,
|
||||
}
|
||||
|
||||
function mint(r0: address, r1: u64) -> Token {
|
||||
return Token {
|
||||
let t: Token = Token {
|
||||
owner: r0,
|
||||
balance: 0u64,
|
||||
amount: r1,
|
||||
};
|
||||
return t;
|
||||
}
|
||||
|
||||
// The `transfer` function sends the specified number of tokens
|
||||
@ -42,7 +43,7 @@ function transfer(r0: Token, r1: Receiver) -> Token {
|
||||
let r4: Token = mint(r0.owner, r0.amount);
|
||||
|
||||
// return (r3, r4);
|
||||
return r3
|
||||
return r3;
|
||||
}
|
||||
|
||||
function main() -> u8 {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
@ -179,17 +179,17 @@ impl Command for Build {
|
||||
tracing::info!("Printing bytecode...\n");
|
||||
println!("{}", bytecode);
|
||||
|
||||
{
|
||||
// Initialize AVM bytecode.
|
||||
Process::from_str(&bytecode);
|
||||
|
||||
// Run program todo: run with real inputs.
|
||||
// Run the `HelloWorld` program with the given inputs.
|
||||
let first = Value::from_str("1field.public");
|
||||
let second = Value::from_str("1field.private");
|
||||
let output = Process::get_function(&Identifier::from_str("main")).unwrap().evaluate(&[first, second]);
|
||||
println!("program output: {}", output.first().unwrap());
|
||||
}
|
||||
// {
|
||||
// // Initialize AVM bytecode.
|
||||
// Process::from_str(&bytecode);
|
||||
//
|
||||
// // Run program todo: run with real inputs.
|
||||
// // Run the `HelloWorld` program with the given inputs.
|
||||
// let first = Value::from_str("1field.public");
|
||||
// let second = Value::from_str("1field.private");
|
||||
// let output = Process::get_function(&Identifier::from_str("main")).unwrap().evaluate(&[first, second]);
|
||||
// println!("program output: {}\n", output.first().unwrap());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
@ -35,7 +35,7 @@ version = "0.5.1"
|
||||
version = "2.2.0"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.137"
|
||||
version = "1.0.138"
|
||||
features = [ "derive", "rc" ]
|
||||
|
||||
[dependencies.thiserror]
|
||||
|
@ -155,6 +155,14 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when a user shadows a record.
|
||||
@formatted
|
||||
shadowed_record {
|
||||
args: (record: impl Display),
|
||||
msg: format!("record `{record}` shadowed by"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when a user shadows a variable.
|
||||
@formatted
|
||||
shadowed_variable {
|
||||
|
@ -120,14 +120,6 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the parser encountered an invalid assignment target.
|
||||
@formatted
|
||||
invalid_assignment_target {
|
||||
args: (),
|
||||
msg: "invalid assignment target",
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the parser encountered an invalid package name.
|
||||
@formatted
|
||||
invalid_package_name {
|
||||
@ -359,19 +351,19 @@ create_messages!(
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Previously, expression statements were allowed, but not anymore.
|
||||
/// Parsed an expression statement.
|
||||
@formatted
|
||||
expr_stmts_disallowed {
|
||||
args: (),
|
||||
msg: "Expression statements are no longer supported.",
|
||||
msg: "Expression statements are not supported.",
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Previously, arbitrary methods were allowed, but not anymore.
|
||||
/// Parsed an unknown method call on the type of an expression.
|
||||
@formatted
|
||||
expr_arbitrary_method_call {
|
||||
args: (),
|
||||
msg: "Arbitrary methods calls are not supported. Only special ones are.",
|
||||
invalid_method_call {
|
||||
args: (expr: impl Display, func: impl Display),
|
||||
msg: format!("The type of `{expr}` has no associated function `{func}`"),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@ -379,7 +371,22 @@ create_messages!(
|
||||
@formatted
|
||||
circuit_functions_unstable {
|
||||
args: (),
|
||||
msg: "Circuit functions are currently an unstable feature and are disabled in Leo for testnet3",
|
||||
msg: "Circuit functions are currently an unstable feature and are disabled in Leo for testnet3.",
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Circuit constants are unstable in testnet3.
|
||||
@formatted
|
||||
circuit_constants_unstable {
|
||||
args: (),
|
||||
msg: "Circuit constants are currently an unstable feature and are disabled in Leo for testnet3.",
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
invalid_associated_access {
|
||||
args: (name: impl Display),
|
||||
msg: format!("Invalid associated access call to circuit {name}."),
|
||||
help: Some("Double colon `::` syntax is only supported for core circuits in Leo for testnet3.".to_string()),
|
||||
}
|
||||
);
|
||||
|
@ -23,6 +23,14 @@ create_messages!(
|
||||
code_mask: 2000i32,
|
||||
code_prefix: "TYC",
|
||||
|
||||
/// For when the parser encountered an invalid assignment target.
|
||||
@formatted
|
||||
invalid_assignment_target {
|
||||
args: (),
|
||||
msg: "invalid assignment target",
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the user tries to assign to a const input.
|
||||
@formatted
|
||||
cannont_assign_to_const_input {
|
||||
@ -182,4 +190,85 @@ create_messages!(
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// For when the user tries initialize a circuit with the incorrect number of args.
|
||||
@formatted
|
||||
incorrect_num_record_variables {
|
||||
args: (expected: impl Display, received: impl Display),
|
||||
msg: format!(
|
||||
"Record expected `{expected}` variables, but got `{received}`",
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// An invalid access call is made e.g., `bool::MAX`
|
||||
@formatted
|
||||
invalid_access_expression {
|
||||
args: (expr: impl Display),
|
||||
msg: format!(
|
||||
"Invalid method call to {expr}."
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Attempted to define more that one circuit member with the same name.
|
||||
@formatted
|
||||
duplicate_circuit_member {
|
||||
args: (circuit: impl Display),
|
||||
msg: format!(
|
||||
"Circuit {circuit} defined with more than one member with the same name."
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Attempted to define more that one record variable with the same name.
|
||||
@formatted
|
||||
duplicate_record_variable {
|
||||
args: (record: impl Display),
|
||||
msg: format!(
|
||||
"Record {record} defined with more than one variable with the same name."
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Attempted to access an invalid circuit.
|
||||
@formatted
|
||||
invalid_circuit {
|
||||
args: (circuit: impl Display),
|
||||
msg: format!(
|
||||
"Circuit {circuit} is not found in the current scope."
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
/// Attempted to access an invalid circuit variable.
|
||||
@formatted
|
||||
invalid_circuit_variable {
|
||||
args: (variable: impl Display, circuit: impl Display),
|
||||
msg: format!(
|
||||
"Circuit variable {variable} is not a member of circuit {circuit}."
|
||||
),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
required_record_variable {
|
||||
args: (name: impl Display, type_: impl Display),
|
||||
msg: format!("The `record` type requires the variable `{name}: {type_}`."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
record_var_wrong_type {
|
||||
args: (name: impl Display, type_: impl Display),
|
||||
msg: format!("The field `{name}` in a `record` must have type `{type_}`."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
compare_address {
|
||||
args: (operator: impl Display),
|
||||
msg: format!("Comparison `{operator}` is not supported for the address type."),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2019-2021 Aleo Systems Inc.
|
||||
// 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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user