impl codegen for testnet3

This commit is contained in:
collin 2022-07-06 00:48:54 -07:00
commit ade332442a
648 changed files with 6148 additions and 5946 deletions

View File

@ -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/"
]
}

View File

@ -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

View File

@ -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
View File

@ -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",

View File

@ -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
View 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(".");
}

View File

@ -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);

View File

@ -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);

View File

@ -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::*;

View File

@ -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);

View File

@ -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),
}
}
}

View File

@ -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),
}
}
}

View File

@ -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)
}
}

View File

@ -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),
}
}
}

View File

@ -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,
})
}

View File

@ -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,
},
}
}

View File

@ -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),
}
}
}

View File

@ -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::*;

View File

@ -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))?
}

View File

@ -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::*;

View File

@ -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)
}
}

View File

@ -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() })
}
}

View 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
}
}

View File

@ -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) {}
}

View File

@ -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(_, _) => {}
};
})
}
}
}

View File

@ -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
}

View File

@ -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, "")
}
}

View File

@ -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)
}
}

View File

@ -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"),

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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] {

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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,
},
))

View File

@ -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))
}

View File

@ -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()
}

View File

@ -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 })),
}
}

View File

@ -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"),

View File

@ -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(),
}
}
}

View File

@ -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) {

View File

@ -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()
))
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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> {}

View File

@ -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())
}
}

View File

@ -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")?;

View File

@ -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)

View File

@ -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
}

View File

@ -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());
}
}
}
}

View 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));
}
}
}

View File

@ -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();
}
}

View File

@ -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)

View File

@ -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
}
}

View File

@ -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()?;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,4 +1,3 @@
[main]
a: u8 = 1u8;
[registers]
r0: field = 1field;
r1: field = 1field;

View File

@ -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 {

View File

@ -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

View File

@ -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());
// }
// }
// }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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 {

View File

@ -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()),
}
);

View File

@ -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,
}
);

View File

@ -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